blob: 3558a620a00cbba39842493e7c47f85dce821a27 [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>
Greg Ungererb2e18102008-02-01 17:34:58 +100023#include <linux/io.h>
Steven King91d60412010-01-22 12:43:03 -080024#include <linux/spi/spi.h>
25#include <linux/gpio.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100026#include <asm/machdep.h>
27#include <asm/coldfire.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100028#include <asm/mcfsim.h>
Greg Ungererb2e18102008-02-01 17:34:58 +100029#include <asm/mcfuart.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100030#include <asm/mcfdma.h>
31#include <asm/mcfwdebug.h>
Steven King91d60412010-01-22 12:43:03 -080032#include <asm/mcfqspi.h>
Greg Ungerer3196cf82006-06-26 10:33:10 +100033
34/***************************************************************************/
35
Greg Ungererb2e18102008-02-01 17:34:58 +100036static struct mcf_platform_uart m532x_uart_platform[] = {
37 {
Matt Waddeladd82402008-12-20 07:16:38 -070038 .mapbase = MCFUART_BASE1,
Greg Ungererb2e18102008-02-01 17:34:58 +100039 .irq = MCFINT_VECBASE + MCFINT_UART0,
40 },
41 {
Matt Waddeladd82402008-12-20 07:16:38 -070042 .mapbase = MCFUART_BASE2,
Greg Ungererb2e18102008-02-01 17:34:58 +100043 .irq = MCFINT_VECBASE + MCFINT_UART1,
44 },
45 {
Matt Waddeladd82402008-12-20 07:16:38 -070046 .mapbase = MCFUART_BASE3,
Greg Ungererb2e18102008-02-01 17:34:58 +100047 .irq = MCFINT_VECBASE + MCFINT_UART2,
48 },
49 { },
50};
51
52static struct platform_device m532x_uart = {
53 .name = "mcfuart",
54 .id = 0,
55 .dev.platform_data = m532x_uart_platform,
56};
57
Greg Ungererffba3f42009-02-26 22:40:38 -080058static struct resource m532x_fec_resources[] = {
59 {
60 .start = 0xfc030000,
61 .end = 0xfc0307ff,
62 .flags = IORESOURCE_MEM,
63 },
64 {
65 .start = 64 + 36,
66 .end = 64 + 36,
67 .flags = IORESOURCE_IRQ,
68 },
69 {
70 .start = 64 + 40,
71 .end = 64 + 40,
72 .flags = IORESOURCE_IRQ,
73 },
74 {
75 .start = 64 + 42,
76 .end = 64 + 42,
77 .flags = IORESOURCE_IRQ,
78 },
79};
80
81static struct platform_device m532x_fec = {
82 .name = "fec",
83 .id = 0,
84 .num_resources = ARRAY_SIZE(m532x_fec_resources),
85 .resource = m532x_fec_resources,
86};
Greg Ungererf6a66272009-05-19 15:00:01 +100087
Steven King91d60412010-01-22 12:43:03 -080088#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
89static struct resource m532x_qspi_resources[] = {
90 {
91 .start = MCFQSPI_IOBASE,
92 .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
93 .flags = IORESOURCE_MEM,
94 },
95 {
96 .start = MCFINT_VECBASE + MCFINT_QSPI,
97 .end = MCFINT_VECBASE + MCFINT_QSPI,
98 .flags = IORESOURCE_IRQ,
99 },
100};
101
102#define MCFQSPI_CS0 84
103#define MCFQSPI_CS1 85
104#define MCFQSPI_CS2 86
105
106static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
107{
108 int status;
109
110 status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
111 if (status) {
112 pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
113 goto fail0;
114 }
115 status = gpio_direction_output(MCFQSPI_CS0, 1);
116 if (status) {
117 pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
118 goto fail1;
119 }
120
121 status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
122 if (status) {
123 pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
124 goto fail1;
125 }
126 status = gpio_direction_output(MCFQSPI_CS1, 1);
127 if (status) {
128 pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
129 goto fail2;
130 }
131
132 status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
133 if (status) {
134 pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
135 goto fail2;
136 }
137 status = gpio_direction_output(MCFQSPI_CS2, 1);
138 if (status) {
139 pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
140 goto fail3;
141 }
142
143 return 0;
144
145fail3:
146 gpio_free(MCFQSPI_CS2);
147fail2:
148 gpio_free(MCFQSPI_CS1);
149fail1:
150 gpio_free(MCFQSPI_CS0);
151fail0:
152 return status;
153}
154
155static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
156{
157 gpio_free(MCFQSPI_CS2);
158 gpio_free(MCFQSPI_CS1);
159 gpio_free(MCFQSPI_CS0);
160}
161
162static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
163 u8 chip_select, bool cs_high)
164{
165 gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
166}
167
168static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
169 u8 chip_select, bool cs_high)
170{
171 gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
172}
173
174static struct mcfqspi_cs_control m532x_cs_control = {
175 .setup = m532x_cs_setup,
176 .teardown = m532x_cs_teardown,
177 .select = m532x_cs_select,
178 .deselect = m532x_cs_deselect,
179};
180
181static struct mcfqspi_platform_data m532x_qspi_data = {
182 .bus_num = 0,
183 .num_chipselect = 3,
184 .cs_control = &m532x_cs_control,
185};
186
187static struct platform_device m532x_qspi = {
188 .name = "mcfqspi",
189 .id = 0,
190 .num_resources = ARRAY_SIZE(m532x_qspi_resources),
191 .resource = m532x_qspi_resources,
192 .dev.platform_data = &m532x_qspi_data,
193};
194
195static void __init m532x_qspi_init(void)
196{
197 /* setup QSPS pins for QSPI with gpio CS control */
198 writew(0x01f0, MCF_GPIO_PAR_QSPI);
199}
200#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
201
202
Greg Ungererb2e18102008-02-01 17:34:58 +1000203static struct platform_device *m532x_devices[] __initdata = {
204 &m532x_uart,
Greg Ungererffba3f42009-02-26 22:40:38 -0800205 &m532x_fec,
Steven King91d60412010-01-22 12:43:03 -0800206#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
207 &m532x_qspi,
208#endif
Greg Ungererb2e18102008-02-01 17:34:58 +1000209};
210
211/***************************************************************************/
212
213static void __init m532x_uart_init_line(int line, int irq)
214{
215 if (line == 0) {
Greg Ungererb2e18102008-02-01 17:34:58 +1000216 /* GPIO initialization */
217 MCF_GPIO_PAR_UART |= 0x000F;
218 } else if (line == 1) {
Greg Ungererb2e18102008-02-01 17:34:58 +1000219 /* GPIO initialization */
220 MCF_GPIO_PAR_UART |= 0x0FF0;
Greg Ungererb2e18102008-02-01 17:34:58 +1000221 }
222}
223
224static void __init m532x_uarts_init(void)
225{
226 const int nrlines = ARRAY_SIZE(m532x_uart_platform);
227 int line;
228
229 for (line = 0; (line < nrlines); line++)
230 m532x_uart_init_line(line, m532x_uart_platform[line].irq);
231}
Greg Ungererffba3f42009-02-26 22:40:38 -0800232/***************************************************************************/
233
234static void __init m532x_fec_init(void)
235{
Greg Ungererffba3f42009-02-26 22:40:38 -0800236 /* Set multi-function pins to ethernet mode for fec0 */
237 MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
238 MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
239 MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
240 MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
241}
Greg Ungerer3196cf82006-06-26 10:33:10 +1000242
243/***************************************************************************/
244
Greg Ungerer384feb92009-04-30 22:03:43 +1000245static void m532x_cpu_reset(void)
246{
247 local_irq_disable();
248 __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
249}
250
251/***************************************************************************/
252
Greg Ungererb2e18102008-02-01 17:34:58 +1000253void __init config_BSP(char *commandp, int size)
Greg Ungerer3196cf82006-06-26 10:33:10 +1000254{
Greg Ungererbc724502007-07-25 22:07:20 +1000255#if !defined(CONFIG_BOOTPARAM)
Greg Ungerer3196cf82006-06-26 10:33:10 +1000256 /* Copy command line from FLASH to local buffer... */
257 memcpy(commandp, (char *) 0x4000, 4);
258 if(strncmp(commandp, "kcl ", 4) == 0){
259 memcpy(commandp, (char *) 0x4004, size);
260 commandp[size-1] = 0;
261 } else {
262 memset(commandp, 0, size);
263 }
264#endif
265
Greg Ungerer35aefb22012-01-23 15:34:58 +1000266 mach_sched_init = hw_timer_init;
267
Greg Ungererb2e18102008-02-01 17:34:58 +1000268#ifdef CONFIG_BDM_DISABLE
Greg Ungerer3196cf82006-06-26 10:33:10 +1000269 /*
270 * Disable the BDM clocking. This also turns off most of the rest of
271 * the BDM device. This is good for EMC reasons. This option is not
272 * incompatible with the memory protection option.
273 */
274 wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
275#endif
276}
277
278/***************************************************************************/
Greg Ungerer3196cf82006-06-26 10:33:10 +1000279
Greg Ungererb2e18102008-02-01 17:34:58 +1000280static int __init init_BSP(void)
281{
282 m532x_uarts_init();
Greg Ungererffba3f42009-02-26 22:40:38 -0800283 m532x_fec_init();
Steven King91d60412010-01-22 12:43:03 -0800284#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
285 m532x_qspi_init();
286#endif
Greg Ungererb2e18102008-02-01 17:34:58 +1000287 platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
288 return 0;
289}
290
291arch_initcall(init_BSP);
292
293/***************************************************************************/
294/* Board initialization */
295/***************************************************************************/
Greg Ungerer3196cf82006-06-26 10:33:10 +1000296/*
297 * PLL min/max specifications
298 */
299#define MAX_FVCO 500000 /* KHz */
300#define MAX_FSYS 80000 /* KHz */
301#define MIN_FSYS 58333 /* KHz */
302#define FREF 16000 /* KHz */
303
304
305#define MAX_MFD 135 /* Multiplier */
306#define MIN_MFD 88 /* Multiplier */
307#define BUSDIV 6 /* Divider */
308
309/*
310 * Low Power Divider specifications
311 */
312#define MIN_LPD (1 << 0) /* Divider (not encoded) */
313#define MAX_LPD (1 << 15) /* Divider (not encoded) */
314#define DEFAULT_LPD (1 << 1) /* Divider (not encoded) */
315
316#define SYS_CLK_KHZ 80000
317#define SYSTEM_PERIOD 12.5
318/*
319 * SDRAM Timing Parameters
320 */
321#define SDRAM_BL 8 /* # of beats in a burst */
322#define SDRAM_TWR 2 /* in clocks */
323#define SDRAM_CASL 2.5 /* CASL in clocks */
324#define SDRAM_TRCD 2 /* in clocks */
325#define SDRAM_TRP 2 /* in clocks */
326#define SDRAM_TRFC 7 /* in clocks */
327#define SDRAM_TREFI 7800 /* in ns */
328
329#define EXT_SRAM_ADDRESS (0xC0000000)
330#define FLASH_ADDRESS (0x00000000)
331#define SDRAM_ADDRESS (0x40000000)
332
333#define NAND_FLASH_ADDRESS (0xD0000000)
334
335int sys_clk_khz = 0;
336int sys_clk_mhz = 0;
337
338void wtm_init(void);
339void scm_init(void);
340void gpio_init(void);
341void fbcs_init(void);
342void sdramc_init(void);
343int clock_pll (int fsys, int flags);
344int clock_limp (int);
345int clock_exit_limp (void);
346int get_sys_clock (void);
347
348asmlinkage void __init sysinit(void)
349{
350 sys_clk_khz = clock_pll(0, 0);
351 sys_clk_mhz = sys_clk_khz/1000;
352
353 wtm_init();
354 scm_init();
355 gpio_init();
356 fbcs_init();
357 sdramc_init();
358}
359
360void wtm_init(void)
361{
362 /* Disable watchdog timer */
363 MCF_WTM_WCR = 0;
364}
365
366#define MCF_SCM_BCR_GBW (0x00000100)
367#define MCF_SCM_BCR_GBR (0x00000200)
368
369void scm_init(void)
370{
371 /* All masters are trusted */
372 MCF_SCM_MPR = 0x77777777;
373
374 /* Allow supervisor/user, read/write, and trusted/untrusted
375 access to all slaves */
376 MCF_SCM_PACRA = 0;
377 MCF_SCM_PACRB = 0;
378 MCF_SCM_PACRC = 0;
379 MCF_SCM_PACRD = 0;
380 MCF_SCM_PACRE = 0;
381 MCF_SCM_PACRF = 0;
382
383 /* Enable bursts */
384 MCF_SCM_BCR = (MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW);
385}
386
387
388void fbcs_init(void)
389{
390 MCF_GPIO_PAR_CS = 0x0000003E;
391
392 /* Latch chip select */
393 MCF_FBCS1_CSAR = 0x10080000;
394
395 MCF_FBCS1_CSCR = 0x002A3780;
396 MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V);
397
398 /* Initialize latch to drive signals to inactive states */
399 *((u16 *)(0x10080000)) = 0xFFFF;
400
401 /* External SRAM */
402 MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS;
403 MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16
404 | MCF_FBCS_CSCR_AA
405 | MCF_FBCS_CSCR_SBM
406 | MCF_FBCS_CSCR_WS(1));
407 MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K
408 | MCF_FBCS_CSMR_V);
409
410 /* Boot Flash connected to FBCS0 */
411 MCF_FBCS0_CSAR = FLASH_ADDRESS;
412 MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16
413 | MCF_FBCS_CSCR_BEM
414 | MCF_FBCS_CSCR_AA
415 | MCF_FBCS_CSCR_SBM
416 | MCF_FBCS_CSCR_WS(7));
417 MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M
418 | MCF_FBCS_CSMR_V);
419}
420
421void sdramc_init(void)
422{
423 /*
424 * Check to see if the SDRAM has already been initialized
425 * by a run control tool
426 */
427 if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) {
428 /* SDRAM chip select initialization */
429
430 /* Initialize SDRAM chip select */
431 MCF_SDRAMC_SDCS0 = (0
432 | MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS)
433 | MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE));
434
435 /*
436 * Basic configuration and initialization
437 */
438 MCF_SDRAMC_SDCFG1 = (0
439 | MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5 ))
440 | MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
441 | MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
442 | MCF_SDRAMC_SDCFG1_ACT2RW((int)((SDRAM_TRCD ) + 0.5))
443 | MCF_SDRAMC_SDCFG1_PRE2ACT((int)((SDRAM_TRP ) + 0.5))
444 | MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC) ) + 0.5))
445 | MCF_SDRAMC_SDCFG1_WTLAT(3));
446 MCF_SDRAMC_SDCFG2 = (0
447 | MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL/2 + 1)
448 | MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL/2 + SDRAM_TWR)
449 | MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL+SDRAM_BL/2-1.0)+0.5))
450 | MCF_SDRAMC_SDCFG2_BL(SDRAM_BL-1));
451
452
453 /*
454 * Precharge and enable write to SDMR
455 */
456 MCF_SDRAMC_SDCR = (0
457 | MCF_SDRAMC_SDCR_MODE_EN
458 | MCF_SDRAMC_SDCR_CKE
459 | MCF_SDRAMC_SDCR_DDR
460 | MCF_SDRAMC_SDCR_MUX(1)
461 | MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
462 | MCF_SDRAMC_SDCR_PS_16
463 | MCF_SDRAMC_SDCR_IPALL);
464
465 /*
466 * Write extended mode register
467 */
468 MCF_SDRAMC_SDMR = (0
469 | MCF_SDRAMC_SDMR_BNKAD_LEMR
470 | MCF_SDRAMC_SDMR_AD(0x0)
471 | MCF_SDRAMC_SDMR_CMD);
472
473 /*
474 * Write mode register and reset DLL
475 */
476 MCF_SDRAMC_SDMR = (0
477 | MCF_SDRAMC_SDMR_BNKAD_LMR
478 | MCF_SDRAMC_SDMR_AD(0x163)
479 | MCF_SDRAMC_SDMR_CMD);
480
481 /*
482 * Execute a PALL command
483 */
484 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL;
485
486 /*
487 * Perform two REF cycles
488 */
489 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
490 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
491
492 /*
493 * Write mode register and clear reset DLL
494 */
495 MCF_SDRAMC_SDMR = (0
496 | MCF_SDRAMC_SDMR_BNKAD_LMR
497 | MCF_SDRAMC_SDMR_AD(0x063)
498 | MCF_SDRAMC_SDMR_CMD);
499
500 /*
501 * Enable auto refresh and lock SDMR
502 */
503 MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
504 MCF_SDRAMC_SDCR |= (0
505 | MCF_SDRAMC_SDCR_REF
506 | MCF_SDRAMC_SDCR_DQS_OE(0xC));
507 }
508}
509
510void gpio_init(void)
511{
512 /* Enable UART0 pins */
513 MCF_GPIO_PAR_UART = ( 0
514 | MCF_GPIO_PAR_UART_PAR_URXD0
515 | MCF_GPIO_PAR_UART_PAR_UTXD0);
516
517 /* Initialize TIN3 as a GPIO output to enable the write
518 half of the latch */
519 MCF_GPIO_PAR_TIMER = 0x00;
sfking@fdwdc.com7846fe82009-06-19 18:11:10 -0700520 __raw_writeb(0x08, MCFGPIO_PDDR_TIMER);
521 __raw_writeb(0x00, MCFGPIO_PCLRR_TIMER);
Greg Ungerer3196cf82006-06-26 10:33:10 +1000522
523}
524
525int clock_pll(int fsys, int flags)
526{
527 int fref, temp, fout, mfd;
528 u32 i;
529
530 fref = FREF;
531
532 if (fsys == 0) {
533 /* Return current PLL output */
534 mfd = MCF_PLL_PFDR;
535
536 return (fref * mfd / (BUSDIV * 4));
537 }
538
539 /* Check bounds of requested system clock */
540 if (fsys > MAX_FSYS)
541 fsys = MAX_FSYS;
542 if (fsys < MIN_FSYS)
543 fsys = MIN_FSYS;
544
545 /* Multiplying by 100 when calculating the temp value,
546 and then dividing by 100 to calculate the mfd allows
547 for exact values without needing to include floating
548 point libraries. */
549 temp = 100 * fsys / fref;
550 mfd = 4 * BUSDIV * temp / 100;
551
552 /* Determine the output frequency for selected values */
553 fout = (fref * mfd / (BUSDIV * 4));
554
555 /*
556 * Check to see if the SDRAM has already been initialized.
557 * If it has then the SDRAM needs to be put into self refresh
558 * mode before reprogramming the PLL.
559 */
560 if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
561 /* Put SDRAM into self refresh mode */
562 MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;
563
564 /*
565 * Initialize the PLL to generate the new system clock frequency.
566 * The device must be put into LIMP mode to reprogram the PLL.
567 */
568
569 /* Enter LIMP mode */
570 clock_limp(DEFAULT_LPD);
571
572 /* Reprogram PLL for desired fsys */
573 MCF_PLL_PODR = (0
574 | MCF_PLL_PODR_CPUDIV(BUSDIV/3)
575 | MCF_PLL_PODR_BUSDIV(BUSDIV));
576
577 MCF_PLL_PFDR = mfd;
578
579 /* Exit LIMP mode */
580 clock_exit_limp();
581
582 /*
583 * Return the SDRAM to normal operation if it is in use.
584 */
585 if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
586 /* Exit self refresh mode */
587 MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;
588
589 /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
590 MCF_SDRAMC_LIMP_FIX = MCF_SDRAMC_REFRESH;
591
592 /* wait for DQS logic to relock */
593 for (i = 0; i < 0x200; i++)
594 ;
595
596 return fout;
597}
598
599int clock_limp(int div)
600{
601 u32 temp;
602
603 /* Check bounds of divider */
604 if (div < MIN_LPD)
605 div = MIN_LPD;
606 if (div > MAX_LPD)
607 div = MAX_LPD;
608
609 /* Save of the current value of the SSIDIV so we don't
610 overwrite the value*/
611 temp = (MCF_CCM_CDR & MCF_CCM_CDR_SSIDIV(0xF));
612
613 /* Apply the divider to the system clock */
614 MCF_CCM_CDR = ( 0
615 | MCF_CCM_CDR_LPDIV(div)
616 | MCF_CCM_CDR_SSIDIV(temp));
617
618 MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;
619
620 return (FREF/(3*(1 << div)));
621}
622
623int clock_exit_limp(void)
624{
625 int fout;
626
627 /* Exit LIMP mode */
628 MCF_CCM_MISCCR = (MCF_CCM_MISCCR & ~ MCF_CCM_MISCCR_LIMP);
629
630 /* Wait for PLL to lock */
631 while (!(MCF_CCM_MISCCR & MCF_CCM_MISCCR_PLL_LOCK))
632 ;
633
634 fout = get_sys_clock();
635
636 return fout;
637}
638
639int get_sys_clock(void)
640{
641 int divider;
642
643 /* Test to see if device is in LIMP mode */
644 if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP) {
645 divider = MCF_CCM_CDR & MCF_CCM_CDR_LPDIV(0xF);
646 return (FREF/(2 << divider));
647 }
648 else
649 return ((FREF * MCF_PLL_PFDR) / (BUSDIV * 4));
650}