aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers/pci/pcie-sh7786.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2011-01-18 05:56:04 -0500
committerPaul Mundt <lethal@linux-sh.org>2011-01-18 05:56:04 -0500
commit1da09c43ce5f4fcd98143feb7d2513fe6fd62848 (patch)
tree0e9c02b16fa5dbb7366e2c732d414a2faae1c00a /arch/sh/drivers/pci/pcie-sh7786.c
parente6f597a1425b5af64917be3448b29e2d5a585ac8 (diff)
sh: pci: Support asynchronous initialization of SH-X3 PCIe channels.
SH-X3 controllers all have pretty dire delays needed for PHY wakeup, so we attempt to mitigate the damage by bringing them up asynchronously, simply using the synchronization points for persistent bridge to channel numbering. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers/pci/pcie-sh7786.c')
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 96e9b058aa1d..ada2e6926f00 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -1,16 +1,19 @@
1/* 1/*
2 * Low-Level PCI Express Support for the SH7786 2 * Low-Level PCI Express Support for the SH7786
3 * 3 *
4 * Copyright (C) 2009 - 2010 Paul Mundt 4 * Copyright (C) 2009 - 2011 Paul Mundt
5 * 5 *
6 * This file is subject to the terms and conditions of the GNU General Public 6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 */ 9 */
10#define pr_fmt(fmt) "PCI: " fmt
11
10#include <linux/pci.h> 12#include <linux/pci.h>
11#include <linux/init.h> 13#include <linux/init.h>
12#include <linux/kernel.h> 14#include <linux/kernel.h>
13#include <linux/io.h> 15#include <linux/io.h>
16#include <linux/async.h>
14#include <linux/delay.h> 17#include <linux/delay.h>
15#include <linux/slab.h> 18#include <linux/slab.h>
16#include <linux/clk.h> 19#include <linux/clk.h>
@@ -31,7 +34,7 @@ static unsigned int nr_ports;
31 34
32static struct sh7786_pcie_hwops { 35static struct sh7786_pcie_hwops {
33 int (*core_init)(void); 36 int (*core_init)(void);
34 int (*port_init_hw)(struct sh7786_pcie_port *port); 37 async_func_ptr *port_init_hw;
35} *sh7786_pcie_hwops; 38} *sh7786_pcie_hwops;
36 39
37static struct resource sh7786_pci0_resources[] = { 40static struct resource sh7786_pci0_resources[] = {
@@ -474,8 +477,9 @@ static int __init sh7786_pcie_core_init(void)
474 return test_mode_pin(MODE_PIN12) ? 3 : 2; 477 return test_mode_pin(MODE_PIN12) ? 3 : 2;
475} 478}
476 479
477static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port) 480static void __init sh7786_pcie_init_hw(void *data, async_cookie_t cookie)
478{ 481{
482 struct sh7786_pcie_port *port = data;
479 int ret; 483 int ret;
480 484
481 /* 485 /*
@@ -488,18 +492,30 @@ static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
488 * Setup clocks, needed both for PHY and PCIe registers. 492 * Setup clocks, needed both for PHY and PCIe registers.
489 */ 493 */
490 ret = pcie_clk_init(port); 494 ret = pcie_clk_init(port);
491 if (unlikely(ret < 0)) 495 if (unlikely(ret < 0)) {
492 return ret; 496 pr_err("clock initialization failed for port#%d\n",
497 port->index);
498 return;
499 }
493 500
494 ret = phy_init(port); 501 ret = phy_init(port);
495 if (unlikely(ret < 0)) 502 if (unlikely(ret < 0)) {
496 return ret; 503 pr_err("phy initialization failed for port#%d\n",
504 port->index);
505 return;
506 }
497 507
498 ret = pcie_init(port); 508 ret = pcie_init(port);
499 if (unlikely(ret < 0)) 509 if (unlikely(ret < 0)) {
500 return ret; 510 pr_err("core initialization failed for port#%d\n",
511 port->index);
512 return;
513 }
501 514
502 return register_pci_controller(port->hose); 515 /* In the interest of preserving device ordering, synchronize */
516 async_synchronize_cookie(cookie);
517
518 register_pci_controller(port->hose);
503} 519}
504 520
505static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = { 521static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
@@ -510,7 +526,7 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
510static int __init sh7786_pcie_init(void) 526static int __init sh7786_pcie_init(void)
511{ 527{
512 struct clk *platclk; 528 struct clk *platclk;
513 int ret = 0, i; 529 int i;
514 530
515 printk(KERN_NOTICE "PCI: Starting initialization.\n"); 531 printk(KERN_NOTICE "PCI: Starting initialization.\n");
516 532
@@ -552,13 +568,7 @@ static int __init sh7786_pcie_init(void)
552 port->hose = sh7786_pci_channels + i; 568 port->hose = sh7786_pci_channels + i;
553 port->hose->io_map_base = port->hose->resources[0].start; 569 port->hose->io_map_base = port->hose->resources[0].start;
554 570
555 ret |= sh7786_pcie_hwops->port_init_hw(port); 571 async_schedule(sh7786_pcie_hwops->port_init_hw, port);
556 }
557
558 if (unlikely(ret)) {
559 clk_disable(platclk);
560 clk_put(platclk);
561 return ret;
562 } 572 }
563 573
564 return 0; 574 return 0;