blob: f105356cb98bf97d268c99dd8e8363a617188946 [file] [log] [blame]
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -06001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/*
14 * MSM PCIe controller driver.
15 */
16
17#define pr_fmt(fmt) "%s: " fmt, __func__
18
Steve Mucklef132c6c2012-06-06 18:30:57 -070019#include <linux/module.h>
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060020#include <linux/bitops.h>
21#include <linux/clk.h>
22#include <linux/debugfs.h>
23#include <linux/delay.h>
24#include <linux/gpio.h>
25#include <linux/iopoll.h>
26#include <linux/kernel.h>
27#include <linux/pci.h>
28#include <linux/platform_device.h>
29#include <linux/regulator/consumer.h>
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -060030#include <linux/slab.h>
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060031#include <linux/types.h>
32#include <asm/mach/pci.h>
33#include <mach/gpiomux.h>
34#include <mach/hardware.h>
35#include <mach/msm_iomap.h>
36
37#include "pcie.h"
38
39/* Root Complex Port vendor/device IDs */
40#define PCIE_VENDOR_ID_RCP 0x17cb
41#define PCIE_DEVICE_ID_RCP 0x0101
42
43#define PCIE20_PARF_PCS_DEEMPH 0x34
44#define PCIE20_PARF_PCS_SWING 0x38
45#define PCIE20_PARF_PHY_CTRL 0x40
46#define PCIE20_PARF_PHY_REFCLK 0x4C
47#define PCIE20_PARF_CONFIG_BITS 0x50
48
49#define PCIE20_ELBI_SYS_CTRL 0x04
50
51#define PCIE20_CAP 0x70
52#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
53
54#define PCIE20_COMMAND_STATUS 0x04
55#define PCIE20_BUSNUMBERS 0x18
56#define PCIE20_MEMORY_BASE_LIMIT 0x20
57
58#define PCIE20_PLR_IATU_VIEWPORT 0x900
59#define PCIE20_PLR_IATU_CTRL1 0x904
60#define PCIE20_PLR_IATU_CTRL2 0x908
61#define PCIE20_PLR_IATU_LBAR 0x90C
62#define PCIE20_PLR_IATU_UBAR 0x910
63#define PCIE20_PLR_IATU_LAR 0x914
64#define PCIE20_PLR_IATU_LTAR 0x918
65#define PCIE20_PLR_IATU_UTAR 0x91c
66
67#define PCIE_RESET (MSM_CLK_CTL_BASE + 0x22dc)
68#define PCIE_SFAB_AXI_S5_FCLK_CTL (MSM_CLK_CTL_BASE + 0x2154)
69
70#define MSM_PCIE_DEV_BAR_ADDR PCIBIOS_MIN_MEM
71#define MSM_PCIE_DEV_CFG_ADDR 0x01000000
72
73#define RD 0
74#define WR 1
75
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -060076/* PCIE AXI address space */
77#define PCIE_AXI_CONF_SIZE SZ_1M
78
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060079/* debug mask sys interface */
80static int msm_pcie_debug_mask;
81module_param_named(debug_mask, msm_pcie_debug_mask,
82 int, S_IRUGO | S_IWUSR | S_IWGRP);
83
84/* resources from device file */
85enum msm_pcie_res {
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -060086 /* platform defined resources */
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060087 MSM_PCIE_RES_PARF,
88 MSM_PCIE_RES_ELBI,
89 MSM_PCIE_RES_PCIE20,
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -060090 MSM_PCIE_MAX_PLATFORM_RES,
91
92 /* other resources */
93 MSM_PCIE_RES_AXI_CONF = MSM_PCIE_MAX_PLATFORM_RES,
94 MSM_PCIE_MAX_RES,
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060095};
96
97/* msm pcie device data */
98static struct msm_pcie_dev_t msm_pcie_dev;
99
100/* regulators */
101static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
102 {NULL, "vp_pcie", 1050000, 1050000, 40900},
103 {NULL, "vptx_pcie", 1050000, 1050000, 18200},
104 {NULL, "vdd_pcie_vph", 0, 0, 0},
105 {NULL, "pcie_ext_3p3v", 0, 0, 0}
106};
107
108/* clocks */
109static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
110 {NULL, "bus_clk"},
111 {NULL, "iface_clk"},
112 {NULL, "ref_clk"}
113};
114
115/* resources */
116static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600117 {"pcie_parf", 0, 0},
118 {"pcie_elbi", 0, 0},
119 {"pcie20", 0, 0},
120 {"pcie_axi_conf", 0, 0},
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600121};
122
123int msm_pcie_get_debug_mask(void)
124{
125 return msm_pcie_debug_mask;
126}
127
128static void msm_pcie_write_mask(void __iomem *addr,
129 uint32_t clear_mask, uint32_t set_mask)
130{
131 uint32_t val;
132
133 val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
134 writel_relaxed(val, addr);
135 wmb(); /* ensure data is written to hardware register */
136}
137
138static int msm_pcie_is_link_up(void)
139{
140 return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
141 BIT(29);
142}
143
144static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
145 int where, int size, u32 *val)
146{
147 uint32_t word_offset, byte_offset, mask;
148 uint32_t rd_val, wr_val;
149 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
150 void __iomem *config_base;
151
152 /*
153 * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
154 * For downstream bus (1), make sure link is up
155 */
156 if ((bus->number > 1) || (devfn != 0)) {
157 PCIE_DBG("invalid %s - bus %d devfn %d\n",
158 (oper == RD) ? "rd" : "wr", bus->number, devfn);
159 *val = ~0;
160 return PCIBIOS_DEVICE_NOT_FOUND;
161 } else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
162 PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
163 (oper == RD) ? "rd" : "wr", bus->number, devfn);
164 *val = ~0;
165 return PCIBIOS_DEVICE_NOT_FOUND;
166 }
167
168 word_offset = where & ~0x3;
169 byte_offset = where & 0x3;
170 mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
171
172 config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
173 rd_val = readl_relaxed(config_base + word_offset);
174
175 if (oper == RD) {
176 *val = ((rd_val & mask) >> (8 * byte_offset));
177
178 PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
179 bus->number, devfn, where, size, *val, rd_val);
180 } else {
181 wr_val = (rd_val & ~mask) |
182 ((*val << (8 * byte_offset)) & mask);
183 writel_relaxed(wr_val, config_base + word_offset);
184 wmb(); /* ensure config data is written to hardware register */
185
186 PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
187 " rd 0x%08x val 0x%08x\n", bus->number,
188 devfn, where, size, wr_val, rd_val, *val);
189 }
190
191 return 0;
192}
193
194static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
195 int size, u32 *val)
196{
197 return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
198}
199
200static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
201 int where, int size, u32 val)
202{
203 return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
204}
205
206static struct pci_ops msm_pcie_ops = {
207 .read = msm_pcie_rd_conf,
208 .write = msm_pcie_wr_conf,
209};
210
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600211static int __init msm_pcie_gpio_init(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600212{
213 int rc, i;
214 struct msm_pcie_gpio_info_t *info;
215
216 for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
217 info = &msm_pcie_dev.gpio[i];
218
219 rc = gpio_request(info->num, info->name);
220 if (rc) {
221 pr_err("can't get gpio %s; %d\n", info->name, rc);
222 break;
223 }
224
225 rc = gpio_direction_output(info->num, 0);
226 if (rc) {
227 pr_err("can't set gpio direction %s; %d\n",
228 info->name, rc);
229 gpio_free(info->num);
230 break;
231 }
232 }
233
234 if (rc)
235 while (i--)
236 gpio_free(msm_pcie_dev.gpio[i].num);
237
238 return rc;
239}
240
241static void msm_pcie_gpio_deinit(void)
242{
243 int i;
244
245 for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
246 gpio_free(msm_pcie_dev.gpio[i].num);
247}
248
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600249static int __init msm_pcie_vreg_init(struct device *dev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600250{
251 int i, rc = 0;
252 struct regulator *vreg;
253 struct msm_pcie_vreg_info_t *info;
254
255 for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
256 info = &msm_pcie_dev.vreg[i];
257
258 vreg = regulator_get(dev, info->name);
259 if (!vreg || IS_ERR(vreg)) {
260 rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
261 pr_err("can't get %s; %d\n", info->name, rc);
262 break;
263 }
264
265 if (info->max_v) {
266 rc = regulator_set_voltage(vreg,
267 info->min_v, info->max_v);
268 if (rc) {
269 pr_err("can't set voltage %s; %d\n",
270 info->name, rc);
271 regulator_put(vreg);
272 break;
273 }
274 }
275
276 if (info->opt_mode) {
277 rc = regulator_set_optimum_mode(vreg, info->opt_mode);
278 if (rc < 0) {
279 pr_err("can't set mode %s; %d\n",
280 info->name, rc);
281 regulator_put(vreg);
282 break;
283 }
284 }
285
286 rc = regulator_enable(vreg);
287 if (rc) {
288 pr_err("can't enable %s, %d\n", info->name, rc);
289 regulator_put(vreg);
290 break;
291 }
292 info->hdl = vreg;
293 }
294
295 if (rc)
296 while (i--) {
297 regulator_disable(msm_pcie_dev.vreg[i].hdl);
298 regulator_put(msm_pcie_dev.vreg[i].hdl);
299 msm_pcie_dev.vreg[i].hdl = NULL;
300 }
301
302 return rc;
303}
304
305static void msm_pcie_vreg_deinit(void)
306{
307 int i;
308
309 for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
310 regulator_disable(msm_pcie_dev.vreg[i].hdl);
311 regulator_put(msm_pcie_dev.vreg[i].hdl);
312 msm_pcie_dev.vreg[i].hdl = NULL;
313 }
314}
315
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600316static int __init msm_pcie_clk_init(struct device *dev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600317{
318 int i, rc = 0;
319 struct clk *clk_hdl;
320 struct msm_pcie_clk_info_t *info;
321
322 for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
323 info = &msm_pcie_dev.clk[i];
324
325 clk_hdl = clk_get(dev, info->name);
326 if (!clk_hdl || IS_ERR(clk_hdl)) {
327 rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
328 pr_err("can't get clk %s; %d\n", info->name, rc);
329 break;
330 }
331 clk_prepare_enable(clk_hdl);
332 info->hdl = clk_hdl;
333 }
334
335 if (rc)
336 while (i--) {
337 clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
338 clk_put(msm_pcie_dev.clk[i].hdl);
339 msm_pcie_dev.clk[i].hdl = NULL;
340 }
341
342 return rc;
343}
344
345static void msm_pcie_clk_deinit(void)
346{
347 int i;
348
349 for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
350 clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
351 clk_put(msm_pcie_dev.clk[i].hdl);
352 msm_pcie_dev.clk[i].hdl = NULL;
353 }
354}
355
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600356static void __init msm_pcie_config_controller(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600357{
358 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600359 struct resource *axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].resource;
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600360
361 /*
362 * program and enable address translation region 0 (device config
363 * address space); region type config;
364 * axi config address range to device config address range
365 */
366 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
367 /* ensure that hardware locks the region before programming it */
368 wmb();
369
370 writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
371 writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
372 writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
373 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
374 writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
375 writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
376 dev->pcie20 + PCIE20_PLR_IATU_LTAR);
377 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
378 /* ensure that hardware registers the configuration */
379 wmb();
380
381 /*
382 * program and enable address translation region 2 (device resource
383 * address space); region type memory;
384 * axi device bar address range to device bar address range
385 */
386 writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
387 /* ensure that hardware locks the region before programming it */
388 wmb();
389
390 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
391 writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600392 writel_relaxed(dev->axi_bar_start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600393 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600394 writel_relaxed(dev->axi_bar_end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600395 writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
396 dev->pcie20 + PCIE20_PLR_IATU_LTAR);
397 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
398 /* ensure that hardware registers the configuration */
399 wmb();
400}
401
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600402static int __init msm_pcie_get_resources(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600403{
404 int i, rc = 0;
405 struct resource *res;
406 struct msm_pcie_res_info_t *info;
407 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
408
409 for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
410 info = &dev->res[i];
411
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600412 if (i < MSM_PCIE_MAX_PLATFORM_RES) {
413 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
414 info->name);
415 } else {
416 res = dev->res[i].resource;
417 if (request_resource(&iomem_resource, res))
418 res = NULL;
419 }
420
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600421 if (!res) {
422 pr_err("can't get %s resource\n", info->name);
423 rc = -ENOMEM;
424 break;
425 }
426
427 info->base = ioremap(res->start, resource_size(res));
428 if (!info->base) {
429 pr_err("can't remap %s\n", info->name);
430 rc = -ENOMEM;
431 break;
432 }
433
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600434 info->resource = res;
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600435 }
436
437 if (rc) {
438 while (i--) {
439 iounmap(dev->res[i].base);
440 dev->res[i].base = NULL;
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600441 if (i >= MSM_PCIE_MAX_PLATFORM_RES)
442 release_resource(dev->res[i].resource);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600443 }
444 } else {
445 dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
446 dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
447 dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
448 dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
449 }
450
451 return rc;
452}
453
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600454static void msm_pcie_release_resources(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600455{
456 int i;
457
458 for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
459 iounmap(msm_pcie_dev.res[i].base);
460 msm_pcie_dev.res[i].base = NULL;
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600461 if (i >= MSM_PCIE_MAX_PLATFORM_RES)
462 release_resource(msm_pcie_dev.res[i].resource);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600463 }
464
465 msm_pcie_dev.parf = NULL;
466 msm_pcie_dev.elbi = NULL;
467 msm_pcie_dev.pcie20 = NULL;
468 msm_pcie_dev.axi_conf = NULL;
469}
470
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600471static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600472{
473 int rc;
474 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
475 uint32_t val;
476
477 PCIE_DBG("bus %d\n", nr);
478 if (nr != 0)
479 return 0;
480
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600481 /*
482 * specify linux PCI framework to allocate device memory (BARs)
483 * from msm_pcie_dev.dev_mem_res resource.
484 */
485 sys->mem_offset = 0;
486 pci_add_resource(&sys->resources, &msm_pcie_dev.dev_mem_res);
487
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600488 /* assert PCIe reset link to keep EP in reset */
489 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
490 dev->gpio[MSM_PCIE_GPIO_RST_N].on);
491
492 /* enable power */
493 rc = msm_pcie_vreg_init(&dev->pdev->dev);
494 if (rc)
495 goto out;
496
497 /* assert PCIe PARF reset while powering the core */
498 msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
499
500 /* enable clocks */
501 rc = msm_pcie_clk_init(&dev->pdev->dev);
502 if (rc)
503 goto clk_fail;
504
505 /* enable pcie power; wait 3ms for clock to stabilize */
506 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
507 dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
508 usleep(3000);
509
510 /*
511 * de-assert PCIe PARF reset;
512 * wait 1us before accessing PARF registers
513 */
514 msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
515 udelay(1);
516
517 /* enable PCIe clocks and resets */
518 msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
519
520 /* PARF programming */
521 writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
522 writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
523 writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
524 /* ensure that hardware registers the PARF configuration */
525 wmb();
526
527 /* enable reference clock */
528 msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
529
530 /* enable access to PCIe slave port on system fabric */
531 writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
532 /* ensure that access is enabled before proceeding */
533 wmb();
534
535 /* de-assert PICe PHY, Core, POR and AXI clk domain resets */
536 msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
537 msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
538 msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
539 msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
540
541 /* wait 150ms for clock acquisition */
542 udelay(150);
543
544 /* de-assert PCIe reset link to bring EP out of reset */
545 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
546 !dev->gpio[MSM_PCIE_GPIO_RST_N].on);
547
548 /* enable link training */
549 msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
550
551 /* poll for link to come up for upto 100ms */
552 rc = readl_poll_timeout(
553 (msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
554 val, (val & BIT(29)), 10000, 100000);
555 if (rc) {
556 pr_err("link initialization failed\n");
557 goto link_fail;
558 } else
559 pr_info("link initialized\n");
560
561 msm_pcie_config_controller();
562 rc = msm_pcie_irq_init(dev);
563 if (!rc)
564 goto out;
565
566link_fail:
567 msm_pcie_clk_deinit();
568clk_fail:
569 msm_pcie_vreg_deinit();
570out:
571 return (rc) ? 0 : 1;
572}
573
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600574static struct pci_bus __init *msm_pcie_scan_bus(int nr,
575 struct pci_sys_data *sys)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600576{
577 struct pci_bus *bus = NULL;
578
579 PCIE_DBG("bus %d\n", nr);
580 if (nr == 0)
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600581 bus = pci_scan_root_bus(NULL, sys->busnr, &msm_pcie_ops, sys,
582 &sys->resources);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600583
584 return bus;
585}
586
Steve Mucklef132c6c2012-06-06 18:30:57 -0700587static int __init msm_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600588{
589 PCIE_DBG("slot %d pin %d\n", slot, pin);
590 return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
591}
592
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600593static struct hw_pci msm_pci __initdata = {
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600594 .nr_controllers = 1,
595 .swizzle = pci_std_swizzle,
596 .setup = msm_pcie_setup,
597 .scan = msm_pcie_scan_bus,
598 .map_irq = msm_pcie_map_irq,
599};
600
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600601static int __init msm_pcie_probe(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600602{
603 const struct msm_pcie_platform *pdata;
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600604 struct resource *res;
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600605 int rc;
606
607 PCIE_DBG("\n");
608
609 msm_pcie_dev.pdev = pdev;
610 pdata = pdev->dev.platform_data;
611 msm_pcie_dev.gpio = pdata->gpio;
612 msm_pcie_dev.vreg = msm_pcie_vreg_info;
613 msm_pcie_dev.clk = msm_pcie_clk_info;
614 msm_pcie_dev.res = msm_pcie_res_info;
615
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600616 /* device memory resource */
617 res = &msm_pcie_dev.dev_mem_res;
618 res->name = "pcie_dev_mem";
619 res->start = MSM_PCIE_DEV_BAR_ADDR;
620 res->end = res->start + pdata->axi_size - 1;
621 res->flags = IORESOURCE_MEM;
622
623 /* axi address space = axi bar space + axi config space */
624 msm_pcie_dev.axi_bar_start = pdata->axi_addr;
625 msm_pcie_dev.axi_bar_end = pdata->axi_addr + pdata->axi_size -
626 PCIE_AXI_CONF_SIZE - 1;
627
628 /* axi config space resource */
629 res = kzalloc(sizeof(*res), GFP_KERNEL);
630 if (!res) {
631 pr_err("can't allocate memory\n");
632 return -ENOMEM;
633 }
634
635 msm_pcie_dev.res[MSM_PCIE_RES_AXI_CONF].resource = res;
636 res->name = msm_pcie_dev.res[MSM_PCIE_RES_AXI_CONF].name;
637 res->start = msm_pcie_dev.axi_bar_end + 1;
638 res->end = res->start + PCIE_AXI_CONF_SIZE - 1;
639 res->flags = IORESOURCE_MEM;
640
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600641 rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
642 if (rc)
643 return rc;
644
645 rc = msm_pcie_gpio_init();
646 if (rc) {
647 msm_pcie_release_resources();
648 return rc;
649 }
650
651 /* kick start ARM PCI configuration framework */
652 pci_common_init(&msm_pci);
653 return 0;
654}
655
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600656static int __exit msm_pcie_remove(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600657{
658 PCIE_DBG("\n");
659
660 msm_pcie_irq_deinit(&msm_pcie_dev);
661 msm_pcie_vreg_deinit();
662 msm_pcie_clk_deinit();
663 msm_pcie_gpio_deinit();
664 msm_pcie_release_resources();
665
666 msm_pcie_dev.pdev = NULL;
667 msm_pcie_dev.vreg = NULL;
668 msm_pcie_dev.clk = NULL;
669 msm_pcie_dev.gpio = NULL;
670 return 0;
671}
672
673static struct platform_driver msm_pcie_driver = {
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600674 .remove = __exit_p(msm_pcie_remove),
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600675 .driver = {
676 .name = "msm_pcie",
677 .owner = THIS_MODULE,
678 },
679};
680
681static int __init msm_pcie_init(void)
682{
683 PCIE_DBG("\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -0700684 pcibios_min_mem = 0x10000000;
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600685 return platform_driver_probe(&msm_pcie_driver, msm_pcie_probe);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600686}
687subsys_initcall(msm_pcie_init);
688
689/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
Niranjana Vishwanathapuradb684cb2012-06-27 11:24:28 -0600690static void __devinit msm_pcie_fixup_early(struct pci_dev *dev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600691{
692 PCIE_DBG("hdr_type %d\n", dev->hdr_type);
693 if (dev->hdr_type == 1)
694 dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
695}
Niranjana Vishwanathapuradb684cb2012-06-27 11:24:28 -0600696DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
697 msm_pcie_fixup_early);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600698
699/*
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600700 * actual physical (BAR) address of the device resources starts from
701 * MSM_PCIE_DEV_BAR_ADDR; the system axi address for the device resources starts
702 * from msm_pcie_dev.axi_bar_start; correct the device resource structure here;
703 * address translation unit handles the required translations
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600704 */
705static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
706{
707 int i;
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600708 struct resource *res;
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600709
710 PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
711 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
Niranjana Vishwanathapura68210ff2012-06-24 18:03:49 -0600712 res = &dev->resource[i];
713 if (res->start & MSM_PCIE_DEV_BAR_ADDR) {
714 res->start -= MSM_PCIE_DEV_BAR_ADDR;
715 res->start += msm_pcie_dev.axi_bar_start;
716 res->end -= MSM_PCIE_DEV_BAR_ADDR;
717 res->end += msm_pcie_dev.axi_bar_start;
718
719 /* If Root Port, request for the changed resource */
720 if ((dev->vendor == PCIE_VENDOR_ID_RCP) &&
721 (dev->device == PCIE_DEVICE_ID_RCP)) {
722 insert_resource(&iomem_resource, res);
723 }
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600724 }
725 }
726}
727DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);