Skip to content

Commit

Permalink
ppc: microwatt: Update for microwatt with standard UART
Browse files Browse the repository at this point in the history
This partially reverts f03d030

powerpc/uart: Choose which UART to use at build time, not runtime

And brings back the assumption that 0 in r3 means microwatt. The
runtime detection will be improved subsequently using the device-tree.

When using standalone microwatt, we now use the syscon registers to
detect the UART type and clock. We also get the right frequency for
the processor timebase.

Signed-off-by: Benjamin Herrenschmidt <[email protected]>
  • Loading branch information
ozbenh committed Jun 23, 2020
1 parent 13ad1a4 commit b2b7eaf
Show file tree
Hide file tree
Showing 11 changed files with 361 additions and 88 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,5 +359,4 @@ jobs:
install:
- sudo apt-get install gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross
script:
- make ${MAKEOPTS} -C ports/powerpc UART=potato
- make ${MAKEOPTS} -C ports/powerpc UART=lpc_serial
- make ${MAKEOPTS} -C ports/powerpc
6 changes: 2 additions & 4 deletions ports/powerpc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include $(TOP)/py/py.mk

# potato or lpc_serial
UART ?= potato

ARCH = $(shell uname -m)
ifneq ("$(ARCH)", "ppc64")
ifneq ("$(ARCH)", "ppc64le")
Expand All @@ -33,7 +30,8 @@ LIBS =

SRC_C = \
main.c \
uart_$(UART).c \
uart_potato.c \
uart_std.c \
lib/utils/printf.c \
lib/utils/stdout_helpers.c \
lib/utils/pyexec.c \
Expand Down
7 changes: 2 additions & 5 deletions ports/powerpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ potato UART.

## Building

By default the port will be built with the potato uart for microwatt:

$ make

To instead build for a machine with LPC serial, such as QEMU powernv:

$ make UART=lpc_serial
The end result will work on Microwatt standalone (with 0 passed
in register r3) or Qemu (with a device-tree passed in r3).

## Cross compilation for POWERPC

Expand Down
53 changes: 53 additions & 0 deletions ports/powerpc/io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#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 */

76 changes: 73 additions & 3 deletions ports/powerpc/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
#include "py/stackctrl.h"
#include "lib/utils/pyexec.h"

#include "io.h"
#include "microwatt_soc.h"
#include "uart_std.h"
#include "uart_potato.h"

unsigned long ppc_tb_freq = 512000000;

#define UART_BAUDS 115200

void __stack_chk_fail(void);
void __stack_chk_fail(void) {
static bool failed_once;
Expand All @@ -58,14 +67,75 @@ static char *stack_top;
#if MICROPY_ENABLE_GC
static char heap[32 * 1024];
#endif
static bool uart_is_potato = false;

// Receive single character
int mp_hal_stdin_rx_chr(void) {
if (uart_is_potato) {
return potato_uart_rx_chr();
} else {
return std_uart_rx_chr();
}
}

// Send string of given length
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
if (uart_is_potato) {
potato_uart_tx_strn(str, len);
} else {
std_uart_tx_strn(str, len);
}
}

static void init_microwatt(void) {
uint64_t sys_info;
uint64_t proc_freq;
uint64_t uart_info = 0;
uint64_t uart_freq = 0;

extern void uart_init_ppc(int qemu);
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_ARTB)) {
ppc_tb_freq = proc_freq;
}

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;

if (uart_info & SYS_REG_UART_IS_16550) {
std_uart_init(UART_BASE, 2, uart_freq, UART_BAUDS);
} else {
uart_is_potato = true;
potato_uart_init(UART_BASE, uart_freq, UART_BAUDS);
}
}

static void init_devicetree(unsigned long devtree) {
#define QEMU_UART_BASE 0x60300d00103f8
/* TODO: Use libfdt to parse the device-tree, in the meantime
* we assume POWER9 powernv (as provided by qemu)
*/
std_uart_init(QEMU_UART_BASE, 0, 1843200, UART_BAUDS);
}

int main(int argc, char **argv) {
int main(unsigned long devtree) {
int stack_dummy;
stack_top = (char *)&stack_dummy;

uart_init_ppc(argc);
/*
* Platform detection. Eventually assume r3 will contain
* a device-tree pointer and use libfdt to parse it, in
* the meantime, if r3 is 0, assume standalone microwatt
*/
if (devtree == 0)
init_microwatt();
else
init_devicetree(devtree);

#if MICROPY_ENABLE_PYSTACK
static mp_obj_t pystack[1024];
Expand Down
155 changes: 155 additions & 0 deletions ports/powerpc/microwatt_soc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#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 */
#define DRAM_INIT_BASE 0xff000000 /* Internal DRAM init firmware */

/*
* 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)


/*
* 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 */
11 changes: 6 additions & 5 deletions ports/powerpc/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@
#define mftb() ({unsigned long rval; \
__asm__ volatile ("mftb %0" : "=r" (rval)); rval;})

#define TBFREQ 512000000
extern unsigned long ppc_tb_freq;

static inline mp_uint_t mp_hal_ticks_ms(void) {
unsigned long tb = mftb();
unsigned long tb = mftb();

return tb * 1000 / TBFREQ;
return tb * 1000 / ppc_tb_freq;
}


static inline mp_uint_t mp_hal_ticks_us(void) {
unsigned long tb = mftb();
unsigned long tb = mftb();

return tb * 1000000 / TBFREQ;
return tb * 1000000 / ppc_tb_freq;
}

static inline void mp_hal_set_interrupt_char(char c) {
Expand Down
Loading

0 comments on commit b2b7eaf

Please sign in to comment.