xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/zynqmp/cpu.c (revision fe84c48eeb8e9cb0b8b80a4c0a53bb089adff9af)
184c7204bSMichal Simek /*
284c7204bSMichal Simek  * (C) Copyright 2014 - 2015 Xilinx, Inc.
384c7204bSMichal Simek  * Michal Simek <michal.simek@xilinx.com>
484c7204bSMichal Simek  *
584c7204bSMichal Simek  * SPDX-License-Identifier:	GPL-2.0+
684c7204bSMichal Simek  */
784c7204bSMichal Simek 
884c7204bSMichal Simek #include <common.h>
984c7204bSMichal Simek #include <asm/arch/hardware.h>
1084c7204bSMichal Simek #include <asm/arch/sys_proto.h>
1196519f31SAlexander Graf #include <asm/armv8/mmu.h>
1284c7204bSMichal Simek #include <asm/io.h>
1384c7204bSMichal Simek 
1484c7204bSMichal Simek #define ZYNQ_SILICON_VER_MASK	0xF000
1584c7204bSMichal Simek #define ZYNQ_SILICON_VER_SHIFT	12
1684c7204bSMichal Simek 
1784c7204bSMichal Simek DECLARE_GLOBAL_DATA_PTR;
1884c7204bSMichal Simek 
1996519f31SAlexander Graf static struct mm_region zynqmp_mem_map[] = {
2096519f31SAlexander Graf 	{
21cd4b0c5fSYork Sun 		.virt = 0x0UL,
22cd4b0c5fSYork Sun 		.phys = 0x0UL,
2396519f31SAlexander Graf 		.size = 0x80000000UL,
2496519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
2596519f31SAlexander Graf 			 PTE_BLOCK_INNER_SHARE
2696519f31SAlexander Graf 	}, {
27cd4b0c5fSYork Sun 		.virt = 0x80000000UL,
28cd4b0c5fSYork Sun 		.phys = 0x80000000UL,
2996519f31SAlexander Graf 		.size = 0x70000000UL,
3096519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
3196519f31SAlexander Graf 			 PTE_BLOCK_NON_SHARE |
3296519f31SAlexander Graf 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
3396519f31SAlexander Graf 	}, {
34cd4b0c5fSYork Sun 		.virt = 0xf8000000UL,
35cd4b0c5fSYork Sun 		.phys = 0xf8000000UL,
3696519f31SAlexander Graf 		.size = 0x07e00000UL,
3796519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
3896519f31SAlexander Graf 			 PTE_BLOCK_NON_SHARE |
3996519f31SAlexander Graf 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
4096519f31SAlexander Graf 	}, {
41189bec47SSiva Durga Prasad Paladugu #if defined(CONFIG_DEFINE_TCM_OCM_MMAP)
42189bec47SSiva Durga Prasad Paladugu 		.virt = 0xffe00000UL,
43189bec47SSiva Durga Prasad Paladugu 		.phys = 0xffe00000UL,
44189bec47SSiva Durga Prasad Paladugu 		.size = 0x00200000UL,
45189bec47SSiva Durga Prasad Paladugu 		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
46189bec47SSiva Durga Prasad Paladugu 			 PTE_BLOCK_INNER_SHARE
47189bec47SSiva Durga Prasad Paladugu 	}, {
48189bec47SSiva Durga Prasad Paladugu #endif
49cd4b0c5fSYork Sun 		.virt = 0x400000000UL,
50cd4b0c5fSYork Sun 		.phys = 0x400000000UL,
5196519f31SAlexander Graf 		.size = 0x200000000UL,
5296519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
5396519f31SAlexander Graf 			 PTE_BLOCK_NON_SHARE |
5496519f31SAlexander Graf 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
5596519f31SAlexander Graf 	}, {
56cd4b0c5fSYork Sun 		.virt = 0x600000000UL,
57cd4b0c5fSYork Sun 		.phys = 0x600000000UL,
5896519f31SAlexander Graf 		.size = 0x800000000UL,
5996519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
6096519f31SAlexander Graf 			 PTE_BLOCK_INNER_SHARE
6196519f31SAlexander Graf 	}, {
62cd4b0c5fSYork Sun 		.virt = 0xe00000000UL,
63cd4b0c5fSYork Sun 		.phys = 0xe00000000UL,
6496519f31SAlexander Graf 		.size = 0xf200000000UL,
6596519f31SAlexander Graf 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
6696519f31SAlexander Graf 			 PTE_BLOCK_NON_SHARE |
6796519f31SAlexander Graf 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
6896519f31SAlexander Graf 	}, {
6996519f31SAlexander Graf 		/* List terminator */
7096519f31SAlexander Graf 		0,
7196519f31SAlexander Graf 	}
7296519f31SAlexander Graf };
7396519f31SAlexander Graf struct mm_region *mem_map = zynqmp_mem_map;
7496519f31SAlexander Graf 
get_page_table_size(void)759c152eddSMichal Simek u64 get_page_table_size(void)
769c152eddSMichal Simek {
779c152eddSMichal Simek 	return 0x14000;
789c152eddSMichal Simek }
799c152eddSMichal Simek 
zynqmp_get_silicon_version_secure(void)800785dfd8SMichal Simek static unsigned int zynqmp_get_silicon_version_secure(void)
810785dfd8SMichal Simek {
820785dfd8SMichal Simek 	u32 ver;
830785dfd8SMichal Simek 
840785dfd8SMichal Simek 	ver = readl(&csu_base->version);
850785dfd8SMichal Simek 	ver &= ZYNQMP_SILICON_VER_MASK;
860785dfd8SMichal Simek 	ver >>= ZYNQMP_SILICON_VER_SHIFT;
870785dfd8SMichal Simek 
880785dfd8SMichal Simek 	return ver;
890785dfd8SMichal Simek }
900785dfd8SMichal Simek 
zynqmp_get_silicon_version(void)9184c7204bSMichal Simek unsigned int zynqmp_get_silicon_version(void)
9284c7204bSMichal Simek {
930785dfd8SMichal Simek 	if (current_el() == 3)
940785dfd8SMichal Simek 		return zynqmp_get_silicon_version_secure();
950785dfd8SMichal Simek 
9684c7204bSMichal Simek 	gd->cpu_clk = get_tbclk();
9784c7204bSMichal Simek 
9884c7204bSMichal Simek 	switch (gd->cpu_clk) {
9916247d28SMichal Simek 	case 0 ... 1000000:
10016247d28SMichal Simek 		return ZYNQMP_CSU_VERSION_VELOCE;
10184c7204bSMichal Simek 	case 50000000:
10284c7204bSMichal Simek 		return ZYNQMP_CSU_VERSION_QEMU;
103be6f6af1SMichal Simek 	case 4000000:
104be6f6af1SMichal Simek 		return ZYNQMP_CSU_VERSION_EP108;
10584c7204bSMichal Simek 	}
10684c7204bSMichal Simek 
107be6f6af1SMichal Simek 	return ZYNQMP_CSU_VERSION_SILICON;
10884c7204bSMichal Simek }
109e0752bc1SSiva Durga Prasad Paladugu 
110e0752bc1SSiva Durga Prasad Paladugu #define ZYNQMP_MMIO_READ	0xC2000014
111e0752bc1SSiva Durga Prasad Paladugu #define ZYNQMP_MMIO_WRITE	0xC2000013
112e0752bc1SSiva Durga Prasad Paladugu 
invoke_smc(u32 pm_api_id,u32 arg0,u32 arg1,u32 arg2,u32 arg3,u32 * ret_payload)113*cb186e74SSiva Durga Prasad Paladugu int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2,
114*cb186e74SSiva Durga Prasad Paladugu 			      u32 arg3, u32 *ret_payload)
115e0752bc1SSiva Durga Prasad Paladugu {
116e0752bc1SSiva Durga Prasad Paladugu 	/*
117e0752bc1SSiva Durga Prasad Paladugu 	 * Added SIP service call Function Identifier
118e0752bc1SSiva Durga Prasad Paladugu 	 * Make sure to stay in x0 register
119e0752bc1SSiva Durga Prasad Paladugu 	 */
120e0752bc1SSiva Durga Prasad Paladugu 	struct pt_regs regs;
121e0752bc1SSiva Durga Prasad Paladugu 
122e0752bc1SSiva Durga Prasad Paladugu 	regs.regs[0] = pm_api_id;
123e0752bc1SSiva Durga Prasad Paladugu 	regs.regs[1] = ((u64)arg1 << 32) | arg0;
124e0752bc1SSiva Durga Prasad Paladugu 	regs.regs[2] = ((u64)arg3 << 32) | arg2;
125e0752bc1SSiva Durga Prasad Paladugu 
126e0752bc1SSiva Durga Prasad Paladugu 	smc_call(&regs);
127e0752bc1SSiva Durga Prasad Paladugu 
128e0752bc1SSiva Durga Prasad Paladugu 	if (ret_payload != NULL) {
129e0752bc1SSiva Durga Prasad Paladugu 		ret_payload[0] = (u32)regs.regs[0];
130e0752bc1SSiva Durga Prasad Paladugu 		ret_payload[1] = upper_32_bits(regs.regs[0]);
131e0752bc1SSiva Durga Prasad Paladugu 		ret_payload[2] = (u32)regs.regs[1];
132e0752bc1SSiva Durga Prasad Paladugu 		ret_payload[3] = upper_32_bits(regs.regs[1]);
133e0752bc1SSiva Durga Prasad Paladugu 		ret_payload[4] = (u32)regs.regs[2];
134e0752bc1SSiva Durga Prasad Paladugu 	}
135e0752bc1SSiva Durga Prasad Paladugu 
136e0752bc1SSiva Durga Prasad Paladugu 	return regs.regs[0];
137e0752bc1SSiva Durga Prasad Paladugu }
138e0752bc1SSiva Durga Prasad Paladugu 
139fb4000e8SMichal Simek #define ZYNQMP_SIP_SVC_GET_API_VERSION		0xC2000001
140fb4000e8SMichal Simek 
141fb4000e8SMichal Simek #define ZYNQMP_PM_VERSION_MAJOR		0
142fb4000e8SMichal Simek #define ZYNQMP_PM_VERSION_MINOR		3
143fb4000e8SMichal Simek #define ZYNQMP_PM_VERSION_MAJOR_SHIFT	16
144fb4000e8SMichal Simek #define ZYNQMP_PM_VERSION_MINOR_MASK	0xFFFF
145fb4000e8SMichal Simek 
146fb4000e8SMichal Simek #define ZYNQMP_PM_VERSION	\
147fb4000e8SMichal Simek 	((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \
148fb4000e8SMichal Simek 				 ZYNQMP_PM_VERSION_MINOR)
149fb4000e8SMichal Simek 
150fb4000e8SMichal Simek #if defined(CONFIG_CLK_ZYNQMP)
zynqmp_pmufw_version(void)151fb4000e8SMichal Simek void zynqmp_pmufw_version(void)
152fb4000e8SMichal Simek {
153fb4000e8SMichal Simek 	int ret;
154fb4000e8SMichal Simek 	u32 ret_payload[PAYLOAD_ARG_CNT];
155fb4000e8SMichal Simek 	u32 pm_api_version;
156fb4000e8SMichal Simek 
157fb4000e8SMichal Simek 	ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0,
158fb4000e8SMichal Simek 			 ret_payload);
159fb4000e8SMichal Simek 	pm_api_version = ret_payload[1];
160fb4000e8SMichal Simek 
161fb4000e8SMichal Simek 	if (ret)
162fb4000e8SMichal Simek 		panic("PMUFW is not found - Please load it!\n");
163fb4000e8SMichal Simek 
164fb4000e8SMichal Simek 	printf("PMUFW:\tv%d.%d\n",
165fb4000e8SMichal Simek 	       pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
166fb4000e8SMichal Simek 	       pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK);
167fb4000e8SMichal Simek 
168fb4000e8SMichal Simek 	if (pm_api_version != ZYNQMP_PM_VERSION)
169fb4000e8SMichal Simek 		panic("PMUFW version error. Expected: v%d.%d\n",
170fb4000e8SMichal Simek 		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
171fb4000e8SMichal Simek }
172fb4000e8SMichal Simek #endif
173fb4000e8SMichal Simek 
zynqmp_mmio_rawwrite(const u32 address,const u32 mask,const u32 value)174*cb186e74SSiva Durga Prasad Paladugu static int zynqmp_mmio_rawwrite(const u32 address,
175e0752bc1SSiva Durga Prasad Paladugu 		      const u32 mask,
176e0752bc1SSiva Durga Prasad Paladugu 		      const u32 value)
177e0752bc1SSiva Durga Prasad Paladugu {
178e0752bc1SSiva Durga Prasad Paladugu 	u32 data;
179e0752bc1SSiva Durga Prasad Paladugu 	u32 value_local = value;
180e0752bc1SSiva Durga Prasad Paladugu 
181e0752bc1SSiva Durga Prasad Paladugu 	zynqmp_mmio_read(address, &data);
182e0752bc1SSiva Durga Prasad Paladugu 	data &= ~mask;
183e0752bc1SSiva Durga Prasad Paladugu 	value_local &= mask;
184e0752bc1SSiva Durga Prasad Paladugu 	value_local |= data;
185e0752bc1SSiva Durga Prasad Paladugu 	writel(value_local, (ulong)address);
186e0752bc1SSiva Durga Prasad Paladugu 	return 0;
187e0752bc1SSiva Durga Prasad Paladugu }
188e0752bc1SSiva Durga Prasad Paladugu 
zynqmp_mmio_rawread(const u32 address,u32 * value)189*cb186e74SSiva Durga Prasad Paladugu static int zynqmp_mmio_rawread(const u32 address, u32 *value)
190e0752bc1SSiva Durga Prasad Paladugu {
191e0752bc1SSiva Durga Prasad Paladugu 	*value = readl((ulong)address);
192e0752bc1SSiva Durga Prasad Paladugu 	return 0;
193e0752bc1SSiva Durga Prasad Paladugu }
194*cb186e74SSiva Durga Prasad Paladugu 
zynqmp_mmio_write(const u32 address,const u32 mask,const u32 value)195*cb186e74SSiva Durga Prasad Paladugu int zynqmp_mmio_write(const u32 address,
196*cb186e74SSiva Durga Prasad Paladugu 		      const u32 mask,
197*cb186e74SSiva Durga Prasad Paladugu 		      const u32 value)
198*cb186e74SSiva Durga Prasad Paladugu {
199*cb186e74SSiva Durga Prasad Paladugu 	if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
200*cb186e74SSiva Durga Prasad Paladugu 		return zynqmp_mmio_rawwrite(address, mask, value);
201*cb186e74SSiva Durga Prasad Paladugu 	else if (!IS_ENABLED(CONFIG_SPL_BUILD))
202*cb186e74SSiva Durga Prasad Paladugu 		return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask,
203*cb186e74SSiva Durga Prasad Paladugu 				  value, 0, NULL);
204*cb186e74SSiva Durga Prasad Paladugu 
205*cb186e74SSiva Durga Prasad Paladugu 	return -EINVAL;
206*cb186e74SSiva Durga Prasad Paladugu }
207*cb186e74SSiva Durga Prasad Paladugu 
zynqmp_mmio_read(const u32 address,u32 * value)208*cb186e74SSiva Durga Prasad Paladugu int zynqmp_mmio_read(const u32 address, u32 *value)
209*cb186e74SSiva Durga Prasad Paladugu {
210*cb186e74SSiva Durga Prasad Paladugu 	u32 ret_payload[PAYLOAD_ARG_CNT];
211*cb186e74SSiva Durga Prasad Paladugu 	u32 ret;
212*cb186e74SSiva Durga Prasad Paladugu 
213*cb186e74SSiva Durga Prasad Paladugu 	if (!value)
214*cb186e74SSiva Durga Prasad Paladugu 		return -EINVAL;
215*cb186e74SSiva Durga Prasad Paladugu 
216*cb186e74SSiva Durga Prasad Paladugu 	if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
217*cb186e74SSiva Durga Prasad Paladugu 		ret = zynqmp_mmio_rawread(address, value);
218*cb186e74SSiva Durga Prasad Paladugu 	} else if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
219*cb186e74SSiva Durga Prasad Paladugu 		ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0,
220*cb186e74SSiva Durga Prasad Paladugu 				 0, ret_payload);
221*cb186e74SSiva Durga Prasad Paladugu 		*value = ret_payload[1];
222*cb186e74SSiva Durga Prasad Paladugu 	}
223*cb186e74SSiva Durga Prasad Paladugu 
224*cb186e74SSiva Durga Prasad Paladugu 	return ret;
225*cb186e74SSiva Durga Prasad Paladugu }
226