diff options
-rw-r--r-- | arch/arm/cpu/armv8/cache.S | 9 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/start.S | 6 | ||||
-rw-r--r-- | arch/arm/lib/bootm.c | 2 | ||||
-rw-r--r-- | arch/arm/lib/cache-cp15.c | 18 | ||||
-rw-r--r-- | board/Marvell/octeontx/board-fdt.c | 20 | ||||
-rw-r--r-- | drivers/clk/mvebu/armada-37xx-periph.c | 1 | ||||
-rw-r--r-- | drivers/clk/mvebu/armada-37xx-tbg.c | 1 | ||||
-rw-r--r-- | drivers/serial/serial_mvebu_a3700.c | 179 | ||||
-rw-r--r-- | include/configs/mvebu_armada-37xx.h | 9 | ||||
-rw-r--r-- | include/configs/turris_mox.h | 9 |
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 |