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(®s);
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