[ARM] mm 10: allow memory type to be specified with ioremap
[linux-2.6] / arch / ppc / 8xx_io / commproc.c
1 /*
2  * General Purpose functions for the global management of the
3  * Communication Processor Module.
4  * Copyright (c) 1997 Dan Malek (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
42 #define immr_map(member)                                                \
43 ({                                                                      \
44         u32 offset = offsetof(immap_t, member);                         \
45         void *addr = ioremap (IMAP_ADDR + offset,                       \
46                               sizeof( ((immap_t*)0)->member));          \
47         addr;                                                           \
48 })
49
50 #define immr_map_size(member, size)                                     \
51 ({                                                                      \
52         u32 offset = offsetof(immap_t, member);                         \
53         void *addr = ioremap (IMAP_ADDR + offset, size);                \
54         addr;                                                           \
55 })
56
57 static void m8xx_cpm_dpinit(void);
58 static  uint    host_buffer;    /* One page of host buffer */
59 static  uint    host_end;       /* end + 1 */
60 cpm8xx_t        *cpmp;          /* Pointer to comm processor space */
61
62 /* CPM interrupt vector functions.
63 */
64 struct  cpm_action {
65         void    (*handler)(void *);
66         void    *dev_id;
67 };
68 static  struct  cpm_action cpm_vecs[CPMVEC_NR];
69 static  irqreturn_t cpm_interrupt(int irq, void * dev);
70 static  irqreturn_t cpm_error_interrupt(int irq, void *dev);
71 static  void    alloc_host_memory(void);
72 /* Define a table of names to identify CPM interrupt handlers in
73  * /proc/interrupts.
74  */
75 const char *cpm_int_name[] =
76         { "error",      "PC4",          "PC5",          "SMC2",
77           "SMC1",       "SPI",          "PC6",          "Timer 4",
78           "",           "PC7",          "PC8",          "PC9",
79           "Timer 3",    "",             "PC10",         "PC11",
80           "I2C",        "RISC Timer",   "Timer 2",      "",
81           "IDMA2",      "IDMA1",        "SDMA error",   "PC12",
82           "PC13",       "Timer 1",      "PC14",         "SCC4",
83           "SCC3",       "SCC2",         "SCC1",         "PC15"
84         };
85
86 static void
87 cpm_mask_irq(unsigned int irq)
88 {
89         int cpm_vec = irq - CPM_IRQ_OFFSET;
90
91         clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
92 }
93
94 static void
95 cpm_unmask_irq(unsigned int irq)
96 {
97         int cpm_vec = irq - CPM_IRQ_OFFSET;
98
99         setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
100 }
101
102 static void
103 cpm_ack(unsigned int irq)
104 {
105         /* We do not need to do anything here. */
106 }
107
108 static void
109 cpm_eoi(unsigned int irq)
110 {
111         int cpm_vec = irq - CPM_IRQ_OFFSET;
112
113         out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr, (1 << cpm_vec));
114 }
115
116 struct hw_interrupt_type cpm_pic = {
117         .typename       = " CPM      ",
118         .enable         = cpm_unmask_irq,
119         .disable        = cpm_mask_irq,
120         .ack            = cpm_ack,
121         .end            = cpm_eoi,
122 };
123
124 void
125 m8xx_cpm_reset(void)
126 {
127         volatile immap_t         *imp;
128         volatile cpm8xx_t       *commproc;
129
130         imp = (immap_t *)IMAP_ADDR;
131         commproc = (cpm8xx_t *)&imp->im_cpm;
132
133 #ifdef CONFIG_UCODE_PATCH
134         /* Perform a reset.
135         */
136         commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
137
138         /* Wait for it.
139         */
140         while (commproc->cp_cpcr & CPM_CR_FLG);
141
142         cpm_load_patch(imp);
143 #endif
144
145         /* Set SDMA Bus Request priority 5.
146          * On 860T, this also enables FEC priority 6.  I am not sure
147          * this is what we realy want for some applications, but the
148          * manual recommends it.
149          * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
150          */
151         out_be32(&imp->im_siu_conf.sc_sdcr, 1),
152
153         /* Reclaim the DP memory for our use. */
154         m8xx_cpm_dpinit();
155
156         /* Tell everyone where the comm processor resides.
157         */
158         cpmp = (cpm8xx_t *)commproc;
159 }
160
161 /* We used to do this earlier, but have to postpone as long as possible
162  * to ensure the kernel VM is now running.
163  */
164 static void
165 alloc_host_memory(void)
166 {
167         dma_addr_t      physaddr;
168
169         /* Set the host page for allocation.
170         */
171         host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
172                         GFP_KERNEL);
173         host_end = host_buffer + PAGE_SIZE;
174 }
175
176 /* This is called during init_IRQ.  We used to do it above, but this
177  * was too early since init_IRQ was not yet called.
178  */
179 static struct irqaction cpm_error_irqaction = {
180         .handler = cpm_error_interrupt,
181         .mask = CPU_MASK_NONE,
182 };
183 static struct irqaction cpm_interrupt_irqaction = {
184         .handler = cpm_interrupt,
185         .mask = CPU_MASK_NONE,
186         .name = "CPM cascade",
187 };
188
189 void
190 cpm_interrupt_init(void)
191 {
192         int i;
193
194         /* Initialize the CPM interrupt controller.
195         */
196         out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr,
197             (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
198                 ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK);
199         out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, 0);
200
201         /* install the CPM interrupt controller routines for the CPM
202          * interrupt vectors
203          */
204         for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
205                 irq_desc[i].chip = &cpm_pic;
206
207         /* Set our interrupt handler with the core CPU. */
208         if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
209                 panic("Could not allocate CPM IRQ!");
210
211         /* Install our own error handler. */
212         cpm_error_irqaction.name = cpm_int_name[CPMVEC_ERROR];
213         if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
214                 panic("Could not allocate CPM error IRQ!");
215
216         setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, CICR_IEN);
217 }
218
219 /*
220  * Get the CPM interrupt vector.
221  */
222 int
223 cpm_get_irq(void)
224 {
225         int cpm_vec;
226
227         /* Get the vector by setting the ACK bit and then reading
228          * the register.
229          */
230         out_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr, 1);
231         cpm_vec = in_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr);
232         cpm_vec >>= 11;
233
234         return cpm_vec;
235 }
236
237 /* CPM interrupt controller cascade interrupt.
238 */
239 static  irqreturn_t
240 cpm_interrupt(int irq, void * dev)
241 {
242         /* This interrupt handler never actually gets called.  It is
243          * installed only to unmask the CPM cascade interrupt in the SIU
244          * and to make the CPM cascade interrupt visible in /proc/interrupts.
245          */
246         return IRQ_HANDLED;
247 }
248
249 /* The CPM can generate the error interrupt when there is a race condition
250  * between generating and masking interrupts.  All we have to do is ACK it
251  * and return.  This is a no-op function so we don't need any special
252  * tests in the interrupt handler.
253  */
254 static  irqreturn_t
255 cpm_error_interrupt(int irq, void *dev)
256 {
257         return IRQ_HANDLED;
258 }
259
260 /* A helper function to translate the handler prototype required by
261  * request_irq() to the handler prototype required by cpm_install_handler().
262  */
263 static irqreturn_t
264 cpm_handler_helper(int irq, void *dev_id)
265 {
266         int cpm_vec = irq - CPM_IRQ_OFFSET;
267
268         (*cpm_vecs[cpm_vec].handler)(dev_id);
269
270         return IRQ_HANDLED;
271 }
272
273 /* Install a CPM interrupt handler.
274  * This routine accepts a CPM interrupt vector in the range 0 to 31.
275  * This routine is retained for backward compatibility.  Rather than using
276  * this routine to install a CPM interrupt handler, you can now use
277  * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
278  * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
279  *
280  * Notice that the prototype of the interrupt handler function must be
281  * different depending on whether you install the handler with
282  * request_irq() or cpm_install_handler().
283  */
284 void
285 cpm_install_handler(int cpm_vec, void (*handler)(void *), void *dev_id)
286 {
287         int err;
288
289         /* If null handler, assume we are trying to free the IRQ.
290         */
291         if (!handler) {
292                 free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
293                 return;
294         }
295
296         if (cpm_vecs[cpm_vec].handler != 0)
297                 printk(KERN_INFO "CPM interrupt %x replacing %x\n",
298                         (uint)handler, (uint)cpm_vecs[cpm_vec].handler);
299         cpm_vecs[cpm_vec].handler = handler;
300         cpm_vecs[cpm_vec].dev_id = dev_id;
301
302         if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
303                                         0, cpm_int_name[cpm_vec], dev_id)))
304                 printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
305                                 err, cpm_vec);
306 }
307
308 /* Free a CPM interrupt handler.
309  * This routine accepts a CPM interrupt vector in the range 0 to 31.
310  * This routine is retained for backward compatibility.
311  */
312 void
313 cpm_free_handler(int cpm_vec)
314 {
315         request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
316                 cpm_vecs[cpm_vec].dev_id);
317
318         cpm_vecs[cpm_vec].handler = NULL;
319         cpm_vecs[cpm_vec].dev_id = NULL;
320 }
321
322 /* We also own one page of host buffer space for the allocation of
323  * UART "fifos" and the like.
324  */
325 uint
326 m8xx_cpm_hostalloc(uint size)
327 {
328         uint    retloc;
329
330         if (host_buffer == 0)
331                 alloc_host_memory();
332
333         if ((host_buffer + size) >= host_end)
334                 return(0);
335
336         retloc = host_buffer;
337         host_buffer += size;
338
339         return(retloc);
340 }
341
342 /* Set a baud rate generator.  This needs lots of work.  There are
343  * four BRGs, any of which can be wired to any channel.
344  * The internal baud rate clock is the system clock divided by 16.
345  * This assumes the baudrate is 16x oversampled by the uart.
346  */
347 #define BRG_INT_CLK             (((bd_t *)__res)->bi_intfreq)
348 #define BRG_UART_CLK            (BRG_INT_CLK/16)
349 #define BRG_UART_CLK_DIV16      (BRG_UART_CLK/16)
350
351 void
352 cpm_setbrg(uint brg, uint rate)
353 {
354         volatile uint   *bp;
355
356         /* This is good enough to get SMCs running.....
357         */
358         bp = (uint *)&cpmp->cp_brgc1;
359         bp += brg;
360         /* The BRG has a 12-bit counter.  For really slow baud rates (or
361          * really fast processors), we may have to further divide by 16.
362          */
363         if (((BRG_UART_CLK / rate) - 1) < 4096)
364                 *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
365         else
366                 *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
367                                                 CPM_BRG_EN | CPM_BRG_DIV16;
368 }
369
370 /*
371  * dpalloc / dpfree bits.
372  */
373 static spinlock_t cpm_dpmem_lock;
374 /*
375  * 16 blocks should be enough to satisfy all requests
376  * until the memory subsystem goes up...
377  */
378 static rh_block_t cpm_boot_dpmem_rh_block[16];
379 static rh_info_t cpm_dpmem_info;
380
381 #define CPM_DPMEM_ALIGNMENT     8
382 static u8* dpram_vbase;
383 static uint dpram_pbase;
384
385 void m8xx_cpm_dpinit(void)
386 {
387         spin_lock_init(&cpm_dpmem_lock);
388
389         dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
390         dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem;
391
392         /* Initialize the info header */
393         rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
394                         sizeof(cpm_boot_dpmem_rh_block) /
395                         sizeof(cpm_boot_dpmem_rh_block[0]),
396                         cpm_boot_dpmem_rh_block);
397
398         /*
399          * Attach the usable dpmem area.
400          * XXX: This is actually crap.  CPM_DATAONLY_BASE and
401          * CPM_DATAONLY_SIZE are a subset of the available dparm.  It varies
402          * with the processor and the microcode patches applied / activated.
403          * But the following should be at least safe.
404          */
405         rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
406 }
407
408 /*
409  * Allocate the requested size worth of DP memory.
410  * This function returns an offset into the DPRAM area.
411  * Use cpm_dpram_addr() to get the virtual address of the area.
412  */
413 uint cpm_dpalloc(uint size, uint align)
414 {
415         void *start;
416         unsigned long flags;
417
418         spin_lock_irqsave(&cpm_dpmem_lock, flags);
419         cpm_dpmem_info.alignment = align;
420         start = rh_alloc(&cpm_dpmem_info, size, "commproc");
421         spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
422
423         return (uint)start;
424 }
425 EXPORT_SYMBOL(cpm_dpalloc);
426
427 int cpm_dpfree(uint offset)
428 {
429         int ret;
430         unsigned long flags;
431
432         spin_lock_irqsave(&cpm_dpmem_lock, flags);
433         ret = rh_free(&cpm_dpmem_info, (void *)offset);
434         spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
435
436         return ret;
437 }
438 EXPORT_SYMBOL(cpm_dpfree);
439
440 uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
441 {
442         void *start;
443         unsigned long flags;
444
445         spin_lock_irqsave(&cpm_dpmem_lock, flags);
446         cpm_dpmem_info.alignment = align;
447         start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
448         spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
449
450         return (uint)start;
451 }
452 EXPORT_SYMBOL(cpm_dpalloc_fixed);
453
454 void cpm_dpdump(void)
455 {
456         rh_dump(&cpm_dpmem_info);
457 }
458 EXPORT_SYMBOL(cpm_dpdump);
459
460 void *cpm_dpram_addr(uint offset)
461 {
462         return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
463 }
464 EXPORT_SYMBOL(cpm_dpram_addr);
465
466 uint cpm_dpram_phys(u8* addr)
467 {
468         return (dpram_pbase + (uint)(addr - dpram_vbase));
469 }
470 EXPORT_SYMBOL(cpm_dpram_phys);