]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/sh/drivers/pci/pcie-sh7786.c
Merge branch 'master' into tk71
[mv-sheeva.git] / arch / sh / drivers / pci / pcie-sh7786.c
index 68cb9b0ac9d28294d00c8cb63a9ece18a5ad7bfd..96e9b058aa1d9afb0245004fc8843a279b30a0eb 100644 (file)
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
 #include "pcie-sh7786.h"
 #include <asm/sizes.h>
 
 struct sh7786_pcie_port {
        struct pci_channel      *hose;
+       struct clk              *fclk, phy_clk;
        unsigned int            index;
        int                     endpoint;
        int                     link;
@@ -51,6 +54,7 @@ static struct resource sh7786_pci0_resources[] = {
                .name   = "PCIe0 MEM 2",
                .start  = 0xfe100000,
                .end    = 0xfe100000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -74,6 +78,7 @@ static struct resource sh7786_pci1_resources[] = {
                .name   = "PCIe1 MEM 2",
                .start  = 0xfe300000,
                .end    = 0xfe300000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -82,6 +87,7 @@ static struct resource sh7786_pci2_resources[] = {
                .name   = "PCIe2 IO",
                .start  = 0xfc800000,
                .end    = 0xfc800000 + SZ_4M - 1,
+               .flags  = IORESOURCE_IO,
        }, {
                .name   = "PCIe2 MEM 0",
                .start  = 0x80000000,
@@ -96,6 +102,7 @@ static struct resource sh7786_pci2_resources[] = {
                .name   = "PCIe2 MEM 2",
                .start  = 0xfcd00000,
                .end    = 0xfcd00000 + SZ_1M - 1,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
@@ -117,7 +124,29 @@ static struct pci_channel sh7786_pci_channels[] = {
        DEFINE_CONTROLLER(0xfcc00000, 2),
 };
 
-static int phy_wait_for_ack(struct pci_channel *chan)
+static struct clk fixed_pciexclkp = {
+       .rate = 100000000,      /* 100 MHz reference clock */
+};
+
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+       /*
+        * Prevent enumeration of root complex resources.
+        */
+       if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+               int i;
+
+               for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+                       dev->resource[i].start  = 0;
+                       dev->resource[i].end    = 0;
+                       dev->resource[i].flags  = 0;
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+                        sh7786_pci_fixup);
+
+static int __init phy_wait_for_ack(struct pci_channel *chan)
 {
        unsigned int timeout = 100;
 
@@ -131,7 +160,7 @@ static int phy_wait_for_ack(struct pci_channel *chan)
        return -ETIMEDOUT;
 }
 
-static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
+static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
 {
        unsigned int timeout = 100;
 
@@ -145,19 +174,14 @@ static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
        return -ETIMEDOUT;
 }
 
-static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
-                         unsigned int lane, unsigned int data)
+static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
+                                unsigned int lane, unsigned int data)
 {
-       unsigned long phyaddr, ctrl;
+       unsigned long phyaddr;
 
        phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
                        ((addr & 0xff) << BITS_ADR);
 
-       /* Enable clock */
-       ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-       ctrl |= (1 << BITS_CKE);
-       pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
-
        /* Set write data */
        pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
        pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
@@ -165,20 +189,74 @@ static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
        phy_wait_for_ack(chan);
 
        /* Clear command */
+       pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
        pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
 
        phy_wait_for_ack(chan);
+}
 
-       /* Disable clock */
-       ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-       ctrl &= ~(1 << BITS_CKE);
-       pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
+static int __init pcie_clk_init(struct sh7786_pcie_port *port)
+{
+       struct pci_channel *chan = port->hose;
+       struct clk *clk;
+       char fclk_name[16];
+       int ret;
+
+       /*
+        * First register the fixed clock
+        */
+       ret = clk_register(&fixed_pciexclkp);
+       if (unlikely(ret != 0))
+               return ret;
+
+       /*
+        * Grab the port's function clock, which the PHY clock depends
+        * on. clock lookups don't help us much at this point, since no
+        * dev_id is available this early. Lame.
+        */
+       snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
+
+       port->fclk = clk_get(NULL, fclk_name);
+       if (IS_ERR(port->fclk)) {
+               ret = PTR_ERR(port->fclk);
+               goto err_fclk;
+       }
+
+       clk_enable(port->fclk);
+
+       /*
+        * And now, set up the PHY clock
+        */
+       clk = &port->phy_clk;
+
+       memset(clk, 0, sizeof(struct clk));
+
+       clk->parent = &fixed_pciexclkp;
+       clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
+       clk->enable_bit = BITS_CKE;
+
+       ret = sh_clk_mstp32_register(clk, 1);
+       if (unlikely(ret < 0))
+               goto err_phy;
+
+       return 0;
+
+err_phy:
+       clk_disable(port->fclk);
+       clk_put(port->fclk);
+err_fclk:
+       clk_unregister(&fixed_pciexclkp);
+
+       return ret;
 }
 
-static int phy_init(struct pci_channel *chan)
+static int __init phy_init(struct sh7786_pcie_port *port)
 {
+       struct pci_channel *chan = port->hose;
        unsigned int timeout = 100;
 
+       clk_enable(&port->phy_clk);
+
        /* Initialize the phy */
        phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
        phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
@@ -187,9 +265,13 @@ static int phy_init(struct pci_channel *chan)
        phy_write_reg(chan, 0x66, 0xf, 0x00000010);
        phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
        phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
+       phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
 
        /* Deassert Standby */
-       phy_write_reg(chan, 0x67, 0xf, 0x00000400);
+       phy_write_reg(chan, 0x67, 0x1, 0x00000400);
+
+       /* Disable clock */
+       clk_disable(&port->phy_clk);
 
        while (timeout--) {
                if (pci_read_reg(chan, SH4A_PCIEPHYSR))
@@ -201,22 +283,33 @@ static int phy_init(struct pci_channel *chan)
        return -ETIMEDOUT;
 }
 
-static int pcie_init(struct sh7786_pcie_port *port)
+static void __init pcie_reset(struct sh7786_pcie_port *port)
+{
+       struct pci_channel *chan = port->hose;
+
+       pci_write_reg(chan, 1, SH4A_PCIESRSTR);
+       pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+       pci_write_reg(chan, 0, SH4A_PCIESRSTR);
+       pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
+}
+
+static int __init pcie_init(struct sh7786_pcie_port *port)
 {
        struct pci_channel *chan = port->hose;
        unsigned int data;
        phys_addr_t memphys;
        size_t memsize;
-       int ret, i;
+       int ret, i, win;
 
        /* Begin initialization */
-       pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+       pcie_reset(port);
 
-       /* Initialize as type1. */
-       data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
-       data &= ~(0x7f << 16);
-       data |= PCI_HEADER_TYPE_BRIDGE << 16;
-       pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+       /*
+        * Initial header for port config space is type 1, set the device
+        * class to match. Hardware takes care of propagating the IDSETR
+        * settings, so there is no need to bother with a quirk.
+        */
+       pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
 
        /* Initialize default capabilities. */
        data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
@@ -268,30 +361,33 @@ static int pcie_init(struct sh7786_pcie_port *port)
         * LAR1/LAMR1.
         */
        if (memsize > SZ_512M) {
-               __raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1);
-               __raw_writel(((memsize - SZ_512M) - SZ_256) | 1,
-                            chan->reg_base + SH4A_PCIELAMR1);
+               pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
+               pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
+                             SH4A_PCIELAMR1);
                memsize = SZ_512M;
        } else {
                /*
                 * Otherwise just zero it out and disable it.
                 */
-               __raw_writel(0, chan->reg_base + SH4A_PCIELAR1);
-               __raw_writel(0, chan->reg_base + SH4A_PCIELAMR1);
+               pci_write_reg(chan, 0, SH4A_PCIELAR1);
+               pci_write_reg(chan, 0, SH4A_PCIELAMR1);
        }
 
        /*
         * LAR0/LAMR0 covers up to the first 512MB, which is enough to
         * cover all of lowmem on most platforms.
         */
-       __raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0);
-       __raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0);
+       pci_write_reg(chan, memphys, SH4A_PCIELAR0);
+       pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
 
        /* Finish initialization */
        data = pci_read_reg(chan, SH4A_PCIETCTLR);
        data |= 0x1;
        pci_write_reg(chan, data, SH4A_PCIETCTLR);
 
