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> | |
dc2380ec | 33 | #include <linux/spinlock.h> |
f2a0bd37 VB |
34 | #include <asm/page.h> |
35 | #include <asm/pgtable.h> | |
36 | #include <asm/8xx_immap.h> | |
b5677d84 | 37 | #include <asm/cpm1.h> |
f2a0bd37 VB |
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 | ||
dc2380ec JF |
46 | #ifdef CONFIG_8xx_GPIO |
47 | #include <linux/of_gpio.h> | |
48 | #endif | |
49 | ||
f2a0bd37 VB |
50 | #define CPM_MAP_SIZE (0x4000) |
51 | ||
fb533d0c SW |
52 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
53 | immap_t __iomem *mpc8xx_immr; | |
54 | static cpic8xx_t __iomem *cpic_reg; | |
f2a0bd37 | 55 | |
f2a0bd37 VB |
56 | static struct irq_host *cpm_pic_host; |
57 | ||
58 | static void cpm_mask_irq(unsigned int irq) | |
59 | { | |
60 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
61 | ||
62 | clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
63 | } | |
64 | ||
65 | static void cpm_unmask_irq(unsigned int irq) | |
66 | { | |
67 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
68 | ||
69 | setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | |
70 | } | |
71 | ||
72 | static void cpm_end_irq(unsigned int irq) | |
73 | { | |
74 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | |
75 | ||
76 | out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); | |
77 | } | |
78 | ||
79 | static struct irq_chip cpm_pic = { | |
b27df672 | 80 | .name = " CPM PIC ", |
f2a0bd37 VB |
81 | .mask = cpm_mask_irq, |
82 | .unmask = cpm_unmask_irq, | |
83 | .eoi = cpm_end_irq, | |
84 | }; | |
85 | ||
86 | int cpm_get_irq(void) | |
87 | { | |
88 | int cpm_vec; | |
89 | ||
90 | /* Get the vector by setting the ACK bit and then reading | |
91 | * the register. | |
92 | */ | |
93 | out_be16(&cpic_reg->cpic_civr, 1); | |
94 | cpm_vec = in_be16(&cpic_reg->cpic_civr); | |
95 | cpm_vec >>= 11; | |
96 | ||
97 | return irq_linear_revmap(cpm_pic_host, cpm_vec); | |
98 | } | |
99 | ||
f2a0bd37 VB |
100 | static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, |
101 | irq_hw_number_t hw) | |
102 | { | |
103 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); | |
104 | ||
6cff46f4 | 105 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
f2a0bd37 VB |
106 | set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); |
107 | return 0; | |
108 | } | |
109 | ||
110 | /* The CPM can generate the error interrupt when there is a race condition | |
111 | * between generating and masking interrupts. All we have to do is ACK it | |
112 | * and return. This is a no-op function so we don't need any special | |
113 | * tests in the interrupt handler. | |
114 | */ | |
4b218e9b | 115 | static irqreturn_t cpm_error_interrupt(int irq, void *dev) |
f2a0bd37 VB |
116 | { |
117 | return IRQ_HANDLED; | |
118 | } | |
119 | ||
120 | static struct irqaction cpm_error_irqaction = { | |
121 | .handler = cpm_error_interrupt, | |
f2a0bd37 VB |
122 | .name = "error", |
123 | }; | |
124 | ||
125 | static struct irq_host_ops cpm_pic_host_ops = { | |
f2a0bd37 VB |
126 | .map = cpm_pic_host_map, |
127 | }; | |
128 | ||
129 | unsigned int cpm_pic_init(void) | |
130 | { | |
131 | struct device_node *np = NULL; | |
132 | struct resource res; | |
133 | unsigned int sirq = NO_IRQ, hwirq, eirq; | |
134 | int ret; | |
135 | ||
136 | pr_debug("cpm_pic_init\n"); | |
137 | ||
fb533d0c SW |
138 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); |
139 | if (np == NULL) | |
140 | np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); | |
f2a0bd37 VB |
141 | if (np == NULL) { |
142 | printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); | |
143 | return sirq; | |
144 | } | |
fb533d0c | 145 | |
f2a0bd37 VB |
146 | ret = of_address_to_resource(np, 0, &res); |
147 | if (ret) | |
148 | goto end; | |
149 | ||
fb533d0c | 150 | cpic_reg = ioremap(res.start, res.end - res.start + 1); |
f2a0bd37 VB |
151 | if (cpic_reg == NULL) |
152 | goto end; | |
153 | ||
154 | sirq = irq_of_parse_and_map(np, 0); | |
155 | if (sirq == NO_IRQ) | |
156 | goto end; | |
157 | ||
158 | /* Initialize the CPM interrupt controller. */ | |
159 | hwirq = (unsigned int)irq_map[sirq].hwirq; | |
160 | out_be32(&cpic_reg->cpic_cicr, | |
161 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | | |
162 | ((hwirq/2) << 13) | CICR_HP_MASK); | |
163 | ||
164 | out_be32(&cpic_reg->cpic_cimr, 0); | |
165 | ||
19fc65b5 | 166 | cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, |
52964f87 | 167 | 64, &cpm_pic_host_ops, 64); |
f2a0bd37 VB |
168 | if (cpm_pic_host == NULL) { |
169 | printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); | |
170 | sirq = NO_IRQ; | |
171 | goto end; | |
172 | } | |
f2a0bd37 VB |
173 | |
174 | /* Install our own error handler. */ | |
fb533d0c SW |
175 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); |
176 | if (np == NULL) | |
177 | np = of_find_node_by_type(NULL, "cpm"); | |
f2a0bd37 VB |
178 | if (np == NULL) { |
179 | printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); | |
180 | goto end; | |
181 | } | |
fb533d0c | 182 | |
4b218e9b | 183 | eirq = irq_of_parse_and_map(np, 0); |
f2a0bd37 VB |
184 | if (eirq == NO_IRQ) |
185 | goto end; | |
186 | ||
187 | if (setup_irq(eirq, &cpm_error_irqaction)) | |
188 | printk(KERN_ERR "Could not allocate CPM error IRQ!"); | |
189 | ||
190 | setbits32(&cpic_reg->cpic_cicr, CICR_IEN); | |
191 | ||
192 | end: | |
193 | of_node_put(np); | |
194 | return sirq; | |
195 | } | |
196 | ||
15f8c604 | 197 | void __init cpm_reset(void) |
f2a0bd37 | 198 | { |
fb533d0c | 199 | sysconf8xx_t __iomem *siu_conf; |
f2a0bd37 | 200 | |
fb533d0c SW |
201 | mpc8xx_immr = ioremap(get_immrbase(), 0x4000); |
202 | if (!mpc8xx_immr) { | |
203 | printk(KERN_CRIT "Could not map IMMR\n"); | |
204 | return; | |
205 | } | |
f2a0bd37 | 206 | |
fb533d0c SW |
207 | cpmp = &mpc8xx_immr->im_cpm; |
208 | ||
209 | #ifndef CONFIG_PPC_EARLY_DEBUG_CPM | |
f2a0bd37 VB |
210 | /* Perform a reset. |
211 | */ | |
fb533d0c | 212 | out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); |
f2a0bd37 VB |
213 | |
214 | /* Wait for it. | |
215 | */ | |
fb533d0c SW |
216 | while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG); |
217 | #endif | |
f2a0bd37 | 218 | |
fb533d0c SW |
219 | #ifdef CONFIG_UCODE_PATCH |
220 | cpm_load_patch(cpmp); | |
f2a0bd37 VB |
221 | #endif |
222 | ||
223 | /* Set SDMA Bus Request priority 5. | |
224 | * On 860T, this also enables FEC priority 6. I am not sure | |
225 | * this is what we realy want for some applications, but the | |
226 | * manual recommends it. | |
227 | * Bit 25, FAM can also be set to use FEC aggressive mode (860T). | |
228 | */ | |
fb533d0c | 229 | siu_conf = immr_map(im_siu_conf); |
f2a0bd37 VB |
230 | out_be32(&siu_conf->sc_sdcr, 1); |
231 | immr_unmap(siu_conf); | |
232 | ||
15f8c604 | 233 | cpm_muram_init(); |
f2a0bd37 VB |
234 | } |
235 | ||
362f9b6f JF |
236 | static DEFINE_SPINLOCK(cmd_lock); |
237 | ||
238 | #define MAX_CR_CMD_LOOPS 10000 | |
239 | ||
240 | int cpm_command(u32 command, u8 opcode) | |
241 | { | |
242 | int i, ret; | |
243 | unsigned long flags; | |
244 | ||
245 | if (command & 0xffffff0f) | |
246 | return -EINVAL; | |
247 | ||
248 | spin_lock_irqsave(&cmd_lock, flags); | |
249 | ||
250 | ret = 0; | |
251 | out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8)); | |
252 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | |
253 | if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) | |
254 | goto out; | |
255 | ||
e48b1b45 | 256 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__); |
362f9b6f JF |
257 | ret = -EIO; |
258 | out: | |
259 | spin_unlock_irqrestore(&cmd_lock, flags); | |
260 | return ret; | |
261 | } | |
262 | EXPORT_SYMBOL(cpm_command); | |
263 | ||
f2a0bd37 VB |
264 | /* Set a baud rate generator. This needs lots of work. There are |
265 | * four BRGs, any of which can be wired to any channel. | |
266 | * The internal baud rate clock is the system clock divided by 16. | |
267 | * This assumes the baudrate is 16x oversampled by the uart. | |
268 | */ | |
269 | #define BRG_INT_CLK (get_brgfreq()) | |
270 | #define BRG_UART_CLK (BRG_INT_CLK/16) | |
271 | #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) | |
272 | ||
273 | void | |
274 | cpm_setbrg(uint brg, uint rate) | |
275 | { | |
fb533d0c | 276 | u32 __iomem *bp; |
f2a0bd37 VB |
277 | |
278 | /* This is good enough to get SMCs running..... | |
279 | */ | |
fb533d0c | 280 | bp = &cpmp->cp_brgc1; |
f2a0bd37 VB |
281 | bp += brg; |
282 | /* The BRG has a 12-bit counter. For really slow baud rates (or | |
283 | * really fast processors), we may have to further divide by 16. | |
284 | */ | |
285 | if (((BRG_UART_CLK / rate) - 1) < 4096) | |
fb533d0c | 286 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); |
f2a0bd37 | 287 | else |
fb533d0c | 288 | out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | |
b5677d84 | 289 | CPM_BRG_EN | CPM_BRG_DIV16); |
f2a0bd37 VB |
290 | } |
291 | ||
663edbd2 | 292 | struct cpm_ioport16 { |
721c0c8a | 293 | __be16 dir, par, odr_sor, dat, intr; |
663edbd2 SW |
294 | __be16 res[3]; |
295 | }; | |
296 | ||
dc2380ec JF |
297 | struct cpm_ioport32b { |
298 | __be32 dir, par, odr, dat; | |
299 | }; | |
300 | ||
301 | struct cpm_ioport32e { | |
302 | __be32 dir, par, sor, odr, dat; | |
663edbd2 SW |
303 | }; |
304 | ||
305 | static void cpm1_set_pin32(int port, int pin, int flags) | |
306 | { | |
dc2380ec | 307 | struct cpm_ioport32e __iomem *iop; |
663edbd2 SW |
308 | pin = 1 << (31 - pin); |
309 | ||
310 | if (port == CPM_PORTB) | |
dc2380ec | 311 | iop = (struct cpm_ioport32e __iomem *) |
663edbd2 SW |
312 | &mpc8xx_immr->im_cpm.cp_pbdir; |
313 | else | |
dc2380ec | 314 | iop = (struct cpm_ioport32e __iomem *) |
663edbd2 SW |
315 | &mpc8xx_immr->im_cpm.cp_pedir; |
316 | ||
317 | if (flags & CPM_PIN_OUTPUT) | |
318 | setbits32(&iop->dir, pin); | |
319 | else | |
320 | clrbits32(&iop->dir, pin); | |
321 | ||
322 | if (!(flags & CPM_PIN_GPIO)) | |
323 | setbits32(&iop->par, pin); | |
324 | else | |
325 | clrbits32(&iop->par, pin); | |
326 | ||
721c0c8a JF |
327 | if (port == CPM_PORTB) { |
328 | if (flags & CPM_PIN_OPENDRAIN) | |
329 | setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | |
330 | else | |
331 | clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | |
332 | } | |
333 | ||
663edbd2 SW |
334 | if (port == CPM_PORTE) { |
335 | if (flags & CPM_PIN_SECONDARY) | |
336 | setbits32(&iop->sor, pin); | |
337 | else | |
338 | clrbits32(&iop->sor, pin); | |
339 | ||
340 | if (flags & CPM_PIN_OPENDRAIN) | |
341 | setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
342 | else | |
343 | clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); | |
344 | } | |
345 | } | |
346 | ||
347 | static void cpm1_set_pin16(int port, int pin, int flags) | |
348 | { | |
349 | struct cpm_ioport16 __iomem *iop = | |
350 | (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; | |
351 | ||
352 | pin = 1 << (15 - pin); | |
353 | ||
354 | if (port != 0) | |
355 | iop += port - 1; | |
356 | ||
357 | if (flags & CPM_PIN_OUTPUT) | |
358 | setbits16(&iop->dir, pin); | |
359 | else | |
360 | clrbits16(&iop->dir, pin); | |
361 | ||
362 | if (!(flags & CPM_PIN_GPIO)) | |
363 | setbits16(&iop->par, pin); | |
364 | else | |
365 | clrbits16(&iop->par, pin); | |
366 | ||
721c0c8a JF |
367 | if (port == CPM_PORTA) { |
368 | if (flags & CPM_PIN_OPENDRAIN) | |
369 | setbits16(&iop->odr_sor, pin); | |
370 | else | |
371 | clrbits16(&iop->odr_sor, pin); | |
372 | } | |
663edbd2 SW |
373 | if (port == CPM_PORTC) { |
374 | if (flags & CPM_PIN_SECONDARY) | |
721c0c8a | 375 | setbits16(&iop->odr_sor, pin); |
663edbd2 | 376 | else |
721c0c8a | 377 | clrbits16(&iop->odr_sor, pin); |
663edbd2 SW |
378 | } |
379 | } | |
380 | ||
381 | void cpm1_set_pin(enum cpm_port port, int pin, int flags) | |
382 | { | |
383 | if (port == CPM_PORTB || port == CPM_PORTE) | |
384 | cpm1_set_pin32(port, pin, flags); | |
385 | else | |
386 | cpm1_set_pin16(port, pin, flags); | |
387 | } | |
388 | ||
389 | int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |
390 | { | |
391 | int shift; | |
392 | int i, bits = 0; | |
393 | u32 __iomem *reg; | |
394 | u32 mask = 7; | |
395 | ||
396 | u8 clk_map[][3] = { | |
397 | {CPM_CLK_SCC1, CPM_BRG1, 0}, | |
398 | {CPM_CLK_SCC1, CPM_BRG2, 1}, | |
399 | {CPM_CLK_SCC1, CPM_BRG3, 2}, | |
400 | {CPM_CLK_SCC1, CPM_BRG4, 3}, | |
401 | {CPM_CLK_SCC1, CPM_CLK1, 4}, | |
402 | {CPM_CLK_SCC1, CPM_CLK2, 5}, | |
403 | {CPM_CLK_SCC1, CPM_CLK3, 6}, | |
404 | {CPM_CLK_SCC1, CPM_CLK4, 7}, | |
405 | ||
406 | {CPM_CLK_SCC2, CPM_BRG1, 0}, | |
407 | {CPM_CLK_SCC2, CPM_BRG2, 1}, | |
408 | {CPM_CLK_SCC2, CPM_BRG3, 2}, | |
409 | {CPM_CLK_SCC2, CPM_BRG4, 3}, | |
410 | {CPM_CLK_SCC2, CPM_CLK1, 4}, | |
411 | {CPM_CLK_SCC2, CPM_CLK2, 5}, | |
412 | {CPM_CLK_SCC2, CPM_CLK3, 6}, | |
413 | {CPM_CLK_SCC2, CPM_CLK4, 7}, | |
414 | ||
415 | {CPM_CLK_SCC3, CPM_BRG1, 0}, | |
416 | {CPM_CLK_SCC3, CPM_BRG2, 1}, | |
417 | {CPM_CLK_SCC3, CPM_BRG3, 2}, | |
418 | {CPM_CLK_SCC3, CPM_BRG4, 3}, | |
419 | {CPM_CLK_SCC3, CPM_CLK5, 4}, | |
420 | {CPM_CLK_SCC3, CPM_CLK6, 5}, | |
421 | {CPM_CLK_SCC3, CPM_CLK7, 6}, | |
422 | {CPM_CLK_SCC3, CPM_CLK8, 7}, | |
423 | ||
424 | {CPM_CLK_SCC4, CPM_BRG1, 0}, | |
425 | {CPM_CLK_SCC4, CPM_BRG2, 1}, | |
426 | {CPM_CLK_SCC4, CPM_BRG3, 2}, | |
427 | {CPM_CLK_SCC4, CPM_BRG4, 3}, | |
428 | {CPM_CLK_SCC4, CPM_CLK5, 4}, | |
429 | {CPM_CLK_SCC4, CPM_CLK6, 5}, | |
430 | {CPM_CLK_SCC4, CPM_CLK7, 6}, | |
431 | {CPM_CLK_SCC4, CPM_CLK8, 7}, | |
432 | ||
433 | {CPM_CLK_SMC1, CPM_BRG1, 0}, | |
434 | {CPM_CLK_SMC1, CPM_BRG2, 1}, | |
435 | {CPM_CLK_SMC1, CPM_BRG3, 2}, | |
436 | {CPM_CLK_SMC1, CPM_BRG4, 3}, | |
437 | {CPM_CLK_SMC1, CPM_CLK1, 4}, | |
438 | {CPM_CLK_SMC1, CPM_CLK2, 5}, | |
439 | {CPM_CLK_SMC1, CPM_CLK3, 6}, | |
440 | {CPM_CLK_SMC1, CPM_CLK4, 7}, | |
441 | ||
442 | {CPM_CLK_SMC2, CPM_BRG1, 0}, | |
443 | {CPM_CLK_SMC2, CPM_BRG2, 1}, | |
444 | {CPM_CLK_SMC2, CPM_BRG3, 2}, | |
445 | {CPM_CLK_SMC2, CPM_BRG4, 3}, | |
446 | {CPM_CLK_SMC2, CPM_CLK5, 4}, | |
447 | {CPM_CLK_SMC2, CPM_CLK6, 5}, | |
448 | {CPM_CLK_SMC2, CPM_CLK7, 6}, | |
449 | {CPM_CLK_SMC2, CPM_CLK8, 7}, | |
450 | }; | |
451 | ||
452 | switch (target) { | |
453 | case CPM_CLK_SCC1: | |
454 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
455 | shift = 0; | |
456 | break; | |
457 | ||
458 | case CPM_CLK_SCC2: | |
459 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
460 | shift = 8; | |
461 | break; | |
462 | ||
463 | case CPM_CLK_SCC3: | |
464 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
465 | shift = 16; | |
466 | break; | |
467 | ||
468 | case CPM_CLK_SCC4: | |
469 | reg = &mpc8xx_immr->im_cpm.cp_sicr; | |
470 | shift = 24; | |
471 | break; | |
472 | ||
473 | case CPM_CLK_SMC1: | |
474 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
475 | shift = 12; | |
476 | break; | |
477 | ||
478 | case CPM_CLK_SMC2: | |
479 | reg = &mpc8xx_immr->im_cpm.cp_simode; | |
480 | shift = 28; | |
481 | break; | |
482 | ||
483 | default: | |
484 | printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); | |
485 | return -EINVAL; | |
486 | } | |
487 | ||
488 | if (reg == &mpc8xx_immr->im_cpm.cp_sicr && mode == CPM_CLK_RX) | |
489 | shift += 3; | |
490 | ||
491 | for (i = 0; i < ARRAY_SIZE(clk_map); i++) { | |
492 | if (clk_map[i][0] == target && clk_map[i][1] == clock) { | |
493 | bits = clk_map[i][2]; | |
494 | break; | |
495 | } | |
496 | } | |
497 | ||
498 | if (i == ARRAY_SIZE(clk_map)) { | |
499 | printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); | |
500 | return -EINVAL; | |
501 | } | |
502 | ||
503 | bits <<= shift; | |
504 | mask <<= shift; | |
505 | out_be32(reg, (in_be32(reg) & ~mask) | bits); | |
506 | ||
507 | return 0; | |
508 | } | |
dc2380ec JF |
509 | |
510 | /* | |
511 | * GPIO LIB API implementation | |
512 | */ | |
513 | #ifdef CONFIG_8xx_GPIO | |
514 | ||
515 | struct cpm1_gpio16_chip { | |
516 | struct of_mm_gpio_chip mm_gc; | |
517 | spinlock_t lock; | |
518 | ||
519 | /* shadowed data register to clear/set bits safely */ | |
520 | u16 cpdata; | |
521 | }; | |
522 | ||
523 | static inline struct cpm1_gpio16_chip * | |
524 | to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc) | |
525 | { | |
526 | return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); | |
527 | } | |
528 | ||
529 | static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) | |
530 | { | |
531 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | |
532 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | |
533 | ||
534 | cpm1_gc->cpdata = in_be16(&iop->dat); | |
535 | } | |
536 | ||
537 | static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) | |
538 | { | |
539 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
540 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | |
541 | u16 pin_mask; | |
542 | ||
543 | pin_mask = 1 << (15 - gpio); | |
544 | ||
545 | return !!(in_be16(&iop->dat) & pin_mask); | |
546 | } | |
547 | ||
f1eaf16a JF |
548 | static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, |
549 | int value) | |
dc2380ec | 550 | { |
dc2380ec JF |
551 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); |
552 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | |
dc2380ec JF |
553 | |
554 | if (value) | |
555 | cpm1_gc->cpdata |= pin_mask; | |
556 | else | |
557 | cpm1_gc->cpdata &= ~pin_mask; | |
558 | ||
559 | out_be16(&iop->dat, cpm1_gc->cpdata); | |
f1eaf16a JF |
560 | } |
561 | ||
562 | static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) | |
563 | { | |
564 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
565 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | |
566 | unsigned long flags; | |
567 | u16 pin_mask = 1 << (15 - gpio); | |
568 | ||
569 | spin_lock_irqsave(&cpm1_gc->lock, flags); | |
570 | ||
571 | __cpm1_gpio16_set(mm_gc, pin_mask, value); | |
dc2380ec JF |
572 | |
573 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | |
574 | } | |
575 | ||
576 | static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |
577 | { | |
578 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
f1eaf16a | 579 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); |
dc2380ec | 580 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
581 | unsigned long flags; |
582 | u16 pin_mask = 1 << (15 - gpio); | |
dc2380ec | 583 | |
f1eaf16a | 584 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
585 | |
586 | setbits16(&iop->dir, pin_mask); | |
f1eaf16a | 587 | __cpm1_gpio16_set(mm_gc, pin_mask, val); |
dc2380ec | 588 | |
f1eaf16a | 589 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
dc2380ec JF |
590 | |
591 | return 0; | |
592 | } | |
593 | ||
594 | static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) | |
595 | { | |
596 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
f1eaf16a | 597 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); |
dc2380ec | 598 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
599 | unsigned long flags; |
600 | u16 pin_mask = 1 << (15 - gpio); | |
dc2380ec | 601 | |
f1eaf16a | 602 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
603 | |
604 | clrbits16(&iop->dir, pin_mask); | |
605 | ||
f1eaf16a JF |
606 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
607 | ||
dc2380ec JF |
608 | return 0; |
609 | } | |
610 | ||
611 | int cpm1_gpiochip_add16(struct device_node *np) | |
612 | { | |
613 | struct cpm1_gpio16_chip *cpm1_gc; | |
614 | struct of_mm_gpio_chip *mm_gc; | |
615 | struct of_gpio_chip *of_gc; | |
616 | struct gpio_chip *gc; | |
617 | ||
618 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | |
619 | if (!cpm1_gc) | |
620 | return -ENOMEM; | |
621 | ||
622 | spin_lock_init(&cpm1_gc->lock); | |
623 | ||
624 | mm_gc = &cpm1_gc->mm_gc; | |
625 | of_gc = &mm_gc->of_gc; | |
626 | gc = &of_gc->gc; | |
627 | ||
628 | mm_gc->save_regs = cpm1_gpio16_save_regs; | |
629 | of_gc->gpio_cells = 2; | |
630 | gc->ngpio = 16; | |
631 | gc->direction_input = cpm1_gpio16_dir_in; | |
632 | gc->direction_output = cpm1_gpio16_dir_out; | |
633 | gc->get = cpm1_gpio16_get; | |
634 | gc->set = cpm1_gpio16_set; | |
635 | ||
636 | return of_mm_gpiochip_add(np, mm_gc); | |
637 | } | |
638 | ||
639 | struct cpm1_gpio32_chip { | |
640 | struct of_mm_gpio_chip mm_gc; | |
641 | spinlock_t lock; | |
642 | ||
643 | /* shadowed data register to clear/set bits safely */ | |
644 | u32 cpdata; | |
645 | }; | |
646 | ||
647 | static inline struct cpm1_gpio32_chip * | |
648 | to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | |
649 | { | |
650 | return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); | |
651 | } | |
652 | ||
653 | static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | |
654 | { | |
655 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | |
656 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | |
657 | ||
658 | cpm1_gc->cpdata = in_be32(&iop->dat); | |
659 | } | |
660 | ||
661 | static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | |
662 | { | |
663 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
664 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | |
665 | u32 pin_mask; | |
666 | ||
667 | pin_mask = 1 << (31 - gpio); | |
668 | ||
669 | return !!(in_be32(&iop->dat) & pin_mask); | |
670 | } | |
671 | ||
f1eaf16a JF |
672 | static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, |
673 | int value) | |
dc2380ec | 674 | { |
dc2380ec JF |
675 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); |
676 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | |
dc2380ec JF |
677 | |
678 | if (value) | |
679 | cpm1_gc->cpdata |= pin_mask; | |
680 | else | |
681 | cpm1_gc->cpdata &= ~pin_mask; | |
682 | ||
683 | out_be32(&iop->dat, cpm1_gc->cpdata); | |
f1eaf16a JF |
684 | } |
685 | ||
686 | static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | |
687 | { | |
688 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
689 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | |
690 | unsigned long flags; | |
691 | u32 pin_mask = 1 << (31 - gpio); | |
692 | ||
693 | spin_lock_irqsave(&cpm1_gc->lock, flags); | |
694 | ||
695 | __cpm1_gpio32_set(mm_gc, pin_mask, value); | |
dc2380ec JF |
696 | |
697 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | |
698 | } | |
699 | ||
700 | static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |
701 | { | |
702 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
f1eaf16a | 703 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); |
dc2380ec | 704 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
705 | unsigned long flags; |
706 | u32 pin_mask = 1 << (31 - gpio); | |
dc2380ec | 707 | |
f1eaf16a | 708 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
709 | |
710 | setbits32(&iop->dir, pin_mask); | |
f1eaf16a | 711 | __cpm1_gpio32_set(mm_gc, pin_mask, val); |
dc2380ec | 712 | |
f1eaf16a | 713 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
dc2380ec JF |
714 | |
715 | return 0; | |
716 | } | |
717 | ||
718 | static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | |
719 | { | |
720 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | |
f1eaf16a | 721 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); |
dc2380ec | 722 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; |
f1eaf16a JF |
723 | unsigned long flags; |
724 | u32 pin_mask = 1 << (31 - gpio); | |
dc2380ec | 725 | |
f1eaf16a | 726 | spin_lock_irqsave(&cpm1_gc->lock, flags); |
dc2380ec JF |
727 | |
728 | clrbits32(&iop->dir, pin_mask); | |
729 | ||
f1eaf16a JF |
730 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); |
731 | ||
dc2380ec JF |
732 | return 0; |
733 | } | |
734 | ||
735 | int cpm1_gpiochip_add32(struct device_node *np) | |
736 | { | |
737 | struct cpm1_gpio32_chip *cpm1_gc; | |
738 | struct of_mm_gpio_chip *mm_gc; | |
739 | struct of_gpio_chip *of_gc; | |
740 | struct gpio_chip *gc; | |
741 | ||
742 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | |
743 | if (!cpm1_gc) | |
744 | return -ENOMEM; | |
745 | ||
746 | spin_lock_init(&cpm1_gc->lock); | |
747 | ||
748 | mm_gc = &cpm1_gc->mm_gc; | |
749 | of_gc = &mm_gc->of_gc; | |
750 | gc = &of_gc->gc; | |
751 | ||
752 | mm_gc->save_regs = cpm1_gpio32_save_regs; | |
753 | of_gc->gpio_cells = 2; | |
754 | gc->ngpio = 32; | |
755 | gc->direction_input = cpm1_gpio32_dir_in; | |
756 | gc->direction_output = cpm1_gpio32_dir_out; | |
757 | gc->get = cpm1_gpio32_get; | |
758 | gc->set = cpm1_gpio32_set; | |
759 | ||
760 | return of_mm_gpiochip_add(np, mm_gc); | |
761 | } | |
762 | ||
763 | static int cpm_init_par_io(void) | |
764 | { | |
765 | struct device_node *np; | |
766 | ||
767 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a") | |
768 | cpm1_gpiochip_add16(np); | |
769 | ||
770 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b") | |
771 | cpm1_gpiochip_add32(np); | |
772 | ||
773 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c") | |
774 | cpm1_gpiochip_add16(np); | |
775 | ||
776 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d") | |
777 | cpm1_gpiochip_add16(np); | |
778 | ||
779 | /* Port E uses CPM2 layout */ | |
780 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e") | |
781 | cpm2_gpiochip_add32(np); | |
782 | return 0; | |
783 | } | |
784 | arch_initcall(cpm_init_par_io); | |
785 | ||
786 | #endif /* CONFIG_8xx_GPIO */ |