pci-layerscape.c 7.3 KB
Newer Older
1 2 3 4 5
/*
 * PCIe host controller driver for Freescale Layerscape SoCs
 *
 * Copyright (C) 2014 Freescale Semiconductor.
 *
6
 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
7 8 9 10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/interrupt.h>
15
#include <linux/init.h>
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/resource.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>

#include "pcie-designware.h"

/* PEX1/2 Misc Ports Status Register */
#define SCFG_PEXMSCPORTSR(pex_idx)	(0x94 + (pex_idx) * 4)
#define LTSSM_STATE_SHIFT	20
#define LTSSM_STATE_MASK	0x3f
#define LTSSM_PCIE_L0		0x11 /* L0 state */

34 35 36 37
/* PEX Internal Configuration Registers */
#define PCIE_STRFMR1		0x71c /* Symbol Timer & Filter Mask Register1 */
#define PCIE_DBI_RO_WR_EN	0x8bc /* DBI Read-Only Write Enable Register */

38
struct ls_pcie_drvdata {
39 40
	u32 lut_offset;
	u32 ltssm_shift;
M
Mingkai Hu 已提交
41
	u32 lut_dbg;
42
	const struct dw_pcie_host_ops *ops;
43
	const struct dw_pcie_ops *dw_pcie_ops;
44 45
};

46
struct ls_pcie {
47
	struct dw_pcie *pci;
48
	void __iomem *lut;
49
	struct regmap *scfg;
50
	const struct ls_pcie_drvdata *drvdata;
51 52 53
	int index;
};

54
#define to_ls_pcie(x)	dev_get_drvdata((x)->dev)
55

56 57
static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
{
58
	struct dw_pcie *pci = pcie->pci;
59 60
	u32 header_type;

61
	header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE);
62 63 64 65 66
	header_type &= 0x7f;

	return header_type == PCI_HEADER_TYPE_BRIDGE;
}

67 68 69
/* Clear multi-function bit */
static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
{
70 71 72
	struct dw_pcie *pci = pcie->pci;

	iowrite8(PCI_HEADER_TYPE_BRIDGE, pci->dbi_base + PCI_HEADER_TYPE);
73 74 75 76 77
}

/* Fix class value */
static void ls_pcie_fix_class(struct ls_pcie *pcie)
{
78 79 80
	struct dw_pcie *pci = pcie->pci;

	iowrite16(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
81 82
}

83 84 85 86
/* Drop MSG TLP except for Vendor MSG */
static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
{
	u32 val;
87
	struct dw_pcie *pci = pcie->pci;
88

89
	val = ioread32(pci->dbi_base + PCIE_STRFMR1);
90
	val &= 0xDFFFFFFF;
91
	iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
92 93
}

94
static int ls1021_pcie_link_up(struct dw_pcie *pci)
95 96
{
	u32 state;
97
	struct ls_pcie *pcie = to_ls_pcie(pci);
98

99 100 101
	if (!pcie->scfg)
		return 0;

102 103 104 105 106 107 108 109 110
	regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
	state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;

	if (state < LTSSM_PCIE_L0)
		return 0;

	return 1;
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
static int ls_pcie_link_up(struct dw_pcie *pci)
{
	struct ls_pcie *pcie = to_ls_pcie(pci);
	u32 state;

	state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >>
		 pcie->drvdata->ltssm_shift) &
		 LTSSM_STATE_MASK;

	if (state < LTSSM_PCIE_L0)
		return 0;

	return 1;
}

static int ls_pcie_host_init(struct pcie_port *pp)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct ls_pcie *pcie = to_ls_pcie(pci);

	iowrite32(1, pci->dbi_base + PCIE_DBI_RO_WR_EN);
	ls_pcie_fix_class(pcie);
	ls_pcie_clear_multifunction(pcie);
	iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);

	ls_pcie_drop_msg_tlp(pcie);

	dw_pcie_setup_rc(pp);

	return 0;
}

143
static int ls1021_pcie_host_init(struct pcie_port *pp)
144
{
145 146 147
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct ls_pcie *pcie = to_ls_pcie(pci);
	struct device *dev = pci->dev;
148
	u32 index[2];
149
	int ret;
150

151
	pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
152 153
						     "fsl,pcie-scfg");
	if (IS_ERR(pcie->scfg)) {
154
		ret = PTR_ERR(pcie->scfg);
155
		dev_err(dev, "No syscfg phandle specified\n");
156
		pcie->scfg = NULL;
157
		return ret;
158 159
	}

160
	if (of_property_read_u32_array(dev->of_node,
161 162
				       "fsl,pcie-scfg", index, 2)) {
		pcie->scfg = NULL;
163
		return -EINVAL;
164 165
	}
	pcie->index = index[1];
166

167
	return ls_pcie_host_init(pp);
168 169
}