+       /* Let things settle down a bit.. */
+       mdelay(100);
+
        /* Enable DL_Active Interrupt generation */
        data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
        data |= PCIEDLINTENR_DLL_ACT_ENABLE;
@@ -302,9 +398,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
        data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
        pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
 
+       /*
+        * This will timeout if we don't have a link, but we permit the
+        * port to register anyways in order to support hotplug on future
+        * hardware.
+        */
        ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
-       if (unlikely(ret != 0))
-               return -ENODEV;
 
        data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
        data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
@@ -317,35 +416,48 @@ static int pcie_init(struct sh7786_pcie_port *port)
 
        wmb();
 
-       data = pci_read_reg(chan, SH4A_PCIEMACSR);
-       printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
-              port->index, (data >> 20) & 0x3f);
-
+       if (ret == 0) {
+               data = pci_read_reg(chan, SH4A_PCIEMACSR);
+               printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
+                      port->index, (data >> 20) & 0x3f);
+       } else
+               printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
+                      port->index);
 
-       for (i = 0; i < chan->nr_resources; i++) {
+       for (i = win = 0; i < chan->nr_resources; i++) {
                struct resource *res = chan->resources + i;
                resource_size_t size;
-               u32 enable_mask;
+               u32 mask;
 
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i));
+               /*
+                * We can't use the 32-bit mode windows in legacy 29-bit
+                * mode, so just skip them entirely.
+                */
+               if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
+                       continue;
 
