162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file contains common code that is intended to be used across
462306a36Sopenharmony_ci * boards so that it's not replicated.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2011 Xilinx
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/cpumask.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/clk/zynq.h>
1662306a36Sopenharmony_ci#include <linux/clocksource.h>
1762306a36Sopenharmony_ci#include <linux/of_address.h>
1862306a36Sopenharmony_ci#include <linux/of_clk.h>
1962306a36Sopenharmony_ci#include <linux/of_irq.h>
2062306a36Sopenharmony_ci#include <linux/of_platform.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/memblock.h>
2362306a36Sopenharmony_ci#include <linux/irqchip.h>
2462306a36Sopenharmony_ci#include <linux/irqchip/arm-gic.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci#include <linux/sys_soc.h>
2762306a36Sopenharmony_ci#include <linux/pgtable.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <asm/mach/arch.h>
3062306a36Sopenharmony_ci#include <asm/mach/map.h>
3162306a36Sopenharmony_ci#include <asm/mach/time.h>
3262306a36Sopenharmony_ci#include <asm/mach-types.h>
3362306a36Sopenharmony_ci#include <asm/page.h>
3462306a36Sopenharmony_ci#include <asm/smp_scu.h>
3562306a36Sopenharmony_ci#include <asm/system_info.h>
3662306a36Sopenharmony_ci#include <asm/hardware/cache-l2x0.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "common.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define ZYNQ_DEVCFG_MCTRL		0x80
4162306a36Sopenharmony_ci#define ZYNQ_DEVCFG_PS_VERSION_SHIFT	28
4262306a36Sopenharmony_ci#define ZYNQ_DEVCFG_PS_VERSION_MASK	0xF
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_civoid __iomem *zynq_scu_base;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * zynq_memory_init - Initialize special memory
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * We need to stop things allocating the low memory as DMA can't work in
5062306a36Sopenharmony_ci * the 1st 512K of memory.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic void __init zynq_memory_init(void)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	if (!__pa(PAGE_OFFSET))
5562306a36Sopenharmony_ci		memblock_reserve(__pa(PAGE_OFFSET), 0x80000);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic struct platform_device zynq_cpuidle_device = {
5962306a36Sopenharmony_ci	.name = "cpuidle-zynq",
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/**
6362306a36Sopenharmony_ci * zynq_get_revision - Get Zynq silicon revision
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * Return: Silicon version or -1 otherwise
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic int __init zynq_get_revision(void)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct device_node *np;
7062306a36Sopenharmony_ci	void __iomem *zynq_devcfg_base;
7162306a36Sopenharmony_ci	u32 revision;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-devcfg-1.0");
7462306a36Sopenharmony_ci	if (!np) {
7562306a36Sopenharmony_ci		pr_err("%s: no devcfg node found\n", __func__);
7662306a36Sopenharmony_ci		return -1;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	zynq_devcfg_base = of_iomap(np, 0);
8062306a36Sopenharmony_ci	of_node_put(np);
8162306a36Sopenharmony_ci	if (!zynq_devcfg_base) {
8262306a36Sopenharmony_ci		pr_err("%s: Unable to map I/O memory\n", __func__);
8362306a36Sopenharmony_ci		return -1;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	revision = readl(zynq_devcfg_base + ZYNQ_DEVCFG_MCTRL);
8762306a36Sopenharmony_ci	revision >>= ZYNQ_DEVCFG_PS_VERSION_SHIFT;
8862306a36Sopenharmony_ci	revision &= ZYNQ_DEVCFG_PS_VERSION_MASK;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	iounmap(zynq_devcfg_base);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return revision;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void __init zynq_init_late(void)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	zynq_core_pm_init();
9862306a36Sopenharmony_ci	zynq_pm_late_init();
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/**
10262306a36Sopenharmony_ci * zynq_init_machine - System specific initialization, intended to be
10362306a36Sopenharmony_ci *		       called from board specific initialization.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic void __init zynq_init_machine(void)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct soc_device_attribute *soc_dev_attr;
10862306a36Sopenharmony_ci	struct soc_device *soc_dev;
10962306a36Sopenharmony_ci	struct device *parent = NULL;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
11262306a36Sopenharmony_ci	if (!soc_dev_attr)
11362306a36Sopenharmony_ci		goto out;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	system_rev = zynq_get_revision();
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	soc_dev_attr->family = kasprintf(GFP_KERNEL, "Xilinx Zynq");
11862306a36Sopenharmony_ci	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "0x%x", system_rev);
11962306a36Sopenharmony_ci	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x",
12062306a36Sopenharmony_ci					 zynq_slcr_get_device_id());
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	soc_dev = soc_device_register(soc_dev_attr);
12362306a36Sopenharmony_ci	if (IS_ERR(soc_dev)) {
12462306a36Sopenharmony_ci		kfree(soc_dev_attr->family);
12562306a36Sopenharmony_ci		kfree(soc_dev_attr->revision);
12662306a36Sopenharmony_ci		kfree(soc_dev_attr->soc_id);
12762306a36Sopenharmony_ci		kfree(soc_dev_attr);
12862306a36Sopenharmony_ci		goto out;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	parent = soc_device_to_device(soc_dev);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciout:
13462306a36Sopenharmony_ci	/*
13562306a36Sopenharmony_ci	 * Finished with the static registrations now; fill in the missing
13662306a36Sopenharmony_ci	 * devices
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	of_platform_default_populate(NULL, NULL, parent);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	platform_device_register(&zynq_cpuidle_device);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void __init zynq_timer_init(void)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	zynq_clock_init();
14662306a36Sopenharmony_ci	of_clk_init(NULL);
14762306a36Sopenharmony_ci	timer_probe();
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic struct map_desc zynq_cortex_a9_scu_map __initdata = {
15162306a36Sopenharmony_ci	.length	= SZ_256,
15262306a36Sopenharmony_ci	.type	= MT_DEVICE,
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic void __init zynq_scu_map_io(void)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	unsigned long base;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	base = scu_a9_get_base();
16062306a36Sopenharmony_ci	zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base);
16162306a36Sopenharmony_ci	/* Expected address is in vmalloc area that's why simple assign here */
16262306a36Sopenharmony_ci	zynq_cortex_a9_scu_map.virtual = base;
16362306a36Sopenharmony_ci	iotable_init(&zynq_cortex_a9_scu_map, 1);
16462306a36Sopenharmony_ci	zynq_scu_base = (void __iomem *)base;
16562306a36Sopenharmony_ci	BUG_ON(!zynq_scu_base);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/**
16962306a36Sopenharmony_ci * zynq_map_io - Create memory mappings needed for early I/O.
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistatic void __init zynq_map_io(void)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	debug_ll_io_init();
17462306a36Sopenharmony_ci	zynq_scu_map_io();
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void __init zynq_irq_init(void)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	zynq_early_slcr_init();
18062306a36Sopenharmony_ci	irqchip_init();
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic const char * const zynq_dt_match[] = {
18462306a36Sopenharmony_ci	"xlnx,zynq-7000",
18562306a36Sopenharmony_ci	NULL
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ciDT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
18962306a36Sopenharmony_ci	/* 64KB way size, 8-way associativity, parity disabled */
19062306a36Sopenharmony_ci	.l2c_aux_val    = 0x00400000,
19162306a36Sopenharmony_ci	.l2c_aux_mask	= 0xffbfffff,
19262306a36Sopenharmony_ci	.smp		= smp_ops(zynq_smp_ops),
19362306a36Sopenharmony_ci	.map_io		= zynq_map_io,
19462306a36Sopenharmony_ci	.init_irq	= zynq_irq_init,
19562306a36Sopenharmony_ci	.init_machine	= zynq_init_machine,
19662306a36Sopenharmony_ci	.init_late	= zynq_init_late,
19762306a36Sopenharmony_ci	.init_time	= zynq_timer_init,
19862306a36Sopenharmony_ci	.dt_compat	= zynq_dt_match,
19962306a36Sopenharmony_ci	.reserve	= zynq_memory_init,
20062306a36Sopenharmony_ciMACHINE_END
201