aboutsummaryrefslogtreecommitdiff
path: root/plat/marvell/a8k/common/mss/mss_bl2_setup.c
blob: 21541855ba036ff1799a2f3c48060a4a5020fb03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (C) 2018 Marvell International Ltd.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 * https://spdx.org/licenses
 */

#include <a8k_common.h>
#include <bl_common.h>
#include <ccu.h>
#include <cp110_setup.h>
#include <debug.h>
#include <marvell_plat_priv.h> /* timer functionality */
#include <mmio.h>
#include <platform_def.h>

#include "mss_scp_bootloader.h"

/* IO windows configuration */
#define IOW_GCR_OFFSET		(0x70)

/* MSS windows configuration */
#define MSS_AEBR(base)			(base + 0x160)
#define MSS_AIBR(base)			(base + 0x164)
#define MSS_AEBR_MASK			0xFFF
#define MSS_AIBR_MASK			0xFFF

#define MSS_EXTERNAL_SPACE		0x50000000
#define MSS_EXTERNAL_ACCESS_BIT		28
#define MSS_EXTERNAL_ADDR_MASK		0xfffffff
#define MSS_INTERNAL_ACCESS_BIT		28

struct addr_map_win ccu_mem_map[] = {
	{MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
};

/* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors,
 * the access to cp0 and cp1 need to be provided. More precisely it is
 * required to:
 *  - get the information about device id which is stored in CP0 registers
 *    (to distinguish between cases where we have cp0 and cp1 or standalone cp0)
 *  - get the access to cp which is needed for loading fw for cp0/cp1
 *    coprocessors
 * This function configures ccu windows accordingly.
 *
 * Note: there is no need to restore previous ccu configuration, since in next
 * phase (BL31) the init_ccu will be called (via apn806_init/
 * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten.
 */
static int bl2_plat_mmap_init(void)
{
	int cfg_num, win_id, cfg_idx;

	cfg_num =  ARRAY_SIZE(ccu_mem_map);

	/* CCU window-0 should not be counted - it's already used */
	if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) {
		ERROR("BL2: %s: trying to open too many windows\n", __func__);
		return -1;
	}

	/* Enable required CCU windows
	 * Do not touch CCU window 0,
	 * it's used for the internal registers access
	 */
	for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) {
		/* Enable required CCU windows */
		ccu_win_check(&ccu_mem_map[cfg_idx]);
		ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
	}

	/* Set the default target id to PIDI */
	mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID);

	return 0;
}

/*****************************************************************************
 * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
 * Return 0 on success, -1 otherwise.
 *****************************************************************************
 */
int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
{
	int ret;

	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");

	/* initialize time (for delay functionality) */
	plat_delay_timer_init();

	ret = bl2_plat_mmap_init();
	if (ret != 0)
		return ret;

	ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base,
		scp_bl2_image_info->image_size);

	if (ret == 0)
		INFO("BL2: SCP_BL2 transferred to SCP\n");
	else
		ERROR("BL2: SCP_BL2 transfer failure\n");

	return ret;
}

uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
{
	return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000;
}

uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
{
	return MVEBU_REGS_BASE + 0x580000;
}

uint32_t bl2_plat_get_cp_count(int ap_idx)
{
	uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
	/* A8040: two CPs.
	 * A7040: one CP.
	 */
	if (revision == MVEBU_80X0_DEV_ID ||
	    revision == MVEBU_80X0_CP115_DEV_ID)
		return 2;
	else
		return 1;
}

uint32_t bl2_plat_get_ap_count(void)
{
	/* A8040 and A7040 have only one AP */
	return 1;
}

void bl2_plat_configure_mss_windows(uintptr_t mss_regs)
{
	/* set AXI External and Internal Address Bus extension */
	mmio_write_32(MSS_AEBR(mss_regs),
		      ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK));
	mmio_write_32(MSS_AIBR(mss_regs),
		      ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK));
}