From: Matt Johnston Date: Mon, 7 Feb 2022 09:07:14 +0000 (+0800) Subject: valentyusb: Add software for liteuart console X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7f9f8485467193af57243c8f87727e3399621797;p=microwatt.git valentyusb: Add software for liteuart console usb_hello is a copy of hello_world but uses both consoles Signed-off-by: Matt Johnston --- diff --git a/include/liteuart_console.h b/include/liteuart_console.h new file mode 100644 index 0000000..851ca7a --- /dev/null +++ b/include/liteuart_console.h @@ -0,0 +1,7 @@ +#pragma once + +int usb_getchar(void); +bool usb_havechar(void); +int usb_putchar(int c); +int usb_puts(const char *str); +void usb_console_init(void); diff --git a/lib/liteuart_console.c b/lib/liteuart_console.c new file mode 100644 index 0000000..3822af3 --- /dev/null +++ b/lib/liteuart_console.c @@ -0,0 +1,239 @@ +#include +#include + +#include "console.h" +#include "liteuart_console.h" +#include "microwatt_soc.h" +#include "io.h" + +#define UART_BAUDS 115200 + +static uint64_t uart_base; + +/* From Linux liteuart.c */ +#define OFF_RXTX 0x00 +#define OFF_TXFULL 0x04 +#define OFF_RXEMPTY 0x08 +#define OFF_EV_STATUS 0x0c +#define OFF_EV_PENDING 0x10 +#define OFF_EV_ENABLE 0x14 + +/* From litex uart.h */ +#define UART_EV_TX 0x1 +#define UART_EV_RX 0x2 + +/* Modified version of csr.h */ +/* uart */ +static inline uint32_t uart_rxtx_read(void) { + return readl(uart_base + OFF_RXTX); +} + +static inline void uart_rxtx_write(uint32_t v) { + writel(v, uart_base + OFF_RXTX); +} + +static inline uint32_t uart_txfull_read(void) { + return readl(uart_base + OFF_TXFULL); +} + +static inline uint32_t uart_rxempty_read(void) { + return readl(uart_base + OFF_RXEMPTY); +} + +static inline uint32_t uart_ev_status_read(void) { + return readl(uart_base + OFF_EV_STATUS); +} + +// static inline uint32_t uart_ev_status_tx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 0) & mask ); +// } +// static inline uint32_t uart_ev_status_tx_read(void) { +// uint32_t word = uart_ev_status_read(); +// return uart_ev_status_tx_extract(word); +// } + +// static inline uint32_t uart_ev_status_rx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 1) & mask ); +// } +// static inline uint32_t uart_ev_status_rx_read(void) { +// uint32_t word = uart_ev_status_read(); +// return uart_ev_status_rx_extract(word); +// } + +static inline uint32_t uart_ev_pending_read(void) { + return readl(uart_base + OFF_EV_PENDING); +} +static inline void uart_ev_pending_write(uint32_t v) { + writel(v, uart_base + OFF_EV_PENDING); +} + +// static inline uint32_t uart_ev_pending_tx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 0) & mask ); +// } +// static inline uint32_t uart_ev_pending_tx_read(void) { +// uint32_t word = uart_ev_pending_read(); +// return uart_ev_pending_tx_extract(word); +// } +// static inline uint32_t uart_ev_pending_tx_replace(uint32_t oldword, uint32_t plain_value) { +// uint32_t mask = ((1 << 1)-1); +// return (oldword & (~(mask << 0))) | (mask & plain_value)<< 0 ; +// } +// static inline void uart_ev_pending_tx_write(uint32_t plain_value) { +// uint32_t oldword = uart_ev_pending_read(); +// uint32_t newword = uart_ev_pending_tx_replace(oldword, plain_value); +// uart_ev_pending_write(newword); +// } +// #define CSR_UART_EV_PENDING_RX_OFFSET 1 +// #define CSR_UART_EV_PENDING_RX_SIZE 1 +// static inline uint32_t uart_ev_pending_rx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 1) & mask ); +// } +// static inline uint32_t uart_ev_pending_rx_read(void) { +// uint32_t word = uart_ev_pending_read(); +// return uart_ev_pending_rx_extract(word); +// } +// static inline uint32_t uart_ev_pending_rx_replace(uint32_t oldword, uint32_t plain_value) { +// uint32_t mask = ((1 << 1)-1); +// return (oldword & (~(mask << 1))) | (mask & plain_value)<< 1 ; +// } +// static inline void uart_ev_pending_rx_write(uint32_t plain_value) { +// uint32_t oldword = uart_ev_pending_read(); +// uint32_t newword = uart_ev_pending_rx_replace(oldword, plain_value); +// uart_ev_pending_write(newword); +// } +// #define CSR_UART_EV_ENABLE_ADDR (CSR_BASE + 0x814L) +// #define CSR_UART_EV_ENABLE_SIZE 1 +// static inline uint32_t uart_ev_enable_read(void) { +// return csr_read_simple(CSR_BASE + 0x814L); +// } +static inline void uart_ev_enable_write(uint32_t v) { + writel(v, uart_base + OFF_EV_ENABLE); +} +// #define CSR_UART_EV_ENABLE_TX_OFFSET 0 +// #define CSR_UART_EV_ENABLE_TX_SIZE 1 +// static inline uint32_t uart_ev_enable_tx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 0) & mask ); +// } +// static inline uint32_t uart_ev_enable_tx_read(void) { +// uint32_t word = uart_ev_enable_read(); +// return uart_ev_enable_tx_extract(word); +// } +// static inline uint32_t uart_ev_enable_tx_replace(uint32_t oldword, uint32_t plain_value) { +// uint32_t mask = ((1 << 1)-1); +// return (oldword & (~(mask << 0))) | (mask & plain_value)<< 0 ; +// } +// static inline void uart_ev_enable_tx_write(uint32_t plain_value) { +// uint32_t oldword = uart_ev_enable_read(); +// uint32_t newword = uart_ev_enable_tx_replace(oldword, plain_value); +// uart_ev_enable_write(newword); +// } +// #define CSR_UART_EV_ENABLE_RX_OFFSET 1 +// #define CSR_UART_EV_ENABLE_RX_SIZE 1 +// static inline uint32_t uart_ev_enable_rx_extract(uint32_t oldword) { +// uint32_t mask = ((1 << 1)-1); +// return ( (oldword >> 1) & mask ); +// } +// static inline uint32_t uart_ev_enable_rx_read(void) { +// uint32_t word = uart_ev_enable_read(); +// return uart_ev_enable_rx_extract(word); +// } +// static inline uint32_t uart_ev_enable_rx_replace(uint32_t oldword, uint32_t plain_value) { +// uint32_t mask = ((1 << 1)-1); +// return (oldword & (~(mask << 1))) | (mask & plain_value)<< 1 ; +// } +// static inline void uart_ev_enable_rx_write(uint32_t plain_value) { +// uint32_t oldword = uart_ev_enable_read(); +// uint32_t newword = uart_ev_enable_rx_replace(oldword, plain_value); +// uart_ev_enable_write(newword); +// } +// #define CSR_UART_TUNING_WORD_ADDR (CSR_BASE + 0x818L) +// #define CSR_UART_TUNING_WORD_SIZE 1 +// static inline uint32_t uart_tuning_word_read(void) { +// return csr_read_simple(CSR_BASE + 0x818L); +// } +// static inline void uart_tuning_word_write(uint32_t v) { +// csr_write_simple(v, CSR_BASE + 0x818L); +// } +// #define CSR_UART_CONFIGURED_ADDR (CSR_BASE + 0x81cL) +// #define CSR_UART_CONFIGURED_SIZE 1 +// static inline uint32_t uart_configured_read(void) { +// return csr_read_simple(CSR_BASE + 0x81cL); +// } +// static inline void uart_configured_write(uint32_t v) { +// csr_write_simple(v, CSR_BASE + 0x81cL); +// } + +// end of csr code + +static char uart_read(void) +{ + char c; + while (uart_rxempty_read()); + c = uart_rxtx_read(); + uart_ev_pending_write(UART_EV_RX); + return c; +} + +static int uart_read_nonblock(void) +{ + return (uart_rxempty_read() == 0); +} + +static void uart_write(char c) +{ + while (uart_txfull_read()); + uart_rxtx_write(c); + uart_ev_pending_write(UART_EV_TX); +} + +static void uart_init(void) +{ + uart_ev_pending_write(uart_ev_pending_read()); + uart_ev_enable_write(UART_EV_TX | UART_EV_RX); +} + +// static void uart_sync(void) +// { +// while (uart_txfull_read()); +// } + +int usb_getchar(void) +{ + return uart_read(); +} + +bool usb_havechar(void) +{ + return uart_read_nonblock(); +} + +int usb_putchar(int c) +{ + uart_write(c); + return c; +} + +int usb_puts(const char *str) +{ + unsigned int i; + + for (i = 0; *str; i++) { + char c = *(str++); + if (c == 10) + usb_putchar(13); + usb_putchar(c); + } + return 0; +} + +void usb_console_init(void) +{ + uart_base = UARTUSB_BASE; + uart_init(); +} + diff --git a/usb_hello/Makefile b/usb_hello/Makefile new file mode 100644 index 0000000..ea3966f --- /dev/null +++ b/usb_hello/Makefile @@ -0,0 +1,38 @@ +ARCH = $(shell uname -m) +ifneq ("$(ARCH)", "ppc64") +ifneq ("$(ARCH)", "ppc64le") + CROSS_COMPILE ?= powerpc64le-linux-gnu- +endif +endif + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy + +CFLAGS = -Os -g -Wall -std=c99 -msoft-float -mno-string -mno-multiple -mno-vsx -mno-altivec -mlittle-endian -fno-stack-protector -mstrict-align -ffreestanding -fdata-sections -ffunction-sections -I../include +CFLAGS += -Werror -Wextra +ASFLAGS = $(CFLAGS) +LDFLAGS = -T powerpc.lds + +all: usb_hello.hex + +console.o: ../lib/console.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +liteuart_console.o: ../lib/liteuart_console.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +usb_hello.elf: usb_hello.o head.o console.o liteuart_console.o + $(LD) $(LDFLAGS) -o $@ $^ + +usb_hello.bin: usb_hello.elf + $(OBJCOPY) -O binary $^ $@ + +usb_hello.hex: usb_hello.bin + ../scripts/bin2hex.py $^ > $@ + +clean: + @rm -f *.o usb_hello.elf usb_hello.bin usb_hello.hex +distclean: clean + rm -f *~ + diff --git a/usb_hello/head.S b/usb_hello/head.S new file mode 100644 index 0000000..6357606 --- /dev/null +++ b/usb_hello/head.S @@ -0,0 +1,107 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define STACK_TOP 0x2000 + +#define FIXUP_ENDIAN \ + tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \ + b 191f; /* Skip trampoline if endian is good */ \ + .long 0xa600607d; /* mfmsr r11 */ \ + .long 0x01006b69; /* xori r11,r11,1 */ \ + .long 0x05009f42; /* bcl 20,31,$+4 */ \ + .long 0xa602487d; /* mflr r10 */ \ + .long 0x14004a39; /* addi r10,r10,20 */ \ + .long 0xa64b5a7d; /* mthsrr0 r10 */ \ + .long 0xa64b7b7d; /* mthsrr1 r11 */ \ + .long 0x2402004c; /* hrfid */ \ +191: + + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + + .section ".head","ax" + + /* + * Microwatt currently enters in LE mode at 0x0, so we don't need to + * do any endian fix ups> + */ + . = 0 +.global _start +_start: + b boot_entry + + /* QEMU enters at 0x10 */ + . = 0x10 + FIXUP_ENDIAN + b boot_entry + + . = 0x100 + FIXUP_ENDIAN + b boot_entry + +.global boot_entry +boot_entry: + /* setup stack */ + LOAD_IMM64(%r1, STACK_TOP - 0x100) + LOAD_IMM64(%r12, main) + mtctr %r12, + bctrl + b . + +#define EXCEPTION(nr) \ + .= nr ;\ + b . + + /* More exception stubs */ + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) +#if 0 + EXCEPTION(0x1000) + EXCEPTION(0x1100) + EXCEPTION(0x1200) + EXCEPTION(0x1300) + EXCEPTION(0x1400) + EXCEPTION(0x1500) + EXCEPTION(0x1600) +#endif diff --git a/usb_hello/powerpc.lds b/usb_hello/powerpc.lds new file mode 100644 index 0000000..2511d1a --- /dev/null +++ b/usb_hello/powerpc.lds @@ -0,0 +1,12 @@ +SECTIONS +{ + . = 0; + .head : { + KEEP(*(.head)) + } + . = 0x1000; + .text : { *(.text) } + . = 0x2a00; + .data : { *(.data) } + .bss : { *(.bss) } +} diff --git a/usb_hello/usb_hello.c b/usb_hello/usb_hello.c new file mode 100644 index 0000000..58f0b9c --- /dev/null +++ b/usb_hello/usb_hello.c @@ -0,0 +1,72 @@ +#include +#include + +#include "console.h" +#include "liteuart_console.h" + +#include "microwatt_soc.h" +#include "io.h" + +static char mw_logo[] = + +"\n" +" .oOOo. \n" +" .\" \". \n" +" ; .mw. ; Microwatt, it works.\n" +" . ' ' . \n" +" \\ || / \n" +" ;..; \n" +" ;..; \n" +" `ww' \n"; + +static void print_hex(unsigned long val, int ndigits) +{ + int i, x; + + for (i = (ndigits - 1) * 4; i >= 0; i -= 4) { + x = (val >> i) & 0xf; + if (x >= 10) + putchar(x + 'a' - 10); + else + putchar(x + '0'); + } +} + +int main(void) +{ + console_init(); + usb_console_init(); + + puts(mw_logo); + + for (int i = 0; i <= 0x14; i+=4) { + unsigned long val = readl(UART0_BASE + i); + puts("reg 0x"); + print_hex(i, 2); + puts(" = 0x"); + print_hex(val, 8); + puts("\n"); + } + puts("printed\n"); + for (int i = 0; i <= 0x14; i+=4) { + unsigned long val = readl(UART0_BASE + i); + puts("reg 0x"); + print_hex(i, 2); + puts(" = 0x"); + print_hex(val, 8); + puts("\n"); + } + puts("printed\n"); + + usb_puts(mw_logo); + + while (1) { + // puts(mw_logo); + // usb_puts(mw_logo); + unsigned char c = usb_getchar(); + putchar(c); + usb_putchar(c); + if (c == 13) // if CR send LF + putchar(10); + } +}