180 lines
5.4 KiB
C
180 lines
5.4 KiB
C
/*
|
|
* 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;
|
|
}
|