Blame view

arch/powerpc/sysdev/cpm1.c 18.6 KB
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  /*
   * General Purpose functions for the global management of the
   * Communication Processor Module.
   * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
   *
   * In addition to the individual control of the communication
   * channels, there are a few functions that globally affect the
   * communication processor.
   *
   * Buffer descriptors must be allocated from the dual ported memory
   * space.  The allocator for that is here.  When the communication
   * process is reset, we reclaim the memory available.  There is
   * currently no deallocator for this memory.
   * The amount of space available is platform dependent.  On the
   * MBX, the EPPC software loads additional microcode into the
   * communication processor, and uses some of the DP ram for this
   * purpose.  Current, the first 512 bytes and the last 256 bytes of
   * memory are used.  Right now I am conservative and only use the
   * memory that can never be used for microcode.  If there are
   * applications that require more DP ram, we can expand the boundaries
   * but then we have to be careful of any downloaded microcode.
   */
  #include <linux/errno.h>
  #include <linux/sched.h>
  #include <linux/kernel.h>
  #include <linux/dma-mapping.h>
  #include <linux/param.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
  #include <linux/module.h>
dc2380ec8   Jochen Friedrich   powerpc: implemen...
33
  #include <linux/spinlock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
35
36
37
  #include <asm/page.h>
  #include <asm/pgtable.h>
  #include <asm/8xx_immap.h>
b5677d848   Jochen Friedrich   [POWERPC] CPM: Re...
38
  #include <asm/cpm1.h>
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
39
40
41
42
  #include <asm/io.h>
  #include <asm/tlbflush.h>
  #include <asm/rheap.h>
  #include <asm/prom.h>
15f8c604a   Scott Wood   [POWERPC] cpm: De...
43
  #include <asm/cpm.h>
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
44
45
  
  #include <asm/fs_pd.h>
dc2380ec8   Jochen Friedrich   powerpc: implemen...
46
47
48
  #ifdef CONFIG_8xx_GPIO
  #include <linux/of_gpio.h>
  #endif
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
49
  #define CPM_MAP_SIZE    (0x4000)
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
50
51
52
  cpm8xx_t __iomem *cpmp;  /* Pointer to comm processor space */
  immap_t __iomem *mpc8xx_immr;
  static cpic8xx_t __iomem *cpic_reg;
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
53

f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
54
  static struct irq_host *cpm_pic_host;
a2073d54a   Lennert Buytenhek   powerpc: sysdev/c...
55
  static void cpm_mask_irq(struct irq_data *d)
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
56
  {
476eb4912   Grant Likely   powerpc/irq: Stop...
57
  	unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
58
59
60
  
  	clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
  }
a2073d54a   Lennert Buytenhek   powerpc: sysdev/c...
61
  static void cpm_unmask_irq(struct irq_data *d)
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
62
  {
476eb4912   Grant Likely   powerpc/irq: Stop...
63
  	unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
64
65
66
  
  	setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
  }
