mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-06-09 23:36:03 +09:00
- mvebu: a37xx: PCI related enhancements and fixes (Pali) - mvebu: turris_omnia: Board specific updates, e.g. rescue boot cmd etc (Marek)
This commit is contained in:
commit
c003d2cd6b
|
@ -323,7 +323,7 @@
|
|||
};
|
||||
|
||||
pcie0: pcie@d0070000 {
|
||||
compatible = "marvell,armada-37xx-pcie";
|
||||
compatible = "marvell,armada-3700-pcie";
|
||||
reg = <0 0xd0070000 0 0x20000>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
|
@ -332,10 +332,17 @@
|
|||
status = "disabled";
|
||||
|
||||
bus-range = <0 0xff>;
|
||||
/*
|
||||
* The 128 MiB address range [0xe8000000-0xf0000000] is
|
||||
* dedicated for PCIe and can be assigned to 8 windows
|
||||
* with size a power of two. Use one 64 KiB window for
|
||||
* IO at the end and the remaining seven windows
|
||||
* (totaling 127 MiB) for MEM.
|
||||
*/
|
||||
ranges = <0x82000000 0 0xe8000000
|
||||
0 0xe8000000 0 0x1000000 /* Port 0 MEM */
|
||||
0x81000000 0 0xe9000000
|
||||
0 0xe9000000 0 0x10000>; /* Port 0 IO*/
|
||||
0 0xe8000000 0 0x7f00000 /* Port 0 MEM */
|
||||
0x81000000 0 0xefff0000
|
||||
0 0xefff0000 0 0x10000>; /* Port 0 IO*/
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <cpu_func.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <fdt_support.h>
|
||||
#include <init.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -53,8 +54,6 @@
|
|||
#define A3700_PTE_BLOCK_DEVICE \
|
||||
(PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
|
||||
|
||||
#define PCIE_PATH "/soc/pcie@d0070000"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
|
||||
|
@ -282,36 +281,81 @@ static u32 find_pcie_window_base(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int fdt_setprop_inplace_u32_partial(void *blob, int node,
|
||||
const char *name,
|
||||
u32 idx, u32 val)
|
||||
{
|
||||
val = cpu_to_fdt32(val);
|
||||
|
||||
return fdt_setprop_inplace_namelen_partial(blob, node, name,
|
||||
strlen(name),
|
||||
idx * sizeof(u32),
|
||||
&val, sizeof(u32));
|
||||
}
|
||||
|
||||
int a3700_fdt_fix_pcie_regions(void *blob)
|
||||
{
|
||||
u32 new_ranges[14], base;
|
||||
int acells, pacells, scells;
|
||||
u32 base, fix_offset;
|
||||
const u32 *ranges;
|
||||
int node, len;
|
||||
|
||||
node = fdt_path_offset(blob, PCIE_PATH);
|
||||
if (node < 0)
|
||||
return node;
|
||||
|
||||
ranges = fdt_getprop(blob, node, "ranges", &len);
|
||||
if (!ranges)
|
||||
return -ENOENT;
|
||||
|
||||
if (len != sizeof(new_ranges))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(new_ranges, ranges, len);
|
||||
int node, pnode;
|
||||
int ret, i, len;
|
||||
|
||||
base = find_pcie_window_base();
|
||||
if (base == -1)
|
||||
return -ENOENT;
|
||||
|
||||
new_ranges[2] = cpu_to_fdt32(base);
|
||||
new_ranges[4] = new_ranges[2];
|
||||
node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
|
||||
if (node < 0)
|
||||
return node;
|
||||
|
||||
new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
|
||||
new_ranges[11] = new_ranges[9];
|
||||
ranges = fdt_getprop(blob, node, "ranges", &len);
|
||||
if (!ranges || len % sizeof(u32))
|
||||
return -ENOENT;
|
||||
|
||||
return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
|
||||
/*
|
||||
* The "ranges" property is an array of
|
||||
* { <child address> <parent address> <size in child address space> }
|
||||
*
|
||||
* All 3 elements can span a diffent number of cells. Fetch their sizes.
|
||||
*/
|
||||
pnode = fdt_parent_offset(blob, node);
|
||||
acells = fdt_address_cells(blob, node);
|
||||
pacells = fdt_address_cells(blob, pnode);
|
||||
scells = fdt_size_cells(blob, node);
|
||||
|
||||
/* Child PCI addresses always use 3 cells */
|
||||
if (acells != 3)
|
||||
return -ENOENT;
|
||||
|
||||
/* Calculate fixup offset from first child address (in last cell) */
|
||||
fix_offset = base - fdt32_to_cpu(ranges[2]);
|
||||
|
||||
/*
|
||||
* Fix address (last cell) of each child address and each parent
|
||||
* address
|
||||
*/
|
||||
for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
|
||||
int idx;
|
||||
|
||||
/* fix child address */
|
||||
idx = i + acells - 1;
|
||||
ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
|
||||
fdt32_to_cpu(ranges[idx]) +
|
||||
fix_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* fix parent address */
|
||||
idx = i + acells + pacells - 1;
|
||||
ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
|
||||
fdt32_to_cpu(ranges[idx]) +
|
||||
fix_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset_cpu(void)
|
||||
|
|
|
@ -337,24 +337,6 @@ static int set_regdomain(void)
|
|||
return env_set("regdomain", rd);
|
||||
}
|
||||
|
||||
/*
|
||||
* default factory reset bootcommand on Omnia first sets all the front LEDs
|
||||
* to green and then tries to load the rescue image from SPI flash memory and
|
||||
* boot it
|
||||
*/
|
||||
#define OMNIA_FACTORY_RESET_BOOTCMD \
|
||||
"i2c dev 2; " \
|
||||
"i2c mw 0x2a.1 0x3 0x1c 1; " \
|
||||
"i2c mw 0x2a.1 0x4 0x1c 1; " \
|
||||
"mw.l 0x01000000 0x00ff000c; " \
|
||||
"i2c write 0x01000000 0x2a.1 0x5 4 -s; " \
|
||||
"setenv bootargs \"earlyprintk console=ttyS0,115200" \
|
||||
" omniarescue=$omnia_reset\"; " \
|
||||
"sf probe; " \
|
||||
"sf read 0x1000000 0x100000 0x700000; " \
|
||||
"bootm 0x1000000; " \
|
||||
"bootz 0x1000000"
|
||||
|
||||
static void handle_reset_button(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -370,8 +352,36 @@ static void handle_reset_button(void)
|
|||
env_set_ulong("omnia_reset", reset_status);
|
||||
|
||||
if (reset_status) {
|
||||
const char * const vars[3] = {
|
||||
"bootcmd",
|
||||
"bootcmd_rescue",
|
||||
"distro_bootcmd",
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the above envs to their default values, in case the user
|
||||
* managed to break them.
|
||||
*/
|
||||
env_set_default_vars(3, (char * const *)vars, 0);
|
||||
|
||||
/* Ensure bootcmd_rescue is used by distroboot */
|
||||
env_set("boot_targets", "rescue");
|
||||
|
||||
printf("RESET button was pressed, overwriting bootcmd!\n");
|
||||
env_set("bootcmd", OMNIA_FACTORY_RESET_BOOTCMD);
|
||||
} else {
|
||||
/*
|
||||
* In case the user somehow managed to save environment with
|
||||
* boot_targets=rescue, reset boot_targets to default value.
|
||||
* This could happen in subsequent commands if bootcmd_rescue
|
||||
* failed.
|
||||
*/
|
||||
if (!strcmp(env_get("boot_targets"), "rescue")) {
|
||||
const char * const vars[1] = {
|
||||
"boot_targets",
|
||||
};
|
||||
|
||||
env_set_default_vars(1, (char * const *)vars, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -99,6 +99,46 @@
|
|||
#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
|
||||
#define PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE BIT(6)
|
||||
|
||||
/* PCIe window configuration */
|
||||
#define OB_WIN_BASE_ADDR 0x4c00
|
||||
#define OB_WIN_BLOCK_SIZE 0x20
|
||||
#define OB_WIN_COUNT 8
|
||||
#define OB_WIN_REG_ADDR(win, offset) (OB_WIN_BASE_ADDR + \
|
||||
OB_WIN_BLOCK_SIZE * (win) + \
|
||||
(offset))
|
||||
#define OB_WIN_MATCH_LS(win) OB_WIN_REG_ADDR(win, 0x00)
|
||||
#define OB_WIN_ENABLE BIT(0)
|
||||
#define OB_WIN_MATCH_MS(win) OB_WIN_REG_ADDR(win, 0x04)
|
||||
#define OB_WIN_REMAP_LS(win) OB_WIN_REG_ADDR(win, 0x08)
|
||||
#define OB_WIN_REMAP_MS(win) OB_WIN_REG_ADDR(win, 0x0c)
|
||||
#define OB_WIN_MASK_LS(win) OB_WIN_REG_ADDR(win, 0x10)
|
||||
#define OB_WIN_MASK_MS(win) OB_WIN_REG_ADDR(win, 0x14)
|
||||
#define OB_WIN_ACTIONS(win) OB_WIN_REG_ADDR(win, 0x18)
|
||||
#define OB_WIN_DEFAULT_ACTIONS (OB_WIN_ACTIONS(OB_WIN_COUNT-1) + 0x4)
|
||||
#define OB_WIN_FUNC_NUM_MASK GENMASK(31, 24)
|
||||
#define OB_WIN_FUNC_NUM_SHIFT 24
|
||||
#define OB_WIN_FUNC_NUM_ENABLE BIT(23)
|
||||
#define OB_WIN_BUS_NUM_BITS_MASK GENMASK(22, 20)
|
||||
#define OB_WIN_BUS_NUM_BITS_SHIFT 20
|
||||
#define OB_WIN_MSG_CODE_ENABLE BIT(22)
|
||||
#define OB_WIN_MSG_CODE_MASK GENMASK(21, 14)
|
||||
#define OB_WIN_MSG_CODE_SHIFT 14
|
||||
#define OB_WIN_MSG_PAYLOAD_LEN BIT(12)
|
||||
#define OB_WIN_ATTR_ENABLE BIT(11)
|
||||
#define OB_WIN_ATTR_TC_MASK GENMASK(10, 8)
|
||||
#define OB_WIN_ATTR_TC_SHIFT 8
|
||||
#define OB_WIN_ATTR_RELAXED BIT(7)
|
||||
#define OB_WIN_ATTR_NOSNOOP BIT(6)
|
||||
#define OB_WIN_ATTR_POISON BIT(5)
|
||||
#define OB_WIN_ATTR_IDO BIT(4)
|
||||
#define OB_WIN_TYPE_MASK GENMASK(3, 0)
|
||||
#define OB_WIN_TYPE_SHIFT 0
|
||||
#define OB_WIN_TYPE_MEM 0x0
|
||||
#define OB_WIN_TYPE_IO 0x4
|
||||
#define OB_WIN_TYPE_CONFIG_TYPE0 0x8
|
||||
#define OB_WIN_TYPE_CONFIG_TYPE1 0x9
|
||||
#define OB_WIN_TYPE_MSG 0xc
|
||||
|
||||
/* LMI registers base address and register offsets */
|
||||
#define LMI_BASE_ADDR 0x6000
|
||||
#define CFG_REG (LMI_BASE_ADDR + 0x0)
|
||||
|
@ -522,6 +562,86 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set PCIe address window register which could be used for memory
|
||||
* mapping.
|
||||
*/
|
||||
static void pcie_advk_set_ob_win(struct pcie_advk *pcie, u8 win_num,
|
||||
phys_addr_t match, phys_addr_t remap,
|
||||
phys_addr_t mask, u32 actions)
|
||||
{
|
||||
advk_writel(pcie, OB_WIN_ENABLE |
|
||||
lower_32_bits(match), OB_WIN_MATCH_LS(win_num));
|
||||
advk_writel(pcie, upper_32_bits(match), OB_WIN_MATCH_MS(win_num));
|
||||
advk_writel(pcie, lower_32_bits(remap), OB_WIN_REMAP_LS(win_num));
|
||||
advk_writel(pcie, upper_32_bits(remap), OB_WIN_REMAP_MS(win_num));
|
||||
advk_writel(pcie, lower_32_bits(mask), OB_WIN_MASK_LS(win_num));
|
||||
advk_writel(pcie, upper_32_bits(mask), OB_WIN_MASK_MS(win_num));
|
||||
advk_writel(pcie, actions, OB_WIN_ACTIONS(win_num));
|
||||
}
|
||||
|
||||
static void pcie_advk_disable_ob_win(struct pcie_advk *pcie, u8 win_num)
|
||||
{
|
||||
advk_writel(pcie, 0, OB_WIN_MATCH_LS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_MATCH_MS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_REMAP_LS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_REMAP_MS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_MASK_LS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_MASK_MS(win_num));
|
||||
advk_writel(pcie, 0, OB_WIN_ACTIONS(win_num));
|
||||
}
|
||||
|
||||
static void pcie_advk_set_ob_region(struct pcie_advk *pcie, int *wins,
|
||||
struct pci_region *region, u32 actions)
|
||||
{
|
||||
phys_addr_t phys_start = region->phys_start;
|
||||
pci_addr_t bus_start = region->bus_start;
|
||||
pci_size_t size = region->size;
|
||||
phys_addr_t win_mask;
|
||||
u64 win_size;
|
||||
|
||||
if (*wins == -1)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The n-th PCIe window is configured by tuple (match, remap, mask)
|
||||
* and an access to address A uses this window it if A matches the
|
||||
* match with given mask.
|
||||
* So every PCIe window size must be a power of two and every start
|
||||
* address must be aligned to window size. Minimal size is 64 KiB
|
||||
* because lower 16 bits of mask must be zero.
|
||||
*/
|
||||
while (*wins < OB_WIN_COUNT && size > 0) {
|
||||
/* Calculate the largest aligned window size */
|
||||
win_size = (1ULL << (fls64(size) - 1)) |
|
||||
(phys_start ? (1ULL << __ffs64(phys_start)) : 0);
|
||||
win_size = 1ULL << __ffs64(win_size);
|
||||
if (win_size < 0x10000)
|
||||
break;
|
||||
|
||||
dev_dbg(pcie->dev,
|
||||
"Configuring PCIe window %d: [0x%llx-0x%llx] as 0x%x\n",
|
||||
*wins, (u64)phys_start, (u64)phys_start + win_size,
|
||||
actions);
|
||||
win_mask = ~(win_size - 1) & ~0xffff;
|
||||
pcie_advk_set_ob_win(pcie, *wins, phys_start, bus_start,
|
||||
win_mask, actions);
|
||||
|
||||
phys_start += win_size;
|
||||
bus_start += win_size;
|
||||
size -= win_size;
|
||||
(*wins)++;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
*wins = -1;
|
||||
dev_err(pcie->dev,
|
||||
"Invalid PCIe region [0x%llx-0x%llx]\n",
|
||||
(u64)region->phys_start,
|
||||
(u64)region->phys_start + region->size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pcie_advk_setup_hw() - PCIe initailzation
|
||||
*
|
||||
|
@ -531,6 +651,8 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie)
|
|||
*/
|
||||
static int pcie_advk_setup_hw(struct pcie_advk *pcie)
|
||||
{
|
||||
struct pci_region *io, *mem, *pref;
|
||||
int i, wins;
|
||||
u32 reg;
|
||||
|
||||
/* Set to Direct mode */
|
||||
|
@ -597,7 +719,9 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie)
|
|||
* configurations (Default User Field: 0xD0074CFC)
|
||||
* are used to transparent address translation for
|
||||
* the outbound transactions. Thus, PCIe address
|
||||
* windows are not required.
|
||||
* windows are not required for transparent memory
|
||||
* access when default outbound window configuration
|
||||
* is set for memory access.
|
||||
*/
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
|
||||
reg |= PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE;
|
||||
|
@ -613,10 +737,33 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie)
|
|||
reg |= PIO_CTRL_ADDR_WIN_DISABLE;
|
||||
advk_writel(pcie, reg, PIO_CTRL);
|
||||
|
||||
/* Start link training */
|
||||
reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
|
||||
reg |= PCIE_CORE_LINK_TRAINING;
|
||||
advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
|
||||
/*
|
||||
* Set memory access in Default User Field so it
|
||||
* is not required to configure PCIe address for
|
||||
* transparent memory access.
|
||||
*/
|
||||
advk_writel(pcie, OB_WIN_TYPE_MEM, OB_WIN_DEFAULT_ACTIONS);
|
||||
|
||||
/*
|
||||
* Configure PCIe address windows for non-memory or
|
||||
* non-transparent access as by default PCIe uses
|
||||
* transparent memory access.
|
||||
*/
|
||||
wins = 0;
|
||||
pci_get_regions(pcie->dev, &io, &mem, &pref);
|
||||
if (io)
|
||||
pcie_advk_set_ob_region(pcie, &wins, io, OB_WIN_TYPE_IO);
|
||||
if (mem && mem->phys_start != mem->bus_start)
|
||||
pcie_advk_set_ob_region(pcie, &wins, mem, OB_WIN_TYPE_MEM);
|
||||
if (pref && pref->phys_start != pref->bus_start)
|
||||
pcie_advk_set_ob_region(pcie, &wins, pref, OB_WIN_TYPE_MEM);
|
||||
|
||||
/* Disable remaining PCIe outbound windows */
|
||||
for (i = ((wins >= 0) ? wins : 0); i < OB_WIN_COUNT; i++)
|
||||
pcie_advk_disable_ob_win(pcie, i);
|
||||
|
||||
if (wins == -1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Wait for PCIe link up */
|
||||
if (pcie_advk_wait_for_link(pcie))
|
||||
|
@ -679,6 +826,16 @@ static int pcie_advk_remove(struct udevice *dev)
|
|||
{
|
||||
struct pcie_advk *pcie = dev_get_priv(dev);
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OB_WIN_COUNT; i++)
|
||||
pcie_advk_disable_ob_win(pcie, i);
|
||||
|
||||
reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
|
||||
reg &= ~(PCIE_CORE_CMD_MEM_ACCESS_EN |
|
||||
PCIE_CORE_CMD_IO_ACCESS_EN |
|
||||
PCIE_CORE_CMD_MEM_IO_REQ_EN);
|
||||
advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
|
||||
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
|
||||
reg &= ~LINK_TRAINING_EN;
|
||||
|
@ -716,7 +873,7 @@ static const struct dm_pci_ops pcie_advk_ops = {
|
|||
};
|
||||
|
||||
static const struct udevice_id pcie_advk_ids[] = {
|
||||
{ .compatible = "marvell,armada-37xx-pcie" },
|
||||
{ .compatible = "marvell,armada-3700-pcie" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -108,12 +108,35 @@
|
|||
|
||||
#include <config_distro_bootcmd.h>
|
||||
|
||||
/*
|
||||
* The factory reset bootcommand on Omnia first sets all the front LEDs to green
|
||||
* and then tries to load the rescue image from SPI flash memory and boot it
|
||||
*/
|
||||
#define TURRIS_OMNIA_BOOTCMD_RESCUE \
|
||||
"i2c dev 2; " \
|
||||
"i2c mw 0x2a.1 0x3 0x1c 1; " \
|
||||
"i2c mw 0x2a.1 0x4 0x1c 1; " \
|
||||
"mw.l 0x01000000 0x00ff000c; " \
|
||||
"i2c write 0x01000000 0x2a.1 0x5 4 -s; " \
|
||||
"setenv bootargs \"earlyprintk console=ttyS0,115200" \
|
||||
" omniarescue=$omnia_reset rescue_mode=$omnia_reset\"; " \
|
||||
"sf probe; " \
|
||||
"sf read 0x1000000 0x100000 0x700000; " \
|
||||
"lzmadec 0x1000000 0x1700000; " \
|
||||
"if gpio input gpio@71_4; then " \
|
||||
"bootm 0x1700000#sfp; " \
|
||||
"else " \
|
||||
"bootm 0x1700000; " \
|
||||
"fi; " \
|
||||
"bootz 0x1000000"
|
||||
|
||||
#define CONFIG_EXTRA_ENV_SETTINGS \
|
||||
RELOCATION_LIMITS_ENV_SETTINGS \
|
||||
LOAD_ADDRESS_ENV_SETTINGS \
|
||||
"fdtfile=" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" \
|
||||
"console=ttyS0,115200\0" \
|
||||
"ethact=ethernet@34000\0" \
|
||||
"bootcmd_rescue=" TURRIS_OMNIA_BOOTCMD_RESCUE "\0" \
|
||||
BOOTENV
|
||||
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
|
Loading…
Reference in New Issue
Block a user