/* arch/arm/arch.c — Cortex-A9 (Zynq-7000 PS) implementation. * Uses the Cadence UART (UART0 at 0xE0000000) present on the real Zynq * and modeled by QEMU's xilinx-zynq-a9 machine. On QEMU/Zynq the UART is * already configured by the bootrom, so we just poll TX-full and write. */ #include "arch.h" #include "console.h" #define UART0_BASE 0xE0000000UL #define UART_CR 0x00 /* control register */ #define UART_MR 0x04 /* mode register */ #define UART_SR 0x2C /* channel status register */ #define UART_FIFO 0x30 /* tx/rx FIFO */ #define UART_SR_TXFULL (1u << 4) #define UART_SR_RXEMPTY (1u << 1) /* Control register bits */ #define CR_RXRES (1u << 0) /* RX logic reset */ #define CR_TXRES (1u << 1) /* TX logic reset */ #define CR_RXEN (1u << 2) #define CR_TXEN (1u << 4) static volatile unsigned int *reg(unsigned long off) { return (volatile unsigned int *)(UART0_BASE + off); } void arch_early_init(void) { /* Reset and enable TX/RX. On real Zynq the bootrom sets the baud * divisors; QEMU ignores baud, so enabling TX is enough. */ *reg(UART_CR) = CR_RXRES | CR_TXRES; /* pulse resets */ *reg(UART_MR) = 0x20; /* 8N1, normal */ *reg(UART_CR) = CR_RXEN | CR_TXEN; /* enable TX/RX */ } void arch_uart_putc(char c) { while (*reg(UART_SR) & UART_SR_TXFULL) ; *reg(UART_FIFO) = (unsigned int)(unsigned char)c; } char arch_uart_getc(void) { while (*reg(UART_SR) & UART_SR_RXEMPTY) /* wait for a received byte */ ; return (char)(*reg(UART_FIFO) & 0xff); } int arch_uart_rx_ready(void) { return (*reg(UART_SR) & UART_SR_RXEMPTY) ? 0 : 1; } /* M1: point the vector base (VBAR) at our table (defined in vectors.S). */ extern void vector_table(void); void arch_set_trap_vector(void) { unsigned long v = (unsigned long)vector_table; __asm__ volatile("mcr p15, 0, %0, c12, c0, 0" :: "r"(v)); /* VBAR */ } const char *arch_name(void) { return "arm (cortex-a9, zynq-7000)"; } const char *arch_cpu_mode(void) { /* CPSR bits[4:0] = mode. 0x13=SVC, 0x10=USR, 0x1F=SYS, 0x12=IRQ. */ unsigned long cpsr; __asm__ volatile("mrs %0, cpsr" : "=r"(cpsr)); switch (cpsr & 0x1f) { case 0x10: return "USR"; case 0x11: return "FIQ"; case 0x12: return "IRQ"; case 0x13: return "SVC"; case 0x1a: return "HYP"; case 0x1f: return "SYS"; default: return "?"; } } void arch_halt(void) { for (;;) __asm__ volatile("wfi"); }