a2073d54a   Lennert Buytenhek   powerpc: sysdev/c...
67
  static void cpm_end_irq(struct irq_data *d)
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
68
  {
476eb4912   Grant Likely   powerpc/irq: Stop...
69
  	unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
70
71
72
73
74
  
  	out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
  }
  
  static struct irq_chip cpm_pic = {
fc380c0c8   Anton Blanchard   powerpc: Remove w...
75
  	.name = "CPM PIC",
a2073d54a   Lennert Buytenhek   powerpc: sysdev/c...
76
77
78
  	.irq_mask = cpm_mask_irq,
  	.irq_unmask = cpm_unmask_irq,
  	.irq_eoi = cpm_end_irq,
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  };
  
  int cpm_get_irq(void)
  {
  	int cpm_vec;
  
  	/* Get the vector by setting the ACK bit and then reading
  	 * the register.
  	 */
  	out_be16(&cpic_reg->cpic_civr, 1);
  	cpm_vec = in_be16(&cpic_reg->cpic_civr);
  	cpm_vec >>= 11;
  
  	return irq_linear_revmap(cpm_pic_host, cpm_vec);
  }
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
94
95
96
97
98
  static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
  			  irq_hw_number_t hw)
  {
  	pr_debug("cpm_pic_host_map(%d, 0x%lx)
  ", virq, hw);
98488db9f   Thomas Gleixner   powerpc: Use prop...
99
  	irq_set_status_flags(virq, IRQ_LEVEL);
ec775d0e7   Thomas Gleixner   powerpc: Convert ...
100
  	irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
101
102
103
104
105
106
107
108
  	return 0;
  }
  
  /* The CPM can generate the error interrupt when there is a race condition
   * between generating and masking interrupts.  All we have to do is ACK it
   * and return.  This is a no-op function so we don't need any special
   * tests in the interrupt handler.
   */
4b218e9bb   Scott Wood   [POWERPC] Whitesp...
109
  static irqreturn_t cpm_error_interrupt(int irq, void *dev)
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
110
111
112
113
114
115
  {
  	return IRQ_HANDLED;
  }
  
  static struct irqaction cpm_error_irqaction = {
  	.handler = cpm_error_interrupt,
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
116
117
118
119
  	.name = "error",
  };
  
  static struct irq_host_ops cpm_pic_host_ops = {
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
120
121
122
123
124
125
126
127
128
129
130
131
  	.map = cpm_pic_host_map,
  };
  
  unsigned int cpm_pic_init(void)
  {
  	struct device_node *np = NULL;
  	struct resource res;
  	unsigned int sirq = NO_IRQ, hwirq, eirq;
  	int ret;
  
  	pr_debug("cpm_pic_init
  ");
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
132
133
134
  	np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic");
  	if (np == NULL)
  		np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
135
136
137
138
139
  	if (np == NULL) {
  		printk(KERN_ERR "CPM PIC init: can not find cpm-pic node
  ");
  		return sirq;
  	}
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
140

f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
141
142
143
  	ret = of_address_to_resource(np, 0, &res);
  	if (ret)
  		goto end;
28f65c11f   Joe Perches   treewide: Convert...
144
  	cpic_reg = ioremap(res.start, resource_size(&res));
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
145
146
147
148
149
150
151
152
  	if (cpic_reg == NULL)
  		goto end;
  
  	sirq = irq_of_parse_and_map(np, 0);
  	if (sirq == NO_IRQ)
  		goto end;
  
  	/* Initialize the CPM interrupt controller. */
476eb4912   Grant Likely   powerpc/irq: Stop...
153
  	hwirq = (unsigned int)virq_to_hw(sirq);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
154
155
156
157
158
  	out_be32(&cpic_reg->cpic_cicr,
  	    (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
  		((hwirq/2) << 13) | CICR_HP_MASK);
  
  	out_be32(&cpic_reg->cpic_cimr, 0);
19fc65b52   Michael Ellerman   powerpc: Fix irq_...
159
  	cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
52964f87c   Michael Ellerman   [POWERPC] Add an ...
160
  				      64, &cpm_pic_host_ops, 64);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
161
162
163
164
165
166
  	if (cpm_pic_host == NULL) {
  		printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!
  ");
  		sirq = NO_IRQ;
  		goto end;
  	}
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
167
168
  
  	/* Install our own error handler. */
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
169
170
171
  	np = of_find_compatible_node(NULL, NULL, "fsl,cpm1");
  	if (np == NULL)
  		np = of_find_node_by_type(NULL, "cpm");
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
172
173
174
175
176
  	if (np == NULL) {
  		printk(KERN_ERR "CPM PIC init: can not find cpm node
  ");
  		goto end;
  	}
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
177

4b218e9bb   Scott Wood   [POWERPC] Whitesp...
178
  	eirq = irq_of_parse_and_map(np, 0);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
179
180
181
182
183
184
185
186
187
188
189
190
  	if (eirq == NO_IRQ)
  		goto end;
  
  	if (setup_irq(eirq, &cpm_error_irqaction))
  		printk(KERN_ERR "Could not allocate CPM error IRQ!");
  
  	setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
  
  end:
  	of_node_put(np);
  	return sirq;
  }
15f8c604a   Scott Wood   [POWERPC] cpm: De...
191
  void __init cpm_reset(void)
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
192
  {
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
193
  	sysconf8xx_t __iomem *siu_conf;
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
194

fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
195
196
197
198
199
200
  	mpc8xx_immr = ioremap(get_immrbase(), 0x4000);
  	if (!mpc8xx_immr) {
  		printk(KERN_CRIT "Could not map IMMR
  ");
  		return;
  	}
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
201

fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
202
203
204
  	cpmp = &mpc8xx_immr->im_cpm;
  
  #ifndef CONFIG_PPC_EARLY_DEBUG_CPM
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
205
206
  	/* Perform a reset.
  	*/
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
207
  	out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
208
209
210
  
  	/* Wait for it.
  	*/
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
211
212
  	while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG);
  #endif
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
213

fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
214
215
  #ifdef CONFIG_UCODE_PATCH
  	cpm_load_patch(cpmp);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
216
217
218
219
  #endif
  
  	/* Set SDMA Bus Request priority 5.
  	 * On 860T, this also enables FEC priority 6.  I am not sure
25985edce   Lucas De Marchi   Fix common misspe...
220
  	 * this is what we really want for some applications, but the
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
221
222
223
  	 * manual recommends it.
  	 * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
  	 */
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
224
  	siu_conf = immr_map(im_siu_conf);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
225
226
  	out_be32(&siu_conf->sc_sdcr, 1);
  	immr_unmap(siu_conf);
15f8c604a   Scott Wood   [POWERPC] cpm: De...
227
  	cpm_muram_init();
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
228
  }
362f9b6fa   Jochen Friedrich   [POWERPC] Move CP...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  static DEFINE_SPINLOCK(cmd_lock);
  
  #define MAX_CR_CMD_LOOPS        10000
  
  int cpm_command(u32 command, u8 opcode)
  {
  	int i, ret;
  	unsigned long flags;
  
  	if (command & 0xffffff0f)
  		return -EINVAL;
  
  	spin_lock_irqsave(&cmd_lock, flags);
  
  	ret = 0;
  	out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8));
  	for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
  		if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
  			goto out;
e48b1b452   Harvey Harrison   [POWERPC] Replace...
248
249
  	printk(KERN_ERR "%s(): Not able to issue CPM command
  ", __func__);
362f9b6fa   Jochen Friedrich   [POWERPC] Move CP...
250
251
252
253
254
255
  	ret = -EIO;
  out:
  	spin_unlock_irqrestore(&cmd_lock, flags);
  	return ret;
  }
  EXPORT_SYMBOL(cpm_command);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
256
257
258
259
260
261
262
263
264
265
266
267
  /* Set a baud rate generator.  This needs lots of work.  There are
   * four BRGs, any of which can be wired to any channel.
   * The internal baud rate clock is the system clock divided by 16.
   * This assumes the baudrate is 16x oversampled by the uart.
   */
  #define BRG_INT_CLK		(get_brgfreq())
  #define BRG_UART_CLK		(BRG_INT_CLK/16)
  #define BRG_UART_CLK_DIV16	(BRG_UART_CLK/16)
  
  void
  cpm_setbrg(uint brg, uint rate)
  {
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
268
  	u32 __iomem *bp;
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
269
270
271
  
  	/* This is good enough to get SMCs running.....
  	*/
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
272
  	bp = &cpmp->cp_brgc1;
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
273
274
275
276
277
  	bp += brg;
  	/* The BRG has a 12-bit counter.  For really slow baud rates (or
  	 * really fast processors), we may have to further divide by 16.
  	 */
  	if (((BRG_UART_CLK / rate) - 1) < 4096)
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
278
  		out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
279
  	else
fb533d0c5   Scott Wood   [POWERPC] 8xx: In...
280
  		out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
b5677d848   Jochen Friedrich   [POWERPC] CPM: Re...
281
  			      CPM_BRG_EN | CPM_BRG_DIV16);
f2a0bd375   Vitaly Bordug   [POWERPC] 8xx: po...
282
  }
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
283
  struct cpm_ioport16 {
721c0c8af   Jochen Friedrich   [POWERPC] Add sup...
284
  	__be16 dir, par, odr_sor, dat, intr;
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
285
286
  	__be16 res[3];
  };
dc2380ec8   Jochen Friedrich   powerpc: implemen...
287
288
289
290
291
292
  struct cpm_ioport32b {
  	__be32 dir, par, odr, dat;
  };
  
  struct cpm_ioport32e {
  	__be32 dir, par, sor, odr, dat;
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
293
294
295
296
  };
  
  static void cpm1_set_pin32(int port, int pin, int flags)
  {
dc2380ec8   Jochen Friedrich   powerpc: implemen...
297
  	struct cpm_ioport32e __iomem *iop;
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
298
299
300
  	pin = 1 << (31 - pin);
  
  	if (port == CPM_PORTB)
dc2380ec8   Jochen Friedrich   powerpc: implemen...
301
  		iop = (struct cpm_ioport32e __iomem *)
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
302
303
  		      &mpc8xx_immr->im_cpm.cp_pbdir;
  	else
dc2380ec8   Jochen Friedrich   powerpc: implemen...
304
  		iop = (struct cpm_ioport32e __iomem *)
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
305
306
307
308
309
310
311
312
313
314
315
  		      &mpc8xx_immr->im_cpm.cp_pedir;
  
  	if (flags & CPM_PIN_OUTPUT)
  		setbits32(&iop->dir, pin);
  	else
  		clrbits32(&iop->dir, pin);
  
  	if (!(flags & CPM_PIN_GPIO))
  		setbits32(&iop->par, pin);
  	else
  		clrbits32(&iop->par, pin);
721c0c8af   Jochen Friedrich   [POWERPC] Add sup...
316
317
318
319
320
321
  	if (port == CPM_PORTB) {
  		if (flags & CPM_PIN_OPENDRAIN)
  			setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
  		else
  			clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
  	}
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  	if (port == CPM_PORTE) {
  		if (flags & CPM_PIN_SECONDARY)
  			setbits32(&iop->sor, pin);
  		else
  			clrbits32(&iop->sor, pin);
  
  		if (flags & CPM_PIN_OPENDRAIN)
  			setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
  		else
  			clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
  	}
  }
  
  static void cpm1_set_pin16(int port, int pin, int flags)
  {
  	struct cpm_ioport16 __iomem *iop =
  		(struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport;
  
  	pin = 1 << (15 - pin);
  
  	if (port != 0)
  		iop += port - 1;
  
  	if (flags & CPM_PIN_OUTPUT)
  		setbits16(&iop->dir, pin);
  	else
  		clrbits16(&iop->dir, pin);
  
  	if (!(flags & CPM_PIN_GPIO))
  		setbits16(&iop->par, pin);
  	else
  		clrbits16(&iop->par, pin);
721c0c8af   Jochen Friedrich   [POWERPC] Add sup...
354
355
356
357
358
359
  	if (port == CPM_PORTA) {
  		if (flags & CPM_PIN_OPENDRAIN)
  			setbits16(&iop->odr_sor, pin);
  		else
  			clrbits16(&iop->odr_sor, pin);
  	}
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
360
361
  	if (port == CPM_PORTC) {
  		if (flags & CPM_PIN_SECONDARY)
721c0c8af   Jochen Friedrich   [POWERPC] Add sup...
362
  			setbits16(&iop->odr_sor, pin);
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
363
  		else
721c0c8af   Jochen Friedrich   [POWERPC] Add sup...
364
  			clrbits16(&iop->odr_sor, pin);
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	}
  }
  
  void cpm1_set_pin(enum cpm_port port, int pin, int flags)
  {
  	if (port == CPM_PORTB || port == CPM_PORTE)
  		cpm1_set_pin32(port, pin, flags);
  	else
  		cpm1_set_pin16(port, pin, flags);
  }
  
  int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
  {
  	int shift;
  	int i, bits = 0;
  	u32 __iomem *reg;
  	u32 mask = 7;
  
  	u8 clk_map[][3] = {
  		{CPM_CLK_SCC1, CPM_BRG1, 0},
  		{CPM_CLK_SCC1, CPM_BRG2, 1},
  		{CPM_CLK_SCC1, CPM_BRG3, 2},
  		{CPM_CLK_SCC1, CPM_BRG4, 3},
  		{CPM_CLK_SCC1, CPM_CLK1, 4},
  		{CPM_CLK_SCC1, CPM_CLK2, 5},
  		{CPM_CLK_SCC1, CPM_CLK3, 6},
  		{CPM_CLK_SCC1, CPM_CLK4, 7},
  
  		{CPM_CLK_SCC2, CPM_BRG1, 0},
  		{CPM_CLK_SCC2, CPM_BRG2, 1},
  		{CPM_CLK_SCC2, CPM_BRG3, 2},
  		{CPM_CLK_SCC2, CPM_BRG4, 3},
  		{CPM_CLK_SCC2, CPM_CLK1, 4},
  		{CPM_CLK_SCC2, CPM_CLK2, 5},
  		{CPM_CLK_SCC2, CPM_CLK3, 6},
  		{CPM_CLK_SCC2, CPM_CLK4, 7},
  
  		{CPM_CLK_SCC3, CPM_BRG1, 0},
  		{CPM_CLK_SCC3, CPM_BRG2, 1},
  		{CPM_CLK_SCC3, CPM_BRG3, 2},
  		{CPM_CLK_SCC3, CPM_BRG4, 3},
  		{CPM_CLK_SCC3, CPM_CLK5, 4},
  		{CPM_CLK_SCC3, CPM_CLK6, 5},
  		{CPM_CLK_SCC3, CPM_CLK7, 6},
  		{CPM_CLK_SCC3, CPM_CLK8, 7},
  
  		{CPM_CLK_SCC4, CPM_BRG1, 0},
  		{CPM_CLK_SCC4, CPM_BRG2, 1},
  		{CPM_CLK_SCC4, CPM_BRG3, 2},
  		{CPM_CLK_SCC4, CPM_BRG4, 3},
  		{CPM_CLK_SCC4, CPM_CLK5, 4},
  		{CPM_CLK_SCC4, CPM_CLK6, 5},
  		{CPM_CLK_SCC4, CPM_CLK7, 6},
  		{CPM_CLK_SCC4, CPM_CLK8, 7},
  
  		{CPM_CLK_SMC1, CPM_BRG1, 0},
  		{CPM_CLK_SMC1, CPM_BRG2, 1},
  		{CPM_CLK_SMC1, CPM_BRG3, 2},
  		{CPM_CLK_SMC1, CPM_BRG4, 3},
  		{CPM_CLK_SMC1, CPM_CLK1, 4},
  		{CPM_CLK_SMC1, CPM_CLK2, 5},
  		{CPM_CLK_SMC1, CPM_CLK3, 6},
  		{CPM_CLK_SMC1, CPM_CLK4, 7},
  
  		{CPM_CLK_SMC2, CPM_BRG1, 0},
  		{CPM_CLK_SMC2, CPM_BRG2, 1},
  		{CPM_CLK_SMC2, CPM_BRG3, 2},
  		{CPM_CLK_SMC2, CPM_BRG4, 3},
  		{CPM_CLK_SMC2, CPM_CLK5, 4},
  		{CPM_CLK_SMC2, CPM_CLK6, 5},
  		{CPM_CLK_SMC2, CPM_CLK7, 6},
  		{CPM_CLK_SMC2, CPM_CLK8, 7},
  	};
  
  	switch (target) {
  	case CPM_CLK_SCC1:
  		reg = &mpc8xx_immr->im_cpm.cp_sicr;
  		shift = 0;
  		break;
  
  	case CPM_CLK_SCC2:
  		reg = &mpc8xx_immr->im_cpm.cp_sicr;
  		shift = 8;
  		break;
  
  	case CPM_CLK_SCC3:
  		reg = &mpc8xx_immr->im_cpm.cp_sicr;
  		shift = 16;
  		break;
  
  	case CPM_CLK_SCC4:
  		reg = &mpc8xx_immr->im_cpm.cp_sicr;
  		shift = 24;
  		break;
  
  	case CPM_CLK_SMC1:
  		reg = &mpc8xx_immr->im_cpm.cp_simode;
  		shift = 12;
  		break;
  
  	case CPM_CLK_SMC2:
  		reg = &mpc8xx_immr->im_cpm.cp_simode;
  		shift = 28;
  		break;
  
  	default:
  		printk(KERN_ERR "cpm1_clock_setup: invalid clock target
  ");
  		return -EINVAL;
  	}
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  	for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
  		if (clk_map[i][0] == target && clk_map[i][1] == clock) {
  			bits = clk_map[i][2];
  			break;
  		}
  	}
  
  	if (i == ARRAY_SIZE(clk_map)) {
  		printk(KERN_ERR "cpm1_clock_setup: invalid clock combination
  ");
  		return -EINVAL;
  	}
  
  	bits <<= shift;
  	mask <<= shift;
1cca2d2b9   Wolfgang Ocker   powerpc/fsl-cpm: ...
490
491
492
493
494
495
496
497
498
499
  
  	if (reg == &mpc8xx_immr->im_cpm.cp_sicr) {
  		if (mode == CPM_CLK_RTX) {
  			bits |= bits << 3;
  			mask |= mask << 3;
  		} else if (mode == CPM_CLK_RX) {
  			bits <<= 3;
  			mask <<= 3;
  		}
  	}
663edbd26   Scott Wood   [POWERPC] 8xx: Ad...
500
501
502
503
  	out_be32(reg, (in_be32(reg) & ~mask) | bits);
  
  	return 0;
  }
dc2380ec8   Jochen Friedrich   powerpc: implemen...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  
  /*
   * GPIO LIB API implementation
   */
  #ifdef CONFIG_8xx_GPIO
  
  struct cpm1_gpio16_chip {
  	struct of_mm_gpio_chip mm_gc;
  	spinlock_t lock;
  
  	/* shadowed data register to clear/set bits safely */
  	u16 cpdata;
  };
  
  static inline struct cpm1_gpio16_chip *
  to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
  {
  	return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
  }
  
  static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
  {
  	struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
  	struct cpm_ioport16 __iomem *iop = mm_gc->regs;
  
  	cpm1_gc->cpdata = in_be16(&iop->dat);
  }
  
  static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  	struct cpm_ioport16 __iomem *iop = mm_gc->regs;
  	u16 pin_mask;
  
  	pin_mask = 1 << (15 - gpio);
  
  	return !!(in_be16(&iop->dat) & pin_mask);
  }
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
542
543
  static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
  	int value)
dc2380ec8   Jochen Friedrich   powerpc: implemen...
544
  {
dc2380ec8   Jochen Friedrich   powerpc: implemen...
545
546
  	struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
  	struct cpm_ioport16 __iomem *iop = mm_gc->regs;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
547
548
549
550
551
552
553
  
  	if (value)
  		cpm1_gc->cpdata |= pin_mask;
  	else
  		cpm1_gc->cpdata &= ~pin_mask;
  
  	out_be16(&iop->dat, cpm1_gc->cpdata);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
554
555
556
557
558
559
560
561
562
563
564
565
  }
  
  static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  	struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
  	unsigned long flags;
  	u16 pin_mask = 1 << (15 - gpio);
  
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
  
  	__cpm1_gpio16_set(mm_gc, pin_mask, value);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
566
567
568
569
570
571
572
  
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
  }
  
  static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
573
  	struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
574
  	struct cpm_ioport16 __iomem *iop = mm_gc->regs;
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
575
576
  	unsigned long flags;
  	u16 pin_mask = 1 << (15 - gpio);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
577

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
578
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
579
580
  
  	setbits16(&iop->dir, pin_mask);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
581
  	__cpm1_gpio16_set(mm_gc, pin_mask, val);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
582

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
583
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
584
585
586
587
588
589
590
  
  	return 0;
  }
  
  static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
