sh: Reworked SH7780 PCI initialization.
Paul Mundt [Fri, 29 Jan 2010 13:19:04 +0000 (22:19 +0900)]
This consolidates the PCI initialization code for all of the pci-sh7780
users, and sets up the memory window dynamically as opposed to using
hardcoded window positions.

A number of bugs were fixed at the same time, including the PIO handling
and master abort timeout settings being incorrect.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>

arch/sh/drivers/pci/fixups-r7780rp.c
arch/sh/drivers/pci/fixups-sdk7780.c
arch/sh/drivers/pci/pci-sh4.h
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/drivers/pci/pci-sh7780.h

index 15ca65c..08b2d86 100644 (file)
@@ -22,15 +22,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return irq_tab[slot];
 }
-
-int pci_fixup_pcic(struct pci_channel *chan)
-{
-       pci_write_reg(chan, 0x000043ff, SH4_PCIINTM);
-       pci_write_reg(chan, 0x00000000, SH7780_PCIIBAR);
-       pci_write_reg(chan, 0x08000000, SH7780_PCICSCR0);
-       pci_write_reg(chan, 0x0000001b, SH7780_PCICSAR0);
-       pci_write_reg(chan, 0xfd000000, SH7780_PCICSCR1);
-       pci_write_reg(chan, 0x0000000f, SH7780_PCICSAR1);
-
-       return 0;
-}
index 250b0ed..0930f98 100644 (file)
@@ -31,22 +31,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return sdk7780_irq_tab[pin-1][slot];
 }
-int pci_fixup_pcic(struct pci_channel *chan)
-{
-       /* Enable all interrupts, so we know what to fix */
-       pci_write_reg(chan, 0x0000C3FF, SH7780_PCIIMR);
-
-       /* Set up standard PCI config registers */
-       pci_write_reg(chan, 0x08000000, SH7780_PCIMBAR0);       /* PCI */
-       pci_write_reg(chan, 0x08000000, SH4_PCILAR0);   /* SHwy */
-       pci_write_reg(chan, 0x07F00001, SH4_PCILSR0);   /* size 128M w/ MBAR */
-
-       pci_write_reg(chan, 0x00000000, SH7780_PCIMBAR1);
-       pci_write_reg(chan, 0x00000000, SH4_PCILAR1);
-       pci_write_reg(chan, 0x00000000, SH4_PCILSR1);
-
-       pci_write_reg(chan, 0xAB000801, SH7780_PCIIBAR);
-       pci_write_reg(chan, 0xA5000C01, SH4_PCICR);
-
-       return 0;
-}
index 4744a7d..43dddd8 100644 (file)
   #define SH4_PCIINT_MWPD        0x00000002    /* Master Write PERR Detect */
   #define SH4_PCIINT_MRPD        0x00000001    /* Master Read PERR Detect */
 #define SH4_PCIINTM            0x118           /* PCI Interrupt Mask */
+  #define SH4_PCIINTM_TTADIM     BIT(14)       /* Target-target abort interrupt */
+  #define SH4_PCIINTM_TMTOIM     BIT(9)        /* Target retry timeout */
+  #define SH4_PCIINTM_MDEIM      BIT(8)        /* Master function disable error */
+  #define SH4_PCIINTM_APEDIM     BIT(7)        /* Address parity error detection */
+  #define SH4_PCIINTM_SDIM       BIT(6)        /* SERR detection */
+  #define SH4_PCIINTM_DPEITWM    BIT(5)        /* Data parity error for target write */
+  #define SH4_PCIINTM_PEDITRM    BIT(4)        /* PERR detection for target read */
+  #define SH4_PCIINTM_TADIMM     BIT(3)        /* Target abort for master */
+  #define SH4_PCIINTM_MADIMM     BIT(2)        /* Master abort for master */
+  #define SH4_PCIINTM_MWPDIM     BIT(1)        /* Master write data parity error */
+  #define SH4_PCIINTM_MRDPEIM    BIT(0)        /* Master read data parity error */
 #define SH4_PCIALR             0x11C           /* Error Address Register */
 #define SH4_PCICLR             0x120           /* Error Command/Data */
   #define SH4_PCICLR_MPIO        0x80000000
@@ -61,7 +72,7 @@
 #define SH4_PCIAINT            0x130           /* Arbiter Interrupt Register */
   #define SH4_PCIAINT_MBKN       0x00002000    /* Master Broken Interrupt */
   #define SH4_PCIAINT_TBTO       0x00001000    /* Target Bus Time Out */
