Commit | Line | Data |
---|---|---|
f2a0bd37 VB |
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> | |
15f8c604 | 42 | #include <asm/cpm.h> |
f2a0bd37 VB |
43 | |
44 | #include <asm/fs_pd.h> | |
45 | ||
46 | #define CPM_MAP_SIZE (0x4000) | |
47 | ||
15f8c604 | 48 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
f2a0bd37 | 49 | static void m8xx_cpm_dpinit(void); |
15f8c604 | 50 | #endif |
4b218e9b SW |
51 | static uint host_buffer; /* One page of host buffer */ |
52 | static uint host_end; /* end + 1 */ | |
fb533d0c SW |
53 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
54 | immap_t __iomem *mpc8xx_immr; | |
55 | static cpic8xx_t __iomem *cpic_reg; | |
f2a0bd37 | 56 | |
f2a0bd37 VB |
57 | static struct irq_host *cpm_pic_host; |
58 | ||
59 | static void cpm_mask_irq(unsigned int irq) | |
60 | { | |
61 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
62 | ||
63 | clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
64 | } | |
65 | ||
66 | static void cpm_unmask_irq(unsigned int irq) | |
67 | { | |
68 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
69 | ||
70 | setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
71 | } | |
72 | ||
73 | static void cpm_end_irq(unsigned int irq) | |
74 | { | |
75 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
76 | ||
77 | out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); | |
78 | } | |
79 | ||
80 | static struct irq_chip cpm_pic = { | |
81 | .typename = " CPM PIC ", | |
82 | .mask = cpm_mask_irq, | |
83 | .unmask = cpm_unmask_irq, | |
84 | .eoi = cpm_end_irq, | |
85 | }; | |
86 | ||
87 | int cpm_get_irq(void) | |
88 | { | |
89 | int cpm_vec; | |
90 | ||
91 | /* Get the vector by setting the ACK bit and then reading | |
92 | * the register. | |
93 | */ | |
94 | out_be16(&cpic_reg->cpic_civr, 1); | |
95 | cpm_vec = in_be16(&cpic_reg->cpic_civr); | |
96 | cpm_vec >>= 11; | |
97 | ||
98 | return irq_linear_revmap(cpm_pic_host, cpm_vec); | |
99 | } | |
100 | ||
f2a0bd37 VB |
101 | static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, |
102 | irq_hw_number_t hw) | |
103 | { | |
104 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); | |
105 | ||
106 | get_irq_desc(virq)->status |= IRQ_LEVEL; | |
107 | set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); | |
108 | return 0; | |
109 | } | |
110 | ||
111 | /* The CPM can generate the error interrupt when there is a race condition | |
112 | * between generating and masking interrupts. All we have to do is ACK it | |
113 | * and return. This is a no-op function so we don't need any special | |
114 | * tests in the interrupt handler. | |
115 | */ | |
4b218e9b | 116 | static irqreturn_t cpm_error_interrupt(int irq, void *dev) |
f2a0bd37 VB |
117 | { |
118 | return IRQ_HANDLED; | |
119 | } | |
120 | ||
121 | static struct irqaction cpm_error_irqaction = { | |
122 | .handler = cpm_error_interrupt, | |
123 | .mask = CPU_MASK_NONE, | |
124 | .name = "error", | |
125 | }; | |
126 | ||
127 | static struct irq_host_ops cpm_pic_host_ops = { | |
f2a0bd37 VB |
128 | .map = cpm_pic_host_map, |
129 | }; | |
130 | ||
131 | unsigned int cpm_pic_init(void) | |
132 | { | |
133 | struct device_node *np = NULL; | |
134 | struct resource res; | |
135 | unsigned int sirq = NO_IRQ, hwirq, eirq; | |
136 | int ret; | |
137 | ||
138 | pr_debug("cpm_pic_init\n"); | |
139 | ||
fb533d0c SW |
140 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); |
141 | if (np == NULL) | |
142 | np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); | |
f2a0bd37 VB |
143 | if (np == NULL) { |
144 | printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); | |
145 | return sirq; | |
146 | } | |
fb533d0c | 147 | |
f2a0bd37 VB |
148 | ret = of_address_to_resource(np, 0, &res); |
149 | if (ret) | |
150 | goto end; | |
151 | ||
fb533d0c | 152 | cpic_reg = ioremap(res.start, res.end - res.start + 1); |
f2a0bd37 VB |
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 | ||
52964f87 ME |
168 | cpm_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR, |
169 | 64, &cpm_pic_host_ops, 64); | |
f2a0bd37 VB |
170 | if (cpm_pic_host == NULL) { |
171 | printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); | |
172 | sirq = NO_IRQ; | |
173 | goto end; | |
174 | } | |
f2a0bd37 VB |
175 | |
176 | /* Install our own error handler. */ | |
fb533d0c SW |
177 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); |
178 | if (np == NULL) | |
179 | np = of_find_node_by_type(NULL, "cpm"); | |
f2a0bd37 VB |
180 | if (np == NULL) { |
181 | printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); | |
182 | goto end; | |
183 | } | |
fb533d0c | 184 | |
4b218e9b | 185 | eirq = irq_of_parse_and_map(np, 0); |
f2a0bd37 VB |
186 | if (eirq == NO_IRQ) |
187 | goto end; | |
188 | ||
189 | if (setup_irq(eirq, &cpm_error_irqaction)) | |
190 | printk(KERN_ERR "Could not allocate CPM error IRQ!"); | |
191 | ||
192 | setbits32(&cpic_reg->cpic_cicr, CICR_IEN); | |
193 | ||
194 | end: | |
195 | of_node_put(np); | |
196 | return sirq; | |
197 | } | |
198 | ||
15f8c604 | 199 | void __init cpm_reset(void) |
f2a0bd37 | 200 | { |
fb533d0c | 201 | sysconf8xx_t __iomem *siu_conf; |
f2a0bd37 | 202 | |
fb533d0c SW |
203 | mpc8xx_immr = ioremap(get_immrbase(), 0x4000); |
204 | if (!mpc8xx_immr) { | |
205 | printk(KERN_CRIT "Could not map IMMR\n"); | |
206 | return; | |
207 | } | |
f2a0bd37 | 208 | |
fb533d0c SW |
209 | cpmp = &mpc8xx_immr->im_cpm; |
210 | ||
211 | #ifndef CONFIG_PPC_EARLY_DEBUG_CPM | |
f2a0bd37 VB |
212 | /* Perform a reset. |
213 | */ | |
fb533d0c | 214 | out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); |
f2a0bd37 VB |
215 | |
216 | /* Wait for it. | |
217 | */ | |
fb533d0c SW |
218 | while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG); |
219 | #endif | |
f2a0bd37 | 220 | |
fb533d0c SW |
221 | #ifdef CONFIG_UCODE_PATCH |
222 | cpm_load_patch(cpmp); | |
f2a0bd37 VB |
223 | #endif |
224 | ||
225 | /* Set SDMA Bus Request priority 5. | |
226 | * On 860T, this also enables FEC priority 6. I am not sure | |
227 | * this is what we realy want for some applications, but the | |
228 | * manual recommends it. | |
229 | * Bit 25, FAM can also be set to use FEC aggressive mode (860T). | |
230 | */ | |
fb533d0c | 231 | siu_conf = immr_map(im_siu_conf); |
f2a0bd37 VB |
232 | out_be32(&siu_conf->sc_sdcr, 1); |
233 | immr_unmap(siu_conf); | |
234 | ||
15f8c604 SW |
235 | #ifdef CONFIG_PPC_CPM_NEW_BINDING |
236 | cpm_muram_init(); | |
237 | #else | |
f2a0bd37 VB |
238 | /* Reclaim the DP memory for our use. */ |
239 | m8xx_cpm_dpinit(); | |
15f8c604 | 240 | #endif |
f2a0bd37 VB |
241 | } |
242 | ||
243 | /* We used to do this earlier, but have to postpone as long as possible | |
244 | * to ensure the kernel VM is now running. | |
245 | */ | |
246 | static void | |
247 | alloc_host_memory(void) | |
248 | { | |
249 | dma_addr_t physaddr; | |
250 | ||
251 | /* Set the host page for allocation. | |
252 | */ | |
253 | host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr, | |
254 | GFP_KERNEL); | |
255 | host_end = host_buffer + PAGE_SIZE; | |
256 | } | |
257 | ||
258 | /* We also own one page of host buffer space for the allocation of | |
259 | * UART "fifos" and the like. | |
260 | */ | |
261 | uint | |
262 | m8xx_cpm_hostalloc(uint size) | |
263 | { | |
264 | uint retloc; | |
265 | ||
266 | if (host_buffer == 0) | |
267 | alloc_host_memory(); | |
268 | ||
269 | if ((host_buffer + size) >= host_end) | |
270 | return(0); | |
271 | ||
272 | retloc = host_buffer; | |
273 | host_buffer += size; | |
274 | ||
275 | return(retloc); | |
276 | } | |
277 | ||
278 | /* Set a baud rate generator. This needs lots of work. There are | |
279 | * four BRGs, any of which can be wired to any channel. | |
280 | * The internal baud rate clock is the system clock divided by 16. | |
281 | * This assumes the baudrate is 16x oversampled by the uart. | |
282 | */ | |
283 | #define BRG_INT_CLK (get_brgfreq()) | |
284 | #define BRG_UART_CLK (BRG_INT_CLK/16) | |
285 | #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) | |
286 | ||
287 | void | |
288 | cpm_setbrg(uint brg, uint rate) | |
289 | { | |
fb533d0c | 290 | u32 __iomem *bp; |
f2a0bd37 VB |
291 | |
292 | /* This is good enough to get SMCs running..... | |
293 | */ | |
fb533d0c | 294 | bp = &cpmp->cp_brgc1; |
f2a0bd37 VB |
295 | bp += brg; |
296 | /* The BRG has a 12-bit counter. For really slow baud rates (or | |
297 | * really fast processors), we may have to further divide by 16. | |
298 | */ | |
299 | if (((BRG_UART_CLK / rate) - 1) < 4096) | |
fb533d0c | 300 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); |
f2a0bd37 | 301 | else |
fb533d0c SW |
302 | out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | |
303 | CPM_BRG_EN | CPM_BRG_DIV16); | |
f2a0bd37 VB |
304 | } |
305 | ||
15f8c604 | 306 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
f2a0bd37 VB |
307 | /* |
308 | * dpalloc / dpfree bits. | |
309 | */ | |
310 | static spinlock_t cpm_dpmem_lock; | |
311 | /* | |
312 | * 16 blocks should be enough to satisfy all requests | |
313 | * until the memory subsystem goes up... | |
314 | */ | |
315 | static rh_block_t cpm_boot_dpmem_rh_block[16]; | |
316 | static rh_info_t cpm_dpmem_info; | |
317 | ||
318 | #define CPM_DPMEM_ALIGNMENT 8 | |
fb533d0c SW |
319 | static u8 __iomem *dpram_vbase; |
320 | static phys_addr_t dpram_pbase; | |
f2a0bd37 | 321 | |
fb533d0c | 322 | static void m8xx_cpm_dpinit(void) |
f2a0bd37 VB |
323 | { |
324 | spin_lock_init(&cpm_dpmem_lock); | |
325 | ||
fb533d0c SW |
326 | dpram_vbase = cpmp->cp_dpmem; |
327 | dpram_pbase = get_immrbase() + offsetof(immap_t, im_cpm.cp_dpmem); | |
f2a0bd37 VB |
328 | |
329 | /* Initialize the info header */ | |
330 | rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT, | |
331 | sizeof(cpm_boot_dpmem_rh_block) / | |
332 | sizeof(cpm_boot_dpmem_rh_block[0]), | |
333 | cpm_boot_dpmem_rh_block); | |
334 | ||
335 | /* | |
336 | * Attach the usable dpmem area. | |
337 | * XXX: This is actually crap. CPM_DATAONLY_BASE and | |
338 | * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies | |
339 | * with the processor and the microcode patches applied / activated. | |
340 | * But the following should be at least safe. | |
341 | */ | |
4c35630c | 342 | rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); |
f2a0bd37 VB |
343 | } |
344 | ||
345 | /* | |
346 | * Allocate the requested size worth of DP memory. | |
347 | * This function returns an offset into the DPRAM area. | |
348 | * Use cpm_dpram_addr() to get the virtual address of the area. | |
349 | */ | |
4c35630c | 350 | unsigned long cpm_dpalloc(uint size, uint align) |
f2a0bd37 | 351 | { |
4c35630c | 352 | unsigned long start; |
f2a0bd37 VB |
353 | unsigned long flags; |
354 | ||
355 | spin_lock_irqsave(&cpm_dpmem_lock, flags); | |
356 | cpm_dpmem_info.alignment = align; | |
357 | start = rh_alloc(&cpm_dpmem_info, size, "commproc"); | |
358 | spin_unlock_irqrestore(&cpm_dpmem_lock, flags); | |
359 | ||
360 | return (uint)start; | |
361 | } | |
362 | EXPORT_SYMBOL(cpm_dpalloc); | |
363 | ||
4c35630c | 364 | int cpm_dpfree(unsigned long offset) |
f2a0bd37 VB |
365 | { |
366 | int ret; | |
367 | unsigned long flags; | |
368 | ||
369 | spin_lock_irqsave(&cpm_dpmem_lock, flags); | |
4c35630c | 370 | ret = rh_free(&cpm_dpmem_info, offset); |
f2a0bd37 VB |
371 | spin_unlock_irqrestore(&cpm_dpmem_lock, flags); |
372 | ||
373 | return ret; | |
374 | } | |
375 | EXPORT_SYMBOL(cpm_dpfree); | |
376 | ||
4c35630c | 377 | unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align) |
f2a0bd37 | 378 | { |
4c35630c | 379 | unsigned long start; |
f2a0bd37 VB |
380 | unsigned long flags; |
381 | ||
382 | spin_lock_irqsave(&cpm_dpmem_lock, flags); | |
383 | cpm_dpmem_info.alignment = align; | |
4c35630c | 384 | start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc"); |
f2a0bd37 VB |
385 | spin_unlock_irqrestore(&cpm_dpmem_lock, flags); |
386 | ||
4c35630c | 387 | return start; |
f2a0bd37 VB |
388 | } |
389 | EXPORT_SYMBOL(cpm_dpalloc_fixed); | |
390 | ||
391 | void cpm_dpdump(void) | |
392 | { | |
393 | rh_dump(&cpm_dpmem_info); | |
394 | } | |
395 | EXPORT_SYMBOL(cpm_dpdump); | |
396 | ||
4c35630c | 397 | void *cpm_dpram_addr(unsigned long offset) |
f2a0bd37 VB |
398 | { |
399 | return (void *)(dpram_vbase + offset); | |
400 | } | |
401 | EXPORT_SYMBOL(cpm_dpram_addr); | |
402 | ||
fb533d0c | 403 | uint cpm_dpram_phys(u8 *addr) |
f2a0bd37 VB |
404 | { |
405 | return (dpram_pbase + (uint)(addr - dpram_vbase)); | |
406 | } | |
83af919e | 407 | EXPORT_SYMBOL(cpm_dpram_phys); |
15f8c604 | 408 | #endif /* !CONFIG_PPC_CPM_NEW_BINDING */ |
663edbd2 SW |
409 | |
410 | struct cpm_ioport16 { | |
411 | __be16 dir, par, sor, dat, intr; | |
412 | __be16 res[3]; | |
413 | }; | |
414 | ||
415 | struct cpm_ioport32 { | |
416 | __be32 dir, par, sor; | |
417 | }; | |
418 | ||
419 | static void cpm1_set_pin32(int port, int pin, int flags) | |
420 | { | |
421 | struct cpm_ioport32 __iomem *iop; | |
422 | pin = 1 << (31 - pin); | |
423 | ||
424 | if (port == CPM_PORTB) | |
425 | iop = (struct cpm_ioport32 __iomem *) | |
426 | &mpc8xx_immr->im_cpm.cp_pbdir; | |
427 | else | |
428 | iop = (struct cpm_ioport32 __iomem *) | |
429 | &mpc8xx_immr->im_cpm.cp_pedir; | |
430 | ||
431 | if (flags & CPM_PIN_OUTPUT) | |
432 | setbits32(&iop->dir, pin); | |
433 | else | |
434 | clrbits32(&iop->dir, pin); | |
435 | ||
436 | if (!(flags & CPM_PIN_GPIO)) | |
437 | setbits32(&iop->par, pin); | |
438 | else | |
439 | clrbits32(&iop->par, pin); | |
440 | ||
441 | if (port == CPM_PORTE) { | |
442 | if (flags & CPM_PIN_SECONDARY) | |
443 | setbits32(&iop->sor, pin); | |
444 | else | |
445 | clrbits32(&iop->sor, pin); | |
446 | ||
447 | if (flags & CPM_PIN_OPENDRAIN) | |
448 | setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
449 | else | |
450 | clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
451 | } | |
452 | } | |
453 | ||
454 | static void cpm1_set_pin16(int port, int pin, int flags) | |
455 | { | |
456 | struct cpm_ioport16 __iomem *iop = | |
457 | (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; | |
458 | ||
459 | pin = 1 << (15 - pin); | |
460 | ||
461 | if (port != 0) | |
462 | iop += port - 1; | |
463 | ||
464 | if (flags & CPM_PIN_OUTPUT) | |
465 | setbits16(&iop->dir, pin); | |
466 | else | |
467 | clrbits16(&iop->dir, pin); | |
468 | ||
469 | if (!(flags & CPM_PIN_GPIO)) | |
470 | setbits16(&iop->par, pin); | |
471 | else | |
472 | clrbits16(&iop->par, pin); | |
473 | ||
474 | if (port == CPM_PORTC) { | |
475 | if (flags & CPM_PIN_SECONDARY) | |
476 | setbits16(&iop->sor, pin); | |
477 | else | |
478 | clrbits16(&iop->sor, pin); | |
479 | } | |
480 | } | |
481 | ||
482 | void cpm1_set_pin(enum cpm_port port, int pin, int flags) | |
483 | { | |
484 | if (port == CPM_PORTB || port == CPM_PORTE) | |
485 | cpm1_set_pin32(port, pin, flags); | |
486 | else | |
487 | cpm1_set_pin16(port, pin, flags); | |
488 | } | |
489 | ||
490 | int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |
491 | { | |
492 | int shift; | |
493 | int i, bits = 0; | |
494 | u32 __iomem *reg; | |
495 | u32 mask = 7; | |
496 | ||
497 | u8 clk_map[][3] = { | |
498 | {CPM_CLK_SCC1, CPM_BRG1, 0}, | |
499 | {CPM_CLK_SCC1, CPM_BRG2, 1}, | |
500 | {CPM_CLK_SCC1, CPM_BRG3, 2}, | |
501 | {CPM_CLK_SCC1, CPM_BRG4, 3}, | |
502 | {CPM_CLK_SCC1, CPM_CLK1, 4}, | |
503 | {CPM_CLK_SCC1, CPM_CLK2, 5}, | |
504 | {CPM_CLK_SCC1, CPM_CLK3, 6}, | |
505 | {CPM_CLK_SCC1, CPM_CLK4, 7}, | |
506 | ||
507 | {CPM_CLK_SCC2, CPM_BRG1, 0}, | |
508 | {CPM_CLK_SCC2, CPM_BRG2, 1}, | |
509 | {CPM_CLK_SCC2, CPM_BRG3, 2}, | |
510 | {CPM_CLK_SCC2, CPM_BRG4, 3}, | |
511 | {CPM_CLK_SCC2, CPM_CLK1, 4}, | |
512 | {CPM_CLK_SCC2, CPM_CLK2, 5}, | |
513 | {CPM_CLK_SCC2, CPM_CLK3, 6}, | |
514 | {CPM_CLK_SCC2, CPM_CLK4, 7}, | |
515 | ||
516 | {CPM_CLK_SCC3, CPM_BRG1, 0}, | |
517 | {CPM_CLK_SCC3, CPM_BRG2, 1}, | |
518 | {CPM_CLK_SCC3, CPM_BRG3, 2}, | |
519 | {CPM_CLK_SCC3, CPM_BRG4, 3}, | |
520 | {CPM_CLK_SCC3, CPM_CLK5, 4}, | |
521 | {CPM_CLK_SCC3, CPM_CLK6, 5}, | |
522 | {CPM_CLK_SCC3, CPM_CLK7, 6}, | |
523 | {CPM_CLK_SCC3, CPM_CLK8, 7}, | |
524 | ||
525 | {CPM_CLK_SCC4, CPM_BRG1, 0}, | |
526 | {CPM_CLK_SCC4, CPM_BRG2, 1}, | |
527 | {CPM_CLK_SCC4, CPM_BRG3, 2}, | |
528 | {CPM_CLK_SCC4, CPM_BRG4, 3}, | |
529 | {CPM_CLK_SCC4, CPM_CLK5, 4}, | |
530 | {CPM_CLK_SCC4, CPM_CLK6, 5}, | |
531 | {CPM_CLK_SCC4, CPM_CLK7, 6}, | |
532 | {CPM_CLK_SCC4, CPM_CLK8, 7}, | |
533 | ||
534 | {CPM_CLK_SMC1, CPM_BRG1, 0}, | |
535 | {CPM_CLK_SMC1, CPM_BRG2, 1}, | |
536 | {CPM_CLK_SMC1, CPM_BRG3, 2}, | |
537 | {CPM_CLK_SMC1, CPM_BRG4, 3}, | |
538 | {CPM_CLK_SMC1, CPM_CLK1, 4}, | |
539 | {CPM_CLK_SMC1, CPM_CLK2, 5}, | |
540 | {CPM_CLK_SMC1, CPM_CLK3, 6}, | |
541 | {CPM_CLK_SMC1, CPM_CLK4, 7}, | |
542 | ||
543 | {CPM_CLK_SMC2, CPM_BRG1, 0}, | |
544 | {CPM_CLK_SMC2, CPM_BRG2, 1}, | |
545 | {CPM_CLK_SMC2, CPM_BRG3, 2}, | |
546 | {CPM_CLK_SMC2, CPM_BRG4, 3}, | |
547 | {CPM_CLK_SMC2, CPM_CLK5, 4}, | |
548 | {CPM_CLK_SMC2, CPM_CLK6, 5}, | |
549 | {CPM_CLK_SMC2, CPM_CLK7, 6}, | |
550 | {CPM_CLK_SMC2, CPM_CLK8, 7}, | |
551 | }; | |
552 | ||
553 | switch (target) { | |
554 | case CPM_CLK_SCC1: | |
555 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
556 | shift = 0; | |
557 | break; | |
558 | ||
559 | case CPM_CLK_SCC2: | |
560 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
561 | shift = 8; | |
562 | break; | |
563 | ||
564 | case CPM_CLK_SCC3: | |
565 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
566 | shift = 16; | |
567 | break; | |
568 | ||
569 | case CPM_CLK_SCC4: | |
570 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
571 | shift = 24; | |
572 | break; | |
573 | ||
574 | case CPM_CLK_SMC1: | |
575 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
576 | shift = 12; | |
577 | break; | |
578 | ||
579 | case CPM_CLK_SMC2: | |
580 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
581 | shift = 28; | |
582 | break; | |
583 | ||
584 | default: | |
585 | printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); | |
586 | return -EINVAL; | |
587 | } | |
588 | ||
589 | if (reg == &mpc8xx_immr->im_cpm.cp_sicr && mode == CPM_CLK_RX) | |
590 | shift += 3; | |
591 | ||
592 | for (i = 0; i < ARRAY_SIZE(clk_map); i++) { | |
593 | if (clk_map[i][0] == target && clk_map[i][1] == clock) { | |
594 | bits = clk_map[i][2]; | |
595 | break; | |
596 | } | |
597 | } | |
598 | ||
599 | if (i == ARRAY_SIZE(clk_map)) { | |
600 | printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); | |
601 | return -EINVAL; | |
602 | } | |
603 | ||
604 | bits <<= shift; | |
605 | mask <<= shift; | |
606 | out_be32(reg, (in_be32(reg) & ~mask) | bits); | |
607 | ||
608 | return 0; | |
609 | } |