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