2008-12-03 05:55:38 +03:00
/*
2009-08-21 10:07:46 +04:00
* linux / arch / arm / mach - w90x900 / cpu . c
2008-12-03 05:55:38 +03:00
*
2009-08-21 10:07:46 +04:00
* Copyright ( c ) 2009 Nuvoton corporation .
2008-12-03 05:55:38 +03:00
*
* Wan ZongShun < mcuos . com @ gmail . com >
*
2009-08-21 10:07:46 +04:00
* NUC900 series cpu common support
2008-12-03 05:55:38 +03:00
*
* 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
2009-05-01 19:14:54 +04:00
* the Free Software Foundation ; version 2 of the License .
2008-12-03 05:55:38 +03:00
*
*/
# 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>
2009-02-04 07:01:38 +03:00
# include <linux/serial_8250.h>
2009-07-31 05:30:32 +04:00
# include <linux/delay.h>
2008-12-03 05:55:38 +03:00
# include <asm/mach/arch.h>
# include <asm/mach/map.h>
# include <asm/mach/irq.h>
# include <asm/irq.h>
2012-03-28 21:30:01 +04:00
# include <asm/system_misc.h>
2008-12-03 05:55:38 +03:00
# include <mach/hardware.h>
# include <mach/regs-serial.h>
2009-07-31 05:30:32 +04:00
# include <mach/regs-clock.h>
2015-01-30 12:45:33 +03:00
# include "regs-ebi.h"
# include "regs-timer.h"
2008-12-03 05:55:38 +03:00
# include "cpu.h"
2009-06-10 18:50:44 +04:00
# include "clock.h"
2011-11-05 18:50:25 +04:00
# include "nuc9xx.h"
2008-12-03 05:55:38 +03:00
/* Initial IO mappings */
2009-08-21 10:07:46 +04:00
static struct map_desc nuc900_iodesc [ ] __initdata = {
2008-12-03 05:55:38 +03:00
IODESC_ENT ( IRQ ) ,
IODESC_ENT ( GCR ) ,
IODESC_ENT ( UART ) ,
IODESC_ENT ( TIMER ) ,
IODESC_ENT ( EBI ) ,
2010-02-19 07:23:36 +03:00
IODESC_ENT ( GPIO ) ,
2008-12-03 05:55:38 +03:00
} ;
2009-06-10 18:50:44 +04:00
/* Initial clock declarations. */
static DEFINE_CLK ( lcd , 0 ) ;
static DEFINE_CLK ( audio , 1 ) ;
static DEFINE_CLK ( fmi , 4 ) ;
2009-07-14 18:10:43 +04:00
static DEFINE_SUBCLK ( ms , 0 ) ;
static DEFINE_SUBCLK ( sd , 1 ) ;
2009-06-10 18:50:44 +04:00
static DEFINE_CLK ( dmac , 5 ) ;
static DEFINE_CLK ( atapi , 6 ) ;
static DEFINE_CLK ( emc , 7 ) ;
2009-07-14 18:10:43 +04:00
static DEFINE_SUBCLK ( rmii , 2 ) ;
2009-06-10 18:50:44 +04:00
static DEFINE_CLK ( usbd , 8 ) ;
static DEFINE_CLK ( usbh , 9 ) ;
2011-07-27 10:06:29 +04:00
static DEFINE_CLK ( g2d , 10 ) ;
2009-06-10 18:50:44 +04:00
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 ) ;
2009-08-14 18:36:44 +04:00
static DEFINE_CLK ( ext , 0 ) ;
2010-02-19 07:21:51 +03:00
static DEFINE_CLK ( timer0 , 19 ) ;
static DEFINE_CLK ( timer1 , 20 ) ;
static DEFINE_CLK ( timer2 , 21 ) ;
static DEFINE_CLK ( timer3 , 22 ) ;
static DEFINE_CLK ( timer4 , 23 ) ;
2009-06-10 18:50:44 +04:00
2009-08-21 10:07:46 +04:00
static struct clk_lookup nuc900_clkregs [ ] = {
DEF_CLKLOOK ( & clk_lcd , " nuc900-lcd " , NULL ) ,
2012-01-09 13:54:59 +04:00
DEF_CLKLOOK ( & clk_audio , " nuc900-ac97 " , NULL ) ,
2009-08-21 10:07:46 +04:00
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 ) ,
2010-07-18 18:10:07 +04:00
DEF_CLKLOOK ( & clk_adc , " nuc900-ts " , NULL ) ,
2009-08-21 10:07:46 +04:00
DEF_CLKLOOK ( & clk_usi , " nuc900-spi " , NULL ) ,
2009-08-14 18:36:44 +04:00
DEF_CLKLOOK ( & clk_ext , NULL , " ext " ) ,
2010-02-19 07:21:51 +03:00
DEF_CLKLOOK ( & clk_timer0 , NULL , " timer0 " ) ,
DEF_CLKLOOK ( & clk_timer1 , NULL , " timer1 " ) ,
DEF_CLKLOOK ( & clk_timer2 , NULL , " timer2 " ) ,
DEF_CLKLOOK ( & clk_timer3 , NULL , " timer3 " ) ,
DEF_CLKLOOK ( & clk_timer4 , NULL , " timer4 " ) ,
2009-06-10 18:50:44 +04:00
} ;
2009-02-04 07:01:38 +03:00
/* Initial serial platform data */
2008-12-03 05:55:38 +03:00
2009-08-21 10:07:46 +04:00
struct plat_serial8250_port nuc900_uart_data [ ] = {
NUC900_8250PORT ( UART0 ) ,
2009-12-18 20:02:46 +03:00
{ } ,
2009-02-04 07:01:38 +03:00
} ;
2008-12-03 05:55:38 +03:00
2009-08-21 10:07:46 +04:00
struct platform_device nuc900_serial_device = {
2009-02-04 07:01:38 +03:00
. name = " serial8250 " ,
. id = PLAT8250_DEV_PLATFORM ,
. dev = {
2009-08-21 10:07:46 +04:00
. platform_data = nuc900_uart_data ,
2009-02-04 07:01:38 +03:00
} ,
} ;
2008-12-03 05:55:38 +03:00
2009-08-21 10:07:46 +04:00
/*Set NUC900 series cpu frequence*/
static int __init nuc900_set_clkval ( unsigned int cpufreq )
2009-07-31 05:30:32 +04:00
{
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 ;
}
2009-08-21 10:07:46 +04:00
static int __init nuc900_set_cpufreq ( char * str )
2009-07-31 05:30:32 +04:00
{
unsigned long cpufreq , val ;
if ( ! * str )
return 0 ;
2014-08-09 01:23:59 +04:00
if ( kstrtoul ( str , 0 , & cpufreq ) )
return 0 ;
2009-07-31 05:30:32 +04:00
2009-08-21 10:07:46 +04:00
nuc900_clock_source ( NULL , " ext " ) ;
2009-07-31 05:30:32 +04:00
2009-08-21 10:07:46 +04:00
nuc900_set_clkval ( cpufreq ) ;
2009-07-31 05:30:32 +04:00
mdelay ( 1 ) ;
val = __raw_readl ( REG_CKSKEW ) ;
val & = ~ 0xff ;
val | = DEFAULTSKEW ;
__raw_writel ( val , REG_CKSKEW ) ;
2009-08-21 10:07:46 +04:00
nuc900_clock_source ( NULL , " pll0 " ) ;
2009-07-31 05:30:32 +04:00
return 1 ;
}
2009-08-21 10:07:46 +04:00
__setup ( " cpufreq= " , nuc900_set_cpufreq ) ;
2009-07-31 05:30:32 +04:00
2009-08-21 10:07:46 +04:00
/*Init NUC900 evb io*/
2008-12-03 05:55:38 +03:00
2009-08-21 10:07:46 +04:00
void __init nuc900_map_io ( struct map_desc * mach_desc , int mach_size )
2008-12-03 05:55:38 +03:00
{
2009-08-21 10:07:46 +04:00
unsigned long idcode = 0x0 ;
2008-12-03 05:55:38 +03:00
2009-08-21 10:07:46 +04:00
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 ) ;
2008-12-03 05:55:38 +03:00
}
2009-08-21 10:07:46 +04:00
/*Init NUC900 clock*/
void __init nuc900_init_clocks ( void )
2008-12-03 05:55:38 +03:00
{
2010-01-12 15:28:00 +03:00
clkdev_add_table ( nuc900_clkregs , ARRAY_SIZE ( nuc900_clkregs ) ) ;
2008-12-03 05:55:38 +03:00
}
2009-08-21 10:07:46 +04:00
2011-11-05 18:50:25 +04:00
# define WTCR (TMR_BA + 0x1C)
# define WTCLK (1 << 10)
# define WTE (1 << 7)
# define WTRE (1 << 1)
2013-07-09 03:01:40 +04:00
void nuc9xx_restart ( enum reboot_mode mode , const char * cmd )
2011-11-05 18:50:25 +04:00
{
2013-07-09 03:01:40 +04:00
if ( mode = = REBOOT_SOFT ) {
2011-11-05 18:50:25 +04:00
/* Jump into ROM at address 0 */
soft_restart ( 0 ) ;
} else {
__raw_writel ( WTE | WTRE | WTCLK , WTCR ) ;
}
}