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