diff --git a/blob/fw_common.S b/blob/fw_common.S index db0f7f7d..a2685cf2 100644 --- a/blob/fw_common.S +++ b/blob/fw_common.S @@ -122,7 +122,10 @@ _start_warm: csrw mie, zero csrw mip, zero - /* HART ID should be within expected limit */ + /* set MSIE bit to receive IPI */ + li a2, MIP_MSIP + csrw mie, a2 + /* HART ID should be withing expected limit */ csrr a6, mhartid li a5, PLAT_HART_COUNT bge a6, a5, _start_hang diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index 38032ed8..c77ffd23 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -36,6 +36,6 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch, void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid); -void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch); +void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid); #endif diff --git a/lib/sbi_console.c b/lib/sbi_console.c index 24b9d3c3..3d17340a 100644 --- a/lib/sbi_console.c +++ b/lib/sbi_console.c @@ -31,6 +31,8 @@ char sbi_getc(void) void sbi_putc(char ch) { + if (ch == '\n') + sbi_platform_console_putc(console_plat, '\r'); sbi_platform_console_putc(console_plat, ch); } @@ -291,7 +293,12 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) } continue; } else if (*format == 'l') { - if (*(format + 1) == 'x') { + if (*(format + 1) == 'u') { + format += 1; + pc += printi(out, out_len, + va_arg(args, unsigned long), + 10, 0, width, flags, 'a'); + } else if (*(format + 1) == 'x') { format += 1; pc += printi(out, out_len, va_arg(args, unsigned long), diff --git a/lib/sbi_hart.c b/lib/sbi_hart.c index db833c78..30f4f03f 100644 --- a/lib/sbi_hart.c +++ b/lib/sbi_hart.c @@ -264,31 +264,34 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch, } #define NO_HOTPLUG_BITMAP_SIZE __riscv_xlen -static spinlock_t coldboot_holding_pen_lock = SPIN_LOCK_INITIALIZER; -static volatile unsigned long coldboot_holding_pen = 0; void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid) { - unsigned long done; + unsigned long mipval; struct sbi_platform *plat = sbi_platform_ptr(scratch); + sbi_printf("%s: In hartid = [%d]\n", __func__, hartid); if ((sbi_platform_hart_count(plat) <= hartid) || (NO_HOTPLUG_BITMAP_SIZE <= hartid)) sbi_hart_hang(); + do { + wfi(); + mipval = csr_read(mip); + /* Make sure the hart woke because of ipi */ + } while (!(mipval && MIP_MSIP) ); - while (1) { - spin_lock(&coldboot_holding_pen_lock); - done = coldboot_holding_pen; - spin_unlock(&coldboot_holding_pen_lock); - if (done) - break; - cpu_relax(); - } + csr_clear(mip, MIP_MSIP); } -void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch) +void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid) { - spin_lock(&coldboot_holding_pen_lock); - coldboot_holding_pen = 1; - spin_unlock(&coldboot_holding_pen_lock); + struct sbi_platform *plat = sbi_platform_ptr(scratch); + int max_hart = sbi_platform_hart_count(plat); + + for(int i = 0; i < max_hart ; i++) { + /* send an IPI to every other hart */ + if (i != hartid) + sbi_platform_ipi_inject(plat, i, hartid); + } + } diff --git a/lib/sbi_init.c b/lib/sbi_init.c index 52c63fa3..82384b39 100644 --- a/lib/sbi_init.c +++ b/lib/sbi_init.c @@ -96,7 +96,7 @@ static void __attribute__((noreturn)) init_coldboot(struct sbi_scratch *scratch, sbi_hart_mark_available(hartid); if (!sbi_platform_has_hart_hotplug(plat)) - sbi_hart_wake_coldboot_harts(scratch); + sbi_hart_wake_coldboot_harts(scratch, hartid); sbi_hart_boot_next(hartid, scratch->next_arg1, scratch->next_addr, scratch->next_mode); diff --git a/plat/common/serial/sifive-uart.c b/plat/common/serial/sifive-uart.c index 50c7cadd..60eade3b 100644 --- a/plat/common/serial/sifive-uart.c +++ b/plat/common/serial/sifive-uart.c @@ -8,6 +8,7 @@ */ #include +#include #include #define UART_REG_TXFIFO 0 @@ -28,6 +29,29 @@ static volatile void *uart_base; static u32 uart_in_freq; static u32 uart_baudrate; +/** + * Find minimum divisor divides in_freq to max_target_hz; + * Based on uart driver n SiFive FSBL. + * + * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1 + * The nearest integer solution requires rounding up as to not exceed max_target_hz. + * div = ceil(f_in / f_baud) - 1 + * = floor((f_in - 1 + f_baud) / f_baud) - 1 + * This should not overflow as long as (f_in - 1 + f_baud) does not exceed + * 2^32 - 1, which is unlikely since we represent frequencies in kHz. + */ +static inline unsigned int uart_min_clk_divisor(uint64_t in_freq, + uint64_t max_target_hz) +{ + uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz); + // Avoid underflow + if (quotient == 0) { + return 0; + } else { + return quotient - 1; + } +} + static u32 get_reg(u32 num) { return readl(uart_base + (num * 0x4)); @@ -61,7 +85,7 @@ int sifive_uart_init(unsigned long base, uart_baudrate = baudrate; /* Configure baudrate */ - set_reg(UART_REG_DIV, (in_freq / baudrate) - 1); + set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate)); /* Disable interrupts */ set_reg(UART_REG_IE, 0); /* Enable TX */ diff --git a/plat/sifive/hifive_u540/config.mk b/plat/sifive/hifive_u540/config.mk index 58ff9191..165c80a4 100644 --- a/plat/sifive/hifive_u540/config.mk +++ b/plat/sifive/hifive_u540/config.mk @@ -9,7 +9,7 @@ # Essential defines required by SBI platform plat-cppflags-y = -DPLAT_NAME="SiFive HiFive U540" -plat-cppflags-y+= -DPLAT_HART_COUNT=1 +plat-cppflags-y+= -DPLAT_HART_COUNT=5 plat-cppflags-y+= -DPLAT_HART_STACK_SIZE=8192 # Compiler flags diff --git a/plat/sifive/hifive_u540/platform.c b/plat/sifive/hifive_u540/platform.c index a4a401ec..5b1c989f 100644 --- a/plat/sifive/hifive_u540/platform.c +++ b/plat/sifive/hifive_u540/platform.c @@ -10,12 +10,12 @@ #include #include #include +#include #include #include #include #define SIFIVE_U_SYS_CLK 1000000000 -#define SIFIVE_U_PERIPH_CLK (SIFIVE_U_SYS_CLK / 2) #define SIFIVE_U_CLINT_ADDR 0x2000000 @@ -23,8 +23,15 @@ #define SIFIVE_U_PLIC_NUM_SOURCES 0x35 #define SIFIVE_U_PLIC_NUM_PRIORITIES 7 -#define SIFIVE_U_UART0_ADDR 0x10013000 -#define SIFIVE_U_UART1_ADDR 0x10023000 +#define SIFIVE_U_UART0_ADDR 0x10010000 +#define SIFIVE_U_UART1_ADDR 0x10011000 +#define SIFIVE_UART_BAUDRATE 115200 + +/* PRCI clock related macros */ +//TODO: Do we need a separate driver for this ? +#define SIFIVE_PRCI_BASE_ADDR 0x10000000 +#define SIFIVE_PRCI_CLKMUXSTATUSREG 0x002C +#define SIFIVE_PRCI_CLKMUX_STATUS_TLCLKSEL (0x1 << 1) static int sifive_u_cold_final_init(void) { @@ -57,8 +64,18 @@ static int sifive_u_pmp_region_info(u32 target_hart, u32 index, static int sifive_u_console_init(void) { + unsigned long peri_in_freq; + + if (readl((volatile void *)SIFIVE_PRCI_BASE_ADDR + + SIFIVE_PRCI_CLKMUXSTATUSREG) & + SIFIVE_PRCI_CLKMUX_STATUS_TLCLKSEL){ + peri_in_freq = SIFIVE_U_SYS_CLK; + } else { + peri_in_freq = SIFIVE_U_SYS_CLK / 2; + } + return sifive_uart_init(SIFIVE_U_UART0_ADDR, - SIFIVE_U_PERIPH_CLK, 115200); + peri_in_freq, SIFIVE_UART_BAUDRATE); } static int sifive_u_cold_irqchip_init(void)