170 171 172
static int ls_pcie_msi_host_init(struct pcie_port *pp,
				 struct msi_controller *chip)
{
173 174
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct device *dev = pci->dev;
175
	struct device_node *np = dev->of_node;
176 177 178 179 180 181 182 183 184 185
	struct device_node *msi_node;

	/*
	 * The MSI domain is set by the generic of_msi_configure().  This
	 * .msi_host_init() function keeps us from doing the default MSI
	 * domain setup in dw_pcie_host_init() and also enforces the
	 * requirement that "msi-parent" exists.
	 */
	msi_node = of_parse_phandle(np, "msi-parent", 0);
	if (!msi_node) {
186
		dev_err(dev, "failed to find msi-parent\n");
187 188 189 190 191 192
		return -EINVAL;
	}

	return 0;
}

193
static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
194
	.host_init = ls1021_pcie_host_init,
195
	.msi_host_init = ls_pcie_msi_host_init,
196 197
};

198
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
199
	.host_init = ls_pcie_host_init,
200
	.msi_host_init = ls_pcie_msi_host_init,
201 202
};

203 204 205 206 207 208 209 210
static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
	.link_up = ls1021_pcie_link_up,
};

static const struct dw_pcie_ops dw_ls_pcie_ops = {
	.link_up = ls_pcie_link_up,
};

211 212
static struct ls_pcie_drvdata ls1021_drvdata = {
	.ops = &ls1021_pcie_host_ops,
213
	.dw_pcie_ops = &dw_ls1021_pcie_ops,
214 215
};

216 217 218
static struct ls_pcie_drvdata ls1043_drvdata = {
	.lut_offset = 0x10000,
	.ltssm_shift = 24,
M
Mingkai Hu 已提交
219 220
	.lut_dbg = 0x7fc,
	.ops = &ls_pcie_host_ops,
221
	.dw_pcie_ops = &dw_ls_pcie_ops,
M
Mingkai Hu 已提交
222 223 224 225 226 227
};

static struct ls_pcie_drvdata ls1046_drvdata = {
	.lut_offset = 0x80000,
	.ltssm_shift = 24,
	.lut_dbg = 0x407fc,
228
	.ops = &ls_pcie_host_ops,
229
	.dw_pcie_ops = &dw_ls_pcie_ops,
230 231 232 233 234
};

static struct ls_pcie_drvdata ls2080_drvdata = {
	.lut_offset = 0x80000,
	.ltssm_shift = 0,
M
Mingkai Hu 已提交
235
	.lut_dbg = 0x7fc,
236
	.ops = &ls_pcie_host_ops,
237
	.dw_pcie_ops = &dw_ls_pcie_ops,
238 239
};

240 241
static const struct of_device_id ls_pcie_of_match[] = {
	{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
242
	{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
M
Mingkai Hu 已提交
243
	{ .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
244
	{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
245
	{ .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
246 247 248
	{ },
};

249
static int __init ls_add_pcie_port(struct ls_pcie *pcie)
250
{
251 252 253
	struct dw_pcie *pci = pcie->pci;
	struct pcie_port *pp = &pci->pp;
	struct device *dev = pci->dev;
254 255
	int ret;

256 257
	pp->ops = pcie->drvdata->ops;

258 259
	ret = dw_pcie_host_init(pp);
	if (ret) {
260
		dev_err(dev, "failed to initialize host\n");
261 262 263 264 265 266 267 268
		return ret;
	}

	return 0;
}

static int __init ls_pcie_probe(struct platform_device *pdev)
{
269
	struct device *dev = &pdev->dev;
270
	struct dw_pcie *pci;
271 272 273 274
	struct ls_pcie *pcie;
	struct resource *dbi_base;
	int ret;

275
	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
276 277 278
	if (!pcie)
		return -ENOMEM;

279 280 281 282
	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
	if (!pci)
		return -ENOMEM;

283
	pcie->drvdata = of_device_get_match_data(dev);
284 285 286

	pci->dev = dev;
	pci->ops = pcie->drvdata->dw_pcie_ops;
287

288 289
	pcie->pci = pci;

290
	dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
291
	pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
292 293
	if (IS_ERR(pci->dbi_base))
		return PTR_ERR(pci->dbi_base);
294

295
	pcie->lut = pci->dbi_base + pcie->drvdata->lut_offset;
296

297 298 299
	if (!ls_pcie_is_bridge(pcie))
		return -ENODEV;

300 301
	platform_set_drvdata(pdev, pcie);

302
	ret = ls_add_pcie_port(pcie);
303 304 305 306 307 308 309 310 311 312
	if (ret < 0)
		return ret;

	return 0;
}

static struct platform_driver ls_pcie_driver = {
	.driver = {
		.name = "layerscape-pcie",
		.of_match_table = ls_pcie_of_match,
313
		.suppress_bind_attrs = true,
314 315
	},
};
316
builtin_platform_driver_probe(ls_pcie_driver, ls_pcie_probe);