-  #define SH4_PCIAINT_MBTO       0x00001000    /* Master Bus Time Out */
+  #define SH4_PCIAINT_MBTO       0x00000800    /* Master Bus Time Out */
   #define SH4_PCIAINT_TABT       0x00000008    /* Target Abort */
   #define SH4_PCIAINT_MABT       0x00000004    /* Master Abort */
   #define SH4_PCIAINT_RDPE       0x00000002    /* Read Data Parity Error */
index 323b92d..019e1af 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Low-Level PCI Support for the SH7780
  *
- *  Copyright (C) 2005 - 2009  Paul Mundt
+ *  Copyright (C) 2005 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include "pci-sh4.h"
+#include <asm/mmu.h>
+#include <asm/sizes.h>
 
 static struct resource sh7785_io_resource = {
        .name   = "SH7785_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
+       .start  = 0x1000,
+       .end    = SH7780_PCI_IO_SIZE - 1,
        .flags  = IORESOURCE_IO
 };
 
@@ -38,25 +40,14 @@ static struct pci_channel sh7780_pci_controller = {
        .io_map_base    = SH7780_PCI_IO_BASE,
 };
 
-static struct sh4_pci_address_map sh7780_pci_map = {
-       .window0        = {
-#if defined(CONFIG_32BIT)
-               .base   = SH7780_32BIT_DDR_BASE_ADDR,
-               .size   = 0x40000000,
-#else
-               .base   = SH7780_CS0_BASE_ADDR,
-               .size   = 0x20000000,
-#endif
-       },
-};
-
 static int __init sh7780_pci_init(void)
 {
        struct pci_channel *chan = &sh7780_pci_controller;
+       phys_addr_t memphys;
+       size_t memsize;
        unsigned int id;
-       const char *type = NULL;
+       const char *type;
        int ret;
-       u32 word;
 
        printk(KERN_NOTICE "PCI: Starting intialization.\n");
 
@@ -65,17 +56,24 @@ static int __init sh7780_pci_init(void)
        /* Enable CPU access to the PCIC registers. */
        __raw_writel(PCIECR_ENBL, PCIECR);
 
-       id = __raw_readw(chan->reg_base + SH7780_PCIVID);
-       if (id != SH7780_VENDOR_ID) {
+       /* Reset */
+       __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST,
+                    chan->reg_base + SH4_PCICR);
+
+       /* Wait for it to come back up.. */
+       mdelay(100);
+
+       id = __raw_readw(chan->reg_base + PCI_VENDOR_ID);
+       if (id != PCI_VENDOR_ID_RENESAS) {
                printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id);
                return -ENODEV;
        }
 
