2011-12-27 11:18:36 +04:00
/*
2014-03-20 21:14:30 +04:00
* SAMSUNG EXYNOS Flattened Device Tree enabled machine
2011-12-27 11:18:36 +04:00
*
2014-03-20 21:14:30 +04:00
* Copyright ( c ) 2010 - 2014 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
2011-12-27 11:18:36 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2014-03-20 21:14:30 +04:00
# include <linux/init.h>
2011-12-27 11:18:36 +04:00
# include <linux/io.h>
2014-03-20 21:14:30 +04:00
# include <linux/kernel.h>
2014-02-14 05:32:45 +04:00
# include <linux/serial_s3c.h>
2012-01-07 16:30:20 +04:00
# include <linux/of.h>
2012-05-15 11:25:23 +04:00
# include <linux/of_address.h>
2014-03-20 21:14:30 +04:00
# include <linux/of_fdt.h>
# include <linux/of_platform.h>
2013-08-30 14:15:04 +04:00
# include <linux/platform_device.h>
2014-03-20 21:14:30 +04:00
# include <linux/pm_domain.h>
2011-12-27 11:18:36 +04:00
2014-03-20 21:14:30 +04:00
# include <asm/cacheflush.h>
2011-12-27 11:18:36 +04:00
# include <asm/hardware/cache-l2x0.h>
2014-03-20 21:14:30 +04:00
# include <asm/mach/arch.h>
2011-12-27 11:18:36 +04:00
# include <asm/mach/map.h>
2014-03-20 21:14:30 +04:00
# include <asm/memory.h>
2011-12-27 11:18:36 +04:00
# include <plat/cpu.h>
# include "common.h"
2014-03-20 21:14:30 +04:00
# include "mfc.h"
2013-12-18 23:06:56 +04:00
# include "regs-pmu.h"
2012-03-08 14:09:12 +04:00
# define L2_AUX_VAL 0x7C470001
# define L2_AUX_MASK 0xC200ffff
2011-12-27 11:18:36 +04:00
2012-02-11 17:15:45 +04:00
static struct map_desc exynos4_iodesc [ ] __initdata = {
{
2011-12-27 11:18:36 +04:00
. virtual = ( unsigned long ) S3C_VA_SYS ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_SYSCON ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S3C_VA_TIMER ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_TIMER ) ,
. length = SZ_16K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S3C_VA_WATCHDOG ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_WATCHDOG ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_SROMC ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_SROMC ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_SYSTIMER ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_SYSTIMER ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_PMU ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_PMU ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_COMBINER_BASE ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_COMBINER ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_GIC_CPU ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_GIC_CPU ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_GIC_DIST ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_GIC_DIST ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
2012-02-11 17:15:45 +04:00
} , {
2011-12-27 11:18:36 +04:00
. virtual = ( unsigned long ) S5P_VA_CMU ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_CMU ) ,
. length = SZ_128K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_COREPERI_BASE ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_COREPERI ) ,
. length = SZ_8K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_L2CC ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_L2CC ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_DMC0 ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_DMC0 ) ,
2011-12-01 10:12:30 +04:00
. length = SZ_64K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_DMC1 ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_DMC1 ) ,
. length = SZ_64K ,
2011-12-27 11:18:36 +04:00
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S3C_VA_USB_HSPHY ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_HSPHY ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} ,
} ;
2012-02-11 17:15:45 +04:00
static struct map_desc exynos5_iodesc [ ] __initdata = {
{
. virtual = ( unsigned long ) S3C_VA_SYS ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_SYSCON ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S3C_VA_TIMER ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_TIMER ) ,
. length = SZ_16K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S3C_VA_WATCHDOG ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_WATCHDOG ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_SROMC ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_SROMC ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_CMU ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_CMU ) ,
. length = 144 * SZ_1K ,
. type = MT_DEVICE ,
} , {
. virtual = ( unsigned long ) S5P_VA_PMU ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_PMU ) ,
. length = SZ_64K ,
. type = MT_DEVICE ,
2012-11-15 10:48:56 +04:00
} ,
} ;
2014-03-20 21:14:30 +04:00
void exynos_restart ( enum reboot_mode mode , const char * cmd )
2012-02-11 17:15:45 +04:00
{
2013-01-24 22:09:13 +04:00
struct device_node * np ;
2014-03-20 21:14:30 +04:00
u32 val = 0x1 ;
void __iomem * addr = EXYNOS_SWRESET ;
2013-06-18 19:29:35 +04:00
if ( of_machine_is_compatible ( " samsung,exynos5440 " ) ) {
2013-05-25 01:33:03 +04:00
u32 status ;
2013-01-24 22:09:13 +04:00
np = of_find_compatible_node ( NULL , NULL , " samsung,exynos5440-clock " ) ;
2013-05-25 01:33:03 +04:00
addr = of_iomap ( np , 0 ) + 0xbc ;
status = __raw_readl ( addr ) ;
2013-01-24 22:09:13 +04:00
addr = of_iomap ( np , 0 ) + 0xcc ;
2013-05-25 01:33:03 +04:00
val = __raw_readl ( addr ) ;
val = ( val & 0xffff0000 ) | ( status & 0xffff ) ;
2012-11-15 10:48:56 +04:00
}
__raw_writel ( val , addr ) ;
2012-02-11 17:15:45 +04:00
}
2013-08-30 14:15:04 +04:00
static struct platform_device exynos_cpuidle = {
. name = " exynos_cpuidle " ,
. id = - 1 ,
} ;
void __init exynos_cpuidle_init ( void )
{
2014-05-09 01:52:59 +04:00
if ( soc_is_exynos5440 ( ) )
return ;
2013-08-30 14:15:04 +04:00
platform_device_register ( & exynos_cpuidle ) ;
}
2013-11-28 16:42:42 +04:00
void __init exynos_cpufreq_init ( void )
{
platform_device_register_simple ( " exynos-cpufreq " , - 1 , NULL , 0 ) ;
}
2012-04-26 06:35:40 +04:00
void __init exynos_init_late ( void )
{
2012-11-15 10:48:56 +04:00
if ( of_machine_is_compatible ( " samsung,exynos5440 " ) )
/* to be supported later */
return ;
2013-12-21 01:33:30 +04:00
pm_genpd_poweroff_unused ( ) ;
2014-03-18 02:28:22 +04:00
exynos_pm_init ( ) ;
2012-04-26 06:35:40 +04:00
}
2013-06-18 20:36:56 +04:00
static int __init exynos_fdt_map_chipid ( unsigned long node , const char * uname ,
2013-04-23 17:46:53 +04:00
int depth , void * data )
{
struct map_desc iodesc ;
__be32 * reg ;
unsigned long len ;
if ( ! of_flat_dt_is_compatible ( node , " samsung,exynos4210-chipid " ) & &
! of_flat_dt_is_compatible ( node , " samsung,exynos5440-clock " ) )
return 0 ;
reg = of_get_flat_dt_prop ( node , " reg " , & len ) ;
if ( reg = = NULL | | len ! = ( sizeof ( unsigned long ) * 2 ) )
return 0 ;
iodesc . pfn = __phys_to_pfn ( be32_to_cpu ( reg [ 0 ] ) ) ;
iodesc . length = be32_to_cpu ( reg [ 1 ] ) - 1 ;
iodesc . virtual = ( unsigned long ) S5P_VA_CHIPID ;
iodesc . type = MT_DEVICE ;
iotable_init ( & iodesc , 1 ) ;
return 1 ;
}
2011-12-27 11:18:36 +04:00
/*
* exynos_map_io
*
* register the standard cpu IO areas
*/
2014-03-20 21:09:39 +04:00
static void __init exynos_map_io ( void )
{
2014-03-20 21:14:30 +04:00
if ( soc_is_exynos4 ( ) )
2014-03-20 21:09:39 +04:00
iotable_init ( exynos4_iodesc , ARRAY_SIZE ( exynos4_iodesc ) ) ;
2014-03-20 21:14:30 +04:00
if ( soc_is_exynos5 ( ) )
2014-03-20 21:09:39 +04:00
iotable_init ( exynos5_iodesc , ARRAY_SIZE ( exynos5_iodesc ) ) ;
}
2011-12-27 11:18:36 +04:00
2013-06-18 20:36:47 +04:00
void __init exynos_init_io ( void )
2011-12-27 11:18:36 +04:00
{
2013-06-06 00:56:33 +04:00
debug_ll_io_init ( ) ;
2013-06-15 04:13:25 +04:00
of_scan_flat_dt ( exynos_fdt_map_chipid , NULL ) ;
2012-11-15 10:48:56 +04:00
2011-12-27 11:18:36 +04:00
/* detect cpu id and rev. */
s5p_init_cpu ( S5P_VA_CHIPID ) ;
2014-03-20 21:09:39 +04:00
exynos_map_io ( ) ;
2012-02-11 17:15:45 +04:00
}
2012-05-15 10:47:40 +04:00
struct bus_type exynos_subsys = {
. name = " exynos-core " ,
. dev_name = " exynos-core " ,
2012-02-11 17:15:45 +04:00
} ;
static int __init exynos_core_init ( void )
2011-12-27 11:18:36 +04:00
{
2012-05-15 10:47:40 +04:00
return subsys_system_register ( & exynos_subsys , NULL ) ;
2011-12-27 11:18:36 +04:00
}
2012-02-11 17:15:45 +04:00
core_initcall ( exynos_core_init ) ;
2011-12-27 11:18:36 +04:00
static int __init exynos4_l2x0_cache_init ( void )
{
2012-04-05 18:59:36 +04:00
int ret ;
2012-03-08 14:09:12 +04:00
ret = l2x0_of_init ( L2_AUX_VAL , L2_AUX_MASK ) ;
2013-06-18 20:36:52 +04:00
if ( ret )
return ret ;
2011-12-27 11:18:36 +04:00
2014-03-13 20:25:52 +04:00
if ( IS_ENABLED ( CONFIG_S5P_SLEEP ) ) {
l2x0_regs_phys = virt_to_phys ( & l2x0_saved_regs ) ;
clean_dcache_area ( & l2x0_regs_phys , sizeof ( unsigned long ) ) ;
}
2011-12-27 11:18:36 +04:00
return 0 ;
}
early_initcall ( exynos4_l2x0_cache_init ) ;
2014-03-20 21:14:30 +04:00
static void __init exynos_dt_machine_init ( void )
2011-12-27 11:18:36 +04:00
{
2014-03-20 21:14:30 +04:00
struct device_node * i2c_np ;
const char * i2c_compat = " samsung,s3c2440-i2c " ;
unsigned int tmp ;
int id ;
/*
* Exynos5 ' s legacy i2c controller and new high speed i2c
* controller have muxed interrupt sources . By default the
* interrupts for 4 - channel HS - I2C controller are enabled .
* If node for first four channels of legacy i2c controller
* are available then re - configure the interrupts via the
* system register .
*/
if ( soc_is_exynos5 ( ) ) {
for_each_compatible_node ( i2c_np , NULL , i2c_compat ) {
if ( of_device_is_available ( i2c_np ) ) {
id = of_alias_get_id ( i2c_np , " i2c " ) ;
if ( id < 4 ) {
tmp = readl ( EXYNOS5_SYS_I2C_CFG ) ;
writel ( tmp & ~ ( 0x1 < < id ) ,
EXYNOS5_SYS_I2C_CFG ) ;
}
}
}
}
2012-02-11 17:15:45 +04:00
2014-03-20 21:14:30 +04:00
exynos_cpuidle_init ( ) ;
exynos_cpufreq_init ( ) ;
of_platform_populate ( NULL , of_default_bus_match_table , NULL , NULL ) ;
2011-12-27 11:18:36 +04:00
}
2014-03-20 21:14:30 +04:00
static char const * exynos_dt_compat [ ] __initconst = {
2014-03-20 21:14:59 +04:00
" samsung,exynos4 " ,
2014-03-20 21:14:30 +04:00
" samsung,exynos4210 " ,
" samsung,exynos4212 " ,
" samsung,exynos4412 " ,
2014-03-20 21:14:59 +04:00
" samsung,exynos5 " ,
2014-03-20 21:14:30 +04:00
" samsung,exynos5250 " ,
" samsung,exynos5420 " ,
" samsung,exynos5440 " ,
NULL
} ;
static void __init exynos_reserve ( void )
{
# ifdef CONFIG_S5P_DEV_MFC
int i ;
char * mfc_mem [ ] = {
" samsung,mfc-v5 " ,
" samsung,mfc-v6 " ,
" samsung,mfc-v7 " ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( mfc_mem ) ; i + + )
if ( of_scan_flat_dt ( s5p_fdt_alloc_mfc_mem , mfc_mem [ i ] ) )
break ;
# endif
}
DT_MACHINE_START ( EXYNOS_DT , " SAMSUNG EXYNOS (Flattened Device Tree) " )
/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
. smp = smp_ops ( exynos_smp_ops ) ,
. map_io = exynos_init_io ,
. init_early = exynos_firmware_init ,
. init_machine = exynos_dt_machine_init ,
. init_late = exynos_init_late ,
. dt_compat = exynos_dt_compat ,
. restart = exynos_restart ,
. reserve = exynos_reserve ,
MACHINE_END