// SPDX-License-Identifier: GPL-2.0-only /* * Address map functions for Marvell EBU SoCs (Kirkwood, Armada * 370/XP, Dove, Orion5x and MV78xx0) * * The Marvell EBU SoCs have a configurable physical address space: * the physical address at which certain devices (PCIe, NOR, NAND, * etc.) sit can be configured. The configuration takes place through * two sets of registers: * * - One to configure the access of the CPU to the devices. Depending * on the families, there are between 8 and 20 configurable windows, * each can be use to create a physical memory window that maps to a * specific device. Devices are identified by a tuple (target, * attribute). * * - One to configure the access to the CPU to the SDRAM. There are * either 2 (for Dove) or 4 (for other families) windows to map the * SDRAM into the physical address space. * * This driver: * * - Reads out the SDRAM address decoding windows at initialization * time, and fills the mvebu_mbus_dram_info structure with these * information. The exported function mv_mbus_dram_info() allow * device drivers to get those information related to the SDRAM * address decoding windows. This is because devices also have their * own windows (configured through registers that are part of each * device register space), and therefore the drivers for Marvell * devices have to configure those device -> SDRAM windows to ensure * that DMA works properly. * * - Provides an API for platform code or device drivers to * dynamically add or remove address decoding windows for the CPU -> * device accesses. This API is mvebu_mbus_add_window_by_id(), * mvebu_mbus_add_window_remap_by_id() and * mvebu_mbus_del_window(). * * - Provides a debugfs interface in /sys/kernel/debug/mvebu-mbus/ to * see the list of CPU -> SDRAM windows and their configuration * (file 'sdram') and the list of CPU -> devices windows and their * configuration (file 'devices').
*/
/* * Used to store the state of one MBus window across suspend/resume.
*/ struct mvebu_mbus_win_data {
u32 ctrl;
u32 base;
u32 remap_lo;
u32 remap_hi;
};
/* Used during suspend/resume */
u32 mbus_bridge_ctrl;
u32 mbus_bridge_base; struct mvebu_mbus_win_data wins[MBUS_WINS_MAX];
};
staticstruct mvebu_mbus_state mbus_state;
/* * We provide two variants of the mv_mbus_dram_info() function: * * - The normal one, where the described DRAM ranges may overlap with * the I/O windows, but for which the DRAM ranges are guaranteed to * have a power of two size. Such ranges are suitable for the DMA * masters that only DMA between the RAM and the device, which is * actually all devices except the crypto engines. * * - The 'nooverlap' one, where the described DRAM ranges are * guaranteed to not overlap with the I/O windows, but for which the * DRAM ranges will not have power of two sizes. They will only be * aligned on a 64 KB boundary, and have a size multiple of 64 * KB. Such ranges are suitable for the DMA masters that DMA between * the crypto SRAM (which is mapped through an I/O window) and a * device. This is the case for the crypto engines.
*/
for (win = 0; win < mbus->soc->num_wins; win++) { /* Skip window if need remap but is not supported */ if ((remap != MVEBU_MBUS_NO_REMAP) &&
!mvebu_mbus_window_is_remappable(mbus, win)) continue;
/* Common function used for Dove, Kirkwood, Armada 370/XP and Orion 5x */ staticint mvebu_sdram_debug_show_orion(struct mvebu_mbus_state *mbus, struct seq_file *seq, void *v)
{ int i;
for (i = 0; i < 4; i++) {
u32 basereg = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
u32 sizereg = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
u64 base;
u32 size;
staticunsignedint armada_370_xp_mbus_win_cfg_offset(int win)
{ /* The register layout is a bit annoying and the below code * tries to cope with it. * - At offset 0x0, there are the registers for the first 8 * windows, with 4 registers of 32 bits per window (ctrl, * base, remap low, remap high) * - Then at offset 0x80, there is a hole of 0x10 bytes for * the internal registers base address and internal units * sync barrier register. * - Then at offset 0x90, there the registers for 12 * windows, with only 2 registers of 32 bits per window * (ctrl, base).
*/ if (win < 8) return win << 4; else return 0x90 + ((win - 8) << 3);
}
/* * Use the memblock information to find the MBus bridge hole in the * physical address space.
*/ staticvoid __init
mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
{
phys_addr_t reg_start, reg_end;
uint64_t i, s = 0;
for_each_mem_range(i, ®_start, ®_end) { /* * This part of the memory is above 4 GB, so we don't * care for the MBus bridge hole.
*/ if ((u64)reg_start >= 0x100000000ULL) continue;
/* * The MBus bridge hole is at the end of the RAM under * the 4 GB limit.
*/ if (reg_end > s)
s = reg_end;
}
*start = s;
*end = 0x100000000ULL;
}
/* * This function fills in the mvebu_mbus_dram_info_nooverlap data * structure, by looking at the mvebu_mbus_dram_info data, and * removing the parts of it that overlap with I/O windows.
*/ staticvoid __init
mvebu_mbus_setup_cpu_target_nooverlap(struct mvebu_mbus_state *mbus)
{
uint64_t mbus_bridge_base, mbus_bridge_end; int cs_nooverlap = 0; int i;
for (i = 0; i < mvebu_mbus_dram_info.num_cs; i++) { struct mbus_dram_window *w;
u64 base, size, end;
w = &mvebu_mbus_dram_info.cs[i];
base = w->base;
size = w->size;
end = base + size;
/* * The CS is fully enclosed inside the MBus bridge * area, so ignore it.
*/ if (base >= mbus_bridge_base && end <= mbus_bridge_end) continue;
/* * Beginning of CS overlaps with end of MBus, raise CS * base address, and shrink its size.
*/ if (base >= mbus_bridge_base && end > mbus_bridge_end) {
size -= mbus_bridge_end - base;
base = mbus_bridge_end;
}
/* * End of CS overlaps with beginning of MBus, shrink * CS size.
*/ if (base < mbus_bridge_base && end > mbus_bridge_base)
size -= end - mbus_bridge_base;
for (i = 0, cs = 0; i < 4; i++) {
u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
/* * We only take care of entries for which the chip * select is enabled, and that don't have high base * address bits set (devices can only access the first * 32 bits of the memory).
*/ if ((size & DDR_SIZE_ENABLED) &&
!(base & DDR_BASE_CS_HIGH_MASK)) { struct mbus_dram_window *w;
/* * Some variants of Orion5x have 4 remappable windows, some other have * only two of them.
*/ staticconststruct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
.num_wins = 8,
.win_cfg_offset = generic_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.win_remap_offset = generic_mbus_win_remap_4_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
/* * Public API of the driver
*/ int mvebu_mbus_add_window_remap_by_id(unsignedint target, unsignedint attribute,
phys_addr_t base, size_t size,
phys_addr_t remap)
{ struct mvebu_mbus_state *s = &mbus_state;
if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) {
pr_err("cannot add window '%x:%x', conflicts with another window\n",
target, attribute); return -EINVAL;
}
static __init int mvebu_mbus_debugfs_init(void)
{ struct mvebu_mbus_state *s = &mbus_state;
/* * If no base has been initialized, doesn't make sense to * register the debugfs entries. We may be on a multiplatform * kernel that isn't running a Marvell EBU SoC.
*/ if (!s->mbuswins_base) return 0;
/* * These are optional, so we make sure that resource_size(x) will * return 0.
*/
memset(mem, 0, sizeof(struct resource));
mem->end = -1;
memset(io, 0, sizeof(struct resource));
io->end = -1;
controller = of_find_node_by_phandle(be32_to_cpup(prop)); if (!controller) {
pr_err("could not find an 'mbus-controller' node\n"); return -ENODEV;
}
if (of_address_to_resource(controller, 0, &mbuswins_res)) {
pr_err("cannot get MBUS register address\n"); return -EINVAL;
}
if (of_address_to_resource(controller, 1, &sdramwins_res)) {
pr_err("cannot get SDRAM register address\n"); return -EINVAL;
}
/* * Set the resource to 0 so that it can be left unmapped by * mvebu_mbus_common_init() if the DT doesn't carry the * necessary information. This is needed to preserve backward * compatibility.
*/
memset(&mbusbridge_res, 0, sizeof(mbusbridge_res));
if (mbus_state.soc->has_mbus_bridge) { if (of_address_to_resource(controller, 2, &mbusbridge_res))
pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n");
}
mbus_state.hw_io_coherency = is_coherent;
/* Get optional pcie-{mem,io}-aperture properties */
mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture,
&mbus_state.pcie_io_aperture);
ret = mvebu_mbus_common_init(&mbus_state,
mbuswins_res.start,
resource_size(&mbuswins_res),
sdramwins_res.start,
resource_size(&sdramwins_res),
mbusbridge_res.start,
resource_size(&mbusbridge_res),
is_coherent); if (ret) return ret;
/* Setup statically declared windows in the DT */ return mbus_dt_setup(&mbus_state, np);
} #endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.