aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv8/cache.S9
-rw-r--r--arch/arm/cpu/armv8/start.S6
-rw-r--r--arch/arm/lib/bootm.c2
-rw-r--r--arch/arm/lib/cache-cp15.c18
-rw-r--r--board/Marvell/octeontx/board-fdt.c20
-rw-r--r--drivers/clk/mvebu/armada-37xx-periph.c1
-rw-r--r--drivers/clk/mvebu/armada-37xx-tbg.c1
-rw-r--r--drivers/serial/serial_mvebu_a3700.c179
-rw-r--r--include/configs/mvebu_armada-37xx.h9
-rw-r--r--include/configs/turris_mox.h9
10 files changed, 219 insertions, 35 deletions
diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S
index 443d94c..e04907d 100644
--- a/arch/arm/cpu/armv8/cache.S
+++ b/arch/arm/cpu/armv8/cache.S
@@ -188,27 +188,24 @@ ENDPROC(__asm_invalidate_icache_all)
.popsection
.pushsection .text.__asm_invalidate_l3_dcache, "ax"
-ENTRY(__asm_invalidate_l3_dcache)
+WEAK(__asm_invalidate_l3_dcache)
mov x0, #0 /* return status as success */
ret
ENDPROC(__asm_invalidate_l3_dcache)
- .weak __asm_invalidate_l3_dcache
.popsection
.pushsection .text.__asm_flush_l3_dcache, "ax"
-ENTRY(__asm_flush_l3_dcache)
+WEAK(__asm_flush_l3_dcache)
mov x0, #0 /* return status as success */
ret
ENDPROC(__asm_flush_l3_dcache)
- .weak __asm_flush_l3_dcache
.popsection
.pushsection .text.__asm_invalidate_l3_icache, "ax"
-ENTRY(__asm_invalidate_l3_icache)
+WEAK(__asm_invalidate_l3_icache)
mov x0, #0 /* return status as success */
ret
ENDPROC(__asm_invalidate_l3_icache)
- .weak __asm_invalidate_l3_icache
.popsection
/*
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index 6624491..9e9c614 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -132,11 +132,13 @@ pie_fixup_done:
msr cntfrq_el0, x0 /* Initialize CNTFRQ */
#endif
b 0f
-2: set_vbar vbar_el2, x0
+2: mrs x1, hcr_el2
+ tbnz x1, #34, 1f /* HCR_EL2.E2H */
+ set_vbar vbar_el2, x0
mov x0, #0x33ff
msr cptr_el2, x0 /* Enable FP/SIMD */
b 0f
-1: set_vbar vbar_el1, x0
+1: set_vbar vbar_el1, x0
mov x0, #3 << 20
msr cpacr_el1, x0 /* Enable FP/SIMD */
0:
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index f60ee3a..23b99a5 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -43,6 +43,7 @@ DECLARE_GLOBAL_DATA_PTR;
static struct tag *params;
+#ifndef CONFIG_ARM64
static ulong get_sp(void)
{
ulong ret;
@@ -86,6 +87,7 @@ void arch_lmb_reserve(struct lmb *lmb)
break;
}
}
+#endif
__weak void board_quiesce_devices(void)
{
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index aab1bf4..0893915 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -93,12 +93,6 @@ void mmu_set_region_dcache_behaviour_phys(phys_addr_t start, phys_addr_t phys,
mmu_page_table_flush(startpt, stoppt);
}
-void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
- enum dcache_option option)
-{
- mmu_set_region_dcache_behaviour_phys(start, start, size, option);
-}
-
__weak void dram_bank_mmu_setup(int bank)
{
struct bd_info *bd = gd->bd;
@@ -311,6 +305,12 @@ int dcache_status(void)
{
return 0; /* always off */
}
+
+void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
+ enum dcache_option option)
+{
+}
+
#else
void dcache_enable(void)
{
@@ -326,4 +326,10 @@ int dcache_status(void)
{
return (get_cr() & CR_C) != 0;
}
+
+void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
+ enum dcache_option option)
+{
+ mmu_set_region_dcache_behaviour_phys(start, start, size, option);
+}
#endif
diff --git a/board/Marvell/octeontx/board-fdt.c b/board/Marvell/octeontx/board-fdt.c
index 0b05ef1..1db2a4a 100644
--- a/board/Marvell/octeontx/board-fdt.c
+++ b/board/Marvell/octeontx/board-fdt.c
@@ -281,20 +281,16 @@ int ft_board_setup(void *blob, struct bd_info *bd)
}
if (blob) {
+ /* delete cavium,bdk node if it exists */
offset = fdt_path_offset(blob, "/cavium,bdk");
- if (offset < 0) {
- printf("ERROR: FDT BDK node not found\n");
- return offset;
- }
-
- /* delete node */
- ret = fdt_del_node(blob, offset);
- if (ret < 0) {
- printf("WARNING : could not remove bdk node\n");
- return ret;
+ if (offset >= 0) {
+ ret = fdt_del_node(blob, offset);
+ if (ret < 0) {
+ printf("WARNING : could not remove bdk node\n");
+ return ret;
+ }
+ debug("%s deleted bdk node\n", __func__);
}
-
- debug("%s deleted bdk node\n", __func__);
}
return 0;
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index b0f47c3..3b767d7 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -626,4 +626,5 @@ U_BOOT_DRIVER(armada_37xx_periph_clk) = {
.ops = &armada_37xx_periph_clk_ops,
.priv_auto = sizeof(struct a37xx_periphclk),
.probe = armada_37xx_periph_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c
index b1c0852..054aff5 100644
--- a/drivers/clk/mvebu/armada-37xx-tbg.c
+++ b/drivers/clk/mvebu/armada-37xx-tbg.c
@@ -152,4 +152,5 @@ U_BOOT_DRIVER(armada_37xx_tbg_clk) = {
.ops = &armada_37xx_tbg_clk_ops,
.priv_auto = sizeof(struct a37xx_tbgclk),
.probe = armada_37xx_tbg_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index 8f40487..c7e66fe 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -4,12 +4,16 @@
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
#include <serial.h>
#include <asm/io.h>
+#include <asm/arch/cpu.h>
struct mvebu_plat {
void __iomem *base;
+ ulong tbg_rate;
+ u8 tbg_idx;
};
/*
@@ -29,8 +33,6 @@ struct mvebu_plat {
#define UART_CTRL_RXFIFO_RESET 0x4000
#define UART_CTRL_TXFIFO_RESET 0x8000
-#define CONFIG_UART_BASE_CLOCK 25804800
-
static int mvebu_serial_putc(struct udevice *dev, const char ch)
{
struct mvebu_plat *plat = dev_get_plat(dev);
@@ -75,18 +77,70 @@ static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
{
struct mvebu_plat *plat = dev_get_plat(dev);
void __iomem *base = plat->base;
+ u32 divider, d1, d2;
+ u32 oversampling;
/*
* Calculate divider
* baudrate = clock / 16 / divider
*/
- writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
+ d1 = d2 = 1;
+ divider = DIV_ROUND_CLOSEST(plat->tbg_rate, baudrate * 16 * d1 * d2);
/*
* Set Programmable Oversampling Stack to 0,
* UART defaults to 16x scheme
*/
- writel(0, base + UART_POSSR_REG);
+ oversampling = 0;
+
+ if (divider < 1)
+ divider = 1;
+ else if (divider > 1023) {
+ /*
+ * If divider is too high for selected baudrate then set
+ * divider d1 to the maximal value 6.
+ */
+ d1 = 6;
+ divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+ baudrate * 16 * d1 * d2);
+ if (divider < 1)
+ divider = 1;
+ else if (divider > 1023) {
+ /*
+ * If divider is still too high then set also divider
+ * d2 to the maximal value 6.
+ */
+ d2 = 6;
+ divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+ baudrate * 16 * d1 * d2);
+ if (divider < 1)
+ divider = 1;
+ else if (divider > 1023) {
+ /*
+ * And if divider is still to high then
+ * use oversampling with maximal factor 63.
+ */
+ oversampling = (63 << 0) | (63 << 8) |
+ (63 << 16) | (63 << 24);
+ divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+ baudrate * 63 * d1 * d2);
+ if (divider < 1)
+ divider = 1;
+ else if (divider > 1023)
+ divider = 1023;
+ }
+ }
+ }
+
+ divider |= BIT(19); /* Do not use XTAL as a base clock */
+ divider |= d1 << 15; /* Set d1 divider */
+ divider |= d2 << 12; /* Set d2 divider */
+ divider |= plat->tbg_idx << 10; /* Use selected TBG as a base clock */
+
+ while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
+ ;
+ writel(divider, base + UART_BAUD_REG);
+ writel(oversampling, base + UART_POSSR_REG);
return 0;
}
@@ -95,6 +149,50 @@ static int mvebu_serial_probe(struct udevice *dev)
{
struct mvebu_plat *plat = dev_get_plat(dev);
void __iomem *base = plat->base;
+ struct udevice *nb_clk;
+ ofnode nb_clk_node;
+ int i, res;
+
+ nb_clk_node = ofnode_by_compatible(ofnode_null(),
+ "marvell,armada-3700-periph-clock-nb");
+ if (!ofnode_valid(nb_clk_node)) {
+ printf("%s: NB periph clock node not available\n", __func__);
+ return -ENODEV;
+ }
+
+ res = device_get_global_by_ofnode(nb_clk_node, &nb_clk);
+ if (res) {
+ printf("%s: Cannot get NB periph clock\n", __func__);
+ return res;
+ }
+
+ /*
+ * Choose the TBG clock with lowest frequency which allows to configure
+ * UART also at lower baudrates.
+ */
+ for (i = 0; i < 4; i++) {
+ struct clk clk;
+ ulong rate;
+
+ res = clk_get_by_index_nodev(nb_clk_node, i, &clk);
+ if (res) {
+ printf("%s: Cannot get TBG clock %i: %i\n", __func__,
+ i, res);
+ return -ENODEV;
+ }
+
+ rate = clk_get_rate(&clk);
+ if (!rate || IS_ERR_VALUE(rate)) {
+ printf("%s: Cannot get rate for TBG clock %i\n",
+ __func__, i);
+ return -EINVAL;
+ }
+
+ if (!i || plat->tbg_rate > rate) {
+ plat->tbg_rate = rate;
+ plat->tbg_idx = i;
+ }
+ }
/* reset FIFOs */
writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
@@ -106,6 +204,71 @@ static int mvebu_serial_probe(struct udevice *dev)
return 0;
}
+static int mvebu_serial_remove(struct udevice *dev)
+{
+ struct mvebu_plat *plat = dev_get_plat(dev);
+ void __iomem *base = plat->base;
+ ulong new_parent_rate, parent_rate;
+ u32 new_divider, divider;
+ u32 new_oversampling;
+ u32 oversampling;
+ u32 d1, d2;
+
+ /*
+ * Switch UART base clock back to XTAL because older Linux kernel
+ * expects it. Otherwise it does not calculate UART divisor correctly
+ * and therefore UART does not work in kernel.
+ */
+ divider = readl(base + UART_BAUD_REG);
+ if (!(divider & BIT(19))) /* UART already uses XTAL */
+ return 0;
+
+ /* Read current divisors settings */
+ d1 = (divider >> 15) & 7;
+ d2 = (divider >> 12) & 7;
+ parent_rate = plat->tbg_rate;
+ divider &= 1023;
+ oversampling = readl(base + UART_POSSR_REG) & 63;
+ if (!oversampling)
+ oversampling = 16;
+
+ /* Calculate new divisor against XTAL clock without changing baudrate */
+ new_oversampling = 0;
+ new_parent_rate = get_ref_clk() * 1000000;
+ new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * d2 *
+ oversampling, parent_rate * 16);
+
+ /*
+ * UART does not work reliably when XTAL divisor is smaller than 4.
+ * In this case we do not switch UART parent to XTAL. User either
+ * configured unsupported settings or has newer kernel with patches
+ * which allow usage of non-XTAL clock as a parent clock.
+ */
+ if (new_divider < 4)
+ return 0;
+
+ /*
+ * If new divisor is larger than maximal supported, try to switch
+ * from default x16 scheme to oversampling with maximal factor 63.
+ */
+ if (new_divider > 1023) {
+ new_oversampling = 63;
+ new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 *
+ d2 * oversampling,
+ parent_rate * new_oversampling);
+ if (new_divider < 4 || new_divider > 1023)
+ return 0;
+ }
+
+ while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
+ ;
+
+ writel(new_divider, base + UART_BAUD_REG);
+ writel(new_oversampling, base + UART_POSSR_REG);
+
+ return 0;
+}
+
static int mvebu_serial_of_to_plat(struct udevice *dev)
{
struct mvebu_plat *plat = dev_get_plat(dev);
@@ -134,6 +297,8 @@ U_BOOT_DRIVER(serial_mvebu) = {
.of_to_plat = mvebu_serial_of_to_plat,
.plat_auto = sizeof(struct mvebu_plat),
.probe = mvebu_serial_probe,
+ .remove = mvebu_serial_remove,
+ .flags = DM_FLAG_OS_PREPARE,
.ops = &mvebu_serial_ops,
};
@@ -144,6 +309,7 @@ U_BOOT_DRIVER(serial_mvebu) = {
static inline void _debug_uart_init(void)
{
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
+ u32 baudrate, parent_rate, divider;
/* reset FIFOs */
writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
@@ -156,7 +322,10 @@ static inline void _debug_uart_init(void)
* Calculate divider
* baudrate = clock / 16 / divider
*/
- writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
+ baudrate = 115200;
+ parent_rate = get_ref_clk() * 1000000;
+ divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
+ writel(divider, base + UART_BAUD_REG);
/*
* Set Programmable Oversampling Stack to 0,
diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h
index 2ad4325..a2bea29 100644
--- a/include/configs/mvebu_armada-37xx.h
+++ b/include/configs/mvebu_armada-37xx.h
@@ -17,8 +17,13 @@
#define CONFIG_SYS_BOOTM_LEN SZ_64M /* Increase max gunzip size */
-#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, \
- 115200, 230400, 460800, 921600 }
+#define CONFIG_SYS_BAUDRATE_TABLE { 300, 600, 1200, 1800, 2400, 4800, \
+ 9600, 19200, 38400, 57600, 115200, \
+ 230400, 460800, 500000, 576000, \
+ 921600, 1000000, 1152000, 1500000, \
+ 2000000, 2500000, 3000000, 3500000, \
+ 4000000, 4500000, 5000000, 5500000, \
+ 6000000 }
/*
* For booting Linux, the board info and command line data
diff --git a/include/configs/turris_mox.h b/include/configs/turris_mox.h
index 9c021a1..6712839 100644
--- a/include/configs/turris_mox.h
+++ b/include/configs/turris_mox.h
@@ -22,8 +22,13 @@
/* auto boot */
-#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, \
- 115200, 230400, 460800, 921600 }
+#define CONFIG_SYS_BAUDRATE_TABLE { 300, 600, 1200, 1800, 2400, 4800, \
+ 9600, 19200, 38400, 57600, 115200, \
+ 230400, 460800, 500000, 576000, \
+ 921600, 1000000, 1152000, 1500000, \
+ 2000000, 2500000, 3000000, 3500000, \
+ 4000000, 4500000, 5000000, 5500000, \
+ 6000000 }
/*
* For booting Linux, the board info and command line data