-               size = resource_size(res);
+               pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
 
                /*
                 * The PAMR mask is calculated in units of 256kB, which
                 * keeps things pretty simple.
                 */
-               __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
-                            chan->reg_base + SH4A_PCIEPAMR(i));
+               size = resource_size(res);
+               mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
+               pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
 
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i));
-               pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i));
+               pci_write_reg(chan, upper_32_bits(res->start),
+                             SH4A_PCIEPARH(win));
+               pci_write_reg(chan, lower_32_bits(res->start),
+                             SH4A_PCIEPARL(win));
 
-               enable_mask = MASK_PARE;
+               mask = MASK_PARE;
                if (res->flags & IORESOURCE_IO)
-                       enable_mask |= MASK_SPC;
+                       mask |= MASK_SPC;
+
+               pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
 
-               pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i));
+               win++;
        }
 
        return 0;
@@ -356,26 +468,33 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
         return 71;
 }
 
-static int sh7786_pcie_core_init(void)
+static int __init sh7786_pcie_core_init(void)
 {
        /* Return the number of ports */
        return test_mode_pin(MODE_PIN12) ? 3 : 2;
 }
 
-static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
+static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
 {
        int ret;
 
-       ret = phy_init(port->hose);
-       if (unlikely(ret < 0))
-               return ret;
-
        /*
         * Check if we are configured in endpoint or root complex mode,
         * this is a fixed pin setting that applies to all PCIe ports.
         */
        port->endpoint = test_mode_pin(MODE_PIN11);
 
+       /*
+        * Setup clocks, needed both for PHY and PCIe registers.
+        */
+       ret = pcie_clk_init(port);
+       if (unlikely(ret < 0))
+               return ret;
+
+       ret = phy_init(port);
+       if (unlikely(ret < 0))
+               return ret;
+
        ret = pcie_init(port);
        if (unlikely(ret < 0))
                return ret;
@@ -390,9 +509,10 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
 
 static int __init sh7786_pcie_init(void)
 {
+       struct clk *platclk;
        int ret = 0, i;
 
-       printk(KERN_NOTICE "PCI: Starting intialization.\n");
+       printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
        sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
 
@@ -407,6 +527,22 @@ static int __init sh7786_pcie_init(void)
        if (unlikely(!sh7786_pcie_ports))
                return -ENOMEM;
 
+       /*
+        * Fetch any optional platform clock associated with this block.
+        *
+        * This is a rather nasty hack for boards with spec-mocking FPGAs
+        * that have a secondary set of clocks outside of the on-chip
+        * ones that need to be accounted for before there is any chance
+        * of touching the existing MSTP bits or CPG clocks.
+        */
+       platclk = clk_get(NULL, "pcie_plat_clk");
+       if (IS_ERR(platclk)) {
+               /* Sane hardware should probably get a WARN_ON.. */
+               platclk = NULL;
+       }
+
+       clk_enable(platclk);
+
        printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
 
        for (i = 0; i < nr_ports; i++) {
@@ -419,8 +555,11 @@ static int __init sh7786_pcie_init(void)
                ret |= sh7786_pcie_hwops->port_init_hw(port);
        }
 
-       if (unlikely(ret))
+       if (unlikely(ret)) {
+               clk_disable(platclk);
+               clk_put(platclk);
                return ret;
+       }
 
        return 0;
 }