exynos.c 7.0 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
static const struct of_device_id exynos_dt_pmu_match[] = {
	{ .compatible = "samsung,exynos3250-pmu" },
	{ .compatible = "samsung,exynos4210-pmu" },
	{ .compatible = "samsung,exynos4212-pmu" },
	{ .compatible = "samsung,exynos4412-pmu" },
174
	{ .compatible = "samsung,exynos4415-pmu" },
175
	{ .compatible = "samsung,exynos5250-pmu" },
176
	{ .compatible = "samsung,exynos5260-pmu" },
177
	{ .compatible = "samsung,exynos5410-pmu" },
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
	{ .compatible = "samsung,exynos5420-pmu" },
	{ /*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);

	if (!pmu_base_addr)
		panic("failed to find exynos pmu register\n");
}

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

205
static void __init exynos_dt_machine_init(void)
206
{
207 208 209 210
	/*
	 * 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.
	 */
211
	if (!IS_ENABLED(CONFIG_SMP))
212 213
		exynos_sysram_init();

214 215 216 217
#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
	if (of_machine_is_compatible("samsung,exynos4210"))
		exynos_cpuidle.dev.platform_data = &cpuidle_coupled_exynos_data;
#endif
218
	if (of_machine_is_compatible("samsung,exynos4210") ||
219 220 221
	    of_machine_is_compatible("samsung,exynos4212") ||
	    (of_machine_is_compatible("samsung,exynos4412") &&
	     of_machine_is_compatible("samsung,trats2")) ||
222
	    of_machine_is_compatible("samsung,exynos3250") ||
223
	    of_machine_is_compatible("samsung,exynos5250"))
224
		platform_device_register(&exynos_cpuidle);
225

226
	platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
227 228

	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
229
}
230

231
static char const *const exynos_dt_compat[] __initconst = {
232 233
	"samsung,exynos3",
	"samsung,exynos3250",
234
	"samsung,exynos4",
235 236 237
	"samsung,exynos4210",
	"samsung,exynos4212",
	"samsung,exynos4412",
238
	"samsung,exynos4415",
239
	"samsung,exynos5",
240
	"samsung,exynos5250",
241
	"samsung,exynos5260",
242 243 244 245 246 247 248 249 250 251 252 253 254
	"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",
255
		"samsung,mfc-v8",
256 257 258 259 260 261 262 263
	};

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

264 265 266 267 268 269 270 271 272
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);
}

273 274 275
DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
	/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
276 277
	.l2c_aux_val	= 0x3c400001,
	.l2c_aux_mask	= 0xc20fffff,
278 279 280
	.smp		= smp_ops(exynos_smp_ops),
	.map_io		= exynos_init_io,
	.init_early	= exynos_firmware_init,
281
	.init_irq	= exynos_init_irq,
282 283 284 285
	.init_machine	= exynos_dt_machine_init,
	.init_late	= exynos_init_late,
	.dt_compat	= exynos_dt_compat,
	.reserve	= exynos_reserve,
286
	.dt_fixup	= exynos_dt_fixup,
287
MACHINE_END