blob: 591f2f801134b495f1dfbf9f49a4868e20319c7b [file] [log] [blame]
Greg Ungerer3196cf82006-06-26 10:33:10 +10001/***************************************************************************/
2
3/*
4 * linux/arch/m68knommu/platform/532x/config.c
5 *
6 * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
7 * Copyright (C) 2000, Lineo (www.lineo.com)
8 * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
9 * Copyright Freescale Semiconductor, Inc 2006
10 * Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18/***************************************************************************/
19
Greg Ungerer3196cf82006-06-26 10:33:10 +100020#include <linux/kernel.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100021#include <linux/param.h>
22#include <linux/init.h>
23#include <linux/interrupt.h>
Greg Ungererb2e18102008-02-01 17:34:58 +100024#include <linux/io.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100025#include <asm/machdep.h>
26#include <asm/coldfire.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100027#include <asm/mcfsim.h>
Greg Ungererb2e18102008-02-01 17:34:58 +100028#include <asm/mcfuart.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100029#include <asm/mcfdma.h>
30#include <asm/mcfwdebug.h>
31
32/***************************************************************************/
33
Greg Ungerer3196cf82006-06-26 10:33:10 +100034void coldfire_reset(void);
35
36extern unsigned int mcf_timervector;
37extern unsigned int mcf_profilevector;
38extern unsigned int mcf_timerlevel;
39
40/***************************************************************************/
41
Greg Ungererb2e18102008-02-01 17:34:58 +100042static struct mcf_platform_uart m532x_uart_platform[] = {
43 {
Matt Waddeladd82402008-12-20 07:16:38 -070044 .mapbase = MCFUART_BASE1,
Greg Ungererb2e18102008-02-01 17:34:58 +100045 .irq = MCFINT_VECBASE + MCFINT_UART0,
46 },
47 {
Matt Waddeladd82402008-12-20 07:16:38 -070048 .mapbase = MCFUART_BASE2,
Greg Ungererb2e18102008-02-01 17:34:58 +100049 .irq = MCFINT_VECBASE + MCFINT_UART1,
50 },
51 {
Matt Waddeladd82402008-12-20 07:16:38 -070052 .mapbase = MCFUART_BASE3,
Greg Ungererb2e18102008-02-01 17:34:58 +100053 .irq = MCFINT_VECBASE + MCFINT_UART2,
54 },
55 { },
56};
57
58static struct platform_device m532x_uart = {
59 .name = "mcfuart",
60 .id = 0,
61 .dev.platform_data = m532x_uart_platform,
62};
63
Greg Ungererffba3f42009-02-26 22:40:38 -080064static struct resource m532x_fec_resources[] = {
65 {
66 .start = 0xfc030000,
67 .end = 0xfc0307ff,
68 .flags = IORESOURCE_MEM,
69 },
70 {
71 .start = 64 + 36,
72 .end = 64 + 36,
73 .flags = IORESOURCE_IRQ,
74 },
75 {
76 .start = 64 + 40,
77 .end = 64 + 40,
78 .flags = IORESOURCE_IRQ,
79 },
80 {
81 .start = 64 + 42,
82 .end = 64 + 42,
83 .flags = IORESOURCE_IRQ,
84 },
85};
86
87static struct platform_device m532x_fec = {
88 .name = "fec",
89 .id = 0,
90 .num_resources = ARRAY_SIZE(m532x_fec_resources),
91 .resource = m532x_fec_resources,
92};
Greg Ungererb2e18102008-02-01 17:34:58 +100093static struct platform_device *m532x_devices[] __initdata = {
94 &m532x_uart,
Greg Ungererffba3f42009-02-26 22:40:38 -080095 &m532x_fec,
Greg Ungererb2e18102008-02-01 17:34:58 +100096};
97
98/***************************************************************************/
99
100static void __init m532x_uart_init_line(int line, int irq)
101{
102 if (line == 0) {
103 MCF_INTC0_ICR26 = 0x3;
104 MCF_INTC0_CIMR = 26;
105 /* GPIO initialization */
106 MCF_GPIO_PAR_UART |= 0x000F;
107 } else if (line == 1) {
108 MCF_INTC0_ICR27 = 0x3;
109 MCF_INTC0_CIMR = 27;
110 /* GPIO initialization */
111 MCF_GPIO_PAR_UART |= 0x0FF0;
112 } else if (line == 2) {
113 MCF_INTC0_ICR28 = 0x3;
114 MCF_INTC0_CIMR = 28;
115 }
116}
117
118static void __init m532x_uarts_init(void)
119{
120 const int nrlines = ARRAY_SIZE(m532x_uart_platform);
121 int line;
122
123 for (line = 0; (line < nrlines); line++)
124 m532x_uart_init_line(line, m532x_uart_platform[line].irq);
125}
Greg Ungererffba3f42009-02-26 22:40:38 -0800126/***************************************************************************/
127
128static void __init m532x_fec_init(void)
129{
130 /* Unmask FEC interrupts at ColdFire interrupt controller */
131 MCF_INTC0_ICR36 = 0x2;
132 MCF_INTC0_ICR40 = 0x2;
133 MCF_INTC0_ICR42 = 0x2;
134
135 MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK36 |
136 MCF_INTC_IMRH_INT_MASK40 | MCF_INTC_IMRH_INT_MASK42);
137
138 /* Set multi-function pins to ethernet mode for fec0 */
139 MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
140 MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
141 MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
142 MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
143}
Greg Ungerer3196cf82006-06-26 10:33:10 +1000144
145/***************************************************************************/
146
147void mcf_settimericr(unsigned int timer, unsigned int level)
148{
149 volatile unsigned char *icrp;
150 unsigned int icr;
151 unsigned char irq;
152
153 if (timer <= 2) {
154 switch (timer) {
155 case 2: irq = 33; icr = MCFSIM_ICR_TIMER2; break;
156 default: irq = 32; icr = MCFSIM_ICR_TIMER1; break;
157 }
158
Matt Waddeladd82402008-12-20 07:16:38 -0700159 icrp = (volatile unsigned char *) (icr);
Greg Ungerer3196cf82006-06-26 10:33:10 +1000160 *icrp = level;
161 mcf_enable_irq0(irq);
162 }
163}
164
165/***************************************************************************/
166
Greg Ungererb2e18102008-02-01 17:34:58 +1000167void __init config_BSP(char *commandp, int size)
Greg Ungerer3196cf82006-06-26 10:33:10 +1000168{
169 mcf_setimr(MCFSIM_IMR_MASKALL);
170
Greg Ungererbc724502007-07-25 22:07:20 +1000171#if !defined(CONFIG_BOOTPARAM)
Greg Ungerer3196cf82006-06-26 10:33:10 +1000172 /* Copy command line from FLASH to local buffer... */
173 memcpy(commandp, (char *) 0x4000, 4);
174 if(strncmp(commandp, "kcl ", 4) == 0){
175 memcpy(commandp, (char *) 0x4004, size);
176 commandp[size-1] = 0;
177 } else {
178 memset(commandp, 0, size);
179 }
180#endif
181
182 mcf_timervector = 64+32;
183 mcf_profilevector = 64+33;
Greg Ungerer3196cf82006-06-26 10:33:10 +1000184 mach_reset = coldfire_reset;
185
Greg Ungererb2e18102008-02-01 17:34:58 +1000186#ifdef CONFIG_BDM_DISABLE
Greg Ungerer3196cf82006-06-26 10:33:10 +1000187 /*
188 * Disable the BDM clocking. This also turns off most of the rest of
189 * the BDM device. This is good for EMC reasons. This option is not
190 * incompatible with the memory protection option.
191 */
192 wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
193#endif
194}
195
196/***************************************************************************/
Greg Ungerer3196cf82006-06-26 10:33:10 +1000197
Greg Ungererb2e18102008-02-01 17:34:58 +1000198static int __init init_BSP(void)
199{
200 m532x_uarts_init();
Greg Ungererffba3f42009-02-26 22:40:38 -0800201 m532x_fec_init();
Greg Ungererb2e18102008-02-01 17:34:58 +1000202 platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
203 return 0;
204}
205
206arch_initcall(init_BSP);
207
208/***************************************************************************/
209/* Board initialization */
210/***************************************************************************/
Greg Ungerer3196cf82006-06-26 10:33:10 +1000211/*
212 * PLL min/max specifications
213 */
214#define MAX_FVCO 500000 /* KHz */
215#define MAX_FSYS 80000 /* KHz */
216#define MIN_FSYS 58333 /* KHz */
217#define FREF 16000 /* KHz */
218
219
220#define MAX_MFD 135 /* Multiplier */
221#define MIN_MFD 88 /* Multiplier */
222#define BUSDIV 6 /* Divider */
223
224/*
225 * Low Power Divider specifications
226 */
227#define MIN_LPD (1 << 0) /* Divider (not encoded) */
228#define MAX_LPD (1 << 15) /* Divider (not encoded) */
229#define DEFAULT_LPD (1 << 1) /* Divider (not encoded) */
230
231#define SYS_CLK_KHZ 80000
232#define SYSTEM_PERIOD 12.5
233/*
234 * SDRAM Timing Parameters
235 */
236#define SDRAM_BL 8 /* # of beats in a burst */
237#define SDRAM_TWR 2 /* in clocks */
238#define SDRAM_CASL 2.5 /* CASL in clocks */
239#define SDRAM_TRCD 2 /* in clocks */
240#define SDRAM_TRP 2 /* in clocks */
241#define SDRAM_TRFC 7 /* in clocks */
242#define SDRAM_TREFI 7800 /* in ns */
243
244#define EXT_SRAM_ADDRESS (0xC0000000)
245#define FLASH_ADDRESS (0x00000000)
246#define SDRAM_ADDRESS (0x40000000)
247
248#define NAND_FLASH_ADDRESS (0xD0000000)
249
250int sys_clk_khz = 0;
251int sys_clk_mhz = 0;
252
253void wtm_init(void);
254void scm_init(void);
255void gpio_init(void);
256void fbcs_init(void);
257void sdramc_init(void);
258int clock_pll (int fsys, int flags);
259int clock_limp (int);
260int clock_exit_limp (void);
261int get_sys_clock (void);
262
263asmlinkage void __init sysinit(void)
264{
265 sys_clk_khz = clock_pll(0, 0);
266 sys_clk_mhz = sys_clk_khz/1000;
267
268 wtm_init();
269 scm_init();
270 gpio_init();
271 fbcs_init();
272 sdramc_init();
273}
274
275void wtm_init(void)
276{
277 /* Disable watchdog timer */
278 MCF_WTM_WCR = 0;
279}
280
281#define MCF_SCM_BCR_GBW (0x00000100)
282#define MCF_SCM_BCR_GBR (0x00000200)
283
284void scm_init(void)
285{
286 /* All masters are trusted */
287 MCF_SCM_MPR = 0x77777777;
288
289 /* Allow supervisor/user, read/write, and trusted/untrusted
290 access to all slaves */
291 MCF_SCM_PACRA = 0;
292 MCF_SCM_PACRB = 0;
293 MCF_SCM_PACRC = 0;
294 MCF_SCM_PACRD = 0;
295 MCF_SCM_PACRE = 0;
296 MCF_SCM_PACRF = 0;
297
298 /* Enable bursts */
299 MCF_SCM_BCR = (MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW);
300}
301
302
303void fbcs_init(void)
304{
305 MCF_GPIO_PAR_CS = 0x0000003E;
306
307 /* Latch chip select */
308 MCF_FBCS1_CSAR = 0x10080000;
309
310 MCF_FBCS1_CSCR = 0x002A3780;
311 MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V);
312
313 /* Initialize latch to drive signals to inactive states */
314 *((u16 *)(0x10080000)) = 0xFFFF;
315
316 /* External SRAM */
317 MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS;
318 MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16
319 | MCF_FBCS_CSCR_AA
320 | MCF_FBCS_CSCR_SBM
321 | MCF_FBCS_CSCR_WS(1));
322 MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K
323 | MCF_FBCS_CSMR_V);
324
325 /* Boot Flash connected to FBCS0 */
326 MCF_FBCS0_CSAR = FLASH_ADDRESS;
327 MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16
328 | MCF_FBCS_CSCR_BEM
329 | MCF_FBCS_CSCR_AA
330 | MCF_FBCS_CSCR_SBM
331 | MCF_FBCS_CSCR_WS(7));
332 MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M
333 | MCF_FBCS_CSMR_V);
334}
335
336void sdramc_init(void)
337{
338 /*
339 * Check to see if the SDRAM has already been initialized
340 * by a run control tool
341 */
342 if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) {
343 /* SDRAM chip select initialization */
344
345 /* Initialize SDRAM chip select */
346 MCF_SDRAMC_SDCS0 = (0
347 | MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS)
348 | MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE));
349
350 /*
351 * Basic configuration and initialization
352 */
353 MCF_SDRAMC_SDCFG1 = (0
354 | MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5 ))
355 | MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
356 | MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
357 | MCF_SDRAMC_SDCFG1_ACT2RW((int)((SDRAM_TRCD ) + 0.5))
358 | MCF_SDRAMC_SDCFG1_PRE2ACT((int)((SDRAM_TRP ) + 0.5))
359 | MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC) ) + 0.5))
360 | MCF_SDRAMC_SDCFG1_WTLAT(3));
361 MCF_SDRAMC_SDCFG2 = (0
362 | MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL/2 + 1)
363 | MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL/2 + SDRAM_TWR)
364 | MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL+SDRAM_BL/2-1.0)+0.5))
365 | MCF_SDRAMC_SDCFG2_BL(SDRAM_BL-1));
366
367
368 /*
369 * Precharge and enable write to SDMR
370 */
371 MCF_SDRAMC_SDCR = (0
372 | MCF_SDRAMC_SDCR_MODE_EN
373 | MCF_SDRAMC_SDCR_CKE
374 | MCF_SDRAMC_SDCR_DDR
375 | MCF_SDRAMC_SDCR_MUX(1)
376 | MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
377 | MCF_SDRAMC_SDCR_PS_16
378 | MCF_SDRAMC_SDCR_IPALL);
379
380 /*
381 * Write extended mode register
382 */
383 MCF_SDRAMC_SDMR = (0
384 | MCF_SDRAMC_SDMR_BNKAD_LEMR
385 | MCF_SDRAMC_SDMR_AD(0x0)
386 | MCF_SDRAMC_SDMR_CMD);
387
388 /*
389 * Write mode register and reset DLL
390 */
391 MCF_SDRAMC_SDMR = (0
392 | MCF_SDRAMC_SDMR_BNKAD_LMR
393 | MCF_SDRAMC_SDMR_AD(0x163)
394 | MCF_SDRAMC_SDMR_CMD);
395
396 /*
397 * Execute a PALL command
398 */
399 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL;
400
401 /*
402 * Perform two REF cycles
403 */
404 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
405 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
406
407 /*
408 * Write mode register and clear reset DLL
409 */
410 MCF_SDRAMC_SDMR = (0
411 | MCF_SDRAMC_SDMR_BNKAD_LMR
412 | MCF_SDRAMC_SDMR_AD(0x063)
413 | MCF_SDRAMC_SDMR_CMD);
414
415 /*
416 * Enable auto refresh and lock SDMR
417 */
418 MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
419 MCF_SDRAMC_SDCR |= (0
420 | MCF_SDRAMC_SDCR_REF
421 | MCF_SDRAMC_SDCR_DQS_OE(0xC));
422 }
423}
424
425void gpio_init(void)
426{
427 /* Enable UART0 pins */
428 MCF_GPIO_PAR_UART = ( 0
429 | MCF_GPIO_PAR_UART_PAR_URXD0
430 | MCF_GPIO_PAR_UART_PAR_UTXD0);
431
432 /* Initialize TIN3 as a GPIO output to enable the write
433 half of the latch */
434 MCF_GPIO_PAR_TIMER = 0x00;
435 MCF_GPIO_PDDR_TIMER = 0x08;
436 MCF_GPIO_PCLRR_TIMER = 0x0;
437
438}
439
440int clock_pll(int fsys, int flags)
441{
442 int fref, temp, fout, mfd;
443 u32 i;
444
445 fref = FREF;
446
447 if (fsys == 0) {
448 /* Return current PLL output */
449 mfd = MCF_PLL_PFDR;
450
451 return (fref * mfd / (BUSDIV * 4));
452 }
453
454 /* Check bounds of requested system clock */
455 if (fsys > MAX_FSYS)
456 fsys = MAX_FSYS;
457 if (fsys < MIN_FSYS)
458 fsys = MIN_FSYS;
459
460 /* Multiplying by 100 when calculating the temp value,
461 and then dividing by 100 to calculate the mfd allows
462 for exact values without needing to include floating
463 point libraries. */
464 temp = 100 * fsys / fref;
465 mfd = 4 * BUSDIV * temp / 100;
466
467 /* Determine the output frequency for selected values */
468 fout = (fref * mfd / (BUSDIV * 4));
469
470 /*
471 * Check to see if the SDRAM has already been initialized.
472 * If it has then the SDRAM needs to be put into self refresh
473 * mode before reprogramming the PLL.
474 */
475 if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
476 /* Put SDRAM into self refresh mode */
477 MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;
478
479 /*
480 * Initialize the PLL to generate the new system clock frequency.
481 * The device must be put into LIMP mode to reprogram the PLL.
482 */
483
484 /* Enter LIMP mode */
485 clock_limp(DEFAULT_LPD);
486
487 /* Reprogram PLL for desired fsys */
488 MCF_PLL_PODR = (0
489 | MCF_PLL_PODR_CPUDIV(BUSDIV/3)
490 | MCF_PLL_PODR_BUSDIV(BUSDIV));
491
492 MCF_PLL_PFDR = mfd;
493
494 /* Exit LIMP mode */
495 clock_exit_limp();
496
497 /*
498 * Return the SDRAM to normal operation if it is in use.
499 */
500 if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
501 /* Exit self refresh mode */
502 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;
503
504 /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
505 MCF_SDRAMC_LIMP_FIX = MCF_SDRAMC_REFRESH;
506
507 /* wait for DQS logic to relock */
508 for (i = 0; i < 0x200; i++)
509 ;
510
511 return fout;
512}
513
514int clock_limp(int div)
515{
516 u32 temp;
517
518 /* Check bounds of divider */
519 if (div < MIN_LPD)
520 div = MIN_LPD;
521 if (div > MAX_LPD)
522 div = MAX_LPD;
523
524 /* Save of the current value of the SSIDIV so we don't
525 overwrite the value*/
526 temp = (MCF_CCM_CDR & MCF_CCM_CDR_SSIDIV(0xF));
527
528 /* Apply the divider to the system clock */
529 MCF_CCM_CDR = ( 0
530 | MCF_CCM_CDR_LPDIV(div)
531 | MCF_CCM_CDR_SSIDIV(temp));
532
533 MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;
534
535 return (FREF/(3*(1 << div)));
536}
537
538int clock_exit_limp(void)
539{
540 int fout;
541
542 /* Exit LIMP mode */
543 MCF_CCM_MISCCR = (MCF_CCM_MISCCR & ~ MCF_CCM_MISCCR_LIMP);
544
545 /* Wait for PLL to lock */
546 while (!(MCF_CCM_MISCCR & MCF_CCM_MISCCR_PLL_LOCK))
547 ;
548
549 fout = get_sys_clock();
550
551 return fout;
552}
553
554int get_sys_clock(void)
555{
556 int divider;
557
558 /* Test to see if device is in LIMP mode */
559 if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP) {
560 divider = MCF_CCM_CDR & MCF_CCM_CDR_LPDIV(0xF);
561 return (FREF/(2 << divider));
562 }
563 else
564 return ((FREF * MCF_PLL_PFDR) / (BUSDIV * 4));
565}