1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file contains common code that is intended to be used across |
4 | * boards so that it's not replicated. |
5 | * |
6 | * Copyright (C) 2011 Xilinx |
7 | */ |
8 | |
9 | #include <linux/init.h> |
10 | #include <linux/io.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/cpumask.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/clk.h> |
15 | #include <linux/clk/zynq.h> |
16 | #include <linux/clocksource.h> |
17 | #include <linux/of_address.h> |
18 | #include <linux/of_clk.h> |
19 | #include <linux/of_irq.h> |
20 | #include <linux/of_platform.h> |
21 | #include <linux/of.h> |
22 | #include <linux/memblock.h> |
23 | #include <linux/irqchip.h> |
24 | #include <linux/irqchip/arm-gic.h> |
25 | #include <linux/slab.h> |
26 | #include <linux/sys_soc.h> |
27 | #include <linux/pgtable.h> |
28 | |
29 | #include <asm/mach/arch.h> |
30 | #include <asm/mach/map.h> |
31 | #include <asm/mach/time.h> |
32 | #include <asm/mach-types.h> |
33 | #include <asm/page.h> |
34 | #include <asm/smp_scu.h> |
35 | #include <asm/system_info.h> |
36 | #include <asm/hardware/cache-l2x0.h> |
37 | |
38 | #include "common.h" |
39 | |
40 | #define ZYNQ_DEVCFG_MCTRL 0x80 |
41 | #define ZYNQ_DEVCFG_PS_VERSION_SHIFT 28 |
42 | #define ZYNQ_DEVCFG_PS_VERSION_MASK 0xF |
43 | |
44 | void __iomem *zynq_scu_base; |
45 | |
46 | /** |
47 | * zynq_memory_init - Initialize special memory |
48 | * |
49 | * We need to stop things allocating the low memory as DMA can't work in |
50 | * the 1st 512K of memory. |
51 | */ |
52 | static void __init zynq_memory_init(void) |
53 | { |
54 | if (!__pa(PAGE_OFFSET)) |
55 | memblock_reserve(__pa(PAGE_OFFSET), size: 0x80000); |
56 | } |
57 | |
58 | static struct platform_device zynq_cpuidle_device = { |
59 | .name = "cpuidle-zynq" , |
60 | }; |
61 | |
62 | /** |
63 | * zynq_get_revision - Get Zynq silicon revision |
64 | * |
65 | * Return: Silicon version or -1 otherwise |
66 | */ |
67 | static int __init zynq_get_revision(void) |
68 | { |
69 | struct device_node *np; |
70 | void __iomem *zynq_devcfg_base; |
71 | u32 revision; |
72 | |
73 | np = of_find_compatible_node(NULL, NULL, compat: "xlnx,zynq-devcfg-1.0" ); |
74 | if (!np) { |
75 | pr_err("%s: no devcfg node found\n" , __func__); |
76 | return -1; |
77 | } |
78 | |
79 | zynq_devcfg_base = of_iomap(node: np, index: 0); |
80 | of_node_put(node: np); |
81 | if (!zynq_devcfg_base) { |
82 | pr_err("%s: Unable to map I/O memory\n" , __func__); |
83 | return -1; |
84 | } |
85 | |
86 | revision = readl(addr: zynq_devcfg_base + ZYNQ_DEVCFG_MCTRL); |
87 | revision >>= ZYNQ_DEVCFG_PS_VERSION_SHIFT; |
88 | revision &= ZYNQ_DEVCFG_PS_VERSION_MASK; |
89 | |
90 | iounmap(addr: zynq_devcfg_base); |
91 | |
92 | return revision; |
93 | } |
94 | |
95 | static void __init zynq_init_late(void) |
96 | { |
97 | zynq_core_pm_init(); |
98 | zynq_pm_late_init(); |
99 | } |
100 | |
101 | /** |
102 | * zynq_init_machine - System specific initialization, intended to be |
103 | * called from board specific initialization. |
104 | */ |
105 | static void __init zynq_init_machine(void) |
106 | { |
107 | struct soc_device_attribute *soc_dev_attr; |
108 | struct soc_device *soc_dev; |
109 | struct device *parent = NULL; |
110 | |
111 | soc_dev_attr = kzalloc(size: sizeof(*soc_dev_attr), GFP_KERNEL); |
112 | if (!soc_dev_attr) |
113 | goto out; |
114 | |
115 | system_rev = zynq_get_revision(); |
116 | |
117 | soc_dev_attr->family = kasprintf(GFP_KERNEL, fmt: "Xilinx Zynq" ); |
118 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, fmt: "0x%x" , system_rev); |
119 | soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, fmt: "0x%x" , |
120 | zynq_slcr_get_device_id()); |
121 | |
122 | soc_dev = soc_device_register(soc_plat_dev_attr: soc_dev_attr); |
123 | if (IS_ERR(ptr: soc_dev)) { |
124 | kfree(objp: soc_dev_attr->family); |
125 | kfree(objp: soc_dev_attr->revision); |
126 | kfree(objp: soc_dev_attr->soc_id); |
127 | kfree(objp: soc_dev_attr); |
128 | goto out; |
129 | } |
130 | |
131 | parent = soc_device_to_device(soc: soc_dev); |
132 | |
133 | out: |
134 | /* |
135 | * Finished with the static registrations now; fill in the missing |
136 | * devices |
137 | */ |
138 | of_platform_default_populate(NULL, NULL, parent); |
139 | |
140 | platform_device_register(&zynq_cpuidle_device); |
141 | } |
142 | |
143 | static void __init zynq_timer_init(void) |
144 | { |
145 | zynq_clock_init(); |
146 | of_clk_init(NULL); |
147 | timer_probe(); |
148 | } |
149 | |
150 | static struct map_desc zynq_cortex_a9_scu_map __initdata = { |
151 | .length = SZ_256, |
152 | .type = MT_DEVICE, |
153 | }; |
154 | |
155 | static void __init zynq_scu_map_io(void) |
156 | { |
157 | unsigned long base; |
158 | |
159 | base = scu_a9_get_base(); |
160 | zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base); |
161 | /* Expected address is in vmalloc area that's why simple assign here */ |
162 | zynq_cortex_a9_scu_map.virtual = base; |
163 | iotable_init(&zynq_cortex_a9_scu_map, 1); |
164 | zynq_scu_base = (void __iomem *)base; |
165 | BUG_ON(!zynq_scu_base); |
166 | } |
167 | |
168 | /** |
169 | * zynq_map_io - Create memory mappings needed for early I/O. |
170 | */ |
171 | static void __init zynq_map_io(void) |
172 | { |
173 | debug_ll_io_init(); |
174 | zynq_scu_map_io(); |
175 | } |
176 | |
177 | static void __init zynq_irq_init(void) |
178 | { |
179 | zynq_early_slcr_init(); |
180 | irqchip_init(); |
181 | } |
182 | |
183 | static const char * const zynq_dt_match[] = { |
184 | "xlnx,zynq-7000" , |
185 | NULL |
186 | }; |
187 | |
188 | DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform" ) |
189 | /* 64KB way size, 8-way associativity, parity disabled */ |
190 | .l2c_aux_val = 0x00400000, |
191 | .l2c_aux_mask = 0xffbfffff, |
192 | .smp = smp_ops(zynq_smp_ops), |
193 | .map_io = zynq_map_io, |
194 | .init_irq = zynq_irq_init, |
195 | .init_machine = zynq_init_machine, |
196 | .init_late = zynq_init_late, |
197 | .init_time = zynq_timer_init, |
198 | .dt_compat = zynq_dt_match, |
199 | .reserve = zynq_memory_init, |
200 | MACHINE_END |
201 | |