From 3d9a298748a20dcb3ef5bb6283c0e37b921f4c85 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 18 Feb 2022 20:11:35 +0000 Subject: [PATCH] add microwatt console lib and #includes --- include/console.h | 16 +++ include/io.h | 58 ++++++++++ include/microwatt_soc.h | 165 +++++++++++++++++++++++++++++ lib/console.c | 228 ++++++++++++++++++++++++++++++++++++++++ src/ls2.py | 17 ++- 5 files changed, 479 insertions(+), 5 deletions(-) create mode 100644 include/console.h create mode 100644 include/io.h create mode 100644 include/microwatt_soc.h create mode 100644 lib/console.c diff --git a/include/console.h b/include/console.h new file mode 100644 index 0000000..9d58bb6 --- /dev/null +++ b/include/console.h @@ -0,0 +1,16 @@ +/* This code is directly from Microwatt and is Copyright and Licensed + under the same terms as Microwatt source code. + https://github.com/antonblanchard/microwatt/blob/master/include/console.h +*/ + +#include + +void console_init(void); +void console_set_irq_en(bool rx_irq, bool tx_irq); +int getchar(void); +int putchar(int c); +int puts(const char *str); + +#ifndef __USE_LIBC +size_t strlen(const char *s); +#endif diff --git a/include/io.h b/include/io.h new file mode 100644 index 0000000..bf29f49 --- /dev/null +++ b/include/io.h @@ -0,0 +1,58 @@ +/* This code is directly from Microwatt and is Copyright and Licensed + under the same terms as Microwatt source code. + https://github.com/antonblanchard/microwatt/blob/master/include/io.h +*/ + +#ifndef __IO_H +#define __IO_H + +static inline uint8_t readb(unsigned long addr) +{ + uint8_t val; + __asm__ volatile("sync; lbzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory"); + return val; +} + +static inline uint16_t readw(unsigned long addr) +{ + uint16_t val; + __asm__ volatile("sync; lhzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory"); + return val; +} + +static inline uint32_t readl(unsigned long addr) +{ + uint32_t val; + __asm__ volatile("sync; lwzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory"); + return val; +} + +static inline uint64_t readq(unsigned long addr) +{ + uint64_t val; + __asm__ volatile("sync; ldcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory"); + return val; +} + +static inline void writeb(uint8_t val, unsigned long addr) +{ + __asm__ volatile("sync; stbcix %0,0,%1" : : "r" (val), "r" (addr) : "memory"); +} + +static inline void writew(uint16_t val, unsigned long addr) +{ + __asm__ volatile("sync; sthcix %0,0,%1" : : "r" (val), "r" (addr) : "memory"); +} + +static inline void writel(uint32_t val, unsigned long addr) +{ + __asm__ volatile("sync; stwcix %0,0,%1" : : "r" (val), "r" (addr) : "memory"); +} + +static inline void writeq(uint64_t val, unsigned long addr) +{ + __asm__ volatile("sync; stdcix %0,0,%1" : : "r" (val), "r" (addr) : "memory"); +} + +#endif /* __IO_H */ + diff --git a/include/microwatt_soc.h b/include/microwatt_soc.h new file mode 100644 index 0000000..22f8c0d --- /dev/null +++ b/include/microwatt_soc.h @@ -0,0 +1,165 @@ +/* This code is directly from Microwatt and is Copyright and Licensed + under the same terms as Microwatt source code. +https://github.com/antonblanchard/microwatt/blob/master/include/microwatt_soc.h +*/ + +#ifndef __MICROWATT_SOC_H +#define __MICROWATT_SOC_H + +/* + * Microwatt SoC memory map + */ + +#define MEMORY_BASE 0x00000000 /* "Main" memory alias, either BRAM or DRAM */ +#define DRAM_BASE 0x40000000 /* DRAM if present */ +#define BRAM_BASE 0x80000000 /* Internal BRAM */ + +#define SYSCON_BASE 0xc0000000 /* System control regs */ +#define UART_BASE 0xc0002000 /* UART */ +#define XICS_ICP_BASE 0xc0004000 /* Interrupt controller */ +#define XICS_ICS_BASE 0xc0005000 /* Interrupt controller */ +#define SPI_FCTRL_BASE 0xc0006000 /* SPI flash controller registers */ +#define DRAM_CTRL_BASE 0xc8000000 /* LiteDRAM control registers */ +#define LETH_CSR_BASE 0xc8020000 /* LiteEth CSR registers */ +#define LETH_SRAM_BASE 0xc8030000 /* LiteEth MMIO space */ +#define SPI_FLASH_BASE 0xf0000000 /* SPI Flash memory map */ +#ifdef STANDALONE_MINI_BIOS +#define DRAM_INIT_BASE 0x00000000 /* alternative, for verilator simulation */ +#else +#define DRAM_INIT_BASE 0xff000000 /* Internal DRAM init firmware */ +#endif + +/* + * Interrupt numbers + */ +#define IRQ_UART0 0 +#define IRQ_ETHERNET 1 + +/* + * Register definitions for the syscon registers + */ + +#define SYS_REG_SIGNATURE 0x00 +#define SYS_REG_INFO 0x08 +#define SYS_REG_INFO_HAS_UART (1ull << 0) +#define SYS_REG_INFO_HAS_DRAM (1ull << 1) +#define SYS_REG_INFO_HAS_BRAM (1ull << 2) +#define SYS_REG_INFO_HAS_SPI_FLASH (1ull << 3) +#define SYS_REG_INFO_HAS_LITEETH (1ull << 4) +#define SYS_REG_INFO_HAS_LARGE_SYSCON (1ull << 5) +#define SYS_REG_INFO_HAS_UART1 (1ull << 6) +#define SYS_REG_INFO_HAS_ARTB (1ull << 7) +#define SYS_REG_BRAMINFO 0x10 +#define SYS_REG_BRAMINFO_SIZE_MASK 0xfffffffffffffull +#define SYS_REG_DRAMINFO 0x18 +#define SYS_REG_DRAMINFO_SIZE_MASK 0xfffffffffffffull +#define SYS_REG_CLKINFO 0x20 +#define SYS_REG_CLKINFO_FREQ_MASK 0xffffffffffull +#define SYS_REG_CTRL 0x28 +#define SYS_REG_CTRL_DRAM_AT_0 (1ull << 0) +#define SYS_REG_CTRL_CORE_RESET (1ull << 1) +#define SYS_REG_CTRL_SOC_RESET (1ull << 2) +#define SYS_REG_DRAMINITINFO 0x30 +#define SYS_REG_SPI_INFO 0x38 +#define SYS_REG_SPI_INFO_FLASH_OFF_MASK 0xffffffff +#define SYS_REG_UART0_INFO 0x40 +#define SYS_REG_UART1_INFO 0x48 +#define SYS_REG_UART_IS_16550 (1ull << 32) +#define SYS_REG_BRAM_BOOTADDR 0x50 + + +/* + * Register definitions for the potato UART + */ +#define POTATO_CONSOLE_TX 0x00 +#define POTATO_CONSOLE_RX 0x08 +#define POTATO_CONSOLE_STATUS 0x10 +#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x01 +#define POTATO_CONSOLE_STATUS_TX_EMPTY 0x02 +#define POTATO_CONSOLE_STATUS_RX_FULL 0x04 +#define POTATO_CONSOLE_STATUS_TX_FULL 0x08 +#define POTATO_CONSOLE_CLOCK_DIV 0x18 +#define POTATO_CONSOLE_IRQ_EN 0x20 +#define POTATO_CONSOLE_IRQ_RX 0x01 +#define POTATO_CONSOLE_IRQ_TX 0x02 + +/* + * Register definitionss for our standard (16550 style) UART + */ +#define UART_REG_RX 0x00 +#define UART_REG_TX 0x00 +#define UART_REG_DLL 0x00 +#define UART_REG_IER 0x04 +#define UART_REG_IER_RDI 0x01 +#define UART_REG_IER_THRI 0x02 +#define UART_REG_IER_RLSI 0x04 +#define UART_REG_IER_MSI 0x08 +#define UART_REG_DLM 0x04 +#define UART_REG_IIR 0x08 +#define UART_REG_FCR 0x08 +#define UART_REG_FCR_EN_FIFO 0x01 +#define UART_REG_FCR_CLR_RCVR 0x02 +#define UART_REG_FCR_CLR_XMIT 0x04 +#define UART_REG_FCR_TRIG1 0x00 +#define UART_REG_FCR_TRIG4 0x40 +#define UART_REG_FCR_TRIG8 0x80 +#define UART_REG_FCR_TRIG14 0xc0 +#define UART_REG_LCR 0x0c +#define UART_REG_LCR_5BIT 0x00 +#define UART_REG_LCR_6BIT 0x01 +#define UART_REG_LCR_7BIT 0x02 +#define UART_REG_LCR_8BIT 0x03 +#define UART_REG_LCR_STOP 0x04 +#define UART_REG_LCR_PAR 0x08 +#define UART_REG_LCR_EVEN_PAR 0x10 +#define UART_REG_LCR_STIC_PAR 0x20 +#define UART_REG_LCR_BREAK 0x40 +#define UART_REG_LCR_DLAB 0x80 +#define UART_REG_MCR 0x10 +#define UART_REG_MCR_DTR 0x01 +#define UART_REG_MCR_RTS 0x02 +#define UART_REG_MCR_OUT1 0x04 +#define UART_REG_MCR_OUT2 0x08 +#define UART_REG_MCR_LOOP 0x10 +#define UART_REG_LSR 0x14 +#define UART_REG_LSR_DR 0x01 +#define UART_REG_LSR_OE 0x02 +#define UART_REG_LSR_PE 0x04 +#define UART_REG_LSR_FE 0x08 +#define UART_REG_LSR_BI 0x10 +#define UART_REG_LSR_THRE 0x20 +#define UART_REG_LSR_TEMT 0x40 +#define UART_REG_LSR_FIFOE 0x80 +#define UART_REG_MSR 0x18 +#define UART_REG_SCR 0x1c + + +/* + * Register definitions for the SPI controller + */ +#define SPI_REG_DATA 0x00 /* Byte access: single wire transfer */ +#define SPI_REG_DATA_DUAL 0x01 /* Byte access: dual wire transfer */ +#define SPI_REG_DATA_QUAD 0x02 /* Byte access: quad wire transfer */ +#define SPI_REG_CTRL 0x04 /* Reset and manual mode control */ +#define SPI_REG_CTRL_RESET 0x01 /* reset all registers */ +#define SPI_REG_CTRL_MANUAL_CS 0x02 /* assert CS, enable manual mode */ +#define SPI_REG_CTRL_CKDIV_SHIFT 8 /* clock div */ +#define SPI_REG_CTRL_CKDIV_MASK (0xff << SPI_REG_CTRL_CKDIV_SHIFT) +#define SPI_REG_AUTO_CFG 0x08 /* Automatic map configuration */ +#define SPI_REG_AUTO_CFG_CMD_SHIFT 0 /* Command to use for reads */ +#define SPI_REG_AUTO_CFG_CMD_MASK (0xff << SPI_REG_AUTO_CFG_CMD_SHIFT) +#define SPI_REG_AUTO_CFG_DUMMIES_SHIFT 8 /* # dummy cycles */ +#define SPI_REG_AUTO_CFG_DUMMIES_MASK (0x7 << SPI_REG_AUTO_CFG_DUMMIES_SHIFT) +#define SPI_REG_AUTO_CFG_MODE_SHIFT 11 /* SPI wire mode */ +#define SPI_REG_AUTO_CFG_MODE_MASK (0x3 << SPI_REG_AUTO_CFG_MODE_SHIFT) +#define SPI_REG_AUT_CFG_MODE_SINGLE (0 << 11) +#define SPI_REG_AUT_CFG_MODE_DUAL (2 << 11) +#define SPI_REG_AUT_CFG_MODE_QUAD (3 << 11) +#define SPI_REG_AUTO_CFG_ADDR4 (1u << 13) /* 3 or 4 addr bytes */ +#define SPI_REG_AUTO_CFG_CKDIV_SHIFT 16 /* clock div */ +#define SPI_REG_AUTO_CFG_CKDIV_MASK (0xff << SPI_REG_AUTO_CFG_CKDIV_SHIFT) +#define SPI_REG_AUTO_CFG_CSTOUT_SHIFT 24 /* CS timeout */ +#define SPI_REG_AUTO_CFG_CSTOUT_MASK (0x3f << SPI_REG_AUTO_CFG_CSTOUT_SHIFT) + + +#endif /* __MICROWATT_SOC_H */ diff --git a/lib/console.c b/lib/console.c new file mode 100644 index 0000000..b44c024 --- /dev/null +++ b/lib/console.c @@ -0,0 +1,228 @@ +/* This code is directly from Microwatt and is Copyright and Licensed + under the same terms as Microwatt source code. + https://github.com/antonblanchard/microwatt/blob/master/lib/console.c +*/ + +#include +#include + +#include "console.h" +#include "microwatt_soc.h" +#include "io.h" + +#define UART_BAUDS 115200 + +/* + * Core UART functions to implement for a port + */ + +bool uart_is_std; + +static uint64_t uart_base; + +static unsigned long uart_divisor(unsigned long uart_freq, unsigned long bauds) +{ + return uart_freq / (bauds * 16); +} + +static uint64_t potato_uart_reg_read(int offset) +{ + return readq(uart_base + offset); +} + +static void potato_uart_reg_write(int offset, uint64_t val) +{ + writeq(val, uart_base + offset); +} + +static int potato_uart_rx_empty(void) +{ + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_RX_EMPTY) + return 1; + + return 0; +} + +static int potato_uart_tx_full(void) +{ + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_TX_FULL) + return 1; + + return 0; +} + +static char potato_uart_read(void) +{ + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_RX); + + return (char)(val & 0x000000ff); +} + +static void potato_uart_write(char c) +{ + uint64_t val; + + val = c; + + potato_uart_reg_write(POTATO_CONSOLE_TX, val); +} + +static void potato_uart_init(uint64_t uart_freq) +{ + unsigned long div = uart_divisor(uart_freq, UART_BAUDS) - 1; + potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, div); +} + +static void potato_uart_set_irq_en(bool rx_irq, bool tx_irq) +{ + uint64_t en = 0; + + if (rx_irq) + en |= POTATO_CONSOLE_IRQ_RX; + if (tx_irq) + en |= POTATO_CONSOLE_IRQ_TX; + potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN, en); +} + +static bool std_uart_rx_empty(void) +{ + return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_DR); +} + +static uint8_t std_uart_read(void) +{ + return readb(uart_base + UART_REG_RX); +} + +static bool std_uart_tx_full(void) +{ + return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_THRE); +} + +static void std_uart_write(uint8_t c) +{ + writeb(c, uart_base + UART_REG_TX); +} + +static void std_uart_set_irq_en(bool rx_irq, bool tx_irq) +{ + uint8_t ier = 0; + + if (tx_irq) + ier |= UART_REG_IER_THRI; + if (rx_irq) + ier |= UART_REG_IER_RDI; + writeb(ier, uart_base + UART_REG_IER); +} + +static void std_uart_init(uint64_t uart_freq) +{ + unsigned long div = uart_divisor(uart_freq, UART_BAUDS); + + writeb(UART_REG_LCR_DLAB, uart_base + UART_REG_LCR); + writeb(div & 0xff, uart_base + UART_REG_DLL); + writeb(div >> 8, uart_base + UART_REG_DLM); + writeb(UART_REG_LCR_8BIT, uart_base + UART_REG_LCR); + writeb(UART_REG_MCR_DTR | + UART_REG_MCR_RTS, uart_base + UART_REG_MCR); + writeb(UART_REG_FCR_EN_FIFO | + UART_REG_FCR_CLR_RCVR | + UART_REG_FCR_CLR_XMIT, uart_base + UART_REG_FCR); +} + +int getchar(void) +{ + if (uart_is_std) { + while (std_uart_rx_empty()) + /* Do nothing */ ; + return std_uart_read(); + } else { + while (potato_uart_rx_empty()) + /* Do nothing */ ; + return potato_uart_read(); + } +} + +int putchar(int c) +{ + if (uart_is_std) { + while(std_uart_tx_full()) + /* Do Nothing */; + std_uart_write(c); + } else { + while (potato_uart_tx_full()) + /* Do Nothing */; + potato_uart_write(c); + } + return c; +} + +int puts(const char *str) +{ + unsigned int i; + + for (i = 0; *str; i++) { + char c = *(str++); + if (c == 10) + putchar(13); + putchar(c); + } + return 0; +} + +#ifndef __USE_LIBC +size_t strlen(const char *s) +{ + size_t len = 0; + + while (*s++) + len++; + + return len; +} +#endif + +void console_init(void) +{ + uint64_t sys_info; + uint64_t proc_freq; + uint64_t uart_info = 0; + uint64_t uart_freq = 0; + + proc_freq = readq(SYSCON_BASE + SYS_REG_CLKINFO) & SYS_REG_CLKINFO_FREQ_MASK; + sys_info = readq(SYSCON_BASE + SYS_REG_INFO); + + if (sys_info & SYS_REG_INFO_HAS_LARGE_SYSCON) { + uart_info = readq(SYSCON_BASE + SYS_REG_UART0_INFO); + uart_freq = uart_info & 0xffffffff; + } + if (uart_freq == 0) + uart_freq = proc_freq; + + uart_base = UART_BASE; + if (uart_info & SYS_REG_UART_IS_16550) { + uart_is_std = true; + std_uart_init(proc_freq); + } else { + uart_is_std = false; + potato_uart_init(proc_freq); + } +} + +void console_set_irq_en(bool rx_irq, bool tx_irq) +{ + if (uart_is_std) + std_uart_set_irq_en(rx_irq, tx_irq); + else + potato_uart_set_irq_en(rx_irq, tx_irq); +} diff --git a/src/ls2.py b/src/ls2.py index 576ec96..54d4f4d 100644 --- a/src/ls2.py +++ b/src/ls2.py @@ -27,7 +27,7 @@ from soc.bus.syscon import MicrowattSYSCON from gram.core import gramCore from gram.phy.ecp5ddrphy import ECP5DDRPHY -from gram.modules import MT41K256M16 +from gram.modules import MT41K256M16, MT41K64M16 from gram.frontend.wishbone import gramWishbone from nmigen_boards.versa_ecp5 import VersaECP5Platform @@ -43,6 +43,7 @@ import os class DDR3SoC(SoC, Elaboratable): def __init__(self, *, + dram_cls, uart_pins, ddr_pins, ddrphy_addr, dramcore_addr, ddr_addr, fw_addr=0x0000_0000, @@ -264,6 +265,11 @@ if __name__ == "__main__": 'ulx3s': 'Trellis', 'sim': None, }.get(fpga, None) + dram_cls = {'arty_a7': None, + 'versa_ecp5': MT41K64M16, + 'ulx3s': None, + 'sim': None, + }.get(fpga, None) if platform_kls is not None: platform = platform_kls(toolchain=toolchain) else: @@ -284,18 +290,19 @@ if __name__ == "__main__": # get DDR resource pins ddr_pins = None - if False and platform is not None and fpga in ['versa_ecp5', 'arty_a7']: + if platform is not None and fpga in ['versa_ecp5', 'arty_a7']: ddr_pins = platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"}, xdr={"clk":4, "a":4, "ba":4, "clk_en":4, "odt":4, "ras":4, "cas":4, "we":4}) # set up the SOC - soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base + soc = DDR3SoC(dram_cls, + ddrphy_addr=0xff000000, # DRAM firmware init base dramcore_addr=0x80000000, ddr_addr=0x10000000, - #fw_addr=fw_addr, - fw_addr=None, + fw_addr=fw_addr, + #fw_addr=None, ddr_pins=ddr_pins, uart_pins=uart_pins, firmware=firmware, -- 2.30.2