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