-       id = __raw_readw(chan->reg_base + SH7780_PCIDID);
-       type = (id == SH7763_DEVICE_ID) ? "SH7763" :
-              (id == SH7780_DEVICE_ID) ? "SH7780" :
-              (id == SH7781_DEVICE_ID) ? "SH7781" :
-              (id == SH7785_DEVICE_ID) ? "SH7785" :
+       id = __raw_readw(chan->reg_base + PCI_DEVICE_ID);
+       type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" :
+              (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" :
+              (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" :
+              (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" :
                                          NULL;
        if (unlikely(!type)) {
                printk(KERN_ERR "PCI: Found an unsupported Renesas host "
@@ -85,59 +83,78 @@ static int __init sh7780_pci_init(void)
 
        printk(KERN_NOTICE "PCI: Found a Renesas %s host "
               "controller, revision %d.\n", type,
-              __raw_readb(chan->reg_base + SH7780_PCIRID));
+              __raw_readb(chan->reg_base + PCI_REVISION_ID));
 
        if ((ret = sh4_pci_check_direct(chan)) != 0)
                return ret;
 
        /*
-        * Set the class and sub-class codes.
+        * Now throw it in to register initialization mode and
+        * start the real work.
         */
-       __raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8,
-                    chan->reg_base + SH7780_PCIBCC);
-       __raw_writeb(PCI_CLASS_BRIDGE_HOST & 0xff,
-                    chan->reg_base + SH7780_PCISUB);
+       __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);
+
+       memphys = __pa(memory_start);
+       memsize = memory_end - memory_start;
 
        /*
         * Set IO and Mem windows to local address
         * Make PCI and local address the same for easy 1 to 1 mapping
         */
-       pci_write_reg(chan, sh7780_pci_map.window0.size - 0xfffff, SH4_PCILSR0);
-       /* Set the values on window 0 PCI config registers */
-       pci_write_reg(chan, sh7780_pci_map.window0.base, SH4_PCILAR0);
-       pci_write_reg(chan, sh7780_pci_map.window0.base, SH7780_PCIMBAR0);
-
-       pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM);
-
-       /* Set up standard PCI config registers */
-       __raw_writew(0xFB00, chan->reg_base + SH7780_PCISTATUS);
-       __raw_writew(0x0047, chan->reg_base + SH7780_PCICMD);
-       __raw_writew(0x1912, chan->reg_base + SH7780_PCISVID);
-       __raw_writew(0x0001, chan->reg_base + SH7780_PCISID);
-
-       __raw_writeb(0x00, chan->reg_base + SH7780_PCIPIF);
-
-       /* Apply any last-minute PCIC fixups */
-       pci_fixup_pcic(chan);
-
-       pci_write_reg(chan, 0xfd000000, SH7780_PCIMBR0);
-       pci_write_reg(chan, 0x00fc0000, SH7780_PCIMBMR0);
-
-#ifdef CONFIG_32BIT
-       pci_write_reg(chan, 0xc0000000, SH7780_PCIMBR2);
-       pci_write_reg(chan, 0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
-#endif
-
-       /* Set IOBR for windows containing area specified in pci.h */
-       pci_write_reg(chan, chan->io_resource->start & ~(SH7780_PCI_IO_SIZE-1),
-                     SH7780_PCIIOBR);
-       pci_write_reg(chan, ((SH7780_PCI_IO_SIZE-1) & (7<<18)),
-                     SH7780_PCIIOBMR);
-
-       /* SH7780 init done, set central function init complete */
-       /* use round robin mode to stop a device starving/overruning */
-       word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO;
-       pci_write_reg(chan, word, SH4_PCICR);
+       __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
+
+       __raw_writel(memphys, chan->reg_base + SH4_PCILAR0);
+       __raw_writel((memsize - 1) << 9 | 1,
+                    chan->reg_base + SH4_PCILSR0);
+
+       /* Clear out PCI arbiter IRQs */
+       __raw_writel(0, chan->reg_base + SH4_PCIAINT);
+
+       /* Unmask all of the arbiter IRQs. */
+       __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \
+                    SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \
+                    SH4_PCIAINT_WDPE, chan->reg_base + SH4_PCIAINTM);
+
+       /* Clear all error conditions */
+       __raw_writew(PCI_STATUS_DETECTED_PARITY  | \
+                    PCI_STATUS_SIG_SYSTEM_ERROR | \
+                    PCI_STATUS_REC_MASTER_ABORT | \
+                    PCI_STATUS_REC_TARGET_ABORT | \
+                    PCI_STATUS_SIG_TARGET_ABORT | \
+                    PCI_STATUS_PARITY, chan->reg_base + PCI_STATUS);
+
+       __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \
+                    PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \
+                    PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND);
+
+       /* Unmask all of the PCI IRQs */
+       __raw_writel(SH4_PCIINTM_TTADIM  | SH4_PCIINTM_TMTOIM  | \
+                    SH4_PCIINTM_MDEIM   | SH4_PCIINTM_APEDIM  | \
+                    SH4_PCIINTM_SDIM    | SH4_PCIINTM_DPEITWM | \
+                    SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM  | \
+                    SH4_PCIINTM_MADIMM  | SH4_PCIINTM_MWPDIM  | \
+                    SH4_PCIINTM_MRDPEIM, chan->reg_base + SH4_PCIINTM);
+
+       /*
+        * Disable the cache snoop controller for non-coherent DMA.
+        */
+       __raw_writel(0, chan->reg_base + SH7780_PCICSCR0);
+       __raw_writel(0, chan->reg_base + SH7780_PCICSAR0);
+       __raw_writel(0, chan->reg_base + SH7780_PCICSCR1);
+       __raw_writel(0, chan->reg_base + SH7780_PCICSAR1);
+
+       __raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0);
+       __raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0);
+
+       __raw_writel(0, chan->reg_base + SH7780_PCIIOBR);
+       __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);
+
+       /*
+        * Initialization mode complete, release the control register and
+        * enable round robin mode to stop device overruns/starvation.
+        */
+       __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO,
+                    chan->reg_base + SH4_PCICR);
 
        register_pci_controller(chan);
 
