2011-12-27 08:18:36 +01:00
/*
2014-03-21 02:14:30 +09:00
* SAMSUNG EXYNOS Flattened Device Tree enabled machine
2011-12-27 08:18:36 +01:00
*
2014-03-21 02:14:30 +09:00
* Copyright ( c ) 2010 - 2014 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
2011-12-27 08:18:36 +01: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-21 02:14:30 +09:00
# include <linux/init.h>
2011-12-27 08:18:36 +01:00
# include <linux/io.h>
2014-03-21 02:14:30 +09:00
# include <linux/kernel.h>
2014-02-14 10:32:45 +09:00
# include <linux/serial_s3c.h>
2012-01-07 12:30:20 +00:00
# include <linux/of.h>
2012-05-15 16:25:23 +09:00
# include <linux/of_address.h>
2014-03-21 02:14:30 +09:00
# include <linux/of_fdt.h>
# include <linux/of_platform.h>
2013-08-30 12:15:04 +02:00
# include <linux/platform_device.h>
2014-03-21 02:14:30 +09:00
# include <linux/pm_domain.h>
2014-07-11 08:08:29 +09:00
# include <linux/irqchip.h>
2011-12-27 08:18:36 +01:00
2014-03-21 02:14:30 +09:00
# include <asm/cacheflush.h>
2011-12-27 08:18:36 +01:00
# include <asm/hardware/cache-l2x0.h>
2014-03-21 02:14:30 +09:00
# include <asm/mach/arch.h>
2011-12-27 08:18:36 +01:00
# include <asm/mach/map.h>
2014-03-21 02:14:30 +09:00
# include <asm/memory.h>
2011-12-27 08:18:36 +01:00
2015-01-09 01:14:23 +09:00
# include <mach/map.h>
2011-12-27 08:18:36 +01:00
# include "common.h"
2014-03-21 02:14:30 +09:00
# include "mfc.h"
2013-12-19 04:06:56 +09:00
# include "regs-pmu.h"
2014-07-11 08:08:29 +09:00
void __iomem * pmu_base_addr ;
2013-12-19 04:06:56 +09:00
2012-02-11 22:15:45 +09:00
static struct map_desc exynos4_iodesc [ ] __initdata = {
{
2011-12-27 08:18:36 +01:00
. virtual = ( unsigned long ) S5P_VA_SROMC ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_SROMC ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
2012-02-11 22:15:45 +09:00
} , {
2011-12-27 08:18:36 +01: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_DMC0 ,
. pfn = __phys_to_pfn ( EXYNOS4_PA_DMC0 ) ,
2011-12-01 15:12:30 +09: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 08:18:36 +01:00
. type = MT_DEVICE ,
} ,
} ;
2012-02-11 22:15:45 +09:00
static struct map_desc exynos5_iodesc [ ] __initdata = {
{
. virtual = ( unsigned long ) S5P_VA_SROMC ,
. pfn = __phys_to_pfn ( EXYNOS5_PA_SROMC ) ,
. length = SZ_4K ,
. type = MT_DEVICE ,
2012-11-15 15:48:56 +09:00
} ,
} ;
2013-08-30 12:15:04 +02:00
static struct platform_device exynos_cpuidle = {
2014-05-09 06:56:29 +09:00
. name = " exynos_cpuidle " ,
2014-09-24 02:18:27 +09:00
# ifdef CONFIG_ARM_EXYNOS_CPUIDLE
2014-05-09 06:56:29 +09:00
. dev . platform_data = exynos_enter_aftr ,
2014-09-24 02:18:27 +09:00
# endif
2014-05-09 06:56:29 +09:00
. id = - 1 ,
2013-08-30 12:15:04 +02:00
} ;
2014-06-02 21:47:46 -07:00
void __iomem * sysram_base_addr ;
void __iomem * sysram_ns_base_addr ;
void __init exynos_sysram_init ( void )
{
struct device_node * node ;
for_each_compatible_node ( node , NULL , " samsung,exynos4210-sysram " ) {
if ( ! of_device_is_available ( node ) )
continue ;
sysram_base_addr = of_iomap ( node , 0 ) ;
break ;
}
for_each_compatible_node ( node , NULL , " samsung,exynos4210-sysram-ns " ) {
if ( ! of_device_is_available ( node ) )
continue ;
sysram_ns_base_addr = of_iomap ( node , 0 ) ;
break ;
}
}
2014-07-08 07:51:11 +09:00
static void __init exynos_init_late ( void )
2012-04-26 10:35:40 +08:00
{
2012-11-15 15:48:56 +09:00
if ( of_machine_is_compatible ( " samsung,exynos5440 " ) )
/* to be supported later */
return ;
2014-03-18 07:28:22 +09:00
exynos_pm_init ( ) ;
2012-04-26 10:35:40 +08:00
}
2013-06-19 01:36:56 +09:00
static int __init exynos_fdt_map_chipid ( unsigned long node , const char * uname ,
2013-04-23 22:46:53 +09:00
int depth , void * data )
{
struct map_desc iodesc ;
2014-05-05 14:56:48 +05:30
const __be32 * reg ;
2014-04-01 23:49:03 -05:00
int len ;
2013-04-23 22:46:53 +09:00
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 08:18:36 +01:00
/*
* exynos_map_io
*
* register the standard cpu IO areas
*/
2014-03-21 02:09:39 +09:00
static void __init exynos_map_io ( void )
{
2014-03-21 02:14:30 +09:00
if ( soc_is_exynos4 ( ) )
2014-03-21 02:09:39 +09:00
iotable_init ( exynos4_iodesc , ARRAY_SIZE ( exynos4_iodesc ) ) ;
2014-03-21 02:14:30 +09:00
if ( soc_is_exynos5 ( ) )
2014-03-21 02:09:39 +09:00
iotable_init ( exynos5_iodesc , ARRAY_SIZE ( exynos5_iodesc ) ) ;
}
2011-12-27 08:18:36 +01:00
2014-07-08 07:51:11 +09:00
static void __init exynos_init_io ( void )
2011-12-27 08:18:36 +01:00
{
2013-06-05 13:56:33 -07:00
debug_ll_io_init ( ) ;
2013-06-15 09:13:25 +09:00
of_scan_flat_dt ( exynos_fdt_map_chipid , NULL ) ;
2012-11-15 15:48:56 +09:00
2011-12-27 08:18:36 +01:00
/* detect cpu id and rev. */
s5p_init_cpu ( S5P_VA_CHIPID ) ;
2014-03-21 02:09:39 +09:00
exynos_map_io ( ) ;
2012-02-11 22:15:45 +09:00
}
2015-03-11 11:13:57 +01:00
/*
* Set or clear the USE_DELAYED_RESET_ASSERTION option . Used by smp code
* and suspend .
*
* This is necessary only on Exynos4 SoCs . When system is running
* USE_DELAYED_RESET_ASSERTION should be set so the ARM CLK clock down
* feature could properly detect global idle state when secondary CPU is
* powered down .
*
* However this should not be set when such system is going into suspend .
*/
void exynos_set_delayed_reset_assertion ( bool enable )
{
2015-05-14 11:43:59 +09:00
if ( of_machine_is_compatible ( " samsung,exynos4 " ) ) {
2015-03-11 11:13:57 +01:00
unsigned int tmp , core_id ;
for ( core_id = 0 ; core_id < num_possible_cpus ( ) ; core_id + + ) {
tmp = pmu_raw_readl ( EXYNOS_ARM_CORE_OPTION ( core_id ) ) ;
if ( enable )
tmp | = S5P_USE_DELAYED_RESET_ASSERTION ;
else
tmp & = ~ ( S5P_USE_DELAYED_RESET_ASSERTION ) ;
pmu_raw_writel ( tmp , EXYNOS_ARM_CORE_OPTION ( core_id ) ) ;
}
}
}
2015-03-11 15:44:52 +00:00
/*
* Apparently , these SoCs are not able to wake - up from suspend using
* the PMU . Too bad . Should they suddenly become capable of such a
* feat , the matches below should be moved to suspend . c .
*/
2014-07-11 08:08:29 +09:00
static const struct of_device_id exynos_dt_pmu_match [ ] = {
2014-07-29 06:17:39 +09:00
{ . compatible = " samsung,exynos5260-pmu " } ,
2014-07-29 06:10:40 +09:00
{ . compatible = " samsung,exynos5410-pmu " } ,
2014-07-11 08:08:29 +09:00
{ /*sentinel*/ } ,
} ;
static void exynos_map_pmu ( void )
{
struct device_node * np ;
np = of_find_matching_node ( NULL , exynos_dt_pmu_match ) ;
if ( np )
pmu_base_addr = of_iomap ( np , 0 ) ;
}
static void __init exynos_init_irq ( void )
{
irqchip_init ( ) ;
/*
* Since platsmp . c needs pmu base address by the time
* DT is not unflatten so we can ' t use DT APIs before
* init_irq
*/
exynos_map_pmu ( ) ;
}
2015-04-03 18:43:48 +02:00
static const struct of_device_id exynos_cpufreq_matches [ ] = {
2015-07-24 12:58:41 +09:00
{ . compatible = " samsung,exynos3250 " , . data = " cpufreq-dt " } ,
2015-04-03 18:43:48 +02:00
{ . compatible = " samsung,exynos4210 " , . data = " cpufreq-dt " } ,
2015-08-12 07:41:11 +09:00
{ . compatible = " samsung,exynos4212 " , . data = " cpufreq-dt " } ,
{ . compatible = " samsung,exynos4412 " , . data = " cpufreq-dt " } ,
2015-07-01 15:10:37 +02:00
{ . compatible = " samsung,exynos5250 " , . data = " cpufreq-dt " } ,
2015-12-15 18:33:18 +01:00
# ifndef CONFIG_BL_SWITCHER
{ . compatible = " samsung,exynos5420 " , . data = " cpufreq-dt " } ,
2015-12-15 18:33:21 +01:00
{ . compatible = " samsung,exynos5800 " , . data = " cpufreq-dt " } ,
2015-12-15 18:33:18 +01:00
# endif
2015-04-03 18:43:48 +02:00
{ /* sentinel */ }
} ;
static void __init exynos_cpufreq_init ( void )
{
struct device_node * root = of_find_node_by_path ( " / " ) ;
const struct of_device_id * match ;
match = of_match_node ( exynos_cpufreq_matches , root ) ;
if ( ! match ) {
platform_device_register_simple ( " exynos-cpufreq " , - 1 , NULL , 0 ) ;
return ;
}
platform_device_register_simple ( match - > data , - 1 , NULL , 0 ) ;
}
2014-03-21 02:14:30 +09:00
static void __init exynos_dt_machine_init ( void )
2011-12-27 08:18:36 +01:00
{
2014-06-02 21:47:46 -07:00
/*
* This is called from smp_prepare_cpus if we ' ve built for SMP , but
* we still need to set it up for PM and firmware ops if not .
*/
2014-07-05 06:09:18 +09:00
if ( ! IS_ENABLED ( CONFIG_SMP ) )
2014-06-02 21:47:46 -07:00
exynos_sysram_init ( ) ;
2015-03-18 03:26:11 +09:00
# if defined(CONFIG_SMP) && defined(CONFIG_ARM_EXYNOS_CPUIDLE)
2015-03-18 14:09:57 +01:00
if ( of_machine_is_compatible ( " samsung,exynos4210 " ) | |
of_machine_is_compatible ( " samsung,exynos3250 " ) )
2015-01-24 14:05:50 +09:00
exynos_cpuidle . dev . platform_data = & cpuidle_coupled_exynos_data ;
# endif
2014-07-19 03:48:35 +09:00
if ( of_machine_is_compatible ( " samsung,exynos4210 " ) | |
2014-09-25 17:59:41 +09:00
of_machine_is_compatible ( " samsung,exynos4212 " ) | |
( of_machine_is_compatible ( " samsung,exynos4412 " ) & &
of_machine_is_compatible ( " samsung,trats2 " ) ) | |
2015-03-27 02:35:52 +09:00
of_machine_is_compatible ( " samsung,exynos3250 " ) | |
2014-09-25 17:59:41 +09:00
of_machine_is_compatible ( " samsung,exynos5250 " ) )
2014-07-19 03:48:35 +09:00
platform_device_register ( & exynos_cpuidle ) ;
2014-07-05 06:24:35 +09:00
2015-04-03 18:43:48 +02:00
exynos_cpufreq_init ( ) ;
2014-03-21 02:14:30 +09:00
of_platform_populate ( NULL , of_default_bus_match_table , NULL , NULL ) ;
2011-12-27 08:18:36 +01:00
}
2014-03-21 02:14:30 +09:00
2015-02-18 21:01:45 +01:00
static char const * const exynos_dt_compat [ ] __initconst = {
2014-05-26 04:12:26 +09:00
" samsung,exynos3 " ,
" samsung,exynos3250 " ,
2014-03-21 02:14:59 +09:00
" samsung,exynos4 " ,
2014-03-21 02:14:30 +09:00
" samsung,exynos4210 " ,
" samsung,exynos4212 " ,
" samsung,exynos4412 " ,
2014-11-07 08:20:09 +09:00
" samsung,exynos4415 " ,
2014-03-21 02:14:59 +09:00
" samsung,exynos5 " ,
2014-03-21 02:14:30 +09:00
" samsung,exynos5250 " ,
2014-05-26 04:28:17 +09:00
" samsung,exynos5260 " ,
2014-03-21 02:14:30 +09:00
" 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 " ,
2015-01-12 17:46:36 +09:00
" samsung,mfc-v8 " ,
2014-03-21 02:14:30 +09:00
} ;
for ( i = 0 ; i < ARRAY_SIZE ( mfc_mem ) ; i + + )
if ( of_scan_flat_dt ( s5p_fdt_alloc_mfc_mem , mfc_mem [ i ] ) )
break ;
# endif
}
2014-07-15 10:03:36 -07:00
static void __init exynos_dt_fixup ( void )
{
/*
* Some versions of uboot pass garbage entries in the memory node ,
* use the old CONFIG_ARM_NR_BANKS
*/
of_fdt_limit_memory ( 8 ) ;
}
2014-03-21 02:14:30 +09:00
DT_MACHINE_START ( EXYNOS_DT , " SAMSUNG EXYNOS (Flattened Device Tree) " )
/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
2014-04-28 15:54:08 +01:00
. l2c_aux_val = 0x3c400001 ,
. l2c_aux_mask = 0xc20fffff ,
2014-03-21 02:14:30 +09:00
. smp = smp_ops ( exynos_smp_ops ) ,
. map_io = exynos_init_io ,
. init_early = exynos_firmware_init ,
2014-07-11 08:08:29 +09:00
. init_irq = exynos_init_irq ,
2014-03-21 02:14:30 +09:00
. init_machine = exynos_dt_machine_init ,
. init_late = exynos_init_late ,
. dt_compat = exynos_dt_compat ,
. reserve = exynos_reserve ,
2014-07-15 10:03:36 -07:00
. dt_fixup = exynos_dt_fixup ,
2014-03-21 02:14:30 +09:00
MACHINE_END