591
  	struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
592
  	struct cpm_ioport16 __iomem *iop = mm_gc->regs;
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
593
594
  	unsigned long flags;
  	u16 pin_mask = 1 << (15 - gpio);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
595

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
596
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
597
598
  
  	clrbits16(&iop->dir, pin_mask);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
599
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
600
601
602
603
604
605
606
  	return 0;
  }
  
  int cpm1_gpiochip_add16(struct device_node *np)
  {
  	struct cpm1_gpio16_chip *cpm1_gc;
  	struct of_mm_gpio_chip *mm_gc;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
607
608
609
610
611
612
613
614
615
  	struct gpio_chip *gc;
  
  	cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
  	if (!cpm1_gc)
  		return -ENOMEM;
  
  	spin_lock_init(&cpm1_gc->lock);
  
  	mm_gc = &cpm1_gc->mm_gc;
a19e3da5b   Anton Vorontsov   of/gpio: Kill of_...
616
  	gc = &mm_gc->gc;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
617
618
  
  	mm_gc->save_regs = cpm1_gpio16_save_regs;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  	gc->ngpio = 16;
  	gc->direction_input = cpm1_gpio16_dir_in;
  	gc->direction_output = cpm1_gpio16_dir_out;
  	gc->get = cpm1_gpio16_get;
  	gc->set = cpm1_gpio16_set;
  
  	return of_mm_gpiochip_add(np, mm_gc);
  }
  
  struct cpm1_gpio32_chip {
  	struct of_mm_gpio_chip mm_gc;
  	spinlock_t lock;
  
  	/* shadowed data register to clear/set bits safely */
  	u32 cpdata;
  };
  
  static inline struct cpm1_gpio32_chip *
  to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
  {
  	return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
  }
  
  static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
  {
  	struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
  	struct cpm_ioport32b __iomem *iop = mm_gc->regs;
  
  	cpm1_gc->cpdata = in_be32(&iop->dat);
  }
  
  static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  	struct cpm_ioport32b __iomem *iop = mm_gc->regs;
  	u32 pin_mask;
  
  	pin_mask = 1 << (31 - gpio);
  
  	return !!(in_be32(&iop->dat) & pin_mask);
  }
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
660
661
  static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
  	int value)
