exynos.c 6.9 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 222
	    of_machine_is_compatible("samsung,exynos4212") ||
	    (of_machine_is_compatible("samsung,exynos4412") &&
	     of_machine_is_compatible("samsung,trats2")) ||
	    of_machine_is_compatible("samsung,exynos5250"))
223
		platform_device_register(&exynos_cpuidle);
224

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

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

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

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

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

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