1 /* 2 * SAMSUNG EXYNOS Flattened Device Tree enabled machine 3 * 4 * Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/init.h> 13 #include <linux/io.h> 14 #include <linux/kernel.h> 15 #include <linux/serial_s3c.h> 16 #include <linux/of.h> 17 #include <linux/of_address.h> 18 #include <linux/of_fdt.h> 19 #include <linux/of_platform.h> 20 #include <linux/platform_device.h> 21 #include <linux/pm_domain.h> 22 23 #include <asm/cacheflush.h> 24 #include <asm/hardware/cache-l2x0.h> 25 #include <asm/mach/arch.h> 26 #include <asm/mach/map.h> 27 #include <asm/memory.h> 28 29 #include <plat/cpu.h> 30 31 #include "common.h" 32 #include "mfc.h" 33 #include "regs-pmu.h" 34 35 #define L2_AUX_VAL 0x7C470001 36 #define L2_AUX_MASK 0xC200ffff 37 38 static struct map_desc exynos4_iodesc[] __initdata = { 39 { 40 .virtual = (unsigned long)S3C_VA_SYS, 41 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSCON), 42 .length = SZ_64K, 43 .type = MT_DEVICE, 44 }, { 45 .virtual = (unsigned long)S3C_VA_TIMER, 46 .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER), 47 .length = SZ_16K, 48 .type = MT_DEVICE, 49 }, { 50 .virtual = (unsigned long)S3C_VA_WATCHDOG, 51 .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG), 52 .length = SZ_4K, 53 .type = MT_DEVICE, 54 }, { 55 .virtual = (unsigned long)S5P_VA_SROMC, 56 .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), 57 .length = SZ_4K, 58 .type = MT_DEVICE, 59 }, { 60 .virtual = (unsigned long)S5P_VA_SYSTIMER, 61 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER), 62 .length = SZ_4K, 63 .type = MT_DEVICE, 64 }, { 65 .virtual = (unsigned long)S5P_VA_PMU, 66 .pfn = __phys_to_pfn(EXYNOS4_PA_PMU), 67 .length = SZ_64K, 68 .type = MT_DEVICE, 69 }, { 70 .virtual = (unsigned long)S5P_VA_COMBINER_BASE, 71 .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER), 72 .length = SZ_4K, 73 .type = MT_DEVICE, 74 }, { 75 .virtual = (unsigned long)S5P_VA_GIC_CPU, 76 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU), 77 .length = SZ_64K, 78 .type = MT_DEVICE, 79 }, { 80 .virtual = (unsigned long)S5P_VA_GIC_DIST, 81 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST), 82 .length = SZ_64K, 83 .type = MT_DEVICE, 84 }, { 85 .virtual = (unsigned long)S5P_VA_CMU, 86 .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), 87 .length = SZ_128K, 88 .type = MT_DEVICE, 89 }, { 90 .virtual = (unsigned long)S5P_VA_COREPERI_BASE, 91 .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI), 92 .length = SZ_8K, 93 .type = MT_DEVICE, 94 }, { 95 .virtual = (unsigned long)S5P_VA_L2CC, 96 .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC), 97 .length = SZ_4K, 98 .type = MT_DEVICE, 99 }, { 100 .virtual = (unsigned long)S5P_VA_DMC0, 101 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), 102 .length = SZ_64K, 103 .type = MT_DEVICE, 104 }, { 105 .virtual = (unsigned long)S5P_VA_DMC1, 106 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1), 107 .length = SZ_64K, 108 .type = MT_DEVICE, 109 }, { 110 .virtual = (unsigned long)S3C_VA_USB_HSPHY, 111 .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), 112 .length = SZ_4K, 113 .type = MT_DEVICE, 114 }, 115 }; 116 117 static struct map_desc exynos4_iodesc0[] __initdata = { 118 { 119 .virtual = (unsigned long)S5P_VA_SYSRAM, 120 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM0), 121 .length = SZ_4K, 122 .type = MT_DEVICE, 123 }, 124 }; 125 126 static struct map_desc exynos4_iodesc1[] __initdata = { 127 { 128 .virtual = (unsigned long)S5P_VA_SYSRAM, 129 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM1), 130 .length = SZ_4K, 131 .type = MT_DEVICE, 132 }, 133 }; 134 135 static struct map_desc exynos4210_iodesc[] __initdata = { 136 { 137 .virtual = (unsigned long)S5P_VA_SYSRAM_NS, 138 .pfn = __phys_to_pfn(EXYNOS4210_PA_SYSRAM_NS), 139 .length = SZ_4K, 140 .type = MT_DEVICE, 141 }, 142 }; 143 144 static struct map_desc exynos4x12_iodesc[] __initdata = { 145 { 146 .virtual = (unsigned long)S5P_VA_SYSRAM_NS, 147 .pfn = __phys_to_pfn(EXYNOS4x12_PA_SYSRAM_NS), 148 .length = SZ_4K, 149 .type = MT_DEVICE, 150 }, 151 }; 152 153 static struct map_desc exynos5250_iodesc[] __initdata = { 154 { 155 .virtual = (unsigned long)S5P_VA_SYSRAM_NS, 156 .pfn = __phys_to_pfn(EXYNOS5250_PA_SYSRAM_NS), 157 .length = SZ_4K, 158 .type = MT_DEVICE, 159 }, 160 }; 161 162 static struct map_desc exynos5_iodesc[] __initdata = { 163 { 164 .virtual = (unsigned long)S3C_VA_SYS, 165 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSCON), 166 .length = SZ_64K, 167 .type = MT_DEVICE, 168 }, { 169 .virtual = (unsigned long)S3C_VA_TIMER, 170 .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER), 171 .length = SZ_16K, 172 .type = MT_DEVICE, 173 }, { 174 .virtual = (unsigned long)S3C_VA_WATCHDOG, 175 .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG), 176 .length = SZ_4K, 177 .type = MT_DEVICE, 178 }, { 179 .virtual = (unsigned long)S5P_VA_SROMC, 180 .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC), 181 .length = SZ_4K, 182 .type = MT_DEVICE, 183 }, { 184 .virtual = (unsigned long)S5P_VA_SYSRAM, 185 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM), 186 .length = SZ_4K, 187 .type = MT_DEVICE, 188 }, { 189 .virtual = (unsigned long)S5P_VA_CMU, 190 .pfn = __phys_to_pfn(EXYNOS5_PA_CMU), 191 .length = 144 * SZ_1K, 192 .type = MT_DEVICE, 193 }, { 194 .virtual = (unsigned long)S5P_VA_PMU, 195 .pfn = __phys_to_pfn(EXYNOS5_PA_PMU), 196 .length = SZ_64K, 197 .type = MT_DEVICE, 198 }, 199 }; 200 201 void exynos_restart(enum reboot_mode mode, const char *cmd) 202 { 203 struct device_node *np; 204 u32 val = 0x1; 205 void __iomem *addr = EXYNOS_SWRESET; 206 207 if (of_machine_is_compatible("samsung,exynos5440")) { 208 u32 status; 209 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); 210 211 addr = of_iomap(np, 0) + 0xbc; 212 status = __raw_readl(addr); 213 214 addr = of_iomap(np, 0) + 0xcc; 215 val = __raw_readl(addr); 216 217 val = (val & 0xffff0000) | (status & 0xffff); 218 } 219 220 __raw_writel(val, addr); 221 } 222 223 static struct platform_device exynos_cpuidle = { 224 .name = "exynos_cpuidle", 225 .id = -1, 226 }; 227 228 void __init exynos_cpuidle_init(void) 229 { 230 platform_device_register(&exynos_cpuidle); 231 } 232 233 void __init exynos_cpufreq_init(void) 234 { 235 platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); 236 } 237 238 void __init exynos_init_late(void) 239 { 240 if (of_machine_is_compatible("samsung,exynos5440")) 241 /* to be supported later */ 242 return; 243 244 pm_genpd_poweroff_unused(); 245 exynos_pm_init(); 246 } 247 248 static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, 249 int depth, void *data) 250 { 251 struct map_desc iodesc; 252 __be32 *reg; 253 unsigned long len; 254 255 if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") && 256 !of_flat_dt_is_compatible(node, "samsung,exynos5440-clock")) 257 return 0; 258 259 reg = of_get_flat_dt_prop(node, "reg", &len); 260 if (reg == NULL || len != (sizeof(unsigned long) * 2)) 261 return 0; 262 263 iodesc.pfn = __phys_to_pfn(be32_to_cpu(reg[0])); 264 iodesc.length = be32_to_cpu(reg[1]) - 1; 265 iodesc.virtual = (unsigned long)S5P_VA_CHIPID; 266 iodesc.type = MT_DEVICE; 267 iotable_init(&iodesc, 1); 268 return 1; 269 } 270 271 /* 272 * exynos_map_io 273 * 274 * register the standard cpu IO areas 275 */ 276 static void __init exynos_map_io(void) 277 { 278 if (soc_is_exynos4()) 279 iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); 280 281 if (soc_is_exynos5()) 282 iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); 283 284 if (soc_is_exynos4210()) { 285 if (samsung_rev() == EXYNOS4210_REV_0) 286 iotable_init(exynos4_iodesc0, 287 ARRAY_SIZE(exynos4_iodesc0)); 288 else 289 iotable_init(exynos4_iodesc1, 290 ARRAY_SIZE(exynos4_iodesc1)); 291 iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc)); 292 } 293 if (soc_is_exynos4212() || soc_is_exynos4412()) 294 iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc)); 295 if (soc_is_exynos5250()) 296 iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc)); 297 } 298 299 void __init exynos_init_io(void) 300 { 301 debug_ll_io_init(); 302 303 of_scan_flat_dt(exynos_fdt_map_chipid, NULL); 304 305 /* detect cpu id and rev. */ 306 s5p_init_cpu(S5P_VA_CHIPID); 307 308 exynos_map_io(); 309 } 310 311 struct bus_type exynos_subsys = { 312 .name = "exynos-core", 313 .dev_name = "exynos-core", 314 }; 315 316 static int __init exynos_core_init(void) 317 { 318 return subsys_system_register(&exynos_subsys, NULL); 319 } 320 core_initcall(exynos_core_init); 321 322 static int __init exynos4_l2x0_cache_init(void) 323 { 324 int ret; 325 326 ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); 327 if (ret) 328 return ret; 329 330 if (IS_ENABLED(CONFIG_S5P_SLEEP)) { 331 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); 332 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); 333 } 334 return 0; 335 } 336 early_initcall(exynos4_l2x0_cache_init); 337 338 static void __init exynos_dt_machine_init(void) 339 { 340 struct device_node *i2c_np; 341 const char *i2c_compat = "samsung,s3c2440-i2c"; 342 unsigned int tmp; 343 int id; 344 345 /* 346 * Exynos5's legacy i2c controller and new high speed i2c 347 * controller have muxed interrupt sources. By default the 348 * interrupts for 4-channel HS-I2C controller are enabled. 349 * If node for first four channels of legacy i2c controller 350 * are available then re-configure the interrupts via the 351 * system register. 352 */ 353 if (soc_is_exynos5()) { 354 for_each_compatible_node(i2c_np, NULL, i2c_compat) { 355 if (of_device_is_available(i2c_np)) { 356 id = of_alias_get_id(i2c_np, "i2c"); 357 if (id < 4) { 358 tmp = readl(EXYNOS5_SYS_I2C_CFG); 359 writel(tmp & ~(0x1 << id), 360 EXYNOS5_SYS_I2C_CFG); 361 } 362 } 363 } 364 } 365 366 exynos_cpuidle_init(); 367 exynos_cpufreq_init(); 368 369 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 370 } 371 372 static char const *exynos_dt_compat[] __initconst = { 373 "samsung,exynos4", 374 "samsung,exynos4210", 375 "samsung,exynos4212", 376 "samsung,exynos4412", 377 "samsung,exynos5", 378 "samsung,exynos5250", 379 "samsung,exynos5420", 380 "samsung,exynos5440", 381 NULL 382 }; 383 384 static void __init exynos_reserve(void) 385 { 386 #ifdef CONFIG_S5P_DEV_MFC 387 int i; 388 char *mfc_mem[] = { 389 "samsung,mfc-v5", 390 "samsung,mfc-v6", 391 "samsung,mfc-v7", 392 }; 393 394 for (i = 0; i < ARRAY_SIZE(mfc_mem); i++) 395 if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i])) 396 break; 397 #endif 398 } 399 400 DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") 401 /* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */ 402 /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ 403 .smp = smp_ops(exynos_smp_ops), 404 .map_io = exynos_init_io, 405 .init_early = exynos_firmware_init, 406 .init_machine = exynos_dt_machine_init, 407 .init_late = exynos_init_late, 408 .dt_compat = exynos_dt_compat, 409 .restart = exynos_restart, 410 .reserve = exynos_reserve, 411 MACHINE_END 412