dc2380ec8   Jochen Friedrich   powerpc: implemen...
662
  {
dc2380ec8   Jochen Friedrich   powerpc: implemen...
663
664
  	struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
  	struct cpm_ioport32b __iomem *iop = mm_gc->regs;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
665
666
667
668
669
670
671
  
  	if (value)
  		cpm1_gc->cpdata |= pin_mask;
  	else
  		cpm1_gc->cpdata &= ~pin_mask;
  
  	out_be32(&iop->dat, cpm1_gc->cpdata);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
672
673
674
675
676
677
678
679
680
681
682
683
  }
  
  static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
  	struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
  	unsigned long flags;
  	u32 pin_mask = 1 << (31 - gpio);
  
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
  
  	__cpm1_gpio32_set(mm_gc, pin_mask, value);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
684
685
686
687
688
689
690
  
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
  }
  
  static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
691
  	struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
692
  	struct cpm_ioport32b __iomem *iop = mm_gc->regs;
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
693
694
  	unsigned long flags;
  	u32 pin_mask = 1 << (31 - gpio);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
695

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
696
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
697
698
  
  	setbits32(&iop->dir, pin_mask);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
699
  	__cpm1_gpio32_set(mm_gc, pin_mask, val);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
700

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
701
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
702
703
704
705
706
707
708
  
  	return 0;
  }
  
  static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
  {
  	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
709
  	struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
710
  	struct cpm_ioport32b __iomem *iop = mm_gc->regs;
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
711
712
  	unsigned long flags;
  	u32 pin_mask = 1 << (31 - gpio);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
713

f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
714
  	spin_lock_irqsave(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
715
716
  
  	clrbits32(&iop->dir, pin_mask);
f1eaf16a9   Jochen Friedrich   powerpc/cpm1: Fix...
717
  	spin_unlock_irqrestore(&cpm1_gc->lock, flags);
dc2380ec8   Jochen Friedrich   powerpc: implemen...
718
719
720
721
722
723
724
  	return 0;
  }
  
  int cpm1_gpiochip_add32(struct device_node *np)
  {
  	struct cpm1_gpio32_chip *cpm1_gc;
  	struct of_mm_gpio_chip *mm_gc;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
725
726
727
728
729
730
731
732
733
  	struct gpio_chip *gc;
  
  	cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
  	if (!cpm1_gc)
  		return -ENOMEM;
  
  	spin_lock_init(&cpm1_gc->lock);
  
  	mm_gc = &cpm1_gc->mm_gc;
a19e3da5b   Anton Vorontsov   of/gpio: Kill of_...
734
  	gc = &mm_gc->gc;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
735
736
  
  	mm_gc->save_regs = cpm1_gpio32_save_regs;
dc2380ec8   Jochen Friedrich   powerpc: implemen...
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  	gc->ngpio = 32;
  	gc->direction_input = cpm1_gpio32_dir_in;
  	gc->direction_output = cpm1_gpio32_dir_out;
  	gc->get = cpm1_gpio32_get;
  	gc->set = cpm1_gpio32_set;
  
  	return of_mm_gpiochip_add(np, mm_gc);
  }
  
  static int cpm_init_par_io(void)
  {
  	struct device_node *np;
  
  	for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a")
  		cpm1_gpiochip_add16(np);
  
  	for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b")
  		cpm1_gpiochip_add32(np);
  
  	for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c")
  		cpm1_gpiochip_add16(np);
  
  	for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d")
  		cpm1_gpiochip_add16(np);
  
  	/* Port E uses CPM2 layout */
  	for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e")
  		cpm2_gpiochip_add32(np);
  	return 0;
  }
  arch_initcall(cpm_init_par_io);
  
  #endif /* CONFIG_8xx_GPIO */