Print this page
bcm2835: use the real uart instead of the mini-uart
The real uart is more capable.  We'll want to use it for the real console
eventually anyway, so let's bite the bullet now when no one will really
notice.  (For comparison, the Linux kernel uses the real uart and totally
lacks a driver for the miniuart.)

*** 16,57 **** #include <sys/elf.h> #include <sys/atag.h> /* ! * The primary serial console that we end up using is not in fact a normal UART, ! * but is instead actually a mini-uart that shares interrupts and registers with ! * the SPI masters as well. While the RPi also supports another more traditional ! * UART, that isn't what we are actually hooking up to generally with the ! * adafruit cable. We already wasted our time having to figure that out. -_- */ ! #define AUX_BASE 0x20215000 ! #define AUX_ENABLES 0x4 ! #define AUX_MU_IO_REG 0x40 ! #define AUX_MU_IER_REG 0x44 ! #define AUX_MU_IIR_REG 0x48 ! #define AUX_MU_LCR_REG 0x4C ! #define AUX_MU_MCR_REG 0x50 ! #define AUX_MU_LSR_REG 0x54 ! #define AUX_MU_CNTL_REG 0x60 ! #define AUX_MU_BAUD 0x68 - #define AUX_MU_RX_READY 0x01 - #define AUX_MU_TX_READY 0x20 /* ! * For the mini UART, all we care about are pins 14 and 15 for the UART. ! * Specifically, alt5 for GPIO14 is TXD1 and GPIO15 is RXD1. Those are ! * controlled by FSEL1. */ #define GPIO_BASE 0x20200000 #define GPIO_FSEL1 0x4 #define GPIO_PUD 0x94 #define GPIO_PUDCLK0 0x98 ! #define GPIO_SEL_ALT5 0x2 #define GPIO_UART_MASK 0xfffc0fff #define GPIO_UART_TX_SHIFT 12 #define GPIO_UART_RX_SHIFT 15 #define GPIO_PUD_DISABLE 0x0 --- 16,60 ---- #include <sys/elf.h> #include <sys/atag.h> /* ! * The primary serial console that we end up using is the normal UART, not ! * the mini-uart that shares interrupts and registers with the SPI masters ! * as well. */ ! #define UART_BASE 0x20201000 ! #define UART_DR 0x0 ! #define UART_FR 0x18 ! #define UART_IBRD 0x24 ! #define UART_FBRD 0x28 ! #define UART_LCRH 0x2c ! #define UART_CR 0x30 ! #define UART_ICR 0x44 ! ! #define UART_FR_RXFE 0x10 /* RX fifo empty */ ! #define UART_FR_TXFF 0x20 /* TX fifo full */ ! ! #define UART_LCRH_FEN 0x00000010 /* fifo enable */ ! #define UART_LCRH_WLEN_8 0x00000060 /* 8 bits */ ! ! #define UART_CR_UARTEN 0x001 /* uart enable */ ! #define UART_CR_TXE 0x100 /* TX enable */ ! #define UART_CR_RXE 0x200 /* RX enable */ /* ! * All we care about are pins 14 and 15 for the UART. Specifically, alt0 ! * for GPIO14 is TXD0 and GPIO15 is RXD0. Those are controlled by FSEL1. */ #define GPIO_BASE 0x20200000 #define GPIO_FSEL1 0x4 #define GPIO_PUD 0x94 #define GPIO_PUDCLK0 0x98 ! #define GPIO_SEL_ALT0 0x4 #define GPIO_UART_MASK 0xfffc0fff #define GPIO_UART_TX_SHIFT 12 #define GPIO_UART_RX_SHIFT 15 #define GPIO_PUD_DISABLE 0x0
*** 73,83 **** /* * A simple nop */ static void ! bcm2835_miniuart_nop(void) { __asm__ volatile("mov r0, r0\n" : : :); } void fakeload_backend_putc(int); --- 76,86 ---- /* * A simple nop */ static void ! uart_nop(void) { __asm__ volatile("mov r0, r0\n" : : :); } void fakeload_backend_putc(int);
*** 95,161 **** fakeload_backend_init(void) { uint32_t v; int i; ! /* Enable the mini UAT */ ! arm_reg_write(AUX_BASE + AUX_ENABLES, 0x1); ! ! /* Disable interrupts */ ! arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0); ! ! /* Disable the RX and TX */ ! arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x0); ! ! /* ! * Enable 8-bit word length. External sources tell us the PRM is buggy ! * here and that even though bit 1 is reserved, we need to actually set ! * it to get 8-bit words. ! */ ! arm_reg_write(AUX_BASE + AUX_MU_LCR_REG, 0x3); ! ! /* Set RTS high */ ! arm_reg_write(AUX_BASE + AUX_MU_MCR_REG, 0x0); ! ! /* Disable interrupts */ ! arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0); ! ! /* Set baud rate */ ! arm_reg_write(AUX_BASE + AUX_MU_IIR_REG, 0xc6); ! arm_reg_write(AUX_BASE + AUX_MU_BAUD, 0x10e); /* TODO: Factor out the gpio bits */ v = arm_reg_read(GPIO_BASE + GPIO_FSEL1); v &= GPIO_UART_MASK; ! v |= GPIO_SEL_ALT5 << GPIO_UART_RX_SHIFT; ! v |= GPIO_SEL_ALT5 << GPIO_UART_TX_SHIFT; arm_reg_write(GPIO_BASE + GPIO_FSEL1, v); arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE); for (i = 0; i < 150; i++) ! bcm2835_miniuart_nop(); arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART); for (i = 0; i < 150; i++) ! bcm2835_miniuart_nop(); ! // XXX: GPIO_PUD_DISABLE again? arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0); ! /* Finally, go back and enable RX and TX */ ! arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x3); } void fakeload_backend_putc(int c) { if (c == '\n') fakeload_backend_putc('\r'); ! for (;;) { ! if (arm_reg_read(AUX_BASE + AUX_MU_LSR_REG) & AUX_MU_TX_READY) ! break; ! } ! arm_reg_write(AUX_BASE + AUX_MU_IO_REG, c & 0x7f); } /* * Add a map for the uart. */ --- 98,151 ---- fakeload_backend_init(void) { uint32_t v; int i; ! /* disable UART */ ! arm_reg_write(UART_BASE + UART_CR, 0); /* TODO: Factor out the gpio bits */ v = arm_reg_read(GPIO_BASE + GPIO_FSEL1); v &= GPIO_UART_MASK; ! v |= GPIO_SEL_ALT0 << GPIO_UART_RX_SHIFT; ! v |= GPIO_SEL_ALT0 << GPIO_UART_TX_SHIFT; arm_reg_write(GPIO_BASE + GPIO_FSEL1, v); arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE); for (i = 0; i < 150; i++) ! uart_nop(); arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART); for (i = 0; i < 150; i++) ! uart_nop(); arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0); ! /* clear all interrupts */ ! arm_reg_write(UART_BASE + UART_ICR, 0x7ff); ! ! /* set the baud rate */ ! arm_reg_write(UART_BASE + UART_IBRD, 1); ! arm_reg_write(UART_BASE + UART_FBRD, 40); ! ! /* select 8-bit, enable FIFOs */ ! arm_reg_write(UART_BASE + UART_LCRH, UART_LCRH_WLEN_8 | UART_LCRH_FEN); ! ! /* enable UART */ ! arm_reg_write(UART_BASE + UART_CR, UART_CR_UARTEN | UART_CR_TXE | ! UART_CR_RXE); } void fakeload_backend_putc(int c) { if (c == '\n') fakeload_backend_putc('\r'); ! while (arm_reg_read(UART_BASE + UART_FR) & UART_FR_TXFF) ! ; ! arm_reg_write(UART_BASE + UART_DR, c & 0x7f); ! if (c == '\n') ! fakeload_backend_putc('\r'); } /* * Add a map for the uart. */
*** 173,184 **** aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE; atag_append(chain, &aim.aim_header); aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; ! aim.aim_paddr = AUX_BASE; ! aim.aim_vaddr = AUX_BASE; aim.aim_vlen = 0x1000; aim.aim_plen = 0x1000; aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE; atag_append(chain, &aim.aim_header); } --- 163,174 ---- aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE; atag_append(chain, &aim.aim_header); aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; ! aim.aim_paddr = UART_BASE; ! aim.aim_vaddr = UART_BASE; aim.aim_vlen = 0x1000; aim.aim_plen = 0x1000; aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE; atag_append(chain, &aim.aim_header); }