aboutsummaryrefslogtreecommitdiff
path: root/plat/marvell/a3700/common/io_addr_dec.c
blob: b27633cf25f0e12ed00658c86a021adfdc74e2a2 (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * Copyright (C) 2016 Marvell International Ltd.
 *
 * SPDX-License-Identifier:	BSD-3-Clause
 * https://spdx.org/licenses
 */

#include <common/debug.h>
#include <lib/mmio.h>

#include <io_addr_dec.h>
#include <plat_marvell.h>

#define MVEBU_DEC_WIN_CTRL_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
						(win) * (off))
#define MVEBU_DEC_WIN_BASE_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
						(win) * (off) + 0x4)
#define MVEBU_DEC_WIN_REMAP_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
						(win) * (off) + 0x8)

#define MVEBU_DEC_WIN_CTRL_SIZE_OFF		(16)
#define MVEBU_DEC_WIN_ENABLE			(0x1)
#define MVEBU_DEC_WIN_CTRL_ATTR_OFF		(8)
#define MVEBU_DEC_WIN_CTRL_TARGET_OFF		(4)
#define MVEBU_DEC_WIN_CTRL_EN_OFF		(0)
#define MVEBU_DEC_WIN_BASE_OFF			(16)

#define MVEBU_WIN_BASE_SIZE_ALIGNMENT		(0x10000)

/* There are up to 14 IO unit which need address decode in Armada-3700 */
#define IO_UNIT_NUM_MAX				(14)

#define MVEBU_MAX_ADDRSS_4GB			(0x100000000ULL)


static void set_io_addr_dec_win(int win_id, uintptr_t base_addr,
				uintptr_t win_size,
				struct dec_win_config *dec_win)
{
	uint32_t ctrl = 0;
	uint32_t base = 0;

	/* set size */
	ctrl = ((win_size / MVEBU_WIN_BASE_SIZE_ALIGNMENT) - 1) <<
	       MVEBU_DEC_WIN_CTRL_SIZE_OFF;
	/* set attr according to IO decode window */
	ctrl |= dec_win->win_attr << MVEBU_DEC_WIN_CTRL_ATTR_OFF;
	/* set target */
	ctrl |= DRAM_CPU_DEC_TARGET_NUM << MVEBU_DEC_WIN_CTRL_TARGET_OFF;
	/* set base */
	base = (base_addr / MVEBU_WIN_BASE_SIZE_ALIGNMENT) <<
	       MVEBU_DEC_WIN_BASE_OFF;

	/* set base address*/
	mmio_write_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
		      win_id, dec_win->win_offset),
		      base);
	/* set remap window, some unit does not have remap window */
	if (win_id < dec_win->max_remap)
		mmio_write_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
			      win_id, dec_win->win_offset), base);
	/* set control register */
	mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
		      win_id, dec_win->win_offset), ctrl);
	/* enable the address decode window at last to make it effective */
	ctrl |= MVEBU_DEC_WIN_ENABLE << MVEBU_DEC_WIN_CTRL_EN_OFF;
	mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
		      win_id, dec_win->win_offset), ctrl);

	INFO("set_io_addr_dec %d result: ctrl(0x%x) base(0x%x)",
	     win_id, mmio_read_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
	     win_id, dec_win->win_offset)),
	     mmio_read_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
			  win_id, dec_win->win_offset)));
	if (win_id < dec_win->max_remap)
		INFO(" remap(%x)\n",
		     mmio_read_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
		     win_id, dec_win->win_offset)));
	else
		INFO("\n");
}

/* Set io decode window */
static int set_io_addr_dec(struct dram_win_map *win_map,
			   struct dec_win_config *dec_win)
{
	struct dram_win *win;
	int id;

	/* disable all windows first */
	for (id = 0; id < dec_win->max_dram_win; id++)
		mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, id,
			      dec_win->win_offset), 0);

	/* configure IO decode windows for DRAM, inheritate DRAM size,
	 * base and target from CPU-DRAM decode window and others
	 * from hard coded IO decode window settings array.
	 */
	if (win_map->dram_win_num > dec_win->max_dram_win) {
		/*
		 * If cpu dram windows number exceeds the io decode windows
		 * max number, then fill the first io decode window
		 * with base(0) and size(4GB).
		 */
		set_io_addr_dec_win(0, 0, MVEBU_MAX_ADDRSS_4GB, dec_win);

		return 0;
	}

	for (id = 0; id < win_map->dram_win_num; id++, win++) {
		win = &win_map->dram_windows[id];
		set_io_addr_dec_win(id, win->base_addr, win->win_size, dec_win);
	}

	return 0;
}

/*
 * init_io_addr_dec
 *
 * This function initializes io address decoder windows by
 * cpu dram window mapping information
 *
 * @input: N/A
 *     - dram_wins_map: cpu dram windows mapping
 *     - io_dec_config: io address decoder windows configuration
 *     - io_unit_num: io address decoder unit number
 * @output: N/A
 *
 * @return:  0 on success and others on failure
 */
int init_io_addr_dec(struct dram_win_map *dram_wins_map,
		     struct dec_win_config *io_dec_config, uint32_t io_unit_num)
{
	int32_t index;
	struct dec_win_config *io_dec_win;
	int32_t ret;

	INFO("Initializing IO address decode windows\n");

	if (io_dec_config == NULL || io_unit_num == 0) {
		ERROR("No IO address decoder windows configurations!\n");
		return -1;
	}

	if (io_unit_num > IO_UNIT_NUM_MAX) {
		ERROR("IO address decoder windows number %d is over max %d\n",
		      io_unit_num, IO_UNIT_NUM_MAX);
		return -1;
	}

	if (dram_wins_map == NULL) {
		ERROR("No cpu dram decoder windows map!\n");
		return -1;
	}

	for (index = 0; index < dram_wins_map->dram_win_num; index++)
		INFO("DRAM mapping %d base(0x%lx) size(0x%lx)\n",
		     index, dram_wins_map->dram_windows[index].base_addr,
		     dram_wins_map->dram_windows[index].win_size);

	/* Set address decode window for each IO */
	for (index = 0; index < io_unit_num; index++) {
		io_dec_win = io_dec_config + index;
		ret = set_io_addr_dec(dram_wins_map, io_dec_win);
		if (ret) {
			ERROR("Failed to set IO address decode\n");
			return -1;
		}
		INFO("Set IO decode window successfully, base(0x%x)",
		     io_dec_win->dec_reg_base);
		INFO(" win_attr(%x) max_dram_win(%d) max_remap(%d)",
		     io_dec_win->win_attr, io_dec_win->max_dram_win,
		     io_dec_win->max_remap);
		INFO(" win_offset(%d)\n", io_dec_win->win_offset);
	}

	return 0;
}