1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 (c) Joyent, Inc. All rights reserved. 14 */ 15 16 /* 17 * A simple uart driver for the RPi. 18 */ 19 #include <sys/types.h> 20 21 extern uint32_t arm_reg_read(uint32_t); 22 extern void arm_reg_write(uint32_t, uint32_t); 23 24 /* 25 * The primary serial console that we end up using is not in fact a normal UART, 26 * but is instead actually a mini-uart that shares interrupts and registers with 27 * the SPI masters as well. While the RPi also supports another more traditional 28 * UART, that isn't what we are actually hooking up to generally with the 29 * adafruit cable. We already wasted our time having to figure that out. -_- 30 */ 31 32 #define AUX_BASE 0x20215000 33 #define AUX_ENABLES 0x4 34 #define AUX_MU_IO_REG 0x40 35 #define AUX_MU_IER_REG 0x44 36 #define AUX_MU_IIR_REG 0x48 37 #define AUX_MU_LCR_REG 0x4C 38 #define AUX_MU_MCR_REG 0x50 39 #define AUX_MU_LSR_REG 0x54 40 #define AUX_MU_CNTL_REG 0x60 41 #define AUX_MU_BAUD 0x68 42 43 #define AUX_MU_RX_READY 0x01 44 #define AUX_MU_TX_READY 0x20 45 46 /* 47 * For the mini UART, all we care about are pins 14 and 15 for the UART. 48 * Specifically, alt5 for GPIO14 is TXD1 and GPIO15 is RXD1. Those are 49 * controlled by FSEL1. 50 */ 51 #define GPIO_BASE 0x20200000 52 #define GPIO_FSEL1 0x4 53 #define GPIO_PUD 0x94 54 #define GPIO_PUDCLK0 0x98 55 56 #define GPIO_SEL_ALT5 0x2 57 #define GPIO_UART_MASK 0xfffc0fff 58 #define GPIO_UART_TX_SHIFT 12 59 #define GPIO_UART_RX_SHIFT 15 60 61 #define GPIO_PUD_DISABLE 0x0 62 #define GPIO_PUDCLK_UART 0x0000c000 63 64 /* 65 * A simple nop 66 */ 67 static void 68 bcm2835_miniuart_nop(void) 69 { 70 __asm__ volatile("mov r0, r0\n" : : :); 71 } 72 73 void 74 bcm2835_miniuart_init(void) 75 { 76 uint32_t v; 77 int i; 78 79 /* Enable the mini UAT */ 80 arm_reg_write(AUX_BASE + AUX_ENABLES, 0x1); 81 82 /* Disable interrupts */ 83 arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0); 84 85 /* Disable the RX and TX */ 86 arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x0); 87 88 /* 89 * Enable 8-bit word length. External sources tell us the PRM is buggy 90 * here and that even though bit 1 is reserved, we need to actually set 91 * it to get 8-bit words. 92 */ 93 arm_reg_write(AUX_BASE + AUX_MU_LCR_REG, 0x3); 94 95 /* Set RTS high */ 96 arm_reg_write(AUX_BASE + AUX_MU_MCR_REG, 0x0); 97 98 /* Disable interrupts */ 99 arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0); 100 101 /* Set baud rate */ 102 arm_reg_write(AUX_BASE + AUX_MU_IIR_REG, 0xc6); 103 arm_reg_write(AUX_BASE + AUX_MU_BAUD, 0x10e); 104 105 /* TODO: Factor out the gpio bits */ 106 v = arm_reg_read(GPIO_BASE + GPIO_FSEL1); 107 v &= GPIO_UART_MASK; 108 v |= GPIO_SEL_ALT5 << GPIO_UART_RX_SHIFT; 109 v |= GPIO_SEL_ALT5 << GPIO_UART_TX_SHIFT; 110 arm_reg_write(GPIO_BASE + GPIO_FSEL1, v); 111 112 arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE); 113 for (i = 0; i < 150; i++) 114 bcm2835_miniuart_nop(); 115 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART); 116 for (i = 0; i < 150; i++) 117 bcm2835_miniuart_nop(); 118 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0); 119 120 /* Finally, go back and enable RX and TX */ 121 arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x3); 122 } 123 124 void 125 bcm2835_miniuart_putc(uint8_t c) 126 { 127 for (;;) { 128 if (arm_reg_read(AUX_BASE + AUX_MU_LSR_REG) & AUX_MU_TX_READY) 129 break; 130 } 131 arm_reg_write(AUX_BASE + AUX_MU_IO_REG, c & 0x7f); 132 if (c == '\n') 133 bcm2835_miniuart_putc('\r'); 134 } 135 136 uint8_t 137 bcm2835_miniuart_getc(void) 138 { 139 for (;;) { 140 if (arm_reg_read(AUX_BASE + AUX_MU_LSR_REG) & AUX_MU_RX_READY) 141 break; 142 } 143 return (arm_reg_read(AUX_BASE + AUX_MU_IO_REG) & 0x7f); 144 } 145 146 int 147 bcm2835_miniuart_isc(void) 148 { 149 return (arm_reg_read(AUX_BASE + AUX_MU_LSR_REG) & AUX_MU_RX_READY); 150 }