1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2014 - 2015 Xilinx, Inc.
3*4882a593Smuzhiyun * Michal Simek <michal.simek@xilinx.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <asm/arch/hardware.h>
10*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
11*4882a593Smuzhiyun #include <asm/armv8/mmu.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define ZYNQ_SILICON_VER_MASK 0xF000
15*4882a593Smuzhiyun #define ZYNQ_SILICON_VER_SHIFT 12
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun static struct mm_region zynqmp_mem_map[] = {
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun .virt = 0x0UL,
22*4882a593Smuzhiyun .phys = 0x0UL,
23*4882a593Smuzhiyun .size = 0x80000000UL,
24*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
25*4882a593Smuzhiyun PTE_BLOCK_INNER_SHARE
26*4882a593Smuzhiyun }, {
27*4882a593Smuzhiyun .virt = 0x80000000UL,
28*4882a593Smuzhiyun .phys = 0x80000000UL,
29*4882a593Smuzhiyun .size = 0x70000000UL,
30*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
31*4882a593Smuzhiyun PTE_BLOCK_NON_SHARE |
32*4882a593Smuzhiyun PTE_BLOCK_PXN | PTE_BLOCK_UXN
33*4882a593Smuzhiyun }, {
34*4882a593Smuzhiyun .virt = 0xf8000000UL,
35*4882a593Smuzhiyun .phys = 0xf8000000UL,
36*4882a593Smuzhiyun .size = 0x07e00000UL,
37*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
38*4882a593Smuzhiyun PTE_BLOCK_NON_SHARE |
39*4882a593Smuzhiyun PTE_BLOCK_PXN | PTE_BLOCK_UXN
40*4882a593Smuzhiyun }, {
41*4882a593Smuzhiyun #if defined(CONFIG_DEFINE_TCM_OCM_MMAP)
42*4882a593Smuzhiyun .virt = 0xffe00000UL,
43*4882a593Smuzhiyun .phys = 0xffe00000UL,
44*4882a593Smuzhiyun .size = 0x00200000UL,
45*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
46*4882a593Smuzhiyun PTE_BLOCK_INNER_SHARE
47*4882a593Smuzhiyun }, {
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun .virt = 0x400000000UL,
50*4882a593Smuzhiyun .phys = 0x400000000UL,
51*4882a593Smuzhiyun .size = 0x200000000UL,
52*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
53*4882a593Smuzhiyun PTE_BLOCK_NON_SHARE |
54*4882a593Smuzhiyun PTE_BLOCK_PXN | PTE_BLOCK_UXN
55*4882a593Smuzhiyun }, {
56*4882a593Smuzhiyun .virt = 0x600000000UL,
57*4882a593Smuzhiyun .phys = 0x600000000UL,
58*4882a593Smuzhiyun .size = 0x800000000UL,
59*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
60*4882a593Smuzhiyun PTE_BLOCK_INNER_SHARE
61*4882a593Smuzhiyun }, {
62*4882a593Smuzhiyun .virt = 0xe00000000UL,
63*4882a593Smuzhiyun .phys = 0xe00000000UL,
64*4882a593Smuzhiyun .size = 0xf200000000UL,
65*4882a593Smuzhiyun .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
66*4882a593Smuzhiyun PTE_BLOCK_NON_SHARE |
67*4882a593Smuzhiyun PTE_BLOCK_PXN | PTE_BLOCK_UXN
68*4882a593Smuzhiyun }, {
69*4882a593Smuzhiyun /* List terminator */
70*4882a593Smuzhiyun 0,
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun struct mm_region *mem_map = zynqmp_mem_map;
74*4882a593Smuzhiyun
get_page_table_size(void)75*4882a593Smuzhiyun u64 get_page_table_size(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun return 0x14000;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
zynqmp_get_silicon_version_secure(void)80*4882a593Smuzhiyun static unsigned int zynqmp_get_silicon_version_secure(void)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun u32 ver;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun ver = readl(&csu_base->version);
85*4882a593Smuzhiyun ver &= ZYNQMP_SILICON_VER_MASK;
86*4882a593Smuzhiyun ver >>= ZYNQMP_SILICON_VER_SHIFT;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun return ver;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
zynqmp_get_silicon_version(void)91*4882a593Smuzhiyun unsigned int zynqmp_get_silicon_version(void)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun if (current_el() == 3)
94*4882a593Smuzhiyun return zynqmp_get_silicon_version_secure();
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun gd->cpu_clk = get_tbclk();
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun switch (gd->cpu_clk) {
99*4882a593Smuzhiyun case 0 ... 1000000:
100*4882a593Smuzhiyun return ZYNQMP_CSU_VERSION_VELOCE;
101*4882a593Smuzhiyun case 50000000:
102*4882a593Smuzhiyun return ZYNQMP_CSU_VERSION_QEMU;
103*4882a593Smuzhiyun case 4000000:
104*4882a593Smuzhiyun return ZYNQMP_CSU_VERSION_EP108;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return ZYNQMP_CSU_VERSION_SILICON;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun #define ZYNQMP_MMIO_READ 0xC2000014
111*4882a593Smuzhiyun #define ZYNQMP_MMIO_WRITE 0xC2000013
112*4882a593Smuzhiyun
invoke_smc(u32 pm_api_id,u32 arg0,u32 arg1,u32 arg2,u32 arg3,u32 * ret_payload)113*4882a593Smuzhiyun int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2,
114*4882a593Smuzhiyun u32 arg3, u32 *ret_payload)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun * Added SIP service call Function Identifier
118*4882a593Smuzhiyun * Make sure to stay in x0 register
119*4882a593Smuzhiyun */
120*4882a593Smuzhiyun struct pt_regs regs;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun regs.regs[0] = pm_api_id;
123*4882a593Smuzhiyun regs.regs[1] = ((u64)arg1 << 32) | arg0;
124*4882a593Smuzhiyun regs.regs[2] = ((u64)arg3 << 32) | arg2;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun smc_call(®s);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (ret_payload != NULL) {
129*4882a593Smuzhiyun ret_payload[0] = (u32)regs.regs[0];
130*4882a593Smuzhiyun ret_payload[1] = upper_32_bits(regs.regs[0]);
131*4882a593Smuzhiyun ret_payload[2] = (u32)regs.regs[1];
132*4882a593Smuzhiyun ret_payload[3] = upper_32_bits(regs.regs[1]);
133*4882a593Smuzhiyun ret_payload[4] = (u32)regs.regs[2];
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return regs.regs[0];
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define ZYNQMP_SIP_SVC_GET_API_VERSION 0xC2000001
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun #define ZYNQMP_PM_VERSION_MAJOR 0
142*4882a593Smuzhiyun #define ZYNQMP_PM_VERSION_MINOR 3
143*4882a593Smuzhiyun #define ZYNQMP_PM_VERSION_MAJOR_SHIFT 16
144*4882a593Smuzhiyun #define ZYNQMP_PM_VERSION_MINOR_MASK 0xFFFF
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun #define ZYNQMP_PM_VERSION \
147*4882a593Smuzhiyun ((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \
148*4882a593Smuzhiyun ZYNQMP_PM_VERSION_MINOR)
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun #if defined(CONFIG_CLK_ZYNQMP)
zynqmp_pmufw_version(void)151*4882a593Smuzhiyun void zynqmp_pmufw_version(void)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun int ret;
154*4882a593Smuzhiyun u32 ret_payload[PAYLOAD_ARG_CNT];
155*4882a593Smuzhiyun u32 pm_api_version;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0,
158*4882a593Smuzhiyun ret_payload);
159*4882a593Smuzhiyun pm_api_version = ret_payload[1];
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (ret)
162*4882a593Smuzhiyun panic("PMUFW is not found - Please load it!\n");
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun printf("PMUFW:\tv%d.%d\n",
165*4882a593Smuzhiyun pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
166*4882a593Smuzhiyun pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (pm_api_version != ZYNQMP_PM_VERSION)
169*4882a593Smuzhiyun panic("PMUFW version error. Expected: v%d.%d\n",
170*4882a593Smuzhiyun ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun #endif
173*4882a593Smuzhiyun
zynqmp_mmio_rawwrite(const u32 address,const u32 mask,const u32 value)174*4882a593Smuzhiyun static int zynqmp_mmio_rawwrite(const u32 address,
175*4882a593Smuzhiyun const u32 mask,
176*4882a593Smuzhiyun const u32 value)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun u32 data;
179*4882a593Smuzhiyun u32 value_local = value;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun zynqmp_mmio_read(address, &data);
182*4882a593Smuzhiyun data &= ~mask;
183*4882a593Smuzhiyun value_local &= mask;
184*4882a593Smuzhiyun value_local |= data;
185*4882a593Smuzhiyun writel(value_local, (ulong)address);
186*4882a593Smuzhiyun return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
zynqmp_mmio_rawread(const u32 address,u32 * value)189*4882a593Smuzhiyun static int zynqmp_mmio_rawread(const u32 address, u32 *value)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun *value = readl((ulong)address);
192*4882a593Smuzhiyun return 0;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
zynqmp_mmio_write(const u32 address,const u32 mask,const u32 value)195*4882a593Smuzhiyun int zynqmp_mmio_write(const u32 address,
196*4882a593Smuzhiyun const u32 mask,
197*4882a593Smuzhiyun const u32 value)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
200*4882a593Smuzhiyun return zynqmp_mmio_rawwrite(address, mask, value);
201*4882a593Smuzhiyun else if (!IS_ENABLED(CONFIG_SPL_BUILD))
202*4882a593Smuzhiyun return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask,
203*4882a593Smuzhiyun value, 0, NULL);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return -EINVAL;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
zynqmp_mmio_read(const u32 address,u32 * value)208*4882a593Smuzhiyun int zynqmp_mmio_read(const u32 address, u32 *value)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun u32 ret_payload[PAYLOAD_ARG_CNT];
211*4882a593Smuzhiyun u32 ret;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (!value)
214*4882a593Smuzhiyun return -EINVAL;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
217*4882a593Smuzhiyun ret = zynqmp_mmio_rawread(address, value);
218*4882a593Smuzhiyun } else if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
219*4882a593Smuzhiyun ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0,
220*4882a593Smuzhiyun 0, ret_payload);
221*4882a593Smuzhiyun *value = ret_payload[1];
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return ret;
225*4882a593Smuzhiyun }
226