Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
f2a0bd37 VB |
2 | /* |
3 | * General Purpose functions for the global management of the | |
4 | * Communication Processor Module. | |
5 | * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) | |
6 | * | |
7 | * In addition to the individual control of the communication | |
8 | * channels, there are a few functions that globally affect the | |
9 | * communication processor. | |
10 | * | |
11 | * Buffer descriptors must be allocated from the dual ported memory | |
12 | * space. The allocator for that is here. When the communication | |
13 | * process is reset, we reclaim the memory available. There is | |
14 | * currently no deallocator for this memory. | |
15 | * The amount of space available is platform dependent. On the | |
16 | * MBX, the EPPC software loads additional microcode into the | |
17 | * communication processor, and uses some of the DP ram for this | |
18 | * purpose. Current, the first 512 bytes and the last 256 bytes of | |
19 | * memory are used. Right now I am conservative and only use the | |
20 | * memory that can never be used for microcode. If there are | |
21 | * applications that require more DP ram, we can expand the boundaries | |
22 | * but then we have to be careful of any downloaded microcode. | |
23 | */ | |
24 | #include <linux/errno.h> | |
25 | #include <linux/sched.h> | |
26 | #include <linux/kernel.h> | |
27 | #include <linux/dma-mapping.h> | |
28 | #include <linux/param.h> | |
29 | #include <linux/string.h> | |
30 | #include <linux/mm.h> | |
31 | #include <linux/interrupt.h> | |
32 | #include <linux/irq.h> | |
33 | #include <linux/module.h> | |
dc2380ec | 34 | #include <linux/spinlock.h> |
5a0e3ad6 | 35 | #include <linux/slab.h> |
f2a0bd37 VB |
36 | #include <asm/page.h> |
37 | #include <asm/pgtable.h> | |
38 | #include <asm/8xx_immap.h> | |
b5677d84 | 39 | #include <asm/cpm1.h> |
f2a0bd37 VB |
40 | #include <asm/io.h> |
41 | #include <asm/tlbflush.h> | |
42 | #include <asm/rheap.h> | |
43 | #include <asm/prom.h> | |
15f8c604 | 44 | #include <asm/cpm.h> |
f2a0bd37 VB |
45 | |
46 | #include <asm/fs_pd.h> | |
47 | ||
dc2380ec JF |
48 | #ifdef CONFIG_8xx_GPIO |
49 | #include <linux/of_gpio.h> | |
50 | #endif | |
51 | ||
f2a0bd37 VB |
52 | #define CPM_MAP_SIZE (0x4000) |
53 | ||
fb533d0c SW |
54 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
55 | immap_t __iomem *mpc8xx_immr; | |
56 | static cpic8xx_t __iomem *cpic_reg; | |
f2a0bd37 | 57 | |
bae1d8f1 | 58 | static struct irq_domain *cpm_pic_host; |
f2a0bd37 | 59 | |
a2073d54 | 60 | static void cpm_mask_irq(struct irq_data *d) |
f2a0bd37 | 61 | { |
476eb491 | 62 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
f2a0bd37 VB |
63 | |
64 | clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
65 | } | |
66 | ||
a2073d54 | 67 | static void cpm_unmask_irq(struct irq_data *d) |
f2a0bd37 | 68 | { |
476eb491 | 69 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
f2a0bd37 VB |
70 | |
71 | setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
72 | } | |
73 | ||
a2073d54 | 74 | static void cpm_end_irq(struct irq_data *d) |
f2a0bd37 | 75 | { |
476eb491 | 76 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
f2a0bd37 VB |
77 | |
78 | out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); | |
79 | } | |
80 | ||
81 | static struct irq_chip cpm_pic = { | |
fc380c0c | 82 | .name = "CPM PIC", |
a2073d54 LB |
83 | .irq_mask = cpm_mask_irq, |
84 | .irq_unmask = cpm_unmask_irq, | |
85 | .irq_eoi = cpm_end_irq, | |
f2a0bd37 VB |
86 | }; |
87 | ||
88 | int cpm_get_irq(void) | |
89 | { | |
90 | int cpm_vec; | |
91 | ||
92 | /* Get the vector by setting the ACK bit and then reading | |
93 | * the register. | |
94 | */ | |
95 | out_be16(&cpic_reg->cpic_civr, 1); | |
96 | cpm_vec = in_be16(&cpic_reg->cpic_civr); | |
97 | cpm_vec >>= 11; | |
98 | ||
99 | return irq_linear_revmap(cpm_pic_host, cpm_vec); | |
100 | } | |
101 | ||
bae1d8f1 | 102 | static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq, |
f2a0bd37 VB |
103 | irq_hw_number_t hw) |
104 | { | |
105 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); | |
106 | ||
98488db9 | 107 | irq_set_status_flags(virq, IRQ_LEVEL); |
ec775d0e | 108 | irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); |
f2a0bd37 VB |
109 | return 0; |
110 | } | |
111 | ||
112 | /* The CPM can generate the error interrupt when there is a race condition | |
113 | * between generating and masking interrupts. All we have to do is ACK it | |
114 | * and return. This is a no-op function so we don't need any special | |
115 | * tests in the interrupt handler. | |
116 | */ | |
4b218e9b | 117 | static irqreturn_t cpm_error_interrupt(int irq, void *dev) |
f2a0bd37 VB |
118 | { |
119 | return IRQ_HANDLED; | |
120 | } | |
121 | ||
122 | static struct irqaction cpm_error_irqaction = { | |
123 | .handler = cpm_error_interrupt, | |
e8003404 | 124 | .flags = IRQF_NO_THREAD, |
f2a0bd37 VB |
125 | .name = "error", |
126 | }; | |
127 | ||
9f70b8eb | 128 | static const struct irq_domain_ops cpm_pic_host_ops = { |
f2a0bd37 VB |
129 | .map = cpm_pic_host_map, |
130 | }; | |
131 | ||
132 | unsigned int cpm_pic_init(void) | |
133 | { | |
134 | struct device_node *np = NULL; | |
135 | struct resource res; | |
ef24ba70 | 136 | unsigned int sirq = 0, hwirq, eirq; |
f2a0bd37 VB |
137 | int ret; |
138 | ||
139 | pr_debug("cpm_pic_init\n"); | |
140 | ||
fb533d0c SW |
141 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); |
142 | if (np == NULL) | |
143 | np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); | |
f2a0bd37 VB |
144 | if (np == NULL) { |
145 | printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); | |
146 | return sirq; | |
147 | } | |
fb533d0c | 148 | |
f2a0bd37 VB |
149 | ret = of_address_to_resource(np, 0, &res); |
150 | if (ret) | |
151 | goto end; | |
152 | ||
28f65c11 | 153 | cpic_reg = ioremap(res.start, resource_size(&res)); |
f2a0bd37 VB |
154 | if (cpic_reg == NULL) |
155 | goto end; | |
156 | ||
157 | sirq = irq_of_parse_and_map(np, 0); | |
ef24ba70 | 158 | if (!sirq) |
f2a0bd37 VB |
159 | goto end; |
160 | ||
161 | /* Initialize the CPM interrupt controller. */ | |
476eb491 | 162 | hwirq = (unsigned int)virq_to_hw(sirq); |
f2a0bd37 VB |
163 | out_be32(&cpic_reg->cpic_cicr, |
164 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | | |
165 | ((hwirq/2) << 13) | CICR_HP_MASK); | |
166 | ||
167 | out_be32(&cpic_reg->cpic_cimr, 0); | |
168 | ||
a8db8cf0 | 169 | cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); |
f2a0bd37 VB |
170 | if (cpm_pic_host == NULL) { |
171 | printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); | |
ef24ba70 | 172 | sirq = 0; |
f2a0bd37 VB |
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); |
ef24ba70 | 186 | if (!eirq) |
f2a0bd37 VB |
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 | |
25985edc | 227 | * this is what we really want for some applications, but the |
f2a0bd37 VB |
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); |
501ea766 CL |
232 | if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */ |
233 | out_be32(&siu_conf->sc_sdcr, 0x40); | |
234 | else | |
235 | out_be32(&siu_conf->sc_sdcr, 1); | |
f2a0bd37 | 236 | immr_unmap(siu_conf); |
f2a0bd37 VB |
237 | } |
238 | ||
362f9b6f JF |
239 | static DEFINE_SPINLOCK(cmd_lock); |
240 | ||
241 | #define MAX_CR_CMD_LOOPS 10000 | |
242 | ||
243 | int cpm_command(u32 command, u8 opcode) | |
244 | { | |
245 | int i, ret; | |
246 | unsigned long flags; | |
247 | ||
248 | if (command & 0xffffff0f) | |
249 | return -EINVAL; | |
250 | ||
251 | spin_lock_irqsave(&cmd_lock, flags); | |
252 | ||
253 | ret = 0; | |
254 | out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8)); | |
255 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | |
256 | if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) | |
257 | goto out; | |
258 | ||
e48b1b45 | 259 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__); |
362f9b6f JF |
260 | ret = -EIO; |
261 | out: | |
262 | spin_unlock_irqrestore(&cmd_lock, flags); | |
263 | return ret; | |
264 | } | |
265 | EXPORT_SYMBOL(cpm_command); | |
266 | ||
f2a0bd37 VB |
267 | /* Set a baud rate generator. This needs lots of work. There are |
268 | * four BRGs, any of which can be wired to any channel. | |
269 | * The internal baud rate clock is the system clock divided by 16. | |
270 | * This assumes the baudrate is 16x oversampled by the uart. | |
271 | */ | |
272 | #define BRG_INT_CLK (get_brgfreq()) | |
273 | #define BRG_UART_CLK (BRG_INT_CLK/16) | |
274 | #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) | |
275 | ||
276 | void | |
277 | cpm_setbrg(uint brg, uint rate) | |
278 | { | |
fb533d0c | 279 | u32 __iomem *bp; |
f2a0bd37 VB |
280 | |
281 | /* This is good enough to get SMCs running..... | |
282 | */ | |
fb533d0c | 283 | bp = &cpmp->cp_brgc1; |
f2a0bd37 VB |
284 | bp += brg; |
285 | /* The BRG has a 12-bit counter. For really slow baud rates (or | |
286 | * really fast processors), we may have to further divide by 16. | |
287 | */ | |
288 | if (((BRG_UART_CLK / rate) - 1) < 4096) | |
fb533d0c | 289 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); |
f2a0bd37 | 290 | else |
fb533d0c | 291 | out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | |
b5677d84 | 292 | CPM_BRG_EN | CPM_BRG_DIV16); |
f2a0bd37 VB |
293 | } |
294 | ||
663edbd2 | 295 | struct cpm_ioport16 { |
721c0c8a | 296 | __be16 dir, par, odr_sor, dat, intr; |
663edbd2 SW |
297 | __be16 res[3]; |
298 | }; | |
299 | ||
dc2380ec JF |
300 | struct cpm_ioport32b { |
301 | __be32 dir, par, odr, dat; | |
302 | }; | |
303 | ||
304 | struct cpm_ioport32e { | |
305 | __be32 dir, par, sor, odr, dat; | |
663edbd2 SW |
306 | }; |
307 | ||
308 | static void cpm1_set_pin32(int port, int pin, int flags) | |
309 | { | |
dc2380ec | 310 | struct cpm_ioport32e __iomem *iop; |
663edbd2 SW |
311 | pin = 1 << (31 - pin); |
312 | ||
313 | if (port == CPM_PORTB) | |
dc2380ec | 314 | iop = (struct cpm_ioport32e __iomem *) |
663edbd2 SW |
315 | &mpc8xx_immr->im_cpm.cp_pbdir; |
316 | else | |
dc2380ec | 317 | iop = (struct cpm_ioport32e __iomem *) |
663edbd2 SW |
318 | &mpc8xx_immr->im_cpm.cp_pedir; |
319 | ||
320 | if (flags & CPM_PIN_OUTPUT) | |
321 | setbits32(&iop->dir, pin); | |
322 | else | |
323 | clrbits32(&iop->dir, pin); | |
324 | ||
325 | if (!(flags & CPM_PIN_GPIO)) | |
326 | setbits32(&iop->par, pin); | |
327 | else | |
328 | clrbits32(&iop->par, pin); | |
329 | ||
721c0c8a JF |
330 | if (port == CPM_PORTB) { |
331 | if (flags & CPM_PIN_OPENDRAIN) | |
332 | setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | |
333 | else | |
334 | clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | |
335 | } | |
336 | ||
663edbd2 SW |
337 | if (port == CPM_PORTE) { |
338 | if (flags & CPM_PIN_SECONDARY) | |
339 | setbits32(&iop->sor, pin); | |
340 | else | |
341 | clrbits32(&iop->sor, pin); | |
342 | ||
343 | if (flags & CPM_PIN_OPENDRAIN) | |
344 | setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
345 | else | |
346 | clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
347 | } | |
348 | } | |
349 | ||
350 | static void cpm1_set_pin16(int port, int pin, int flags) | |
351 | { | |
352 | struct cpm_ioport16 __iomem *iop = | |
353 | (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; | |
354 | ||
355 | pin = 1 << (15 - pin); | |
356 | ||
357 | if (port != 0) | |
358 | iop += port - 1; | |
359 | ||
360 | if (flags & CPM_PIN_OUTPUT) | |
361 | setbits16(&iop->dir, pin); | |
362 | else | |
363 | clrbits16(&iop->dir, pin); | |
364 | ||
365 | if (!(flags & CPM_PIN_GPIO)) | |
366 | setbits16(&iop->par, pin); | |
367 | else | |
368 | clrbits16(&iop->par, pin); | |
369 | ||
721c0c8a JF |
370 | if (port == CPM_PORTA) { |
371 | if (flags & CPM_PIN_OPENDRAIN) | |
372 | setbits16(&iop->odr_sor, pin); | |
373 | else | |
374 | clrbits16(&iop->odr_sor, pin); | |
375 | } | |
663edbd2 SW |
376 | if (port == CPM_PORTC) { |
377 | if (flags & CPM_PIN_SECONDARY) | |
721c0c8a | 378 | setbits16(&iop->odr_sor, pin); |
663edbd2 | 379 | else |
721c0c8a | 380 | clrbits16(&iop->odr_sor, pin); |
726bd223 CL |
381 | if (flags & CPM_PIN_FALLEDGE) |
382 | setbits16(&iop->intr, pin); | |
383 | else | |
384 | clrbits16(&iop->intr, pin); | |
663edbd2 SW |
385 | } |
386 | } | |
387 | ||
388 | void cpm1_set_pin(enum cpm_port port, int pin, int flags) | |
389 | { | |
390 | if (port == CPM_PORTB || port == CPM_PORTE) | |
391 | cpm1_set_pin32(port, pin, flags); | |
392 | else | |
393 | cpm1_set_pin16(port, pin, flags); | |
394 | } | |
395 | ||
396 | int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |
397 | { | |
398 | int shift; | |
399 | int i, bits = 0; | |
400 | u32 __iomem *reg; | |
401 | u32 mask = 7; | |
402 | ||
403 | u8 clk_map[][3] = { | |
404 | {CPM_CLK_SCC1, CPM_BRG1, 0}, | |
405 | {CPM_CLK_SCC1, CPM_BRG2, 1}, | |
406 | {CPM_CLK_SCC1, CPM_BRG3, 2}, | |
407 | {CPM_CLK_SCC1, CPM_BRG4, 3}, | |
408 | {CPM_CLK_SCC1, CPM_CLK1, 4}, | |
409 | {CPM_CLK_SCC1, CPM_CLK2, 5}, | |
410 | {CPM_CLK_SCC1, CPM_CLK3, 6}, | |
411 | {CPM_CLK_SCC1, CPM_CLK4, 7}, | |
412 | ||
413 | {CPM_CLK_SCC2, CPM_BRG1, 0}, | |
414 | {CPM_CLK_SCC2, CPM_BRG2, 1}, | |
415 | {CPM_CLK_SCC2, CPM_BRG3, 2}, | |
416 | {CPM_CLK_SCC2, CPM_BRG4, 3}, | |
417 | {CPM_CLK_SCC2, CPM_CLK1, 4}, | |
418 | {CPM_CLK_SCC2, CPM_CLK2, 5}, | |
419 | {CPM_CLK_SCC2, CPM_CLK3, 6}, | |
420 | {CPM_CLK_SCC2, CPM_CLK4, 7}, | |
421 | ||
422 | {CPM_CLK_SCC3, CPM_BRG1, 0}, | |
423 | {CPM_CLK_SCC3, CPM_BRG2, 1}, | |
424 | {CPM_CLK_SCC3, CPM_BRG3, 2}, | |
425 | {CPM_CLK_SCC3, CPM_BRG4, 3}, | |
426 | {CPM_CLK_SCC3, CPM_CLK5, 4}, | |
427 | {CPM_CLK_SCC3, CPM_CLK6, 5}, | |
428 | {CPM_CLK_SCC3, CPM_CLK7, 6}, | |
429 | {CPM_CLK_SCC3, CPM_CLK8, 7}, | |
430 | ||
431 | {CPM_CLK_SCC4, CPM_BRG1, 0}, | |
432 | {CPM_CLK_SCC4, CPM_BRG2, 1}, | |
433 | {CPM_CLK_SCC4, CPM_BRG3, 2}, | |
434 | {CPM_CLK_SCC4, CPM_BRG4, 3}, | |
435 | {CPM_CLK_SCC4, CPM_CLK5, 4}, | |
436 | {CPM_CLK_SCC4, CPM_CLK6, 5}, | |
437 | {CPM_CLK_SCC4, CPM_CLK7, 6}, | |
438 | {CPM_CLK_SCC4, CPM_CLK8, 7}, | |
439 | ||
440 | {CPM_CLK_SMC1, CPM_BRG1, 0}, | |
441 | {CPM_CLK_SMC1, CPM_BRG2, 1}, | |
442 | {CPM_CLK_SMC1, CPM_BRG3, 2}, | |
443 | {CPM_CLK_SMC1, CPM_BRG4, 3}, | |
444 | {CPM_CLK_SMC1, CPM_CLK1, 4}, | |
445 | {CPM_CLK_SMC1, CPM_CLK2, 5}, | |
446 | {CPM_CLK_SMC1, CPM_CLK3, 6}, | |
447 | {CPM_CLK_SMC1, CPM_CLK4, 7}, | |
448 | ||
449 | {CPM_CLK_SMC2, CPM_BRG1, 0}, | |
450 | {CPM_CLK_SMC2, CPM_BRG2, 1}, | |
451 | {CPM_CLK_SMC2, CPM_BRG3, 2}, | |
452 | {CPM_CLK_SMC2, CPM_BRG4, 3}, | |
453 | {CPM_CLK_SMC2, CPM_CLK5, 4}, | |
454 | {CPM_CLK_SMC2, CPM_CLK6, 5}, | |
455 | {CPM_CLK_SMC2, CPM_CLK7, 6}, | |
456 | {CPM_CLK_SMC2, CPM_CLK8, 7}, | |
457 | }; | |
458 | ||
459 | switch (target) { | |
460 | case CPM_CLK_SCC1: | |
461 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
462 | shift = 0; | |
463 | break; | |
464 | ||
465 | case CPM_CLK_SCC2: | |
466 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
467 | shift = 8; | |
468 | break; | |
469 | ||
470 | case CPM_CLK_SCC3: | |
471 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
472 | shift = 16; | |
473 | break; | |
474 | ||
475 | case CPM_CLK_SCC4: | |
476 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
477 | shift = 24; | |
478 | break; | |
479 | ||
480 | case CPM_CLK_SMC1: | |
481 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
482 | shift = 12; | |
483 | break; | |
484 | ||
485 | case CPM_CLK_SMC2: | |
486 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
487 | shift = 28; | |
488 | break; | |
489 | ||
490 | default: | |
491 | printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); | |
492 | return -EINVAL; | |
493 | } | |
494 | ||
663edbd2 SW |
495 | for (i = 0; i < ARRAY_SIZE(clk_map); i++) { |
496 | if (clk_map[i][0] == target && clk_map[i][1] == clock) { | |
497 | bits = clk_map[i][2]; | |
498 | break; | |
499 | } | |
500 | } | |
501 | ||
502 | if (i == ARRAY_SIZE(clk_map)) { | |
503 | printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); | |
504 | return -EINVAL; | |
505 | } | |
506 | ||
507 | bits <<= shift; | |
508 | mask <<= shift; | |
1cca2d2b WO |
509 | |
510 | if (reg == &mpc8xx_immr->im_cpm.cp_sicr) { | |
511 | if (mode == CPM_CLK_RTX) { | |
512 | bits |= bits << 3; | |
513 | mask |= mask << 3; | |
514 | } else if (mode == CPM_CLK_RX) { | |
515 | bits <<= 3; | |
516 | mask <<= 3; | |
517 | } | |
518 | } | |
519 | ||
663edbd2 SW |
520 | out_be32(reg, (in_be32(reg) & ~mask) | bits); |
521 | ||
522 | return 0; | |
523 | } | |
dc2380ec JF |
524 | |
525 | /* | |
526 | * GPIO LIB API implementation | |
527 | */ | |
528 | #ifdef CONFIG_8xx_GPIO | |
529 | ||
530 | struct cpm1_gpio16_chip { | |
531 | struct of_mm_gpio_chip mm_gc; | |
532 | spinlock_t lock; | |
533 | ||
534 | /* shadowed data register to clear/set bits safely */ | |
535 | u16 cpdata; | |
726bd223 CL |
536 | |
537 | /* IRQ associated with Pins when relevant */ | |
538 | int irq[16]; | |
dc2380ec JF |
539 | }; |
540 | ||
dc2380ec JF |
541 | static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) |
542 | { | |
41017a75 CL |
543 | struct cpm1_gpio16_chip *cpm1_gc = |
544 | container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); | |
dc2380ec JF |
545 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
546 | ||
547 | cpm1_gc->cpdata = in_be16(&iop->dat); | |
548 | } | |
549 | ||
550 | static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) | |
551 | { | |
552 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
553 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | |
554 | u16 pin_mask; | |
555 | ||
556 | pin_mask = 1 << (15 - gpio); | |
557 | ||
558 | return !!(in_be16(&iop->dat) & pin_mask); | |
559 | } | |
560 | ||
f1eaf16a JF |
561 | static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, |
562 | int value) | |
dc2380ec | 563 | { |
e65078f1 | 564 | struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 565 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
dc2380ec JF |
566 | |
567 | if (value) | |
568 | cpm1_gc->cpdata |= pin_mask; | |
569 | else | |
570 | cpm1_gc->cpdata &= ~pin_mask; | |
571 | ||
572 | out_be16(&iop->dat, cpm1_gc->cpdata); | |
f1eaf16a JF |
573 | } |
574 | ||
575 | static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) | |
576 | { | |
577 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 578 | struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
f1eaf16a JF |
579 | unsigned long flags; |
580 | u16 pin_mask = 1 << (15 - gpio); | |
581 | ||
582 | spin_lock_irqsave(&cpm1_gc->lock, flags); | |
583 | ||
584 | __cpm1_gpio16_set(mm_gc, pin_mask, value); | |
dc2380ec JF |
585 | |
586 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | |
587 | } | |
588 | ||
726bd223 CL |
589 | static int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio) |
590 | { | |
591 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
592 | struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); | |
593 | ||
594 | return cpm1_gc->irq[gpio] ? : -ENXIO; | |
595 | } | |
596 | ||
dc2380ec JF |
597 | static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
598 | { | |
599 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 600 | struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 601 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
602 | unsigned long flags; |
603 | u16 pin_mask = 1 << (15 - gpio); | |
dc2380ec | 604 | |
f1eaf16a | 605 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
606 | |
607 | setbits16(&iop->dir, pin_mask); | |
f1eaf16a | 608 | __cpm1_gpio16_set(mm_gc, pin_mask, val); |
dc2380ec | 609 | |
f1eaf16a | 610 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
dc2380ec JF |
611 | |
612 | return 0; | |
613 | } | |
614 | ||
615 | static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) | |
616 | { | |
617 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 618 | struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 619 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
620 | unsigned long flags; |
621 | u16 pin_mask = 1 << (15 - gpio); | |
dc2380ec | 622 | |
f1eaf16a | 623 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
624 | |
625 | clrbits16(&iop->dir, pin_mask); | |
626 | ||
f1eaf16a JF |
627 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
628 | ||
dc2380ec JF |
629 | return 0; |
630 | } | |
631 | ||
632 | int cpm1_gpiochip_add16(struct device_node *np) | |
633 | { | |
634 | struct cpm1_gpio16_chip *cpm1_gc; | |
635 | struct of_mm_gpio_chip *mm_gc; | |
dc2380ec | 636 | struct gpio_chip *gc; |
726bd223 | 637 | u16 mask; |
dc2380ec JF |
638 | |
639 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | |
640 | if (!cpm1_gc) | |
641 | return -ENOMEM; | |
642 | ||
643 | spin_lock_init(&cpm1_gc->lock); | |
644 | ||
726bd223 CL |
645 | if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) { |
646 | int i, j; | |
647 | ||
648 | for (i = 0, j = 0; i < 16; i++) | |
649 | if (mask & (1 << (15 - i))) | |
650 | cpm1_gc->irq[i] = irq_of_parse_and_map(np, j++); | |
651 | } | |
652 | ||
dc2380ec | 653 | mm_gc = &cpm1_gc->mm_gc; |
a19e3da5 | 654 | gc = &mm_gc->gc; |
dc2380ec JF |
655 | |
656 | mm_gc->save_regs = cpm1_gpio16_save_regs; | |
dc2380ec JF |
657 | gc->ngpio = 16; |
658 | gc->direction_input = cpm1_gpio16_dir_in; | |
659 | gc->direction_output = cpm1_gpio16_dir_out; | |
660 | gc->get = cpm1_gpio16_get; | |
661 | gc->set = cpm1_gpio16_set; | |
726bd223 | 662 | gc->to_irq = cpm1_gpio16_to_irq; |
dc2380ec | 663 | |
e65078f1 | 664 | return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); |
dc2380ec JF |
665 | } |
666 | ||
667 | struct cpm1_gpio32_chip { | |
668 | struct of_mm_gpio_chip mm_gc; | |
669 | spinlock_t lock; | |
670 | ||
671 | /* shadowed data register to clear/set bits safely */ | |
672 | u32 cpdata; | |
673 | }; | |
674 | ||
dc2380ec JF |
675 | static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) |
676 | { | |
41017a75 CL |
677 | struct cpm1_gpio32_chip *cpm1_gc = |
678 | container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); | |
dc2380ec JF |
679 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
680 | ||
681 | cpm1_gc->cpdata = in_be32(&iop->dat); | |
682 | } | |
683 | ||
684 | static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | |
685 | { | |
686 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
687 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | |
688 | u32 pin_mask; | |
689 | ||
690 | pin_mask = 1 << (31 - gpio); | |
691 | ||
692 | return !!(in_be32(&iop->dat) & pin_mask); | |
693 | } | |
694 | ||
f1eaf16a JF |
695 | static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, |
696 | int value) | |
dc2380ec | 697 | { |
e65078f1 | 698 | struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 699 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
dc2380ec JF |
700 | |
701 | if (value) | |
702 | cpm1_gc->cpdata |= pin_mask; | |
703 | else | |
704 | cpm1_gc->cpdata &= ~pin_mask; | |
705 | ||
706 | out_be32(&iop->dat, cpm1_gc->cpdata); | |
f1eaf16a JF |
707 | } |
708 | ||
709 | static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | |
710 | { | |
711 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 712 | struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
f1eaf16a JF |
713 | unsigned long flags; |
714 | u32 pin_mask = 1 << (31 - gpio); | |
715 | ||
716 | spin_lock_irqsave(&cpm1_gc->lock, flags); | |
717 | ||
718 | __cpm1_gpio32_set(mm_gc, pin_mask, value); | |
dc2380ec JF |
719 | |
720 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | |
721 | } | |
722 | ||
723 | static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |
724 | { | |
725 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 726 | struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 727 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
728 | unsigned long flags; |
729 | u32 pin_mask = 1 << (31 - gpio); | |
dc2380ec | 730 | |
f1eaf16a | 731 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
732 | |
733 | setbits32(&iop->dir, pin_mask); | |
f1eaf16a | 734 | __cpm1_gpio32_set(mm_gc, pin_mask, val); |
dc2380ec | 735 | |
f1eaf16a | 736 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
dc2380ec JF |
737 | |
738 | return 0; | |
739 | } | |
740 | ||
741 | static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | |
742 | { | |
743 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
e65078f1 | 744 | struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); |
dc2380ec | 745 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
746 | unsigned long flags; |
747 | u32 pin_mask = 1 << (31 - gpio); | |
dc2380ec | 748 | |
f1eaf16a | 749 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
750 | |
751 | clrbits32(&iop->dir, pin_mask); | |
752 | ||
f1eaf16a JF |
753 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
754 | ||
dc2380ec JF |
755 | return 0; |
756 | } | |
757 | ||
758 | int cpm1_gpiochip_add32(struct device_node *np) | |
759 | { | |
760 | struct cpm1_gpio32_chip *cpm1_gc; | |
761 | struct of_mm_gpio_chip *mm_gc; | |
dc2380ec JF |
762 | struct gpio_chip *gc; |
763 | ||
764 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | |
765 | if (!cpm1_gc) | |
766 | return -ENOMEM; | |
767 | ||
768 | spin_lock_init(&cpm1_gc->lock); | |
769 | ||
770 | mm_gc = &cpm1_gc->mm_gc; | |
a19e3da5 | 771 | gc = &mm_gc->gc; |
dc2380ec JF |
772 | |
773 | mm_gc->save_regs = cpm1_gpio32_save_regs; | |
dc2380ec JF |
774 | gc->ngpio = 32; |
775 | gc->direction_input = cpm1_gpio32_dir_in; | |
776 | gc->direction_output = cpm1_gpio32_dir_out; | |
777 | gc->get = cpm1_gpio32_get; | |
778 | gc->set = cpm1_gpio32_set; | |
779 | ||
e65078f1 | 780 | return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); |
dc2380ec JF |
781 | } |
782 | ||
783 | static int cpm_init_par_io(void) | |
784 | { | |
785 | struct device_node *np; | |
786 | ||
787 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a") | |
788 | cpm1_gpiochip_add16(np); | |
789 | ||
790 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b") | |
791 | cpm1_gpiochip_add32(np); | |
792 | ||
793 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c") | |
794 | cpm1_gpiochip_add16(np); | |
795 | ||
796 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d") | |
797 | cpm1_gpiochip_add16(np); | |
798 | ||
799 | /* Port E uses CPM2 layout */ | |
800 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e") | |
801 | cpm2_gpiochip_add32(np); | |
802 | return 0; | |
803 | } | |
804 | arch_initcall(cpm_init_par_io); | |
805 | ||
806 | #endif /* CONFIG_8xx_GPIO */ |