2 * PCIe host controller driver for Freescale Layerscape SoCs
4 * Copyright (C) 2014 Freescale Semiconductor.
6 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/kernel.h>
14 #include <linux/delay.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/of_pci.h>
18 #include <linux/of_platform.h>
19 #include <linux/of_irq.h>
20 #include <linux/of_address.h>
21 #include <linux/pci.h>
22 #include <linux/platform_device.h>
23 #include <linux/resource.h>
24 #include <linux/mfd/syscon.h>
25 #include <linux/regmap.h>
27 #include "pcie-designware.h"
29 /* PEX1/2 Misc Ports Status Register */
30 #define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
31 #define LTSSM_STATE_SHIFT 20
32 #define LTSSM_STATE_MASK 0x3f
33 #define LTSSM_PCIE_L0 0x11 /* L0 state */
35 /* Symbol Timer Register and Filter Mask Register 1 */
36 #define PCIE_STRFMR1 0x71c
39 struct list_head node
;
49 #define to_ls_pcie(x) container_of(x, struct ls_pcie, pp)
51 static int ls_pcie_link_up(struct pcie_port
*pp
)
54 struct ls_pcie
*pcie
= to_ls_pcie(pp
);
56 regmap_read(pcie
->scfg
, SCFG_PEXMSCPORTSR(pcie
->index
), &state
);
57 state
= (state
>> LTSSM_STATE_SHIFT
) & LTSSM_STATE_MASK
;
59 if (state
< LTSSM_PCIE_L0
)
65 static int ls_pcie_establish_link(struct pcie_port
*pp
)
69 while (!dw_pcie_link_up(pp
)) {
70 usleep_range(100, 1000);
73 dev_err(pp
->dev
, "phy link never came up\n");
81 static void ls_pcie_host_init(struct pcie_port
*pp
)
83 struct ls_pcie
*pcie
= to_ls_pcie(pp
);
87 ls_pcie_establish_link(pp
);
90 * LS1021A Workaround for internal TKT228622
91 * to fix the INTx hang issue
93 val
= ioread32(pcie
->dbi
+ PCIE_STRFMR1
);
95 iowrite32(val
, pcie
->dbi
+ PCIE_STRFMR1
);
98 static struct pcie_host_ops ls_pcie_host_ops
= {
99 .link_up
= ls_pcie_link_up
,
100 .host_init
= ls_pcie_host_init
,
103 static int ls_add_pcie_port(struct ls_pcie
*pcie
)
105 struct pcie_port
*pp
;
110 pp
->dbi_base
= pcie
->dbi
;
111 pp
->root_bus_nr
= -1;
112 pp
->ops
= &ls_pcie_host_ops
;
114 ret
= dw_pcie_host_init(pp
);
116 dev_err(pp
->dev
, "failed to initialize host\n");
123 static int __init
ls_pcie_probe(struct platform_device
*pdev
)
125 struct ls_pcie
*pcie
;
126 struct resource
*dbi_base
;
130 pcie
= devm_kzalloc(&pdev
->dev
, sizeof(*pcie
), GFP_KERNEL
);
134 pcie
->dev
= &pdev
->dev
;
136 dbi_base
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "regs");
137 pcie
->dbi
= devm_ioremap_resource(&pdev
->dev
, dbi_base
);
138 if (IS_ERR(pcie
->dbi
)) {
139 dev_err(&pdev
->dev
, "missing *regs* space\n");
140 return PTR_ERR(pcie
->dbi
);
143 pcie
->scfg
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
145 if (IS_ERR(pcie
->scfg
)) {
146 dev_err(&pdev
->dev
, "No syscfg phandle specified\n");
147 return PTR_ERR(pcie
->scfg
);
150 ret
= of_property_read_u32_array(pdev
->dev
.of_node
,
151 "fsl,pcie-scfg", index
, 2);
154 pcie
->index
= index
[1];
156 ret
= ls_add_pcie_port(pcie
);
160 platform_set_drvdata(pdev
, pcie
);
165 static const struct of_device_id ls_pcie_of_match
[] = {
166 { .compatible
= "fsl,ls1021a-pcie" },
169 MODULE_DEVICE_TABLE(of
, ls_pcie_of_match
);
171 static struct platform_driver ls_pcie_driver
= {
173 .name
= "layerscape-pcie",
174 .of_match_table
= ls_pcie_of_match
,
178 module_platform_driver_probe(ls_pcie_driver
, ls_pcie_probe
);
180 MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>");
181 MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver");
182 MODULE_LICENSE("GPL v2");