]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
757e3c16 | 2 | * Low-Level PCI Support for the SH7751 |
1da177e4 | 3 | * |
757e3c16 PM |
4 | * Copyright (C) 2003 - 2009 Paul Mundt |
5 | * Copyright (C) 2001 Dustin McIntire | |
1da177e4 | 6 | * |
757e3c16 | 7 | * With cleanup by Paul van Gool <pvangool@mimotech.com>, 2003. |
1da177e4 | 8 | * |
757e3c16 PM |
9 | * This file is subject to the terms and conditions of the GNU General Public |
10 | * License. See the file "COPYING" in the main directory of this archive | |
11 | * for more details. | |
1da177e4 | 12 | */ |
1da177e4 LT |
13 | #include <linux/init.h> |
14 | #include <linux/pci.h> | |
959f85f8 | 15 | #include <linux/types.h> |
1da177e4 | 16 | #include <linux/errno.h> |
757e3c16 | 17 | #include <linux/io.h> |
959f85f8 PM |
18 | #include "pci-sh4.h" |
19 | #include <asm/addrspace.h> | |
e3a4317e | 20 | #include <asm/sizes.h> |
1da177e4 | 21 | |
b8b47bfb MD |
22 | static int __init __area_sdram_check(struct pci_channel *chan, |
23 | unsigned int area) | |
1da177e4 | 24 | { |
757e3c16 | 25 | unsigned long word; |
1da177e4 | 26 | |
757e3c16 | 27 | word = __raw_readl(SH7751_BCR1); |
1da177e4 | 28 | /* check BCR for SDRAM in area */ |
5283ecb5 | 29 | if (((word >> area) & 1) == 0) { |
757e3c16 | 30 | printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%lx\n", |
1da177e4 LT |
31 | area, word); |
32 | return 0; | |
33 | } | |
b8b47bfb | 34 | pci_write_reg(chan, word, SH4_PCIBCR1); |
1da177e4 | 35 | |
757e3c16 | 36 | word = __raw_readw(SH7751_BCR2); |
1da177e4 | 37 | /* check BCR2 for 32bit SDRAM interface*/ |
5283ecb5 | 38 | if (((word >> (area << 1)) & 0x3) != 0x3) { |
757e3c16 | 39 | printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%lx\n", |
1da177e4 LT |
40 | area, word); |
41 | return 0; | |
42 | } | |
b8b47bfb | 43 | pci_write_reg(chan, word, SH4_PCIBCR2); |
1da177e4 LT |
44 | |
45 | return 1; | |
46 | } | |
47 | ||
b6c58b1d PM |
48 | static struct resource sh7751_pci_resources[] = { |
49 | { | |
50 | .name = "SH7751_IO", | |
e3a4317e MD |
51 | .start = 0x1000, |
52 | .end = SZ_4M - 1, | |
b6c58b1d PM |
53 | .flags = IORESOURCE_IO |
54 | }, { | |
55 | .name = "SH7751_mem", | |
56 | .start = SH7751_PCI_MEMORY_BASE, | |
57 | .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, | |
58 | .flags = IORESOURCE_MEM | |
59 | }, | |
757e3c16 PM |
60 | }; |
61 | ||
62 | static struct pci_channel sh7751_pci_controller = { | |
63 | .pci_ops = &sh4_pci_ops, | |
b6c58b1d PM |
64 | .resources = sh7751_pci_resources, |
65 | .nr_resources = ARRAY_SIZE(sh7751_pci_resources), | |
757e3c16 | 66 | .mem_offset = 0x00000000, |
757e3c16 | 67 | .io_offset = 0x00000000, |
d076d2bd | 68 | .io_map_base = SH7751_PCI_IO_BASE, |
757e3c16 PM |
69 | }; |
70 | ||
71 | static struct sh4_pci_address_map sh7751_pci_map = { | |
72 | .window0 = { | |
73 | .base = SH7751_CS3_BASE_ADDR, | |
74 | .size = 0x04000000, | |
75 | }, | |
76 | }; | |
77 | ||
78 | static int __init sh7751_pci_init(void) | |
1da177e4 | 79 | { |
757e3c16 PM |
80 | struct pci_channel *chan = &sh7751_pci_controller; |
81 | unsigned int id; | |
82 | u32 word, reg; | |
757e3c16 PM |
83 | |
84 | printk(KERN_NOTICE "PCI: Starting intialization.\n"); | |
85 | ||
86 | chan->reg_base = 0xfe200000; | |
87 | ||
88 | /* check for SH7751/SH7751R hardware */ | |
89 | id = pci_read_reg(chan, SH7751_PCICONF0); | |
90 | if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && | |
91 | id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { | |
92 | pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); | |
93 | return -ENODEV; | |
94 | } | |
95 | ||
1da177e4 | 96 | /* Set the BCR's to enable PCI access */ |
9d56dd3b | 97 | reg = __raw_readl(SH7751_BCR1); |
1da177e4 | 98 | reg |= 0x80000; |
9d56dd3b | 99 | __raw_writel(reg, SH7751_BCR1); |
959f85f8 | 100 | |
1da177e4 | 101 | /* Turn the clocks back on (not done in reset)*/ |
b8b47bfb | 102 | pci_write_reg(chan, 0, SH4_PCICLKR); |
1da177e4 | 103 | /* Clear Powerdown IRQ's (not done in reset) */ |
959f85f8 | 104 | word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0; |
b8b47bfb | 105 | pci_write_reg(chan, word, SH4_PCIPINT); |
1da177e4 | 106 | |
1da177e4 LT |
107 | /* set the command/status bits to: |
108 | * Wait Cycle Control + Parity Enable + Bus Master + | |
109 | * Mem space enable | |
110 | */ | |
cd6c7ea2 | 111 | word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | |
1da177e4 | 112 | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; |
b8b47bfb | 113 | pci_write_reg(chan, word, SH7751_PCICONF1); |
1da177e4 LT |
114 | |
115 | /* define this host as the host bridge */ | |
959f85f8 | 116 | word = PCI_BASE_CLASS_BRIDGE << 24; |
b8b47bfb | 117 | pci_write_reg(chan, word, SH7751_PCICONF2); |
1da177e4 | 118 | |
cd6c7ea2 PM |
119 | /* Set IO and Mem windows to local address |
120 | * Make PCI and local address the same for easy 1 to 1 mapping | |
1da177e4 | 121 | */ |
757e3c16 | 122 | word = sh7751_pci_map.window0.size - 1; |
b8b47bfb | 123 | pci_write_reg(chan, word, SH4_PCILSR0); |
1da177e4 | 124 | /* Set the values on window 0 PCI config registers */ |
757e3c16 | 125 | word = P2SEGADDR(sh7751_pci_map.window0.base); |
b8b47bfb MD |
126 | pci_write_reg(chan, word, SH4_PCILAR0); |
127 | pci_write_reg(chan, word, SH7751_PCICONF5); | |
1da177e4 | 128 | |
959f85f8 | 129 | /* Set the local 16MB PCI memory space window to |
1da177e4 LT |
130 | * the lowest PCI mapped address |
131 | */ | |
b6c58b1d | 132 | word = chan->resources[1].start & SH4_PCIMBR_MASK; |
959f85f8 | 133 | pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word); |
b8b47bfb | 134 | pci_write_reg(chan, word , SH4_PCIMBR); |
1da177e4 | 135 | |
959f85f8 PM |
136 | /* Make sure the MSB's of IO window are set to access PCI space |
137 | * correctly */ | |
b6c58b1d | 138 | word = chan->resources[0].start & SH4_PCIIOBR_MASK; |
959f85f8 | 139 | pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word); |
b8b47bfb | 140 | pci_write_reg(chan, word, SH4_PCIIOBR); |
959f85f8 | 141 | |
1da177e4 LT |
142 | /* Set PCI WCRx, BCRx's, copy from BSC locations */ |
143 | ||
144 | /* check BCR for SDRAM in specified area */ | |
757e3c16 | 145 | switch (sh7751_pci_map.window0.base) { |
b8b47bfb MD |
146 | case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(chan, 0); break; |
147 | case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(chan, 1); break; | |
148 | case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(chan, 2); break; | |
149 | case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(chan, 3); break; | |
150 | case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(chan, 4); break; | |
151 | case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(chan, 5); break; | |
152 | case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(chan, 6); break; | |
1da177e4 | 153 | } |
cd6c7ea2 | 154 | |
1da177e4 | 155 | if (!word) |
d0e3db40 | 156 | return -1; |
1da177e4 LT |
157 | |
158 | /* configure the wait control registers */ | |
9d56dd3b | 159 | word = __raw_readl(SH7751_WCR1); |
b8b47bfb | 160 | pci_write_reg(chan, word, SH4_PCIWCR1); |
9d56dd3b | 161 | word = __raw_readl(SH7751_WCR2); |
b8b47bfb | 162 | pci_write_reg(chan, word, SH4_PCIWCR2); |
9d56dd3b | 163 | word = __raw_readl(SH7751_WCR3); |
b8b47bfb | 164 | pci_write_reg(chan, word, SH4_PCIWCR3); |
9d56dd3b | 165 | word = __raw_readl(SH7751_MCR); |
b8b47bfb | 166 | pci_write_reg(chan, word, SH4_PCIMCR); |
1da177e4 LT |
167 | |
168 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | |
169 | * TODO: add support for the internal error interrupts and | |
170 | * DMA interrupts... | |
171 | */ | |
172 | ||
b8b47bfb | 173 | pci_fixup_pcic(chan); |
1da177e4 LT |
174 | |
175 | /* SH7751 init done, set central function init complete */ | |
176 | /* use round robin mode to stop a device starving/overruning */ | |
959f85f8 | 177 | word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM; |
b8b47bfb | 178 | pci_write_reg(chan, word, SH4_PCICR); |
1da177e4 | 179 | |
bcf39352 | 180 | return register_pci_controller(chan); |
1da177e4 | 181 | } |
757e3c16 | 182 | arch_initcall(sh7751_pci_init); |