/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #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 deocode 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 number %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) win_offset(%d)\n", io_dec_win->win_attr, io_dec_win->max_dram_win, io_dec_win->max_remap, io_dec_win->win_offset); } return 0; }