linux/arch/arm/mach-exynos/exynos.c
<<
>>
Prefs
   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/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_fdt.h>
  17#include <linux/of_platform.h>
  18#include <linux/platform_device.h>
  19#include <linux/irqchip.h>
  20#include <linux/soc/samsung/exynos-regs-pmu.h>
  21
  22#include <asm/cacheflush.h>
  23#include <asm/hardware/cache-l2x0.h>
  24#include <asm/mach/arch.h>
  25#include <asm/mach/map.h>
  26
  27#include <mach/map.h>
  28
  29#include "common.h"
  30#include "mfc.h"
  31
  32static struct map_desc exynos4_iodesc[] __initdata = {
  33        {
  34                .virtual        = (unsigned long)S5P_VA_SROMC,
  35                .pfn            = __phys_to_pfn(EXYNOS4_PA_SROMC),
  36                .length         = SZ_4K,
  37                .type           = MT_DEVICE,
  38        }, {
  39                .virtual        = (unsigned long)S5P_VA_CMU,
  40                .pfn            = __phys_to_pfn(EXYNOS4_PA_CMU),
  41                .length         = SZ_128K,
  42                .type           = MT_DEVICE,
  43        }, {
  44                .virtual        = (unsigned long)S5P_VA_COREPERI_BASE,
  45                .pfn            = __phys_to_pfn(EXYNOS4_PA_COREPERI),
  46                .length         = SZ_8K,
  47                .type           = MT_DEVICE,
  48        }, {
  49                .virtual        = (unsigned long)S5P_VA_DMC0,
  50                .pfn            = __phys_to_pfn(EXYNOS4_PA_DMC0),
  51                .length         = SZ_64K,
  52                .type           = MT_DEVICE,
  53        }, {
  54                .virtual        = (unsigned long)S5P_VA_DMC1,
  55                .pfn            = __phys_to_pfn(EXYNOS4_PA_DMC1),
  56                .length         = SZ_64K,
  57                .type           = MT_DEVICE,
  58        },
  59};
  60
  61static struct map_desc exynos5_iodesc[] __initdata = {
  62        {
  63                .virtual        = (unsigned long)S5P_VA_SROMC,
  64                .pfn            = __phys_to_pfn(EXYNOS5_PA_SROMC),
  65                .length         = SZ_4K,
  66                .type           = MT_DEVICE,
  67        },
  68};
  69
  70static struct platform_device exynos_cpuidle = {
  71        .name              = "exynos_cpuidle",
  72#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
  73        .dev.platform_data = exynos_enter_aftr,
  74#endif
  75        .id                = -1,
  76};
  77
  78void __iomem *sysram_base_addr;
  79void __iomem *sysram_ns_base_addr;
  80
  81void __init exynos_sysram_init(void)
  82{
  83        struct device_node *node;
  84
  85        for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram") {
  86                if (!of_device_is_available(node))
  87                        continue;
  88                sysram_base_addr = of_iomap(node, 0);
  89                break;
  90        }
  91
  92        for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram-ns") {
  93                if (!of_device_is_available(node))
  94                        continue;
  95                sysram_ns_base_addr = of_iomap(node, 0);
  96                break;
  97        }
  98}
  99
 100static void __init exynos_init_late(void)
 101{
 102        if (of_machine_is_compatible("samsung,exynos5440"))
 103                /* to be supported later */
 104                return;
 105
 106        exynos_pm_init();
 107}
 108
 109static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
 110                                        int depth, void *data)
 111{
 112        struct map_desc iodesc;
 113        const __be32 *reg;
 114        int len;
 115
 116        if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") &&
 117                !of_flat_dt_is_compatible(node, "samsung,exynos5440-clock"))
 118                return 0;
 119
 120        reg = of_get_flat_dt_prop(node, "reg", &len);
 121        if (reg == NULL || len != (sizeof(unsigned long) * 2))
 122                return 0;
 123
 124        iodesc.pfn = __phys_to_pfn(be32_to_cpu(reg[0]));
 125        iodesc.length = be32_to_cpu(reg[1]) - 1;
 126        iodesc.virtual = (unsigned long)S5P_VA_CHIPID;
 127        iodesc.type = MT_DEVICE;
 128        iotable_init(&iodesc, 1);
 129        return 1;
 130}
 131
 132/*
 133 * exynos_map_io
 134 *
 135 * register the standard cpu IO areas
 136 */
 137static void __init exynos_map_io(void)
 138{
 139        if (soc_is_exynos4())
 140                iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
 141
 142        if (soc_is_exynos5())
 143                iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
 144}
 145
 146static void __init exynos_init_io(void)
 147{
 148        debug_ll_io_init();
 149
 150        of_scan_flat_dt(exynos_fdt_map_chipid, NULL);
 151
 152        /* detect cpu id and rev. */
 153        s5p_init_cpu(S5P_VA_CHIPID);
 154
 155        exynos_map_io();
 156}
 157
 158/*
 159 * Set or clear the USE_DELAYED_RESET_ASSERTION option. Used by smp code
 160 * and suspend.
 161 *
 162 * This is necessary only on Exynos4 SoCs. When system is running
 163 * USE_DELAYED_RESET_ASSERTION should be set so the ARM CLK clock down
 164 * feature could properly detect global idle state when secondary CPU is
 165 * powered down.
 166 *
 167 * However this should not be set when such system is going into suspend.
 168 */
 169void exynos_set_delayed_reset_assertion(bool enable)
 170{
 171        if (of_machine_is_compatible("samsung,exynos4")) {
 172                unsigned int tmp, core_id;
 173
 174                for (core_id = 0; core_id < num_possible_cpus(); core_id++) {
 175                        tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id));
 176                        if (enable)
 177                                tmp |= S5P_USE_DELAYED_RESET_ASSERTION;
 178                        else
 179                                tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION);
 180                        pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id));
 181                }
 182        }
 183}
 184
 185/*
 186 * Apparently, these SoCs are not able to wake-up from suspend using
 187 * the PMU. Too bad. Should they suddenly become capable of such a
 188 * feat, the matches below should be moved to suspend.c.
 189 */
 190static const struct of_device_id exynos_dt_pmu_match[] = {
 191        { .compatible = "samsung,exynos5260-pmu" },
 192        { .compatible = "samsung,exynos5410-pmu" },
 193        { /*sentinel*/ },
 194};
 195
 196static void exynos_map_pmu(void)
 197{
 198        struct device_node *np;
 199
 200        np = of_find_matching_node(NULL, exynos_dt_pmu_match);
 201        if (np)
 202                pmu_base_addr = of_iomap(np, 0);
 203}
 204
 205static void __init exynos_init_irq(void)
 206{
 207        irqchip_init();
 208        /*
 209         * Since platsmp.c needs pmu base address by the time
 210         * DT is not unflatten so we can't use DT APIs before
 211         * init_irq
 212         */
 213        exynos_map_pmu();
 214}
 215
 216static const struct of_device_id exynos_cpufreq_matches[] = {
 217        { .compatible = "samsung,exynos3250", .data = "cpufreq-dt" },
 218        { .compatible = "samsung,exynos4210", .data = "cpufreq-dt" },
 219        { .compatible = "samsung,exynos4212", .data = "cpufreq-dt" },
 220        { .compatible = "samsung,exynos4412", .data = "cpufreq-dt" },
 221        { .compatible = "samsung,exynos5250", .data = "cpufreq-dt" },
 222#ifndef CONFIG_BL_SWITCHER
 223        { .compatible = "samsung,exynos5420", .data = "cpufreq-dt" },
 224        { .compatible = "samsung,exynos5800", .data = "cpufreq-dt" },
 225#endif
 226        { /* sentinel */ }
 227};
 228
 229static void __init exynos_cpufreq_init(void)
 230{
 231        struct device_node *root = of_find_node_by_path("/");
 232        const struct of_device_id *match;
 233
 234        match = of_match_node(exynos_cpufreq_matches, root);
 235        if (!match) {
 236                platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
 237                return;
 238        }
 239
 240        platform_device_register_simple(match->data, -1, NULL, 0);
 241}
 242
 243static void __init exynos_dt_machine_init(void)
 244{
 245        /*
 246         * This is called from smp_prepare_cpus if we've built for SMP, but
 247         * we still need to set it up for PM and firmware ops if not.
 248         */
 249        if (!IS_ENABLED(CONFIG_SMP))
 250                exynos_sysram_init();
 251
 252#if defined(CONFIG_SMP) && defined(CONFIG_ARM_EXYNOS_CPUIDLE)
 253        if (of_machine_is_compatible("samsung,exynos4210") ||
 254            of_machine_is_compatible("samsung,exynos3250"))
 255                exynos_cpuidle.dev.platform_data = &cpuidle_coupled_exynos_data;
 256#endif
 257        if (of_machine_is_compatible("samsung,exynos4210") ||
 258            of_machine_is_compatible("samsung,exynos4212") ||
 259            (of_machine_is_compatible("samsung,exynos4412") &&
 260             of_machine_is_compatible("samsung,trats2")) ||
 261            of_machine_is_compatible("samsung,exynos3250") ||
 262            of_machine_is_compatible("samsung,exynos5250"))
 263                platform_device_register(&exynos_cpuidle);
 264
 265        exynos_cpufreq_init();
 266
 267        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 268}
 269
 270static char const *const exynos_dt_compat[] __initconst = {
 271        "samsung,exynos3",
 272        "samsung,exynos3250",
 273        "samsung,exynos4",
 274        "samsung,exynos4210",
 275        "samsung,exynos4212",
 276        "samsung,exynos4412",
 277        "samsung,exynos4415",
 278        "samsung,exynos5",
 279        "samsung,exynos5250",
 280        "samsung,exynos5260",
 281        "samsung,exynos5420",
 282        "samsung,exynos5440",
 283        NULL
 284};
 285
 286static void __init exynos_reserve(void)
 287{
 288#ifdef CONFIG_S5P_DEV_MFC
 289        int i;
 290        char *mfc_mem[] = {
 291                "samsung,mfc-v5",
 292                "samsung,mfc-v6",
 293                "samsung,mfc-v7",
 294                "samsung,mfc-v8",
 295        };
 296
 297        for (i = 0; i < ARRAY_SIZE(mfc_mem); i++)
 298                if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i]))
 299                        break;
 300#endif
 301}
 302
 303static void __init exynos_dt_fixup(void)
 304{
 305        /*
 306         * Some versions of uboot pass garbage entries in the memory node,
 307         * use the old CONFIG_ARM_NR_BANKS
 308         */
 309        of_fdt_limit_memory(8);
 310}
 311
 312DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
 313        /* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
 314        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
 315        .l2c_aux_val    = 0x3c400001,
 316        .l2c_aux_mask   = 0xc20fffff,
 317        .smp            = smp_ops(exynos_smp_ops),
 318        .map_io         = exynos_init_io,
 319        .init_early     = exynos_firmware_init,
 320        .init_irq       = exynos_init_irq,
 321        .init_machine   = exynos_dt_machine_init,
 322        .init_late      = exynos_init_late,
 323        .dt_compat      = exynos_dt_compat,
 324        .reserve        = exynos_reserve,
 325        .dt_fixup       = exynos_dt_fixup,
 326MACHINE_END
 327