diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/boards/overdrive |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/sh/boards/overdrive')
-rw-r--r-- | arch/sh/boards/overdrive/Makefile | 8 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/fpga.c | 134 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/galileo.c | 588 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/io.c | 173 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/irq.c | 192 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/led.c | 59 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/mach.c | 62 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/pcidma.c | 46 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/setup.c | 41 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/time.c | 119 |
10 files changed, 1422 insertions, 0 deletions
diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile new file mode 100644 index 000000000000..1762b59e9279 --- /dev/null +++ b/arch/sh/boards/overdrive/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the STMicroelectronics Overdrive specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o io.o irq.o led.o time.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o | ||
8 | |||
diff --git a/arch/sh/boards/overdrive/fpga.c b/arch/sh/boards/overdrive/fpga.c new file mode 100644 index 000000000000..3a1ec9403441 --- /dev/null +++ b/arch/sh/boards/overdrive/fpga.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file handles programming up the Altera Flex10K that interfaces to | ||
8 | * the Galileo, and does the PS/2 keyboard and mouse | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/smp.h> | ||
16 | #include <linux/smp_lock.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/delay.h> | ||
21 | |||
22 | |||
23 | #include <asm/overdriver/gt64111.h> | ||
24 | #include <asm/overdrive/overdrive.h> | ||
25 | #include <asm/overdrive/fpga.h> | ||
26 | |||
27 | #define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT | ||
28 | #define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK | ||
29 | |||
30 | /* I need to find out what (if any) the real delay factor here is */ | ||
31 | /* The delay is definately not critical */ | ||
32 | #define long_delay() {int i;for(i=0;i<10000;i++);} | ||
33 | #define short_delay() {int i;for(i=0;i<100;i++);} | ||
34 | |||
35 | static void __init program_overdrive_fpga(const unsigned char *fpgacode, | ||
36 | int size) | ||
37 | { | ||
38 | int timeout = 0; | ||
39 | int i, j; | ||
40 | unsigned char b; | ||
41 | static volatile unsigned char *FPGA_ControlReg = | ||
42 | (volatile unsigned char *) (OVERDRIVE_CTRL); | ||
43 | static volatile unsigned char *FPGA_ProgramReg = | ||
44 | (volatile unsigned char *) (FPGA_DCLK_ADDRESS); | ||
45 | |||
46 | printk("FPGA: Commencing FPGA Programming\n"); | ||
47 | |||
48 | /* The PCI reset but MUST be low when programming the FPGA !!! */ | ||
49 | b = (*FPGA_ControlReg) & RESET_PCI_MASK; | ||
50 | |||
51 | (*FPGA_ControlReg) = b; | ||
52 | |||
53 | /* Prepare FPGA to program */ | ||
54 | |||
55 | FPGA_NotConfigHigh(); | ||
56 | long_delay(); | ||
57 | |||
58 | FPGA_NotConfigLow(); | ||
59 | short_delay(); | ||
60 | |||
61 | while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) { | ||
62 | printk("FPGA: Waiting for NotStatus to go Low ... \n"); | ||
63 | } | ||
64 | |||
65 | FPGA_NotConfigHigh(); | ||
66 | |||
67 | /* Wait for FPGA "ready to be programmed" signal */ | ||
68 | printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n"); | ||
69 | |||
70 | for (timeout = 0; | ||
71 | (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0) | ||
72 | && (timeout < FPGA_TIMEOUT)); timeout++); | ||
73 | |||
74 | /* Check if timeout condition occured - i.e. an error */ | ||
75 | |||
76 | if (timeout == FPGA_TIMEOUT) { | ||
77 | printk | ||
78 | ("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | printk("FPGA: Copying data to FPGA ... %d bytes\n", size); | ||
83 | |||
84 | /* Copy array to FPGA - bit at a time */ | ||
85 | |||
86 | for (i = 0; i < size; i++) { | ||
87 | volatile unsigned w = 0; | ||
88 | |||
89 | for (j = 0; j < 8; j++) { | ||
90 | *FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01; | ||
91 | short_delay(); | ||
92 | } | ||
93 | if ((i & 0x3ff) == 0) { | ||
94 | printk("."); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /* Waiting for CONFDONE to go high - means the program is complete */ | ||
99 | |||
100 | for (timeout = 0; | ||
101 | (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0) | ||
102 | && (timeout < FPGA_TIMEOUT)); timeout++) { | ||
103 | |||
104 | *FPGA_ProgramReg = 0x0; | ||
105 | long_delay(); | ||
106 | } | ||
107 | |||
108 | if (timeout == FPGA_TIMEOUT) { | ||
109 | printk | ||
110 | ("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n"); | ||
111 | return; | ||
112 | } else { /* Clock another 10 times - gets the device into a working state */ | ||
113 | for (i = 0; i < 10; i++) { | ||
114 | *FPGA_ProgramReg = 0x0; | ||
115 | short_delay(); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | printk("FPGA: Programming complete\n"); | ||
120 | } | ||
121 | |||
122 | |||
123 | static const unsigned char __init fpgacode[] = { | ||
124 | #include "./overdrive.ttf" /* Code from maxplus2 compiler */ | ||
125 | , 0, 0 | ||
126 | }; | ||
127 | |||
128 | |||
129 | int __init init_overdrive_fpga(void) | ||
130 | { | ||
131 | program_overdrive_fpga(fpgacode, sizeof(fpgacode)); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c new file mode 100644 index 000000000000..276fa11ee4ce --- /dev/null +++ b/arch/sh/boards/overdrive/galileo.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file contains the PCI routines required for the Galileo GT6411 | ||
8 | * PCI bridge as used on the Orion and Overdrive boards. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/ioport.h> | ||
22 | |||
23 | #include <asm/overdrive/overdrive.h> | ||
24 | #include <asm/overdrive/gt64111.h> | ||
25 | |||
26 | |||
27 | /* After boot, we shift the Galileo registers so that they appear | ||
28 | * in BANK6, along with IO space. This means we can have one contingous | ||
29 | * lump of PCI address space without these registers appearing in the | ||
30 | * middle of them | ||
31 | */ | ||
32 | |||
33 | #define GT64111_BASE_ADDRESS 0xbb000000 | ||
34 | #define GT64111_IO_BASE_ADDRESS 0x1000 | ||
35 | /* The GT64111 registers appear at this address to the SH4 after reset */ | ||
36 | #define RESET_GT64111_BASE_ADDRESS 0xb4000000 | ||
37 | |||
38 | /* Macros used to access the Galileo registers */ | ||
39 | #define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x) | ||
40 | #define GT64111_REG(x) (GT64111_BASE_ADDRESS+x) | ||
41 | |||
42 | #define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x)) | ||
43 | |||
44 | #define RESET_GT_READ(x) readl(RESET_GT64111_REG(x)) | ||
45 | |||
46 | #define GT_WRITE(x,v) writel((v),GT64111_REG(x)) | ||
47 | #define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x)) | ||
48 | #define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x)) | ||
49 | |||
50 | #define GT_READ(x) readl(GT64111_REG(x)) | ||
51 | #define GT_READ_BYTE(x) readb(GT64111_REG(x)) | ||
52 | #define GT_READ_SHORT(x) readw(GT64111_REG(x)) | ||
53 | |||
54 | |||
55 | /* Where the various SH banks start at */ | ||
56 | #define SH_BANK4_ADR 0xb0000000 | ||
57 | #define SH_BANK5_ADR 0xb4000000 | ||
58 | #define SH_BANK6_ADR 0xb8000000 | ||
59 | |||
60 | /* Masks out everything but lines 28,27,26 */ | ||
61 | #define BANK_SELECT_MASK 0x1c000000 | ||
62 | |||
63 | #define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK) | ||
64 | |||
65 | /* | ||
66 | * Masks used for address conversaion. Bank 6 is used for IO and | ||
67 | * has all the address bits zeroed by the FPGA. Special case this | ||
68 | */ | ||
69 | #define MEMORY_BANK_MASK 0x1fffffff | ||
70 | #define IO_BANK_MASK 0x03ffffff | ||
71 | |||
72 | /* Mark bank 6 as the bank used for IO. You can change this in the FPGA code | ||
73 | * if you want | ||
74 | */ | ||
75 | #define IO_BANK_ADR PCI_GTIO_BASE | ||
76 | |||
77 | /* Will select the correct mask to apply depending on the SH$ address */ | ||
78 | #define SELECT_BANK_MASK(x) \ | ||
79 | ( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK) | ||
80 | |||
81 | /* Converts between PCI space and P2 region */ | ||
82 | #define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x)) | ||
83 | |||
84 | /* Various macros for figuring out what to stick in the Galileo registers. | ||
85 | * You *really* don't want to figure this stuff out by hand, you always get | ||
86 | * it wrong | ||
87 | */ | ||
88 | #define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff) | ||
89 | #define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f) | ||
90 | #define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff) | ||
91 | |||
92 | #define PROGRAM_HI_LO(block,a,s) \ | ||
93 | GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\ | ||
94 | GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1)) | ||
95 | |||
96 | #define PROGRAM_SUB_HI_LO(block,a,s) \ | ||
97 | GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\ | ||
98 | GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1)) | ||
99 | |||
100 | /* We need to set the size, and the offset register */ | ||
101 | |||
102 | #define GT_BAR_MASK(x) ((x)&~0xfff) | ||
103 | |||
104 | /* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */ | ||
105 | #define PROGRAM_GT_BAR(block,a,s) \ | ||
106 | GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\ | ||
107 | write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\ | ||
108 | GT_BAR_MASK(a)) | ||
109 | |||
110 | #define DISABLE_GT_BAR(block) \ | ||
111 | GT_WRITE(PCI_##block##_BANK_SIZE,0),\ | ||
112 | GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\ | ||
113 | 0x80000000) | ||
114 | |||
115 | /* Macros to disable things we are not going to use */ | ||
116 | #define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\ | ||
117 | GT_WRITE(x##_HI_DEC_ADR,0x00) | ||
118 | |||
119 | #define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\ | ||
120 | GT_WRITE(x##_HI_DEC_ADR,0x00) | ||
121 | |||
122 | static void __init reset_pci(void) | ||
123 | { | ||
124 | /* Set RESET_PCI bit high */ | ||
125 | writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL); | ||
126 | udelay(250); | ||
127 | |||
128 | /* Set RESET_PCI bit low */ | ||
129 | writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL); | ||
130 | udelay(250); | ||
131 | |||
132 | writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL); | ||
133 | udelay(250); | ||
134 | } | ||
135 | |||
136 | static int write_config_to_galileo(int where, u32 val); | ||
137 | #define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val) | ||
138 | |||
139 | #define ENABLE_PCI_DRAM | ||
140 | |||
141 | |||
142 | #ifdef TEST_DRAM | ||
143 | /* Test function to check out if the PCI DRAM is working OK */ | ||
144 | static int /* __init */ test_dram(unsigned *base, unsigned size) | ||
145 | { | ||
146 | unsigned *p = base; | ||
147 | unsigned *end = (unsigned *) (((unsigned) base) + size); | ||
148 | unsigned w; | ||
149 | |||
150 | for (p = base; p < end; p++) { | ||
151 | *p = 0xffffffff; | ||
152 | if (*p != 0xffffffff) { | ||
153 | printk("AAARGH -write failed!!! at %p is %x\n", p, | ||
154 | *p); | ||
155 | return 0; | ||
156 | } | ||
157 | *p = 0x0; | ||
158 | if (*p != 0x0) { | ||
159 | printk("AAARGH -write failed!!!\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | for (p = base; p < end; p++) { | ||
165 | *p = (unsigned) p; | ||
166 | if (*p != (unsigned) p) { | ||
167 | printk("Failed at 0x%p, actually is 0x%x\n", p, | ||
168 | *p); | ||
169 | return 0; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | for (p = base; p < end; p++) { | ||
174 | w = ((unsigned) p & 0xffff0000); | ||
175 | *p = w | (w >> 16); | ||
176 | } | ||
177 | |||
178 | for (p = base; p < end; p++) { | ||
179 | w = ((unsigned) p & 0xffff0000); | ||
180 | w |= (w >> 16); | ||
181 | if (*p != w) { | ||
182 | printk | ||
183 | ("Failed at 0x%p, should be 0x%x actually is 0x%x\n", | ||
184 | p, w, *p); | ||
185 | return 0; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | return 1; | ||
190 | } | ||
191 | #endif | ||
192 | |||
193 | |||
194 | /* Function to set up and initialise the galileo. This sets up the BARS, | ||
195 | * maps the DRAM into the address space etc,etc | ||
196 | */ | ||
197 | int __init galileo_init(void) | ||
198 | { | ||
199 | reset_pci(); | ||
200 | |||
201 | /* Now shift the galileo regs into this block */ | ||
202 | RESET_GT_WRITE(INTERNAL_SPACE_DEC, | ||
203 | GT_MEM_LO_ADR(GT64111_BASE_ADDRESS)); | ||
204 | |||
205 | /* Should have a sanity check here, that you can read back at the new | ||
206 | * address what you just wrote | ||
207 | */ | ||
208 | |||
209 | /* Disable decode for all regions */ | ||
210 | DISABLE_DECODE(RAS10); | ||
211 | DISABLE_DECODE(RAS32); | ||
212 | DISABLE_DECODE(CS20); | ||
213 | DISABLE_DECODE(CS3); | ||
214 | DISABLE_DECODE(PCI_IO); | ||
215 | DISABLE_DECODE(PCI_MEM0); | ||
216 | DISABLE_DECODE(PCI_MEM1); | ||
217 | |||
218 | /* Disable all BARS */ | ||
219 | GT_WRITE(BAR_ENABLE_ADR, 0x1ff); | ||
220 | DISABLE_GT_BAR(RAS10); | ||
221 | DISABLE_GT_BAR(RAS32); | ||
222 | DISABLE_GT_BAR(CS20); | ||
223 | DISABLE_GT_BAR(CS3); | ||
224 | |||
225 | /* Tell the BAR where the IO registers now are */ | ||
226 | GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK( | ||
227 | (GT64111_IO_BASE_ADDRESS & | ||
228 | IO_BANK_MASK))); | ||
229 | /* set up a 112 Mb decode */ | ||
230 | PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024); | ||
231 | |||
232 | /* Set up a 32 MB io space decode */ | ||
233 | PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024); | ||
234 | |||
235 | #ifdef ENABLE_PCI_DRAM | ||
236 | /* Program up the DRAM configuration - there is DRAM only in bank 0 */ | ||
237 | /* Now set up the DRAM decode */ | ||
238 | PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE); | ||
239 | /* And the sub decode */ | ||
240 | PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE); | ||
241 | |||
242 | DISABLE_SUB_DECODE(RAS1); | ||
243 | |||
244 | /* Set refresh rate */ | ||
245 | GT_WRITE(DRAM_BANK0_PARMS, 0x3f); | ||
246 | GT_WRITE(DRAM_CFG, 0x100); | ||
247 | |||
248 | /* we have to lob off the top bits rememeber!! */ | ||
249 | PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE); | ||
250 | |||
251 | #endif | ||
252 | |||
253 | /* We are only interested in decoding RAS10 and the Galileo's internal | ||
254 | * registers (as IO) on the PCI bus | ||
255 | */ | ||
256 | #ifdef ENABLE_PCI_DRAM | ||
257 | GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff); | ||
258 | #else | ||
259 | GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff); | ||
260 | #endif | ||
261 | |||
262 | /* Change the class code to host bridge, it actually powers up | ||
263 | * as a memory controller | ||
264 | */ | ||
265 | GT_CONFIG_WRITE(8, 0x06000011); | ||
266 | |||
267 | /* Allow the galileo to master the PCI bus */ | ||
268 | GT_CONFIG_WRITE(PCI_COMMAND, | ||
269 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | ||
270 | PCI_COMMAND_IO); | ||
271 | |||
272 | |||
273 | #if 0 | ||
274 | printk("Testing PCI DRAM - "); | ||
275 | if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) { | ||
276 | printk("Passed\n"); | ||
277 | }else { | ||
278 | printk("FAILED\n"); | ||
279 | } | ||
280 | #endif | ||
281 | return 0; | ||
282 | |||
283 | } | ||
284 | |||
285 | |||
286 | #define SET_CONFIG_BITS(bus,devfn,where)\ | ||
287 | ((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | ||
288 | |||
289 | #define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where) | ||
290 | |||
291 | /* This write to the galileo config registers, unlike the functions below, can | ||
292 | * be used before the PCI subsystem has started up | ||
293 | */ | ||
294 | static int __init write_config_to_galileo(int where, u32 val) | ||
295 | { | ||
296 | GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where)); | ||
297 | |||
298 | GT_WRITE(PCI_CFG_DATA, val); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* We exclude the galileo and slot 31, the galileo because I don't know how to stop | ||
303 | * the setup code shagging up the setup I have done on it, and 31 because the whole | ||
304 | * thing locks up if you try to access that slot (which doesn't exist of course anyway | ||
305 | */ | ||
306 | |||
307 | #define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31))) | ||
308 | |||
309 | static int galileo_read_config_byte(struct pci_dev *dev, int where, | ||
310 | u8 * val) | ||
311 | { | ||
312 | |||
313 | |||
314 | /* I suspect this doesn't work because this drives a special cycle ? */ | ||
315 | if (EXCLUDED_DEV(dev)) { | ||
316 | *val = 0xff; | ||
317 | return PCIBIOS_SUCCESSFUL; | ||
318 | } | ||
319 | /* Start the config cycle */ | ||
320 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
321 | /* Read back the result */ | ||
322 | *val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3)); | ||
323 | |||
324 | return PCIBIOS_SUCCESSFUL; | ||
325 | } | ||
326 | |||
327 | |||
328 | static int galileo_read_config_word(struct pci_dev *dev, int where, | ||
329 | u16 * val) | ||
330 | { | ||
331 | |||
332 | if (EXCLUDED_DEV(dev)) { | ||
333 | *val = 0xffff; | ||
334 | return PCIBIOS_SUCCESSFUL; | ||
335 | } | ||
336 | |||
337 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
338 | *val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2)); | ||
339 | |||
340 | return PCIBIOS_SUCCESSFUL; | ||
341 | } | ||
342 | |||
343 | |||
344 | static int galileo_read_config_dword(struct pci_dev *dev, int where, | ||
345 | u32 * val) | ||
346 | { | ||
347 | if (EXCLUDED_DEV(dev)) { | ||
348 | *val = 0xffffffff; | ||
349 | return PCIBIOS_SUCCESSFUL; | ||
350 | } | ||
351 | |||
352 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
353 | *val = GT_READ(PCI_CFG_DATA); | ||
354 | |||
355 | return PCIBIOS_SUCCESSFUL; | ||
356 | } | ||
357 | |||
358 | static int galileo_write_config_byte(struct pci_dev *dev, int where, | ||
359 | u8 val) | ||
360 | { | ||
361 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
362 | |||
363 | GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val); | ||
364 | |||
365 | return PCIBIOS_SUCCESSFUL; | ||
366 | } | ||
367 | |||
368 | |||
369 | static int galileo_write_config_word(struct pci_dev *dev, int where, | ||
370 | u16 val) | ||
371 | { | ||
372 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
373 | |||
374 | GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val); | ||
375 | |||
376 | return PCIBIOS_SUCCESSFUL; | ||
377 | } | ||
378 | |||
379 | static int galileo_write_config_dword(struct pci_dev *dev, int where, | ||
380 | u32 val) | ||
381 | { | ||
382 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
383 | |||
384 | GT_WRITE(PCI_CFG_DATA, val); | ||
385 | |||
386 | return PCIBIOS_SUCCESSFUL; | ||
387 | } | ||
388 | |||
389 | static struct pci_ops pci_config_ops = { | ||
390 | galileo_read_config_byte, | ||
391 | galileo_read_config_word, | ||
392 | galileo_read_config_dword, | ||
393 | galileo_write_config_byte, | ||
394 | galileo_write_config_word, | ||
395 | galileo_write_config_dword | ||
396 | }; | ||
397 | |||
398 | |||
399 | /* Everything hangs off this */ | ||
400 | static struct pci_bus *pci_root_bus; | ||
401 | |||
402 | |||
403 | static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) | ||
404 | { | ||
405 | return PCI_SLOT(dev->devfn); | ||
406 | } | ||
407 | |||
408 | static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
409 | { | ||
410 | /* Slot 1: Galileo | ||
411 | * Slot 2: PCI Slot 1 | ||
412 | * Slot 3: PCI Slot 2 | ||
413 | * Slot 4: ESS | ||
414 | */ | ||
415 | switch (slot) { | ||
416 | case 2: | ||
417 | return OVERDRIVE_PCI_IRQ1; | ||
418 | case 3: | ||
419 | /* Note this assumes you have a hacked card in slot 2 */ | ||
420 | return OVERDRIVE_PCI_IRQ2; | ||
421 | case 4: | ||
422 | return OVERDRIVE_ESS_IRQ; | ||
423 | default: | ||
424 | /* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */ | ||
425 | return -1; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | |||
430 | |||
431 | void __init | ||
432 | pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) | ||
433 | { | ||
434 | ranges->io_start -= bus->resource[0]->start; | ||
435 | ranges->io_end -= bus->resource[0]->start; | ||
436 | ranges->mem_start -= bus->resource[1]->start; | ||
437 | ranges->mem_end -= bus->resource[1]->start; | ||
438 | } | ||
439 | |||
440 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | /* | ||
445 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
446 | */ | ||
447 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
448 | return; | ||
449 | printk("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
450 | for(i=0; i<4; i++) { | ||
451 | struct resource *r = &d->resource[i]; | ||
452 | if ((r->start & ~0x80) == 0x374) { | ||
453 | r->start |= 2; | ||
454 | r->end = r->start; | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
459 | |||
460 | void __init pcibios_init(void) | ||
461 | { | ||
462 | static struct resource galio,galmem; | ||
463 | |||
464 | /* Allocate the registers used by the Galileo */ | ||
465 | galio.flags = IORESOURCE_IO; | ||
466 | galio.name = "Galileo GT64011"; | ||
467 | galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH; | ||
468 | galmem.name = "Galileo GT64011 DRAM"; | ||
469 | |||
470 | allocate_resource(&ioport_resource, &galio, 256, | ||
471 | GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL); | ||
472 | allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE, | ||
473 | PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE, | ||
474 | PCI_DRAM_SIZE, NULL, NULL); | ||
475 | |||
476 | /* ok, do the scan man */ | ||
477 | pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); | ||
478 | |||
479 | pci_assign_unassigned_resources(); | ||
480 | pci_fixup_irqs(no_swizzle, map_od_irq); | ||
481 | |||
482 | #ifdef TEST_DRAM | ||
483 | printk("Testing PCI DRAM - "); | ||
484 | if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) { | ||
485 | printk("Passed\n"); | ||
486 | }else { | ||
487 | printk("FAILED\n"); | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | } | ||
492 | |||
493 | char * __init pcibios_setup(char *str) | ||
494 | { | ||
495 | return str; | ||
496 | } | ||
497 | |||
498 | |||
499 | |||
500 | int pcibios_enable_device(struct pci_dev *dev) | ||
501 | { | ||
502 | |||
503 | u16 cmd, old_cmd; | ||
504 | int idx; | ||
505 | struct resource *r; | ||
506 | |||
507 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
508 | old_cmd = cmd; | ||
509 | for (idx = 0; idx < 6; idx++) { | ||
510 | r = dev->resource + idx; | ||
511 | if (!r->start && r->end) { | ||
512 | printk(KERN_ERR | ||
513 | "PCI: Device %s not available because" | ||
514 | " of resource collisions\n", | ||
515 | pci_name(dev)); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | if (r->flags & IORESOURCE_IO) | ||
519 | cmd |= PCI_COMMAND_IO; | ||
520 | if (r->flags & IORESOURCE_MEM) | ||
521 | cmd |= PCI_COMMAND_MEMORY; | ||
522 | } | ||
523 | if (cmd != old_cmd) { | ||
524 | printk("PCI: enabling device %s (%04x -> %04x)\n", | ||
525 | pci_name(dev), old_cmd, cmd); | ||
526 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
527 | } | ||
528 | return 0; | ||
529 | |||
530 | } | ||
531 | |||
532 | /* We should do some optimisation work here I think. Ok for now though */ | ||
533 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
534 | { | ||
535 | |||
536 | } | ||
537 | |||
538 | void pcibios_align_resource(void *data, struct resource *res, | ||
539 | unsigned long size) | ||
540 | { | ||
541 | } | ||
542 | |||
543 | void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, | ||
544 | struct resource *res, int resource) | ||
545 | { | ||
546 | |||
547 | unsigned long where, size; | ||
548 | u32 reg; | ||
549 | |||
550 | |||
551 | printk("PCI: Assigning %3s %08lx to %s\n", | ||
552 | res->flags & IORESOURCE_IO ? "IO" : "MEM", | ||
553 | res->start, dev->name); | ||
554 | |||
555 | where = PCI_BASE_ADDRESS_0 + resource * 4; | ||
556 | size = res->end - res->start; | ||
557 | |||
558 | pci_read_config_dword(dev, where, ®); | ||
559 | reg = (reg & size) | (((u32) (res->start - root->start)) & ~size); | ||
560 | pci_write_config_dword(dev, where, reg); | ||
561 | } | ||
562 | |||
563 | |||
564 | void __init pcibios_update_irq(struct pci_dev *dev, int irq) | ||
565 | { | ||
566 | printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); | ||
567 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * If we set up a device for bus mastering, we need to check the latency | ||
572 | * timer as certain crappy BIOSes forget to set it properly. | ||
573 | */ | ||
574 | unsigned int pcibios_max_latency = 255; | ||
575 | |||
576 | void pcibios_set_master(struct pci_dev *dev) | ||
577 | { | ||
578 | u8 lat; | ||
579 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
580 | if (lat < 16) | ||
581 | lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; | ||
582 | else if (lat > pcibios_max_latency) | ||
583 | lat = pcibios_max_latency; | ||
584 | else | ||
585 | return; | ||
586 | printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); | ||
587 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
588 | } | ||
diff --git a/arch/sh/boards/overdrive/io.c b/arch/sh/boards/overdrive/io.c new file mode 100644 index 000000000000..65f3fd0563d3 --- /dev/null +++ b/arch/sh/boards/overdrive/io.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file contains the I/O routines for use on the overdrive board | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <asm/processor.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/addrspace.h> | ||
17 | |||
18 | #include <asm/overdrive/overdrive.h> | ||
19 | |||
20 | /* | ||
21 | * readX/writeX() are used to access memory mapped devices. On some | ||
22 | * architectures the memory mapped IO stuff needs to be accessed | ||
23 | * differently. On the SuperH architecture, we just read/write the | ||
24 | * memory location directly. | ||
25 | */ | ||
26 | |||
27 | #define dprintk(x...) | ||
28 | |||
29 | /* Translates an IO address to where it is mapped in memory */ | ||
30 | |||
31 | #define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE) | ||
32 | |||
33 | unsigned char od_inb(unsigned long port) | ||
34 | { | ||
35 | dprintk("od_inb(%x)\n", port); | ||
36 | return readb(io_addr(port)) & 0xff; | ||
37 | } | ||
38 | |||
39 | |||
40 | unsigned short od_inw(unsigned long port) | ||
41 | { | ||
42 | dprintk("od_inw(%x)\n", port); | ||
43 | return readw(io_addr(port)) & 0xffff; | ||
44 | } | ||
45 | |||
46 | unsigned int od_inl(unsigned long port) | ||
47 | { | ||
48 | dprintk("od_inl(%x)\n", port); | ||
49 | return readl(io_addr(port)); | ||
50 | } | ||
51 | |||
52 | void od_outb(unsigned char value, unsigned long port) | ||
53 | { | ||
54 | dprintk("od_outb(%x, %x)\n", value, port); | ||
55 | writeb(value, io_addr(port)); | ||
56 | } | ||
57 | |||
58 | void od_outw(unsigned short value, unsigned long port) | ||
59 | { | ||
60 | dprintk("od_outw(%x, %x)\n", value, port); | ||
61 | writew(value, io_addr(port)); | ||
62 | } | ||
63 | |||
64 | void od_outl(unsigned int value, unsigned long port) | ||
65 | { | ||
66 | dprintk("od_outl(%x, %x)\n", value, port); | ||
67 | writel(value, io_addr(port)); | ||
68 | } | ||
69 | |||
70 | /* This is horrible at the moment - needs more work to do something sensible */ | ||
71 | #define IO_DELAY() udelay(10) | ||
72 | |||
73 | #define OUT_DELAY(x,type) \ | ||
74 | void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();} | ||
75 | |||
76 | #define IN_DELAY(x,type) \ | ||
77 | unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;} | ||
78 | |||
79 | |||
80 | OUT_DELAY(b,char) | ||
81 | OUT_DELAY(w,short) | ||
82 | OUT_DELAY(l,int) | ||
83 | |||
84 | IN_DELAY(b,char) | ||
85 | IN_DELAY(w,short) | ||
86 | IN_DELAY(l,int) | ||
87 | |||
88 | |||
89 | /* Now for the string version of these functions */ | ||
90 | void od_outsb(unsigned long port, const void *addr, unsigned long count) | ||
91 | { | ||
92 | int i; | ||
93 | unsigned char *p = (unsigned char *) addr; | ||
94 | |||
95 | for (i = 0; i < count; i++, p++) { | ||
96 | outb(*p, port); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | void od_insb(unsigned long port, void *addr, unsigned long count) | ||
102 | { | ||
103 | int i; | ||
104 | unsigned char *p = (unsigned char *) addr; | ||
105 | |||
106 | for (i = 0; i < count; i++, p++) { | ||
107 | *p = inb(port); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* For the 16 and 32 bit string functions, we have to worry about alignment. | ||
112 | * The SH does not do unaligned accesses, so we have to read as bytes and | ||
113 | * then write as a word or dword. | ||
114 | * This can be optimised a lot more, especially in the case where the data | ||
115 | * is aligned | ||
116 | */ | ||
117 | |||
118 | void od_outsw(unsigned long port, const void *addr, unsigned long count) | ||
119 | { | ||
120 | int i; | ||
121 | unsigned short tmp; | ||
122 | unsigned char *p = (unsigned char *) addr; | ||
123 | |||
124 | for (i = 0; i < count; i++, p += 2) { | ||
125 | tmp = (*p) | ((*(p + 1)) << 8); | ||
126 | outw(tmp, port); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | |||
131 | void od_insw(unsigned long port, void *addr, unsigned long count) | ||
132 | { | ||
133 | int i; | ||
134 | unsigned short tmp; | ||
135 | unsigned char *p = (unsigned char *) addr; | ||
136 | |||
137 | for (i = 0; i < count; i++, p += 2) { | ||
138 | tmp = inw(port); | ||
139 | p[0] = tmp & 0xff; | ||
140 | p[1] = (tmp >> 8) & 0xff; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | void od_outsl(unsigned long port, const void *addr, unsigned long count) | ||
146 | { | ||
147 | int i; | ||
148 | unsigned tmp; | ||
149 | unsigned char *p = (unsigned char *) addr; | ||
150 | |||
151 | for (i = 0; i < count; i++, p += 4) { | ||
152 | tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) | | ||
153 | ((*(p + 3)) << 24); | ||
154 | outl(tmp, port); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | |||
159 | void od_insl(unsigned long port, void *addr, unsigned long count) | ||
160 | { | ||
161 | int i; | ||
162 | unsigned tmp; | ||
163 | unsigned char *p = (unsigned char *) addr; | ||
164 | |||
165 | for (i = 0; i < count; i++, p += 4) { | ||
166 | tmp = inl(port); | ||
167 | p[0] = tmp & 0xff; | ||
168 | p[1] = (tmp >> 8) & 0xff; | ||
169 | p[2] = (tmp >> 16) & 0xff; | ||
170 | p[3] = (tmp >> 24) & 0xff; | ||
171 | |||
172 | } | ||
173 | } | ||
diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c new file mode 100644 index 000000000000..23adc6be71e7 --- /dev/null +++ b/arch/sh/boards/overdrive/irq.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Looks after interrupts on the overdrive board. | ||
8 | * | ||
9 | * Bases on the IPR irq system | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #include <asm/overdrive/overdrive.h> | ||
20 | |||
21 | struct od_data { | ||
22 | int overdrive_irq; | ||
23 | int irq_mask; | ||
24 | }; | ||
25 | |||
26 | #define NUM_EXTERNAL_IRQS 16 | ||
27 | #define EXTERNAL_IRQ_NOT_IN_USE (-1) | ||
28 | #define EXTERNAL_IRQ_NOT_ASSIGNED (-1) | ||
29 | |||
30 | /* | ||
31 | * This table is used to determine what to program into the FPGA's CT register | ||
32 | * for the specified Linux IRQ. | ||
33 | * | ||
34 | * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0)) | ||
35 | * but is one greater than that because the because the FPGA treats 0 | ||
36 | * as disabled, a value of 1 asserts PCI_Int0, and so on. | ||
37 | * | ||
38 | * The overdrive_irq specifies which of the eight interrupt sources generates | ||
39 | * that interrupt, and but is multiplied by four to give the bit offset into | ||
40 | * the CT register. | ||
41 | * | ||
42 | * The seven interrupts levels (SH4 IRL's) we have available here is hardwired | ||
43 | * by the EPLD. The assignments here of which PCI interrupt generates each | ||
44 | * level is arbitary. | ||
45 | */ | ||
46 | static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = { | ||
47 | /* overdrive_irq , irq_mask */ | ||
48 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */ | ||
49 | {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */ | ||
50 | {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */ | ||
51 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */ | ||
52 | {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */ | ||
53 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */ | ||
54 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */ | ||
55 | {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */ | ||
56 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */ | ||
57 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */ | ||
58 | {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */ | ||
59 | {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */ | ||
60 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */ | ||
61 | {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */ | ||
62 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */ | ||
63 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */ | ||
64 | }; | ||
65 | |||
66 | static void set_od_data(int overdrive_irq, int irq) | ||
67 | { | ||
68 | if (irq >= NUM_EXTERNAL_IRQS || irq < 0) | ||
69 | return; | ||
70 | od_data_table[irq].overdrive_irq = overdrive_irq << 2; | ||
71 | } | ||
72 | |||
73 | static void enable_od_irq(unsigned int irq); | ||
74 | void disable_od_irq(unsigned int irq); | ||
75 | |||
76 | /* shutdown is same as "disable" */ | ||
77 | #define shutdown_od_irq disable_od_irq | ||
78 | |||
79 | static void mask_and_ack_od(unsigned int); | ||
80 | static void end_od_irq(unsigned int irq); | ||
81 | |||
82 | static unsigned int startup_od_irq(unsigned int irq) | ||
83 | { | ||
84 | enable_od_irq(irq); | ||
85 | return 0; /* never anything pending */ | ||
86 | } | ||
87 | |||
88 | static struct hw_interrupt_type od_irq_type = { | ||
89 | "Overdrive-IRQ", | ||
90 | startup_od_irq, | ||
91 | shutdown_od_irq, | ||
92 | enable_od_irq, | ||
93 | disable_od_irq, | ||
94 | mask_and_ack_od, | ||
95 | end_od_irq | ||
96 | }; | ||
97 | |||
98 | static void disable_od_irq(unsigned int irq) | ||
99 | { | ||
100 | unsigned val, flags; | ||
101 | int overdrive_irq; | ||
102 | unsigned mask; | ||
103 | |||
104 | /* Not a valid interrupt */ | ||
105 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
106 | return; | ||
107 | |||
108 | /* Is is necessary to use a cli here? Would a spinlock not be | ||
109 | * mroe efficient? | ||
110 | */ | ||
111 | local_irq_save(flags); | ||
112 | overdrive_irq = od_data_table[irq].overdrive_irq; | ||
113 | if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) { | ||
114 | mask = ~(0x7 << overdrive_irq); | ||
115 | val = ctrl_inl(OVERDRIVE_INT_CT); | ||
116 | val &= mask; | ||
117 | ctrl_outl(val, OVERDRIVE_INT_CT); | ||
118 | } | ||
119 | local_irq_restore(flags); | ||
120 | } | ||
121 | |||
122 | static void enable_od_irq(unsigned int irq) | ||
123 | { | ||
124 | unsigned val, flags; | ||
125 | int overdrive_irq; | ||
126 | unsigned mask; | ||
127 | |||
128 | /* Not a valid interrupt */ | ||
129 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
130 | return; | ||
131 | |||
132 | /* Set priority in OD back to original value */ | ||
133 | local_irq_save(flags); | ||
134 | /* This one is not in use currently */ | ||
135 | overdrive_irq = od_data_table[irq].overdrive_irq; | ||
136 | if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) { | ||
137 | val = ctrl_inl(OVERDRIVE_INT_CT); | ||
138 | mask = ~(0x7 << overdrive_irq); | ||
139 | val &= mask; | ||
140 | mask = od_data_table[irq].irq_mask << overdrive_irq; | ||
141 | val |= mask; | ||
142 | ctrl_outl(val, OVERDRIVE_INT_CT); | ||
143 | } | ||
144 | local_irq_restore(flags); | ||
145 | } | ||
146 | |||
147 | |||
148 | |||
149 | /* this functions sets the desired irq handler to be an overdrive type */ | ||
150 | static void __init make_od_irq(unsigned int irq) | ||
151 | { | ||
152 | disable_irq_nosync(irq); | ||
153 | irq_desc[irq].handler = &od_irq_type; | ||
154 | disable_od_irq(irq); | ||
155 | } | ||
156 | |||
157 | |||
158 | static void mask_and_ack_od(unsigned int irq) | ||
159 | { | ||
160 | disable_od_irq(irq); | ||
161 | } | ||
162 | |||
163 | static void end_od_irq(unsigned int irq) | ||
164 | { | ||
165 | enable_od_irq(irq); | ||
166 | } | ||
167 | |||
168 | void __init init_overdrive_irq(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | /* Disable all interrupts */ | ||
173 | ctrl_outl(0, OVERDRIVE_INT_CT); | ||
174 | |||
175 | /* Update interrupt pin mode to use encoded interrupts */ | ||
176 | i = ctrl_inw(INTC_ICR); | ||
177 | i &= ~INTC_ICR_IRLM; | ||
178 | ctrl_outw(i, INTC_ICR); | ||
179 | |||
180 | for (i = 0; i < NUM_EXTERNAL_IRQS; i++) { | ||
181 | if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) { | ||
182 | make_od_irq(i); | ||
183 | } else if (i != 15) { // Cannot use imask on level 15 | ||
184 | make_imask_irq(i); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /* Set up the interrupts */ | ||
189 | set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1); | ||
190 | set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2); | ||
191 | set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ); | ||
192 | } | ||
diff --git a/arch/sh/boards/overdrive/led.c b/arch/sh/boards/overdrive/led.c new file mode 100644 index 000000000000..734742e92279 --- /dev/null +++ b/arch/sh/boards/overdrive/led.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/overdrive/led.c | ||
3 | * | ||
4 | * Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains an Overdrive specific LED feature. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/system.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/overdrive/overdrive.h> | ||
16 | |||
17 | static void mach_led(int position, int value) | ||
18 | { | ||
19 | unsigned long flags; | ||
20 | unsigned long reg; | ||
21 | |||
22 | local_irq_save(flags); | ||
23 | |||
24 | reg = readl(OVERDRIVE_CTRL); | ||
25 | if (value) { | ||
26 | reg |= (1<<3); | ||
27 | } else { | ||
28 | reg &= ~(1<<3); | ||
29 | } | ||
30 | writel(reg, OVERDRIVE_CTRL); | ||
31 | |||
32 | local_irq_restore(flags); | ||
33 | } | ||
34 | |||
35 | #ifdef CONFIG_HEARTBEAT | ||
36 | |||
37 | #include <linux/sched.h> | ||
38 | |||
39 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
40 | void heartbeat_od(void) | ||
41 | { | ||
42 | static unsigned cnt = 0, period = 0, dist = 0; | ||
43 | |||
44 | if (cnt == 0 || cnt == dist) | ||
45 | mach_led( -1, 1); | ||
46 | else if (cnt == 7 || cnt == dist+7) | ||
47 | mach_led( -1, 0); | ||
48 | |||
49 | if (++cnt > period) { | ||
50 | cnt = 0; | ||
51 | /* The hyperbolic function below modifies the heartbeat period | ||
52 | * length in dependency of the current (5min) load. It goes | ||
53 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
54 | * f(inf)->30. */ | ||
55 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
56 | dist = period / 4; | ||
57 | } | ||
58 | } | ||
59 | #endif /* CONFIG_HEARTBEAT */ | ||
diff --git a/arch/sh/boards/overdrive/mach.c b/arch/sh/boards/overdrive/mach.c new file mode 100644 index 000000000000..2834a03ae477 --- /dev/null +++ b/arch/sh/boards/overdrive/mach.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/overdrive/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the STMicroelectronics Overdrive | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io_unknown.h> | ||
19 | #include <asm/io_generic.h> | ||
20 | #include <asm/overdrive/io.h> | ||
21 | |||
22 | void heartbeat_od(void); | ||
23 | void init_overdrive_irq(void); | ||
24 | void galileo_pcibios_init(void); | ||
25 | |||
26 | /* | ||
27 | * The Machine Vector | ||
28 | */ | ||
29 | |||
30 | struct sh_machine_vector mv_od __initmv = { | ||
31 | .mv_nr_irqs = 48, | ||
32 | |||
33 | .mv_inb = od_inb, | ||
34 | .mv_inw = od_inw, | ||
35 | .mv_inl = od_inl, | ||
36 | .mv_outb = od_outb, | ||
37 | .mv_outw = od_outw, | ||
38 | .mv_outl = od_outl, | ||
39 | |||
40 | .mv_inb_p = od_inb_p, | ||
41 | .mv_inw_p = od_inw_p, | ||
42 | .mv_inl_p = od_inl_p, | ||
43 | .mv_outb_p = od_outb_p, | ||
44 | .mv_outw_p = od_outw_p, | ||
45 | .mv_outl_p = od_outl_p, | ||
46 | |||
47 | .mv_insb = od_insb, | ||
48 | .mv_insw = od_insw, | ||
49 | .mv_insl = od_insl, | ||
50 | .mv_outsb = od_outsb, | ||
51 | .mv_outsw = od_outsw, | ||
52 | .mv_outsl = od_outsl, | ||
53 | |||
54 | #ifdef CONFIG_PCI | ||
55 | .mv_init_irq = init_overdrive_irq, | ||
56 | #endif | ||
57 | #ifdef CONFIG_HEARTBEAT | ||
58 | .mv_heartbeat = heartbeat_od, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
62 | ALIAS_MV(od) | ||
diff --git a/arch/sh/boards/overdrive/pcidma.c b/arch/sh/boards/overdrive/pcidma.c new file mode 100644 index 000000000000..1c9bfeda00b7 --- /dev/null +++ b/arch/sh/boards/overdrive/pcidma.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Dynamic DMA mapping support. | ||
8 | * | ||
9 | * On the overdrive, we can only DMA from memory behind the PCI bus! | ||
10 | * this means that all DMA'able memory must come from there. | ||
11 | * this restriction will not apply to later boards. | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, | ||
21 | dma_addr_t * dma_handle) | ||
22 | { | ||
23 | void *ret; | ||
24 | int gfp = GFP_ATOMIC; | ||
25 | |||
26 | printk("BUG: pci_alloc_consistent() called - not yet supported\n"); | ||
27 | /* We ALWAYS need DMA memory on the overdrive hardware, | ||
28 | * due to it's extreme weirdness | ||
29 | * Need to flush the cache here as well, since the memory | ||
30 | * can still be seen through the cache! | ||
31 | */ | ||
32 | gfp |= GFP_DMA; | ||
33 | ret = (void *) __get_free_pages(gfp, get_order(size)); | ||
34 | |||
35 | if (ret != NULL) { | ||
36 | memset(ret, 0, size); | ||
37 | *dma_handle = virt_to_bus(ret); | ||
38 | } | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | void pci_free_consistent(struct pci_dev *hwdev, size_t size, | ||
43 | void *vaddr, dma_addr_t dma_handle) | ||
44 | { | ||
45 | free_pages((unsigned long) vaddr, get_order(size)); | ||
46 | } | ||
diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c new file mode 100644 index 000000000000..a36ce0284ed3 --- /dev/null +++ b/arch/sh/boards/overdrive/setup.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * arch/sh/overdrive/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * STMicroelectronics Overdrive Support. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/io.h> | ||
16 | |||
17 | #include <asm/overdrive/overdrive.h> | ||
18 | #include <asm/overdrive/fpga.h> | ||
19 | |||
20 | extern void od_time_init(void); | ||
21 | |||
22 | const char *get_system_type(void) | ||
23 | { | ||
24 | return "SH7750 Overdrive"; | ||
25 | } | ||
26 | |||
27 | /* | ||
28 | * Initialize the board | ||
29 | */ | ||
30 | int __init platform_setup(void) | ||
31 | { | ||
32 | #ifdef CONFIG_PCI | ||
33 | init_overdrive_fpga(); | ||
34 | galileo_init(); | ||
35 | #endif | ||
36 | |||
37 | board_time_init = od_time_init; | ||
38 | |||
39 | /* Enable RS232 receive buffers */ | ||
40 | writel(0x1e, OVERDRIVE_CTRL); | ||
41 | } | ||
diff --git a/arch/sh/boards/overdrive/time.c b/arch/sh/boards/overdrive/time.c new file mode 100644 index 000000000000..68533690e097 --- /dev/null +++ b/arch/sh/boards/overdrive/time.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/overdrive/time.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org) | ||
6 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public | ||
8 | * License. See linux/COPYING for more information. | ||
9 | * | ||
10 | * STMicroelectronics Overdrive Support. | ||
11 | */ | ||
12 | |||
13 | void od_time_init(void) | ||
14 | { | ||
15 | struct frqcr_data { | ||
16 | unsigned short frqcr; | ||
17 | struct { | ||
18 | unsigned char multiplier; | ||
19 | unsigned char divisor; | ||
20 | } factor[3]; | ||
21 | }; | ||
22 | |||
23 | static struct frqcr_data st40_frqcr_table[] = { | ||
24 | { 0x000, {{1,1}, {1,1}, {1,2}}}, | ||
25 | { 0x002, {{1,1}, {1,1}, {1,4}}}, | ||
26 | { 0x004, {{1,1}, {1,1}, {1,8}}}, | ||
27 | { 0x008, {{1,1}, {1,2}, {1,2}}}, | ||
28 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, | ||
29 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, | ||
30 | { 0x011, {{1,1}, {2,3}, {1,6}}}, | ||
31 | { 0x013, {{1,1}, {2,3}, {1,3}}}, | ||
32 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, | ||
33 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, | ||
34 | { 0x023, {{1,1}, {2,3}, {1,3}}}, | ||
35 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, | ||
36 | { 0x048, {{1,2}, {1,2}, {1,4}}}, | ||
37 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, | ||
38 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, | ||
39 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, | ||
40 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, | ||
41 | { 0x063, {{1,2}, {1,4}, {1,4}}}, | ||
42 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, | ||
43 | { 0x091, {{1,3}, {1,3}, {1,6}}}, | ||
44 | { 0x093, {{1,3}, {1,3}, {1,6}}}, | ||
45 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, | ||
46 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, | ||
47 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, | ||
48 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, | ||
49 | { 0x123, {{1,4}, {1,4}, {1,8}}}, | ||
50 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, | ||
51 | }; | ||
52 | |||
53 | struct memclk_data { | ||
54 | unsigned char multiplier; | ||
55 | unsigned char divisor; | ||
56 | }; | ||
57 | static struct memclk_data st40_memclk_table[8] = { | ||
58 | {1,1}, // 000 | ||
59 | {1,2}, // 001 | ||
60 | {1,3}, // 010 | ||
61 | {2,3}, // 011 | ||
62 | {1,4}, // 100 | ||
63 | {1,6}, // 101 | ||
64 | {1,8}, // 110 | ||
65 | {1,8} // 111 | ||
66 | }; | ||
67 | |||
68 | unsigned long pvr; | ||
69 | |||
70 | /* | ||
71 | * This should probably be moved into the SH3 probing code, and then | ||
72 | * use the processor structure to determine which CPU we are running | ||
73 | * on. | ||
74 | */ | ||
75 | pvr = ctrl_inl(CCN_PVR); | ||
76 | printk("PVR %08x\n", pvr); | ||
77 | |||
78 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { | ||
79 | /* | ||
80 | * Unfortunatly the STB1 FRQCR values are different from the | ||
81 | * 7750 ones. | ||
82 | */ | ||
83 | struct frqcr_data *d; | ||
84 | int a; | ||
85 | unsigned long memclkcr; | ||
86 | struct memclk_data *e; | ||
87 | |||
88 | for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { | ||
89 | d = &st40_frqcr_table[a]; | ||
90 | if (d->frqcr == (frqcr & 0x1ff)) | ||
91 | break; | ||
92 | } | ||
93 | if (a == ARRAY_SIZE(st40_frqcr_table)) { | ||
94 | d = st40_frqcr_table; | ||
95 | printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); | ||
96 | } | ||
97 | |||
98 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); | ||
99 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; | ||
100 | |||
101 | printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n", | ||
102 | d->factor[0].multiplier, d->factor[0].divisor, | ||
103 | d->factor[1].multiplier, d->factor[1].divisor, | ||
104 | e->multiplier, e->divisor, | ||
105 | d->factor[2].multiplier, d->factor[2].divisor); | ||
106 | |||
107 | current_cpu_data.master_clock = current_cpu_data.module_clock * | ||
108 | d->factor[2].divisor / | ||
109 | d->factor[2].multiplier; | ||
110 | current_cpu_data.bus_clock = current_cpu_data.master_clock * | ||
111 | d->factor[1].multiplier / | ||
112 | d->factor[1].divisor; | ||
113 | current_cpu_data.memory_clock = current_cpu_data.master_clock * | ||
114 | e->multiplier / e->divisor; | ||
115 | current_cpu_data.cpu_clock = current_cpu_data.master_clock * | ||
116 | d->factor[0].multiplier / | ||
117 | d->factor[0].divisor; | ||
118 | } | ||
119 | |||