exynos.c 7.6 KB
Newer Older
1
/*
2
 * SAMSUNG EXYNOS Flattened Device Tree enabled machine
3
 *
4 5
 * Copyright (c) 2010-2014 Samsung Electronics Co., Ltd.
 *		http://www.samsung.com
6 7 8 9 10 11
 *
 * 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.
 */

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 19
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
20
#include <linux/platform_device.h>
21
#include <linux/pm_domain.h>
22
#include <linux/irqchip.h>
23

24
#include <asm/cacheflush.h>
25
#include <asm/hardware/cache-l2x0.h>
26
#include <asm/mach/arch.h>
27
#include <asm/mach/map.h>
28
#include <asm/memory.h>
29

30 31
#include <mach/map.h>

32
#include "common.h"
33
#include "mfc.h"
34 35
#include "regs-pmu.h"

36
void __iomem *pmu_base_addr;
37

38 39
static struct map_desc exynos4_iodesc[] __initdata = {
	{
40 41 42 43
		.virtual	= (unsigned long)S5P_VA_SROMC,
		.pfn		= __phys_to_pfn(EXYNOS4_PA_SROMC),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
44
	}, {
45 46 47 48 49 50 51 52 53 54 55 56
		.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),
57 58 59 60 61 62
		.length		= SZ_64K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S5P_VA_DMC1,
		.pfn		= __phys_to_pfn(EXYNOS4_PA_DMC1),
		.length		= SZ_64K,
63 64 65 66
		.type		= MT_DEVICE,
	},
};

67 68 69 70 71 72 73 74 75 76 77
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,
	}, {
		.virtual	= (unsigned long)S5P_VA_CMU,
		.pfn		= __phys_to_pfn(EXYNOS5_PA_CMU),
		.length		= 144 * SZ_1K,
		.type		= MT_DEVICE,
78 79 80
	},
};

81
static struct platform_device exynos_cpuidle = {
82
	.name              = "exynos_cpuidle",
83
#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
84
	.dev.platform_data = exynos_enter_aftr,
85
#endif
86
	.id                = -1,
87 88
};

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
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;
	}
}

111
static void __init exynos_init_late(void)
112
{
113 114 115 116
	if (of_machine_is_compatible("samsung,exynos5440"))
		/* to be supported later */
		return;

117
	exynos_pm_init();
118 119
}

120
static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
121 122 123
					int depth, void *data)
{
	struct map_desc iodesc;
124
	const __be32 *reg;
125
	int len;
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

	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;
}

143 144 145 146 147
/*
 * exynos_map_io
 *
 * register the standard cpu IO areas
 */
148 149
static void __init exynos_map_io(void)
{
150
	if (soc_is_exynos4())
151 152
		iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));

153
	if (soc_is_exynos5())
154 155
		iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
}
156

157
static void __init exynos_init_io(void)
158
{
159 160
	debug_ll_io_init();

161
	of_scan_flat_dt(exynos_fdt_map_chipid, NULL);
162

163 164 165
	/* detect cpu id and rev. */
	s5p_init_cpu(S5P_VA_CHIPID);

166
	exynos_map_io();
167 168
}

169 170 171 172 173 174 175 176 177 178 179 180 181
/*
 * 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)
{
182
	if (of_machine_is_compatible("samsung,exynos4")) {
183 184 185 186 187 188 189 190 191 192 193 194 195
		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));
		}
	}
}

196 197 198 199 200
/*
 * 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.
 */
201
static const struct of_device_id exynos_dt_pmu_match[] = {
202
	{ .compatible = "samsung,exynos5260-pmu" },
203
	{ .compatible = "samsung,exynos5410-pmu" },
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
	{ /*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();
}

227
static void __init exynos_dt_machine_init(void)
228
{
229 230 231 232
	/*
	 * 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.
	 */
233
	if (!IS_ENABLED(CONFIG_SMP))
234 235
		exynos_sysram_init();

236
#if defined(CONFIG_SMP) && defined(CONFIG_ARM_EXYNOS_CPUIDLE)
237 238 239
	if (of_machine_is_compatible("samsung,exynos4210"))
		exynos_cpuidle.dev.platform_data = &cpuidle_coupled_exynos_data;
#endif
240
	if (of_machine_is_compatible("samsung,exynos4210") ||
241 242 243
	    of_machine_is_compatible("samsung,exynos4212") ||
	    (of_machine_is_compatible("samsung,exynos4412") &&
	     of_machine_is_compatible("samsung,trats2")) ||
244
	    of_machine_is_compatible("samsung,exynos3250") ||
245
	    of_machine_is_compatible("samsung,exynos5250"))
246
		platform_device_register(&exynos_cpuidle);
247

248
	platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
249 250

	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
251
}
252

253
static char const *const exynos_dt_compat[] __initconst = {
254 255
	"samsung,exynos3",
	"samsung,exynos3250",
256
	"samsung,exynos4",
257 258 259
	"samsung,exynos4210",
	"samsung,exynos4212",
	"samsung,exynos4412",
260
	"samsung,exynos4415",
261
	"samsung,exynos5",
262
	"samsung,exynos5250",
263
	"samsung,exynos5260",
264 265 266 267 268 269 270 271 272 273 274 275 276
	"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",
277
		"samsung,mfc-v8",
278 279 280 281 282 283 284 285
	};

	for (i = 0; i < ARRAY_SIZE(mfc_mem); i++)
		if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i]))
			break;
#endif
}

286 287 288 289 290 291 292 293 294
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);
}

295 296 297
DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
	/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
298 299
	.l2c_aux_val	= 0x3c400001,
	.l2c_aux_mask	= 0xc20fffff,
300 301 302
	.smp		= smp_ops(exynos_smp_ops),
	.map_io		= exynos_init_io,
	.init_early	= exynos_firmware_init,
303
	.init_irq	= exynos_init_irq,
304 305 306 307
	.init_machine	= exynos_dt_machine_init,
	.init_late	= exynos_init_late,
	.dt_compat	= exynos_dt_compat,
	.reserve	= exynos_reserve,
308
	.dt_fixup	= exynos_dt_fixup,
309
MACHINE_END