Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 Marvell International Ltd. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | * https://spdx.org/licenses |
| 6 | */ |
| 7 | |
Konstantin Porotchkin | 91db290 | 2018-07-29 13:30:51 +0300 | [diff] [blame] | 8 | #include <armada_common.h> |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 9 | #include <bl_common.h> |
| 10 | #include <ccu.h> |
| 11 | #include <cp110_setup.h> |
| 12 | #include <debug.h> |
| 13 | #include <marvell_plat_priv.h> /* timer functionality */ |
| 14 | #include <mmio.h> |
| 15 | #include <platform_def.h> |
| 16 | |
| 17 | #include "mss_scp_bootloader.h" |
| 18 | |
| 19 | /* IO windows configuration */ |
| 20 | #define IOW_GCR_OFFSET (0x70) |
| 21 | |
| 22 | /* MSS windows configuration */ |
| 23 | #define MSS_AEBR(base) (base + 0x160) |
| 24 | #define MSS_AIBR(base) (base + 0x164) |
| 25 | #define MSS_AEBR_MASK 0xFFF |
| 26 | #define MSS_AIBR_MASK 0xFFF |
| 27 | |
| 28 | #define MSS_EXTERNAL_SPACE 0x50000000 |
| 29 | #define MSS_EXTERNAL_ACCESS_BIT 28 |
| 30 | #define MSS_EXTERNAL_ADDR_MASK 0xfffffff |
| 31 | #define MSS_INTERNAL_ACCESS_BIT 28 |
| 32 | |
| 33 | struct addr_map_win ccu_mem_map[] = { |
| 34 | {MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID} |
| 35 | }; |
| 36 | |
| 37 | /* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors, |
| 38 | * the access to cp0 and cp1 need to be provided. More precisely it is |
| 39 | * required to: |
| 40 | * - get the information about device id which is stored in CP0 registers |
| 41 | * (to distinguish between cases where we have cp0 and cp1 or standalone cp0) |
| 42 | * - get the access to cp which is needed for loading fw for cp0/cp1 |
| 43 | * coprocessors |
| 44 | * This function configures ccu windows accordingly. |
| 45 | * |
| 46 | * Note: there is no need to restore previous ccu configuration, since in next |
| 47 | * phase (BL31) the init_ccu will be called (via apn806_init/ |
| 48 | * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten. |
| 49 | */ |
| 50 | static int bl2_plat_mmap_init(void) |
| 51 | { |
| 52 | int cfg_num, win_id, cfg_idx; |
| 53 | |
| 54 | cfg_num = ARRAY_SIZE(ccu_mem_map); |
| 55 | |
| 56 | /* CCU window-0 should not be counted - it's already used */ |
| 57 | if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) { |
| 58 | ERROR("BL2: %s: trying to open too many windows\n", __func__); |
| 59 | return -1; |
| 60 | } |
| 61 | |
| 62 | /* Enable required CCU windows |
| 63 | * Do not touch CCU window 0, |
| 64 | * it's used for the internal registers access |
| 65 | */ |
| 66 | for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) { |
| 67 | /* Enable required CCU windows */ |
| 68 | ccu_win_check(&ccu_mem_map[cfg_idx]); |
| 69 | ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id); |
| 70 | } |
| 71 | |
| 72 | /* Set the default target id to PIDI */ |
| 73 | mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID); |
| 74 | |
| 75 | return 0; |
| 76 | } |
| 77 | |
| 78 | /***************************************************************************** |
| 79 | * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. |
| 80 | * Return 0 on success, -1 otherwise. |
| 81 | ***************************************************************************** |
| 82 | */ |
| 83 | int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) |
| 84 | { |
| 85 | int ret; |
| 86 | |
| 87 | INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 88 | |
| 89 | /* initialize time (for delay functionality) */ |
| 90 | plat_delay_timer_init(); |
| 91 | |
| 92 | ret = bl2_plat_mmap_init(); |
| 93 | if (ret != 0) |
| 94 | return ret; |
| 95 | |
| 96 | ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base, |
| 97 | scp_bl2_image_info->image_size); |
| 98 | |
| 99 | if (ret == 0) |
| 100 | INFO("BL2: SCP_BL2 transferred to SCP\n"); |
| 101 | else |
| 102 | ERROR("BL2: SCP_BL2 transfer failure\n"); |
| 103 | |
| 104 | return ret; |
| 105 | } |
| 106 | |
| 107 | uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx) |
| 108 | { |
| 109 | return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000; |
| 110 | } |
| 111 | |
| 112 | uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx) |
| 113 | { |
| 114 | return MVEBU_REGS_BASE + 0x580000; |
| 115 | } |
| 116 | |
| 117 | uint32_t bl2_plat_get_cp_count(int ap_idx) |
| 118 | { |
| 119 | uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); |
| 120 | /* A8040: two CPs. |
| 121 | * A7040: one CP. |
| 122 | */ |
| 123 | if (revision == MVEBU_80X0_DEV_ID || |
| 124 | revision == MVEBU_80X0_CP115_DEV_ID) |
| 125 | return 2; |
| 126 | else |
| 127 | return 1; |
| 128 | } |
| 129 | |
| 130 | uint32_t bl2_plat_get_ap_count(void) |
| 131 | { |
| 132 | /* A8040 and A7040 have only one AP */ |
| 133 | return 1; |
| 134 | } |
| 135 | |
| 136 | void bl2_plat_configure_mss_windows(uintptr_t mss_regs) |
| 137 | { |
| 138 | /* set AXI External and Internal Address Bus extension */ |
| 139 | mmio_write_32(MSS_AEBR(mss_regs), |
| 140 | ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK)); |
| 141 | mmio_write_32(MSS_AIBR(mss_regs), |
| 142 | ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK)); |
| 143 | } |