aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorVitaly Bordug <vbordug@ru.mvista.com>2007-01-24 14:41:24 -0500
committerPaul Mackerras <paulus@samba.org>2007-02-06 22:03:17 -0500
commitf2a0bd3753dad7ea4605ebd5435716b39e9f92bb (patch)
treef14b6a7b9e3588a388be0f2b6602284c49c026e4 /arch/powerpc
parent88bdc6f061cfb4579d2327fd457d4b7807525a0e (diff)
[POWERPC] 8xx: powerpc port of core CPM PIC
This covers common CPM access functions, CPM interrupt controller code, micropatch and a few compatibility things to kee the same driver base working with arch/ppc. This version is refined with all the comments (mostly PIC-related) addressed. Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/commproc.c398
-rw-r--r--arch/powerpc/sysdev/micropatch.c743
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c197
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.h12
5 files changed, 1352 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 2621a7e72d2d..85dcdf178415 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -22,4 +22,6 @@ endif
22ifeq ($(ARCH),powerpc) 22ifeq ($(ARCH),powerpc)
23obj-$(CONFIG_MTD) += rom.o 23obj-$(CONFIG_MTD) += rom.o
24obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o 24obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
25obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o
26obj-$(CONFIG_UCODE_PATCH) += micropatch.o
25endif 27endif
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
new file mode 100644
index 000000000000..9b4fafd9a840
--- /dev/null
+++ b/arch/powerpc/sysdev/commproc.c
@@ -0,0 +1,398 @@
1/*
2 * General Purpose functions for the global management of the
3 * Communication Processor Module.
4 * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
5 *
6 * In addition to the individual control of the communication
7 * channels, there are a few functions that globally affect the
8 * communication processor.
9 *
10 * Buffer descriptors must be allocated from the dual ported memory
11 * space. The allocator for that is here. When the communication
12 * process is reset, we reclaim the memory available. There is
13 * currently no deallocator for this memory.
14 * The amount of space available is platform dependent. On the
15 * MBX, the EPPC software loads additional microcode into the
16 * communication processor, and uses some of the DP ram for this
17 * purpose. Current, the first 512 bytes and the last 256 bytes of
18 * memory are used. Right now I am conservative and only use the
19 * memory that can never be used for microcode. If there are
20 * applications that require more DP ram, we can expand the boundaries
21 * but then we have to be careful of any downloaded microcode.
22 */
23#include <linux/errno.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/param.h>
28#include <linux/string.h>
29#include <linux/mm.h>
30#include <linux/interrupt.h>
31#include <linux/irq.h>
32#include <linux/module.h>
33#include <asm/mpc8xx.h>
34#include <asm/page.h>
35#include <asm/pgtable.h>
36#include <asm/8xx_immap.h>
37#include <asm/commproc.h>
38#include <asm/io.h>
39#include <asm/tlbflush.h>
40#include <asm/rheap.h>
41#include <asm/prom.h>
42
43#include <asm/fs_pd.h>
44
45#define CPM_MAP_SIZE (0x4000)
46
47static void m8xx_cpm_dpinit(void);
48static uint host_buffer; /* One page of host buffer */
49static uint host_end; /* end + 1 */
50cpm8xx_t *cpmp; /* Pointer to comm processor space */
51cpic8xx_t *cpic_reg;
52
53static struct device_node *cpm_pic_node;
54static struct irq_host *cpm_pic_host;
55
56static void cpm_mask_irq(unsigned int irq)
57{
58 unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
59
60 clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
61}
62
63static void cpm_unmask_irq(unsigned int irq)
64{
65 unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
66
67 setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
68}
69
70static void cpm_end_irq(unsigned int irq)
71{
72 unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
73
74 out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
75}
76
77static struct irq_chip cpm_pic = {
78 .typename = " CPM PIC ",
79 .mask = cpm_mask_irq,
80 .unmask = cpm_unmask_irq,
81 .eoi = cpm_end_irq,
82};
83
84int cpm_get_irq(void)
85{
86 int cpm_vec;
87
88 /* Get the vector by setting the ACK bit and then reading
89 * the register.
90 */
91 out_be16(&cpic_reg->cpic_civr, 1);
92 cpm_vec = in_be16(&cpic_reg->cpic_civr);
93 cpm_vec >>= 11;
94
95 return irq_linear_revmap(cpm_pic_host, cpm_vec);
96}
97
98static int cpm_pic_host_match(struct irq_host *h, struct device_node *node)
99{
100 return cpm_pic_node == node;
101}
102
103static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
104 irq_hw_number_t hw)
105{
106 pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
107
108 get_irq_desc(virq)->status |= IRQ_LEVEL;
109 set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
110 return 0;
111}
112
113/* The CPM can generate the error interrupt when there is a race condition
114 * between generating and masking interrupts. All we have to do is ACK it
115 * and return. This is a no-op function so we don't need any special
116 * tests in the interrupt handler.
117 */
118static irqreturn_t cpm_error_interrupt(int irq, void *dev)
119{
120 return IRQ_HANDLED;
121}
122
123static struct irqaction cpm_error_irqaction = {
124 .handler = cpm_error_interrupt,
125 .mask = CPU_MASK_NONE,
126 .name = "error",
127};
128
129static struct irq_host_ops cpm_pic_host_ops = {
130 .match = cpm_pic_host_match,
131 .map = cpm_pic_host_map,
132};
133
134unsigned int cpm_pic_init(void)
135{
136 struct device_node *np = NULL;
137 struct resource res;
138 unsigned int sirq = NO_IRQ, hwirq, eirq;
139 int ret;
140
141 pr_debug("cpm_pic_init\n");
142
143 np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
144 if (np == NULL) {
145 printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n");
146 return sirq;
147 }
148 ret = of_address_to_resource(np, 0, &res);
149 if (ret)
150 goto end;
151
152 cpic_reg = (void *)ioremap(res.start, res.end - res.start + 1);
153 if (cpic_reg == NULL)
154 goto end;
155
156 sirq = irq_of_parse_and_map(np, 0);
157 if (sirq == NO_IRQ)
158 goto end;
159
160 /* Initialize the CPM interrupt controller. */
161 hwirq = (unsigned int)irq_map[sirq].hwirq;
162 out_be32(&cpic_reg->cpic_cicr,
163 (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
164 ((hwirq/2) << 13) | CICR_HP_MASK);
165
166 out_be32(&cpic_reg->cpic_cimr, 0);
167
168 cpm_pic_node = of_node_get(np);
169
170 cpm_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm_pic_host_ops, 64);
171 if (cpm_pic_host == NULL) {
172 printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
173 sirq = NO_IRQ;
174 goto end;
175 }
176 of_node_put(np);
177
178 /* Install our own error handler. */
179 np = of_find_node_by_type(NULL, "cpm");
180 if (np == NULL) {
181 printk(KERN_ERR "CPM PIC init: can not find cpm node\n");
182 goto end;
183 }
184 eirq= irq_of_parse_and_map(np, 0);
185 if (eirq == NO_IRQ)
186 goto end;
187
188 if (setup_irq(eirq, &cpm_error_irqaction))
189 printk(KERN_ERR "Could not allocate CPM error IRQ!");
190
191 setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
192
193end:
194 of_node_put(np);
195 return sirq;
196}
197
198void cpm_reset(void)
199{
200 cpm8xx_t *commproc;
201 sysconf8xx_t *siu_conf;
202
203 commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
204
205#ifdef CONFIG_UCODE_PATCH
206 /* Perform a reset.
207 */
208 out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
209
210 /* Wait for it.
211 */
212 while (in_be16(&commproc->cp_cpcr) & CPM_CR_FLG);
213
214 cpm_load_patch(commproc);
215#endif
216
217 /* Set SDMA Bus Request priority 5.
218 * On 860T, this also enables FEC priority 6. I am not sure
219 * this is what we realy want for some applications, but the
220 * manual recommends it.
221 * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
222 */
223 siu_conf = (sysconf8xx_t*)immr_map(im_siu_conf);
224 out_be32(&siu_conf->sc_sdcr, 1);
225 immr_unmap(siu_conf);
226
227 /* Reclaim the DP memory for our use. */
228 m8xx_cpm_dpinit();
229
230 /* Tell everyone where the comm processor resides.
231 */
232 cpmp = commproc;
233}
234
235/* We used to do this earlier, but have to postpone as long as possible
236 * to ensure the kernel VM is now running.
237 */
238static void
239alloc_host_memory(void)
240{
241 dma_addr_t physaddr;
242
243 /* Set the host page for allocation.
244 */
245 host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
246 GFP_KERNEL);
247 host_end = host_buffer + PAGE_SIZE;
248}
249
250/* We also own one page of host buffer space for the allocation of
251 * UART "fifos" and the like.
252 */
253uint
254m8xx_cpm_hostalloc(uint size)
255{
256 uint retloc;
257
258 if (host_buffer == 0)
259 alloc_host_memory();
260
261 if ((host_buffer + size) >= host_end)
262 return(0);
263
264 retloc = host_buffer;
265 host_buffer += size;
266
267 return(retloc);
268}
269
270/* Set a baud rate generator. This needs lots of work. There are
271 * four BRGs, any of which can be wired to any channel.
272 * The internal baud rate clock is the system clock divided by 16.
273 * This assumes the baudrate is 16x oversampled by the uart.
274 */
275#define BRG_INT_CLK (get_brgfreq())
276#define BRG_UART_CLK (BRG_INT_CLK/16)
277#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
278
279void
280cpm_setbrg(uint brg, uint rate)
281{
282 volatile uint *bp;
283
284 /* This is good enough to get SMCs running.....
285 */
286 bp = (uint *)&cpmp->cp_brgc1;
287 bp += brg;
288 /* The BRG has a 12-bit counter. For really slow baud rates (or
289 * really fast processors), we may have to further divide by 16.
290 */
291 if (((BRG_UART_CLK / rate) - 1) < 4096)
292 *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
293 else
294 *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
295 CPM_BRG_EN | CPM_BRG_DIV16;
296}
297
298/*
299 * dpalloc / dpfree bits.
300 */
301static spinlock_t cpm_dpmem_lock;
302/*
303 * 16 blocks should be enough to satisfy all requests
304 * until the memory subsystem goes up...
305 */
306static rh_block_t cpm_boot_dpmem_rh_block[16];
307static rh_info_t cpm_dpmem_info;
308
309#define CPM_DPMEM_ALIGNMENT 8
310static u8* dpram_vbase;
311static uint dpram_pbase;
312
313void m8xx_cpm_dpinit(void)
314{
315 spin_lock_init(&cpm_dpmem_lock);
316
317 dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
318 dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem;
319
320 /* Initialize the info header */
321 rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
322 sizeof(cpm_boot_dpmem_rh_block) /
323 sizeof(cpm_boot_dpmem_rh_block[0]),
324 cpm_boot_dpmem_rh_block);
325
326 /*
327 * Attach the usable dpmem area.
328 * XXX: This is actually crap. CPM_DATAONLY_BASE and
329 * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies
330 * with the processor and the microcode patches applied / activated.
331 * But the following should be at least safe.
332 */
333 rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
334}
335
336/*
337 * Allocate the requested size worth of DP memory.
338 * This function returns an offset into the DPRAM area.
339 * Use cpm_dpram_addr() to get the virtual address of the area.
340 */
341uint cpm_dpalloc(uint size, uint align)
342{
343 void *start;
344 unsigned long flags;
345
346 spin_lock_irqsave(&cpm_dpmem_lock, flags);
347 cpm_dpmem_info.alignment = align;
348 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
349 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
350
351 return (uint)start;
352}
353EXPORT_SYMBOL(cpm_dpalloc);
354
355int cpm_dpfree(uint offset)
356{
357 int ret;
358 unsigned long flags;
359
360 spin_lock_irqsave(&cpm_dpmem_lock, flags);
361 ret = rh_free(&cpm_dpmem_info, (void *)offset);
362 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
363
364 return ret;
365}
366EXPORT_SYMBOL(cpm_dpfree);
367
368uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
369{
370 void *start;
371 unsigned long flags;
372
373 spin_lock_irqsave(&cpm_dpmem_lock, flags);
374 cpm_dpmem_info.alignment = align;
375 start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
376 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
377
378 return (uint)start;
379}
380EXPORT_SYMBOL(cpm_dpalloc_fixed);
381
382void cpm_dpdump(void)
383{
384 rh_dump(&cpm_dpmem_info);
385}
386EXPORT_SYMBOL(cpm_dpdump);
387
388void *cpm_dpram_addr(uint offset)
389{
390 return (void *)(dpram_vbase + offset);
391}
392EXPORT_SYMBOL(cpm_dpram_addr);
393
394uint cpm_dpram_phys(u8* addr)
395{
396 return (dpram_pbase + (uint)(addr - dpram_vbase));
397}
398EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
new file mode 100644
index 000000000000..712b10a55f87
--- /dev/null
+++ b/arch/powerpc/sysdev/micropatch.c
@@ -0,0 +1,743 @@
1
2/* Microcode patches for the CPM as supplied by Motorola.
3 * This is the one for IIC/SPI. There is a newer one that
4 * also relocates SMC2, but this would require additional changes
5 * to uart.c, so I am holding off on that for a moment.
6 */
7#include <linux/errno.h>
8#include <linux/sched.h>
9#include <linux/kernel.h>
10#include <linux/param.h>
11#include <linux/string.h>
12#include <linux/mm.h>
13#include <linux/interrupt.h>
14#include <asm/irq.h>
15#include <asm/mpc8xx.h>
16#include <asm/page.h>
17#include <asm/pgtable.h>
18#include <asm/8xx_immap.h>
19#include <asm/commproc.h>
20
21/*
22 * I2C/SPI relocation patch arrays.
23 */
24
25#ifdef CONFIG_I2C_SPI_UCODE_PATCH
26
27uint patch_2000[] = {
28 0x7FFFEFD9,
29 0x3FFD0000,
30 0x7FFB49F7,
31 0x7FF90000,
32 0x5FEFADF7,
33 0x5F89ADF7,
34 0x5FEFAFF7,
35 0x5F89AFF7,
36 0x3A9CFBC8,
37 0xE7C0EDF0,
38 0x77C1E1BB,
39 0xF4DC7F1D,
40 0xABAD932F,
41 0x4E08FDCF,
42 0x6E0FAFF8,
43 0x7CCF76CF,
44 0xFD1FF9CF,
45 0xABF88DC6,
46 0xAB5679F7,
47 0xB0937383,
48 0xDFCE79F7,
49 0xB091E6BB,
50 0xE5BBE74F,
51 0xB3FA6F0F,
52 0x6FFB76CE,
53 0xEE0DF9CF,
54 0x2BFBEFEF,
55 0xCFEEF9CF,
56 0x76CEAD24,
57 0x90B2DF9A,
58 0x7FDDD0BF,
59 0x4BF847FD,
60 0x7CCF76CE,
61 0xCFEF7E1F,
62 0x7F1D7DFD,
63 0xF0B6EF71,
64 0x7FC177C1,
65 0xFBC86079,
66 0xE722FBC8,
67 0x5FFFDFFF,
68 0x5FB2FFFB,
69 0xFBC8F3C8,
70 0x94A67F01,
71 0x7F1D5F39,
72 0xAFE85F5E,
73 0xFFDFDF96,
74 0xCB9FAF7D,
75 0x5FC1AFED,
76 0x8C1C5FC1,
77 0xAFDD5FC3,
78 0xDF9A7EFD,
79 0xB0B25FB2,
80 0xFFFEABAD,
81 0x5FB2FFFE,
82 0x5FCE600B,
83 0xE6BB600B,
84 0x5FCEDFC6,
85 0x27FBEFDF,
86 0x5FC8CFDE,
87 0x3A9CE7C0,
88 0xEDF0F3C8,
89 0x7F0154CD,
90 0x7F1D2D3D,
91 0x363A7570,
92 0x7E0AF1CE,
93 0x37EF2E68,
94 0x7FEE10EC,
95 0xADF8EFDE,
96 0xCFEAE52F,
97 0x7D0FE12B,
98 0xF1CE5F65,
99 0x7E0A4DF8,
100 0xCFEA5F72,
101 0x7D0BEFEE,
102 0xCFEA5F74,
103 0xE522EFDE,
104 0x5F74CFDA,
105 0x0B627385,
106 0xDF627E0A,
107 0x30D8145B,
108 0xBFFFF3C8,
109 0x5FFFDFFF,
110 0xA7F85F5E,
111 0xBFFE7F7D,
112 0x10D31450,
113 0x5F36BFFF,
114 0xAF785F5E,
115 0xBFFDA7F8,
116 0x5F36BFFE,
117 0x77FD30C0,
118 0x4E08FDCF,
119 0xE5FF6E0F,
120 0xAFF87E1F,
121 0x7E0FFD1F,
122 0xF1CF5F1B,
123 0xABF80D5E,
124 0x5F5EFFEF,
125 0x79F730A2,
126 0xAFDD5F34,
127 0x47F85F34,
128 0xAFED7FDD,
129 0x50B24978,
130 0x47FD7F1D,
131 0x7DFD70AD,
132 0xEF717EC1,
133 0x6BA47F01,
134 0x2D267EFD,
135 0x30DE5F5E,
136 0xFFFD5F5E,
137 0xFFEF5F5E,
138 0xFFDF0CA0,
139 0xAFED0A9E,
140 0xAFDD0C3A,
141 0x5F3AAFBD,
142 0x7FBDB082,
143 0x5F8247F8
144};
145
146uint patch_2f00[] = {
147 0x3E303430,
148 0x34343737,
149 0xABF7BF9B,
150 0x994B4FBD,
151 0xBD599493,
152 0x349FFF37,
153 0xFB9B177D,
154 0xD9936956,
155 0xBBFDD697,
156 0xBDD2FD11,
157 0x31DB9BB3,
158 0x63139637,
159 0x93733693,
160 0x193137F7,
161 0x331737AF,
162 0x7BB9B999,
163 0xBB197957,
164 0x7FDFD3D5,
165 0x73B773F7,
166 0x37933B99,
167 0x1D115316,
168 0x99315315,
169 0x31694BF4,
170 0xFBDBD359,
171 0x31497353,
172 0x76956D69,
173 0x7B9D9693,
174 0x13131979,
175 0x79376935
176};
177#endif
178
179/*
180 * I2C/SPI/SMC1 relocation patch arrays.
181 */
182
183#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
184
185uint patch_2000[] = {
186 0x3fff0000,
187 0x3ffd0000,
188 0x3ffb0000,
189 0x3ff90000,
190 0x5f13eff8,
191 0x5eb5eff8,
192 0x5f88adf7,
193 0x5fefadf7,
194 0x3a9cfbc8,
195 0x77cae1bb,
196 0xf4de7fad,
197 0xabae9330,
198 0x4e08fdcf,
199 0x6e0faff8,
200 0x7ccf76cf,
201 0xfdaff9cf,
202 0xabf88dc8,
203 0xab5879f7,
204 0xb0925d8d,
205 0xdfd079f7,
206 0xb090e6bb,
207 0xe5bbe74f,
208 0x9e046f0f,
209 0x6ffb76ce,
210 0xee0cf9cf,
211 0x2bfbefef,
212 0xcfeef9cf,
213 0x76cead23,
214 0x90b3df99,
215 0x7fddd0c1,
216 0x4bf847fd,
217 0x7ccf76ce,
218 0xcfef77ca,
219 0x7eaf7fad,
220 0x7dfdf0b7,
221 0xef7a7fca,
222 0x77cafbc8,
223 0x6079e722,
224 0xfbc85fff,
225 0xdfff5fb3,
226 0xfffbfbc8,
227 0xf3c894a5,
228 0xe7c9edf9,
229 0x7f9a7fad,
230 0x5f36afe8,
231 0x5f5bffdf,
232 0xdf95cb9e,
233 0xaf7d5fc3,
234 0xafed8c1b,
235 0x5fc3afdd,
236 0x5fc5df99,
237 0x7efdb0b3,
238 0x5fb3fffe,
239 0xabae5fb3,
240 0xfffe5fd0,
241 0x600be6bb,
242 0x600b5fd0,
243 0xdfc827fb,
244 0xefdf5fca,
245 0xcfde3a9c,
246 0xe7c9edf9,
247 0xf3c87f9e,
248 0x54ca7fed,
249 0x2d3a3637,
250 0x756f7e9a,
251 0xf1ce37ef,
252 0x2e677fee,
253 0x10ebadf8,
254 0xefdecfea,
255 0xe52f7d9f,
256 0xe12bf1ce,
257 0x5f647e9a,
258 0x4df8cfea,
259 0x5f717d9b,
260 0xefeecfea,
261 0x5f73e522,
262 0xefde5f73,
263 0xcfda0b61,
264 0x5d8fdf61,
265 0xe7c9edf9,
266 0x7e9a30d5,
267 0x1458bfff,
268 0xf3c85fff,
269 0xdfffa7f8,
270 0x5f5bbffe,
271 0x7f7d10d0,
272 0x144d5f33,
273 0xbfffaf78,
274 0x5f5bbffd,
275 0xa7f85f33,
276 0xbffe77fd,
277 0x30bd4e08,
278 0xfdcfe5ff,
279 0x6e0faff8,
280 0x7eef7e9f,
281 0xfdeff1cf,
282 0x5f17abf8,
283 0x0d5b5f5b,
284 0xffef79f7,
285 0x309eafdd,
286 0x5f3147f8,
287 0x5f31afed,
288 0x7fdd50af,
289 0x497847fd,
290 0x7f9e7fed,
291 0x7dfd70a9,
292 0xef7e7ece,
293 0x6ba07f9e,
294 0x2d227efd,
295 0x30db5f5b,
296 0xfffd5f5b,
297 0xffef5f5b,
298 0xffdf0c9c,
299 0xafed0a9a,
300 0xafdd0c37,
301 0x5f37afbd,
302 0x7fbdb081,
303 0x5f8147f8,
304 0x3a11e710,
305 0xedf0ccdd,
306 0xf3186d0a,
307 0x7f0e5f06,
308 0x7fedbb38,
309 0x3afe7468,
310 0x7fedf4fc,
311 0x8ffbb951,
312 0xb85f77fd,
313 0xb0df5ddd,
314 0xdefe7fed,
315 0x90e1e74d,
316 0x6f0dcbf7,
317 0xe7decfed,
318 0xcb74cfed,
319 0xcfeddf6d,
320 0x91714f74,
321 0x5dd2deef,
322 0x9e04e7df,
323 0xefbb6ffb,
324 0xe7ef7f0e,
325 0x9e097fed,
326 0xebdbeffa,
327 0xeb54affb,
328 0x7fea90d7,
329 0x7e0cf0c3,
330 0xbffff318,
331 0x5fffdfff,
332 0xac59efea,
333 0x7fce1ee5,
334 0xe2ff5ee1,
335 0xaffbe2ff,
336 0x5ee3affb,
337 0xf9cc7d0f,
338 0xaef8770f,
339 0x7d0fb0c6,
340 0xeffbbfff,
341 0xcfef5ede,
342 0x7d0fbfff,
343 0x5ede4cf8,
344 0x7fddd0bf,
345 0x49f847fd,
346 0x7efdf0bb,
347 0x7fedfffd,
348 0x7dfdf0b7,
349 0xef7e7e1e,
350 0x5ede7f0e,
351 0x3a11e710,
352 0xedf0ccab,
353 0xfb18ad2e,
354 0x1ea9bbb8,
355 0x74283b7e,
356 0x73c2e4bb,
357 0x2ada4fb8,
358 0xdc21e4bb,
359 0xb2a1ffbf,
360 0x5e2c43f8,
361 0xfc87e1bb,
362 0xe74ffd91,
363 0x6f0f4fe8,
364 0xc7ba32e2,
365 0xf396efeb,
366 0x600b4f78,
367 0xe5bb760b,
368 0x53acaef8,
369 0x4ef88b0e,
370 0xcfef9e09,
371 0xabf8751f,
372 0xefef5bac,
373 0x741f4fe8,
374 0x751e760d,
375 0x7fdbf081,
376 0x741cafce,
377 0xefcc7fce,
378 0x751e70ac,
379 0x741ce7bb,
380 0x3372cfed,
381 0xafdbefeb,
382 0xe5bb760b,
383 0x53f2aef8,
384 0xafe8e7eb,
385 0x4bf8771e,
386 0x7e247fed,
387 0x4fcbe2cc,
388 0x7fbc30a9,
389 0x7b0f7a0f,
390 0x34d577fd,
391 0x308b5db7,
392 0xde553e5f,
393 0xaf78741f,
394 0x741f30f0,
395 0xcfef5e2c,
396 0x741f3eac,
397 0xafb8771e,
398 0x5e677fed,
399 0x0bd3e2cc,
400 0x741ccfec,
401 0xe5ca53cd,
402 0x6fcb4f74,
403 0x5dadde4b,
404 0x2ab63d38,
405 0x4bb3de30,
406 0x751f741c,
407 0x6c42effa,
408 0xefea7fce,
409 0x6ffc30be,
410 0xefec3fca,
411 0x30b3de2e,
412 0xadf85d9e,
413 0xaf7daefd,
414 0x5d9ede2e,
415 0x5d9eafdd,
416 0x761f10ac,
417 0x1da07efd,
418 0x30adfffe,
419 0x4908fb18,
420 0x5fffdfff,
421 0xafbb709b,
422 0x4ef85e67,
423 0xadf814ad,
424 0x7a0f70ad,
425 0xcfef50ad,
426 0x7a0fde30,
427 0x5da0afed,
428 0x3c12780f,
429 0xefef780f,
430 0xefef790f,
431 0xa7f85e0f,
432 0xffef790f,
433 0xefef790f,
434 0x14adde2e,
435 0x5d9eadfd,
436 0x5e2dfffb,
437 0xe79addfd,
438 0xeff96079,
439 0x607ae79a,
440 0xddfceff9,
441 0x60795dff,
442 0x607acfef,
443 0xefefefdf,
444 0xefbfef7f,
445 0xeeffedff,
446 0xebffe7ff,
447 0xafefafdf,
448 0xafbfaf7f,
449 0xaeffadff,
450 0xabffa7ff,
451 0x6fef6fdf,
452 0x6fbf6f7f,
453 0x6eff6dff,
454 0x6bff67ff,
455 0x2fef2fdf,
456 0x2fbf2f7f,
457 0x2eff2dff,
458 0x2bff27ff,
459 0x4e08fd1f,
460 0xe5ff6e0f,
461 0xaff87eef,
462 0x7e0ffdef,
463 0xf11f6079,
464 0xabf8f542,
465 0x7e0af11c,
466 0x37cfae3a,
467 0x7fec90be,
468 0xadf8efdc,
469 0xcfeae52f,
470 0x7d0fe12b,
471 0xf11c6079,
472 0x7e0a4df8,
473 0xcfea5dc4,
474 0x7d0befec,
475 0xcfea5dc6,
476 0xe522efdc,
477 0x5dc6cfda,
478 0x4e08fd1f,
479 0x6e0faff8,
480 0x7c1f761f,
481 0xfdeff91f,
482 0x6079abf8,
483 0x761cee24,
484 0xf91f2bfb,
485 0xefefcfec,
486 0xf91f6079,
487 0x761c27fb,
488 0xefdf5da7,
489 0xcfdc7fdd,
490 0xd09c4bf8,
491 0x47fd7c1f,
492 0x761ccfcf,
493 0x7eef7fed,
494 0x7dfdf093,
495 0xef7e7f1e,
496 0x771efb18,
497 0x6079e722,
498 0xe6bbe5bb,
499 0xae0ae5bb,
500 0x600bae85,
501 0xe2bbe2bb,
502 0xe2bbe2bb,
503 0xaf02e2bb,
504 0xe2bb2ff9,
505 0x6079e2bb
506};
507
508uint patch_2f00[] = {
509 0x30303030,
510 0x3e3e3434,
511 0xabbf9b99,
512 0x4b4fbdbd,
513 0x59949334,
514 0x9fff37fb,
515 0x9b177dd9,
516 0x936956bb,
517 0xfbdd697b,
518 0xdd2fd113,
519 0x1db9f7bb,
520 0x36313963,
521 0x79373369,
522 0x3193137f,
523 0x7331737a,
524 0xf7bb9b99,
525 0x9bb19795,
526 0x77fdfd3d,
527 0x573b773f,
528 0x737933f7,
529 0xb991d115,
530 0x31699315,
531 0x31531694,
532 0xbf4fbdbd,
533 0x35931497,
534 0x35376956,
535 0xbd697b9d,
536 0x96931313,
537 0x19797937,
538 0x6935af78,
539 0xb9b3baa3,
540 0xb8788683,
541 0x368f78f7,
542 0x87778733,
543 0x3ffffb3b,
544 0x8e8f78b8,
545 0x1d118e13,
546 0xf3ff3f8b,
547 0x6bd8e173,
548 0xd1366856,
549 0x68d1687b,
550 0x3daf78b8,
551 0x3a3a3f87,
552 0x8f81378f,
553 0xf876f887,
554 0x77fd8778,
555 0x737de8d6,
556 0xbbf8bfff,
557 0xd8df87f7,
558 0xfd876f7b,
559 0x8bfff8bd,
560 0x8683387d,
561 0xb873d87b,
562 0x3b8fd7f8,
563 0xf7338883,
564 0xbb8ee1f8,
565 0xef837377,
566 0x3337b836,
567 0x817d11f8,
568 0x7378b878,
569 0xd3368b7d,
570 0xed731b7d,
571 0x833731f3,
572 0xf22f3f23
573};
574
575uint patch_2e00[] = {
576 0x27eeeeee,
577 0xeeeeeeee,
578 0xeeeeeeee,
579 0xeeeeeeee,
580 0xee4bf4fb,
581 0xdbd259bb,
582 0x1979577f,
583 0xdfd2d573,
584 0xb773f737,
585 0x4b4fbdbd,
586 0x25b9b177,
587 0xd2d17376,
588 0x956bbfdd,
589 0x697bdd2f,
590 0xff9f79ff,
591 0xff9ff22f
592};
593#endif
594
595/*
596 * USB SOF patch arrays.
597 */
598
599#ifdef CONFIG_USB_SOF_UCODE_PATCH
600
601uint patch_2000[] = {
602 0x7fff0000,
603 0x7ffd0000,
604 0x7ffb0000,
605 0x49f7ba5b,
606 0xba383ffb,
607 0xf9b8b46d,
608 0xe5ab4e07,
609 0xaf77bffe,
610 0x3f7bbf79,
611 0xba5bba38,
612 0xe7676076,
613 0x60750000
614};
615
616uint patch_2f00[] = {
617 0x3030304c,
618 0xcab9e441,
619 0xa1aaf220
620};
621#endif
622
623void
624cpm_load_patch(cpm8xx_t *cp)
625{
626 volatile uint *dp; /* Dual-ported RAM. */
627 volatile cpm8xx_t *commproc;
628 volatile iic_t *iip;
629 volatile spi_t *spp;
630 volatile smc_uart_t *smp;
631 int i;
632
633 commproc = cp;
634
635#ifdef CONFIG_USB_SOF_UCODE_PATCH
636 commproc->cp_rccr = 0;
637
638 dp = (uint *)(commproc->cp_dpmem);
639 for (i=0; i<(sizeof(patch_2000)/4); i++)
640 *dp++ = patch_2000[i];
641
642 dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
643 for (i=0; i<(sizeof(patch_2f00)/4); i++)
644 *dp++ = patch_2f00[i];
645
646 commproc->cp_rccr = 0x0009;
647
648 printk("USB SOF microcode patch installed\n");
649#endif /* CONFIG_USB_SOF_UCODE_PATCH */
650
651#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
652 defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
653
654 commproc->cp_rccr = 0;
655
656 dp = (uint *)(commproc->cp_dpmem);
657 for (i=0; i<(sizeof(patch_2000)/4); i++)
658 *dp++ = patch_2000[i];
659
660 dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
661 for (i=0; i<(sizeof(patch_2f00)/4); i++)
662 *dp++ = patch_2f00[i];
663
664 iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
665# define RPBASE 0x0500
666 iip->iic_rpbase = RPBASE;
667
668 /* Put SPI above the IIC, also 32-byte aligned.
669 */
670 i = (RPBASE + sizeof(iic_t) + 31) & ~31;
671 spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
672 spp->spi_rpbase = i;
673
674# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
675 commproc->cp_cpmcr1 = 0x802a;
676 commproc->cp_cpmcr2 = 0x8028;
677 commproc->cp_cpmcr3 = 0x802e;
678 commproc->cp_cpmcr4 = 0x802c;
679 commproc->cp_rccr = 1;
680
681 printk("I2C/SPI microcode patch installed.\n");
682# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
683
684# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
685
686 dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
687 for (i=0; i<(sizeof(patch_2e00)/4); i++)
688 *dp++ = patch_2e00[i];
689
690 commproc->cp_cpmcr1 = 0x8080;
691 commproc->cp_cpmcr2 = 0x808a;
692 commproc->cp_cpmcr3 = 0x8028;
693 commproc->cp_cpmcr4 = 0x802a;
694 commproc->cp_rccr = 3;
695
696 smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
697 smp->smc_rpbase = 0x1FC0;
698
699 printk("I2C/SPI/SMC1 microcode patch installed.\n");
700# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
701
702#endif /* some variation of the I2C/SPI patch was selected */
703}
704
705/*
706 * Take this entire routine out, since no one calls it and its
707 * logic is suspect.
708 */
709
710#if 0
711void
712verify_patch(volatile immap_t *immr)
713{
714 volatile uint *dp;
715 volatile cpm8xx_t *commproc;
716 int i;
717
718 commproc = (cpm8xx_t *)&immr->im_cpm;
719
720 printk("cp_rccr %x\n", commproc->cp_rccr);
721 commproc->cp_rccr = 0;
722
723 dp = (uint *)(commproc->cp_dpmem);
724 for (i=0; i<(sizeof(patch_2000)/4); i++)
725 if (*dp++ != patch_2000[i]) {
726 printk("patch_2000 bad at %d\n", i);
727 dp--;
728 printk("found 0x%X, wanted 0x%X\n", *dp, patch_2000[i]);
729 break;
730 }
731
732 dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
733 for (i=0; i<(sizeof(patch_2f00)/4); i++)
734 if (*dp++ != patch_2f00[i]) {
735 printk("patch_2f00 bad at %d\n", i);
736 dp--;
737 printk("found 0x%X, wanted 0x%X\n", *dp, patch_2f00[i]);
738 break;
739 }
740
741 commproc->cp_rccr = 0x0009;
742}
743#endif
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
new file mode 100644
index 000000000000..2fc2bcd79b5e
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -0,0 +1,197 @@
1#include <linux/kernel.h>
2#include <linux/module.h>
3#include <linux/stddef.h>
4#include <linux/init.h>
5#include <linux/sched.h>
6#include <linux/signal.h>
7#include <linux/irq.h>
8#include <linux/dma-mapping.h>
9#include <asm/prom.h>
10#include <asm/irq.h>
11#include <asm/io.h>
12#include <asm/8xx_immap.h>
13#include <asm/mpc8xx.h>
14
15#include "mpc8xx_pic.h"
16
17
18#define PIC_VEC_SPURRIOUS 15
19
20extern int cpm_get_irq(struct pt_regs *regs);
21
22static struct device_node *mpc8xx_pic_node;
23static struct irq_host *mpc8xx_pic_host;
24#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
25static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
26static sysconf8xx_t *siu_reg;
27
28int cpm_get_irq(struct pt_regs *regs);
29
30static void mpc8xx_unmask_irq(unsigned int virq)
31{
32 int bit, word;
33 unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
34
35 bit = irq_nr & 0x1f;
36 word = irq_nr >> 5;
37
38 ppc_cached_irq_mask[word] |= (1 << (31-bit));
39 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
40}
41
42static void mpc8xx_mask_irq(unsigned int virq)
43{
44 int bit, word;
45 unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
46
47 bit = irq_nr & 0x1f;
48 word = irq_nr >> 5;
49
50 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
51 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
52}
53
54static void mpc8xx_ack(unsigned int virq)
55{
56 int bit;
57 unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
58
59 bit = irq_nr & 0x1f;
60 out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
61}
62
63static void mpc8xx_end_irq(unsigned int virq)
64{
65 int bit, word;
66 unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
67
68 bit = irq_nr & 0x1f;
69 word = irq_nr >> 5;
70
71 ppc_cached_irq_mask[word] |= (1 << (31-bit));
72 out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
73}
74
75static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
76{
77 struct irq_desc *desc = get_irq_desc(virq);
78
79 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
80 desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
81 if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
82 desc->status |= IRQ_LEVEL;
83
84 if (flow_type & IRQ_TYPE_EDGE_FALLING) {
85 irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
86 unsigned int siel = in_be32(&siu_reg->sc_siel);
87
88 /* only external IRQ senses are programmable */
89 if ((hw & 1) == 0) {
90 siel |= (0x80000000 >> hw);
91 out_be32(&siu_reg->sc_siel, siel);
92 desc->handle_irq = handle_edge_irq;
93 }
94 }
95 return 0;
96}
97
98static struct irq_chip mpc8xx_pic = {
99 .typename = " MPC8XX SIU ",
100 .unmask = mpc8xx_unmask_irq,
101 .mask = mpc8xx_mask_irq,
102 .ack = mpc8xx_ack,
103 .eoi = mpc8xx_end_irq,
104 .set_type = mpc8xx_set_irq_type,
105};
106
107unsigned int mpc8xx_get_irq(void)
108{
109 int irq;
110
111 /* For MPC8xx, read the SIVEC register and shift the bits down
112 * to get the irq number.
113 */
114 irq = in_be32(&siu_reg->sc_sivec) >> 26;
115
116 if (irq == PIC_VEC_SPURRIOUS)
117 irq = NO_IRQ;
118
119 return irq_linear_revmap(mpc8xx_pic_host, irq);
120
121}
122
123static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node)
124{
125 return mpc8xx_pic_node == node;
126}
127
128static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
129 irq_hw_number_t hw)
130{
131 pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
132
133 /* Set default irq handle */
134 set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
135 return 0;
136}
137
138
139static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
140 u32 *intspec, unsigned int intsize,
141 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
142{
143 static unsigned char map_pic_senses[4] = {
144 IRQ_TYPE_EDGE_RISING,
145 IRQ_TYPE_LEVEL_LOW,
146 IRQ_TYPE_LEVEL_HIGH,
147 IRQ_TYPE_EDGE_FALLING,
148 };
149
150 *out_hwirq = intspec[0];
151 if (intsize > 1 && intspec[1] < 4)
152 *out_flags = map_pic_senses[intspec[1]];
153 else
154 *out_flags = IRQ_TYPE_NONE;
155
156 return 0;
157}
158
159
160static struct irq_host_ops mpc8xx_pic_host_ops = {
161 .match = mpc8xx_pic_host_match,
162 .map = mpc8xx_pic_host_map,
163 .xlate = mpc8xx_pic_host_xlate,
164};
165
166int mpc8xx_pic_init(void)
167{
168 struct resource res;
169 struct device_node *np = NULL;
170 int ret;
171
172 np = of_find_node_by_type(np, "mpc8xx-pic");
173
174 if (np == NULL) {
175 printk(KERN_ERR "Could not find open-pic node\n");
176 return -ENOMEM;
177 }
178
179 mpc8xx_pic_node = of_node_get(np);
180
181 ret = of_address_to_resource(np, 0, &res);
182 of_node_put(np);
183 if (ret)
184 return ret;
185
186 siu_reg = (void *)ioremap(res.start, res.end - res.start + 1);
187 if (siu_reg == NULL)
188 return -EINVAL;
189
190 mpc8xx_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64);
191 if (mpc8xx_pic_host == NULL) {
192 printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
193 ret = -ENOMEM;
194 }
195
196 return ret;
197}
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
new file mode 100644
index 000000000000..afa2ee6717c1
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -0,0 +1,12 @@
1#ifndef _PPC_KERNEL_MPC8xx_H
2#define _PPC_KERNEL_MPC8xx_H
3
4#include <linux/irq.h>
5#include <linux/interrupt.h>
6
7extern struct hw_interrupt_type mpc8xx_pic;
8
9int mpc8xx_pic_init(void);
10unsigned int mpc8xx_get_irq(void);
11
12#endif /* _PPC_KERNEL_PPC8xx_H */