valentyusb: Add software for liteuart console
usb_hello is a copy of hello_world but uses both consoles Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>pull/347/head
							parent
							
								
									6be3e1a336
								
							
						
					
					
						commit
						7f9f848546
					
				| @ -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); | ||||
| @ -0,0 +1,239 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #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(); | ||||
| } | ||||
|  | ||||
| @ -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 *~ | ||||
|  | ||||
| @ -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 | ||||
| @ -0,0 +1,12 @@ | ||||
| SECTIONS | ||||
| { | ||||
| 	. = 0; | ||||
| 	.head : { | ||||
| 		KEEP(*(.head)) | ||||
|  	} | ||||
| 	. = 0x1000; | ||||
| 	.text : { *(.text) } | ||||
| 	. = 0x2a00; | ||||
| 	.data : { *(.data) } | ||||
| 	.bss : { *(.bss) } | ||||
| } | ||||
| @ -0,0 +1,72 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #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); | ||||
| 	} | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue
	
	 Matt Johnston
						Matt Johnston