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