xref: /OK3568_Linux_fs/u-boot/arch/arm/cpu/armv8/zynqmp/cpu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&regs);
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