index 4a52478..dee069c 100644 (file)
 #ifndef _PCI_SH7780_H_
 #define _PCI_SH7780_H_
 
-/* Platform Specific Values */
-#define SH7780_VENDOR_ID       0x1912
-#define SH7781_DEVICE_ID       0x0001
-#define SH7780_DEVICE_ID       0x0002
-#define SH7763_DEVICE_ID       0x0004
-#define SH7785_DEVICE_ID       0x0007
+#define PCI_VENDOR_ID_RENESAS          0x1912
+#define PCI_DEVICE_ID_RENESAS_SH7781   0x0001
+#define PCI_DEVICE_ID_RENESAS_SH7780   0x0002
+#define PCI_DEVICE_ID_RENESAS_SH7763   0x0004
+#define PCI_DEVICE_ID_RENESAS_SH7785   0x0007
 
 /* SH7780 Control Registers */
 #define        PCIECR                  0xFE000008
 #define SH7780_PCIREG_BASE     0xFE040000      /* PCI regs base address */
 
 /* SH7780 PCI Config Registers */
-#define SH7780_PCIVID          0x000           /* Vendor ID */
-#define SH7780_PCIDID          0x002           /* Device ID */
-#define SH7780_PCICMD          0x004           /* Command */
-#define SH7780_PCISTATUS       0x006           /* Status */
-#define SH7780_PCIRID          0x008           /* Revision ID */
-#define SH7780_PCIPIF          0x009           /* Program Interface */
-#define SH7780_PCISUB          0x00a           /* Sub class code */
-#define SH7780_PCIBCC          0x00b           /* Base class code */
-#define SH7780_PCICLS          0x00c           /* Cache line size */
-#define SH7780_PCILTM          0x00d           /* latency timer */
-#define SH7780_PCIHDR          0x00e           /* Header type */
-#define SH7780_PCIBIST         0x00f           /* BIST */
-#define SH7780_PCIIBAR         0x010           /* IO Base address */
-#define SH7780_PCIMBAR0                0x014           /* Memory base address0 */
-#define SH7780_PCIMBAR1                0x018           /* Memory base address1 */
-#define SH7780_PCISVID         0x02c           /* Sub system vendor ID */
-#define SH7780_PCISID          0x02e           /* Sub system ID */
-#define SH7780_PCICP           0x034
-#define SH7780_PCIINTLINE      0x03c           /* Interrupt line */
-#define SH7780_PCIINTPIN       0x03d           /* Interrupt pin */
-#define SH7780_PCIMINGNT       0x03e           /* Minumum grand */
-#define SH7780_PCIMAXLAT       0x03f           /* Maxmum latency */
-#define SH7780_PCICID          0x040
-#define SH7780_PCINIP          0x041
-#define SH7780_PCIPMC          0x042
-#define SH7780_PCIPMCSR                0x044
-#define SH7780_PCIPMCSR_BSE    0x046
-#define SH7780_PCICDD          0x047
-
 #define SH7780_PCIIR           0x114           /* PCI Interrupt Register */
 #define SH7780_PCIIMR          0x118           /* PCI Interrupt Mask Register */
 #define SH7780_PCIAIR          0x11C           /* Error Address Register */
@@ -78,6 +48,8 @@
 
 #define SH7780_PCIMBR0         0x1E0
 #define SH7780_PCIMBMR0                0x1E4
+#define SH7780_PCIMBR1         0x1E8
+#define SH7780_PCIMBMR1                0x1EC
 #define SH7780_PCIMBR2         0x1F0
 #define SH7780_PCIMBMR2                0x1F4
 #define SH7780_PCIIOBR         0x1F8
 #define SH7780_PCICSAR0                0x218   /* Cache Snoop1 Addr. Register */
 #define SH7780_PCICSAR1                0x21C   /* Cache Snoop2 Addr. Register */
 
-/* General Memory Config Addresses */
-#define SH7780_CS0_BASE_ADDR   0x0
-#define SH7780_MEM_REGION_SIZE 0x04000000
-#define SH7780_CS1_BASE_ADDR   (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-#define SH7780_CS2_BASE_ADDR   (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-#define SH7780_CS3_BASE_ADDR   (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-#define SH7780_CS4_BASE_ADDR   (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-#define SH7780_CS5_BASE_ADDR   (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-#define SH7780_CS6_BASE_ADDR   (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE)
-
-#define SH7780_32BIT_DDR_BASE_ADDR     0x40000000
-
 #endif /* _PCI_SH7780_H_ */