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