1 /*
2 * Copyright (C) 2018 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
8 #include <platform_def.h>
9
10 #include <common/bl_common.h>
11 #include <common/debug.h>
12 #include <drivers/marvell/ccu.h>
13 #include <drivers/marvell/mochi/ap_setup.h>
14 #include <drivers/marvell/mochi/cp110_setup.h>
15 #include <lib/mmio.h>
16
17 #include <armada_common.h>
18 #include <marvell_plat_priv.h> /* timer functionality */
19 #include "mss_defs.h"
20 #include "mss_scp_bootloader.h"
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 */
bl2_plat_mmap_init(void)50 static int bl2_plat_mmap_init(void)
51 {
52 int cfg_num, win_id, cfg_idx, cp;
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;
67 (win_id < MVEBU_CCU_MAX_WINS) && (cfg_idx < cfg_num); win_id++) {
68 /* Skip already enabled CCU windows */
69 if (ccu_is_win_enabled(MVEBU_AP0, win_id))
70 continue;
71 /* Enable required CCU windows */
72 ccu_win_check(&ccu_mem_map[cfg_idx]);
73 ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
74 cfg_idx++;
75 }
76
77 /* Config address for each cp other than cp0 */
78 for (cp = 1; cp < CP_COUNT; cp++)
79 update_cp110_default_win(cp);
80
81 /* There is need to configure IO_WIN windows again to overwrite
82 * temporary configuration done during update_cp110_default_win
83 */
84 init_io_win(MVEBU_AP0);
85
86 /* Open AMB bridge required for MG access */
87 for (cp = 0; cp < CP_COUNT; cp++)
88 cp110_amb_init(MVEBU_CP_REGS_BASE(cp));
89
90 return 0;
91 }
92
93 /*****************************************************************************
94 * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
95 * Return 0 on success, -1 otherwise.
96 *****************************************************************************
97 */
bl2_plat_handle_scp_bl2(image_info_t * scp_bl2_image_info)98 int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
99 {
100 int ret;
101
102 INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
103
104 /* initialize time (for delay functionality) */
105 plat_delay_timer_init();
106
107 ret = bl2_plat_mmap_init();
108 if (ret != 0)
109 return ret;
110
111 ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base,
112 scp_bl2_image_info->image_size);
113
114 if (ret == 0)
115 INFO("BL2: SCP_BL2 transferred to SCP\n");
116 else
117 ERROR("BL2: SCP_BL2 transfer failure\n");
118
119 return ret;
120 }
121
bl2_plat_get_cp_mss_regs(int ap_idx,int cp_idx)122 uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
123 {
124 return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_REGS_OFFSET;
125 }
126
bl2_plat_get_cp_mss_sram(int ap_idx,int cp_idx)127 uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx)
128 {
129 return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET;
130 }
131
bl2_plat_get_ap_mss_regs(int ap_idx)132 uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
133 {
134 return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET;
135 }
136
bl2_plat_get_cp_count(int ap_idx)137 uint32_t bl2_plat_get_cp_count(int ap_idx)
138 {
139 uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
140 /* A8040: two CPs.
141 * A7040: one CP.
142 */
143 if (revision == MVEBU_80X0_DEV_ID ||
144 revision == MVEBU_80X0_CP115_DEV_ID)
145 return 2;
146 else if (revision == MVEBU_CN9130_DEV_ID)
147 return CP_COUNT;
148 else
149 return 1;
150 }
151
bl2_plat_get_ap_count(void)152 uint32_t bl2_plat_get_ap_count(void)
153 {
154 /* A8040 and A7040 have only one AP */
155 return 1;
156 }
157
bl2_plat_configure_mss_windows(uintptr_t mss_regs)158 void bl2_plat_configure_mss_windows(uintptr_t mss_regs)
159 {
160 /* set AXI External and Internal Address Bus extension */
161 mmio_write_32(MSS_AEBR(mss_regs),
162 ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK));
163 mmio_write_32(MSS_AIBR(mss_regs),
164 ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK));
165 }
166