| /* |
| * linux/arch/arm/mach-w90x900/cpu.c |
| * |
| * Copyright (c) 2009 Nuvoton corporation. |
| * |
| * Wan ZongShun <mcuos.com@gmail.com> |
| * |
| * NUC900 series cpu common support |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation;version 2 of the License. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <linux/interrupt.h> |
| #include <linux/list.h> |
| #include <linux/timer.h> |
| #include <linux/init.h> |
| #include <linux/platform_device.h> |
| #include <linux/io.h> |
| #include <linux/serial_8250.h> |
| #include <linux/delay.h> |
| |
| #include <asm/mach/arch.h> |
| #include <asm/mach/map.h> |
| #include <asm/mach/irq.h> |
| #include <asm/irq.h> |
| |
| #include <mach/hardware.h> |
| #include <mach/regs-serial.h> |
| #include <mach/regs-clock.h> |
| #include <mach/regs-ebi.h> |
| |
| #include "cpu.h" |
| #include "clock.h" |
| |
| /* Initial IO mappings */ |
| |
| static struct map_desc nuc900_iodesc[] __initdata = { |
| IODESC_ENT(IRQ), |
| IODESC_ENT(GCR), |
| IODESC_ENT(UART), |
| IODESC_ENT(TIMER), |
| IODESC_ENT(EBI), |
| }; |
| |
| /* Initial clock declarations. */ |
| static DEFINE_CLK(lcd, 0); |
| static DEFINE_CLK(audio, 1); |
| static DEFINE_CLK(fmi, 4); |
| static DEFINE_SUBCLK(ms, 0); |
| static DEFINE_SUBCLK(sd, 1); |
| static DEFINE_CLK(dmac, 5); |
| static DEFINE_CLK(atapi, 6); |
| static DEFINE_CLK(emc, 7); |
| static DEFINE_SUBCLK(rmii, 2); |
| static DEFINE_CLK(usbd, 8); |
| static DEFINE_CLK(usbh, 9); |
| static DEFINE_CLK(g2d, 10);; |
| static DEFINE_CLK(pwm, 18); |
| static DEFINE_CLK(ps2, 24); |
| static DEFINE_CLK(kpi, 25); |
| static DEFINE_CLK(wdt, 26); |
| static DEFINE_CLK(gdma, 27); |
| static DEFINE_CLK(adc, 28); |
| static DEFINE_CLK(usi, 29); |
| static DEFINE_CLK(ext, 0); |
| |
| static struct clk_lookup nuc900_clkregs[] = { |
| DEF_CLKLOOK(&clk_lcd, "nuc900-lcd", NULL), |
| DEF_CLKLOOK(&clk_audio, "nuc900-audio", NULL), |
| DEF_CLKLOOK(&clk_fmi, "nuc900-fmi", NULL), |
| DEF_CLKLOOK(&clk_ms, "nuc900-fmi", "MS"), |
| DEF_CLKLOOK(&clk_sd, "nuc900-fmi", "SD"), |
| DEF_CLKLOOK(&clk_dmac, "nuc900-dmac", NULL), |
| DEF_CLKLOOK(&clk_atapi, "nuc900-atapi", NULL), |
| DEF_CLKLOOK(&clk_emc, "nuc900-emc", NULL), |
| DEF_CLKLOOK(&clk_rmii, "nuc900-emc", "RMII"), |
| DEF_CLKLOOK(&clk_usbd, "nuc900-usbd", NULL), |
| DEF_CLKLOOK(&clk_usbh, "nuc900-usbh", NULL), |
| DEF_CLKLOOK(&clk_g2d, "nuc900-g2d", NULL), |
| DEF_CLKLOOK(&clk_pwm, "nuc900-pwm", NULL), |
| DEF_CLKLOOK(&clk_ps2, "nuc900-ps2", NULL), |
| DEF_CLKLOOK(&clk_kpi, "nuc900-kpi", NULL), |
| DEF_CLKLOOK(&clk_wdt, "nuc900-wdt", NULL), |
| DEF_CLKLOOK(&clk_gdma, "nuc900-gdma", NULL), |
| DEF_CLKLOOK(&clk_adc, "nuc900-adc", NULL), |
| DEF_CLKLOOK(&clk_usi, "nuc900-spi", NULL), |
| DEF_CLKLOOK(&clk_ext, NULL, "ext"), |
| }; |
| |
| /* Initial serial platform data */ |
| |
| struct plat_serial8250_port nuc900_uart_data[] = { |
| NUC900_8250PORT(UART0), |
| }; |
| |
| struct platform_device nuc900_serial_device = { |
| .name = "serial8250", |
| .id = PLAT8250_DEV_PLATFORM, |
| .dev = { |
| .platform_data = nuc900_uart_data, |
| }, |
| }; |
| |
| /*Set NUC900 series cpu frequence*/ |
| static int __init nuc900_set_clkval(unsigned int cpufreq) |
| { |
| unsigned int pllclk, ahbclk, apbclk, val; |
| |
| pllclk = 0; |
| ahbclk = 0; |
| apbclk = 0; |
| |
| switch (cpufreq) { |
| case 66: |
| pllclk = PLL_66MHZ; |
| ahbclk = AHB_CPUCLK_1_1; |
| apbclk = APB_AHB_1_2; |
| break; |
| |
| case 100: |
| pllclk = PLL_100MHZ; |
| ahbclk = AHB_CPUCLK_1_1; |
| apbclk = APB_AHB_1_2; |
| break; |
| |
| case 120: |
| pllclk = PLL_120MHZ; |
| ahbclk = AHB_CPUCLK_1_2; |
| apbclk = APB_AHB_1_2; |
| break; |
| |
| case 166: |
| pllclk = PLL_166MHZ; |
| ahbclk = AHB_CPUCLK_1_2; |
| apbclk = APB_AHB_1_2; |
| break; |
| |
| case 200: |
| pllclk = PLL_200MHZ; |
| ahbclk = AHB_CPUCLK_1_2; |
| apbclk = APB_AHB_1_2; |
| break; |
| } |
| |
| __raw_writel(pllclk, REG_PLLCON0); |
| |
| val = __raw_readl(REG_CLKDIV); |
| val &= ~(0x03 << 24 | 0x03 << 26); |
| val |= (ahbclk << 24 | apbclk << 26); |
| __raw_writel(val, REG_CLKDIV); |
| |
| return 0; |
| } |
| static int __init nuc900_set_cpufreq(char *str) |
| { |
| unsigned long cpufreq, val; |
| |
| if (!*str) |
| return 0; |
| |
| strict_strtoul(str, 0, &cpufreq); |
| |
| nuc900_clock_source(NULL, "ext"); |
| |
| nuc900_set_clkval(cpufreq); |
| |
| mdelay(1); |
| |
| val = __raw_readl(REG_CKSKEW); |
| val &= ~0xff; |
| val |= DEFAULTSKEW; |
| __raw_writel(val, REG_CKSKEW); |
| |
| nuc900_clock_source(NULL, "pll0"); |
| |
| return 1; |
| } |
| |
| __setup("cpufreq=", nuc900_set_cpufreq); |
| |
| /*Init NUC900 evb io*/ |
| |
| void __init nuc900_map_io(struct map_desc *mach_desc, int mach_size) |
| { |
| unsigned long idcode = 0x0; |
| |
| iotable_init(mach_desc, mach_size); |
| iotable_init(nuc900_iodesc, ARRAY_SIZE(nuc900_iodesc)); |
| |
| idcode = __raw_readl(NUC900PDID); |
| if (idcode == NUC910_CPUID) |
| printk(KERN_INFO "CPU type 0x%08lx is NUC910\n", idcode); |
| else if (idcode == NUC920_CPUID) |
| printk(KERN_INFO "CPU type 0x%08lx is NUC920\n", idcode); |
| else if (idcode == NUC950_CPUID) |
| printk(KERN_INFO "CPU type 0x%08lx is NUC950\n", idcode); |
| else if (idcode == NUC960_CPUID) |
| printk(KERN_INFO "CPU type 0x%08lx is NUC960\n", idcode); |
| } |
| |
| /*Init NUC900 clock*/ |
| |
| void __init nuc900_init_clocks(void) |
| { |
| clks_register(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs)); |
| } |
| |