1 /*
2 * Copyright (C) 2016 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
8 #include <common/debug.h>
9 #include <lib/mmio.h>
10
11 #include <io_addr_dec.h>
12 #include <plat_marvell.h>
13
14 #define MVEBU_DEC_WIN_CTRL_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \
15 (win) * (off))
16 #define MVEBU_DEC_WIN_BASE_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \
17 (win) * (off) + 0x4)
18 #define MVEBU_DEC_WIN_REMAP_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \
19 (win) * (off) + 0x8)
20
21 #define MVEBU_DEC_WIN_CTRL_SIZE_OFF (16)
22 #define MVEBU_DEC_WIN_ENABLE (0x1)
23 #define MVEBU_DEC_WIN_CTRL_ATTR_OFF (8)
24 #define MVEBU_DEC_WIN_CTRL_TARGET_OFF (4)
25 #define MVEBU_DEC_WIN_CTRL_EN_OFF (0)
26 #define MVEBU_DEC_WIN_BASE_OFF (16)
27
28 #define MVEBU_WIN_BASE_SIZE_ALIGNMENT (0x10000)
29
30 /* There are up to 14 IO unit which need address decode in Armada-3700 */
31 #define IO_UNIT_NUM_MAX (14)
32
33 #define MVEBU_MAX_ADDRSS_4GB (0x100000000ULL)
34
35
set_io_addr_dec_win(int win_id,uintptr_t base_addr,uintptr_t win_size,struct dec_win_config * dec_win)36 static void set_io_addr_dec_win(int win_id, uintptr_t base_addr,
37 uintptr_t win_size,
38 struct dec_win_config *dec_win)
39 {
40 uint32_t ctrl = 0;
41 uint32_t base = 0;
42
43 /* set size */
44 ctrl = ((win_size / MVEBU_WIN_BASE_SIZE_ALIGNMENT) - 1) <<
45 MVEBU_DEC_WIN_CTRL_SIZE_OFF;
46 /* set attr according to IO decode window */
47 ctrl |= dec_win->win_attr << MVEBU_DEC_WIN_CTRL_ATTR_OFF;
48 /* set target */
49 ctrl |= DRAM_CPU_DEC_TARGET_NUM << MVEBU_DEC_WIN_CTRL_TARGET_OFF;
50 /* set base */
51 base = (base_addr / MVEBU_WIN_BASE_SIZE_ALIGNMENT) <<
52 MVEBU_DEC_WIN_BASE_OFF;
53
54 /* set base address*/
55 mmio_write_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
56 win_id, dec_win->win_offset),
57 base);
58 /* set remap window, some unit does not have remap window */
59 if (win_id < dec_win->max_remap)
60 mmio_write_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
61 win_id, dec_win->win_offset), base);
62 /* set control register */
63 mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
64 win_id, dec_win->win_offset), ctrl);
65 /* enable the address decode window at last to make it effective */
66 ctrl |= MVEBU_DEC_WIN_ENABLE << MVEBU_DEC_WIN_CTRL_EN_OFF;
67 mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
68 win_id, dec_win->win_offset), ctrl);
69
70 INFO("set_io_addr_dec %d result: ctrl(0x%x) base(0x%x) remap(0x%x)\n",
71 win_id, mmio_read_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
72 win_id, dec_win->win_offset)),
73 mmio_read_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
74 win_id, dec_win->win_offset)),
75 (win_id < dec_win->max_remap) ?
76 mmio_read_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
77 win_id, dec_win->win_offset)) : 0);
78 }
79
80 /* Set io decode window */
set_io_addr_dec(struct dram_win_map * win_map,struct dec_win_config * dec_win)81 static int set_io_addr_dec(struct dram_win_map *win_map,
82 struct dec_win_config *dec_win)
83 {
84 struct dram_win *win;
85 int id;
86
87 /* disable all windows first */
88 for (id = 0; id < dec_win->max_dram_win; id++)
89 mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, id,
90 dec_win->win_offset), 0);
91
92 /* configure IO decode windows for DRAM, inheritate DRAM size,
93 * base and target from CPU-DRAM decode window and others
94 * from hard coded IO decode window settings array.
95 */
96 if (win_map->dram_win_num > dec_win->max_dram_win) {
97 /*
98 * If cpu dram windows number exceeds the io decode windows
99 * max number, then fill the first io decode window
100 * with base(0) and size(4GB).
101 */
102 set_io_addr_dec_win(0, 0, MVEBU_MAX_ADDRSS_4GB, dec_win);
103
104 return 0;
105 }
106
107 for (id = 0; id < win_map->dram_win_num; id++, win++) {
108 win = &win_map->dram_windows[id];
109 set_io_addr_dec_win(id, win->base_addr, win->win_size, dec_win);
110 }
111
112 return 0;
113 }
114
115 /*
116 * init_io_addr_dec
117 *
118 * This function initializes io address decoder windows by
119 * cpu dram window mapping information
120 *
121 * @input: N/A
122 * - dram_wins_map: cpu dram windows mapping
123 * - io_dec_config: io address decoder windows configuration
124 * - io_unit_num: io address decoder unit number
125 * @output: N/A
126 *
127 * @return: 0 on success and others on failure
128 */
init_io_addr_dec(struct dram_win_map * dram_wins_map,struct dec_win_config * io_dec_config,uint32_t io_unit_num)129 int init_io_addr_dec(struct dram_win_map *dram_wins_map,
130 struct dec_win_config *io_dec_config, uint32_t io_unit_num)
131 {
132 int32_t index;
133 struct dec_win_config *io_dec_win;
134 int32_t ret;
135
136 INFO("Initializing IO address decode windows\n");
137
138 if (io_dec_config == NULL || io_unit_num == 0) {
139 ERROR("No IO address decoder windows configurations!\n");
140 return -1;
141 }
142
143 if (io_unit_num > IO_UNIT_NUM_MAX) {
144 ERROR("IO address decoder windows number %d is over max %d\n",
145 io_unit_num, IO_UNIT_NUM_MAX);
146 return -1;
147 }
148
149 if (dram_wins_map == NULL) {
150 ERROR("No cpu dram decoder windows map!\n");
151 return -1;
152 }
153
154 for (index = 0; index < dram_wins_map->dram_win_num; index++)
155 INFO("DRAM mapping %d base(0x%lx) size(0x%lx)\n",
156 index, dram_wins_map->dram_windows[index].base_addr,
157 dram_wins_map->dram_windows[index].win_size);
158
159 /* Set address decode window for each IO */
160 for (index = 0; index < io_unit_num; index++) {
161 io_dec_win = io_dec_config + index;
162 ret = set_io_addr_dec(dram_wins_map, io_dec_win);
163 if (ret) {
164 ERROR("Failed to set IO address decode\n");
165 return -1;
166 }
167 INFO("Set IO decode window successfully, base(0x%x)"
168 " win_attr(%x) max_dram_win(%d) max_remap(%d)"
169 " win_offset(%d)\n", io_dec_win->dec_reg_base,
170 io_dec_win->win_attr, io_dec_win->max_dram_win,
171 io_dec_win->max_remap, io_dec_win->win_offset);
172 }
173
174 return 0;
175 }
176