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 * Copyright 2015 (c) Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 15 */ 16 17 /* 18 * A simple uart driver for the RPi. 19 */ 20 #include <sys/types.h> 21 22 #include "bcm2835_uart.h" 23 24 extern uint32_t arm_reg_read(uint32_t); 25 extern void arm_reg_write(uint32_t, uint32_t); 26 27 /* 28 * The primary serial console that we end up using is the normal UART, not 29 * the mini-uart that shares interrupts and registers with the SPI masters 30 * as well. 31 */ 32 33 #define UART_BASE 0x20201000 34 #define UART_DR 0x0 35 #define UART_FR 0x18 36 #define UART_IBRD 0x24 37 #define UART_FBRD 0x28 38 #define UART_LCRH 0x2c 39 #define UART_CR 0x30 40 #define UART_ICR 0x44 41 42 #define UART_FR_RXFE 0x10 /* RX fifo empty */ 43 #define UART_FR_TXFF 0x20 /* TX fifo full */ 44 45 #define UART_LCRH_FEN 0x00000010 /* fifo enable */ 46 #define UART_LCRH_WLEN_8 0x00000060 /* 8 bits */ 47 48 #define UART_CR_UARTEN 0x001 /* uart enable */ 49 #define UART_CR_TXE 0x100 /* TX enable */ 50 #define UART_CR_RXE 0x200 /* RX enable */ 51 52 53 /* 54 * All we care about are pins 14 and 15 for the UART. Specifically, alt0 55 * for GPIO14 is TXD0 and GPIO15 is RXD0. Those are controlled by FSEL1. 56 */ 57 #define GPIO_BASE 0x20200000 58 #define GPIO_FSEL1 0x4 59 #define GPIO_PUD 0x94 60 #define GPIO_PUDCLK0 0x98 61 62 #define GPIO_SEL_ALT0 0x4 63 #define GPIO_UART_MASK 0xfffc0fff 64 #define GPIO_UART_TX_SHIFT 12 65 #define GPIO_UART_RX_SHIFT 15 66 67 #define GPIO_PUD_DISABLE 0x0 68 #define GPIO_PUDCLK_UART 0x0000c000 69 70 /* 71 * A simple nop 72 */ 73 static void 74 bcm2835_uart_nop(void) 75 { 76 __asm__ volatile("mov r0, r0\n" : : :); 77 } 78 79 void 80 bcm2835_uart_init(void) 81 { 82 uint32_t v; 83 int i; 84 85 /* disable UART */ 86 arm_reg_write(UART_BASE + UART_CR, 0); 87 88 /* TODO: Factor out the gpio bits */ 89 v = arm_reg_read(GPIO_BASE + GPIO_FSEL1); 90 v &= GPIO_UART_MASK; 91 v |= GPIO_SEL_ALT0 << GPIO_UART_RX_SHIFT; 92 v |= GPIO_SEL_ALT0 << GPIO_UART_TX_SHIFT; 93 arm_reg_write(GPIO_BASE + GPIO_FSEL1, v); 94 95 arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE); 96 for (i = 0; i < 150; i++) 97 bcm2835_uart_nop(); 98 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART); 99 for (i = 0; i < 150; i++) 100 bcm2835_uart_nop(); 101 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0); 102 103 /* clear all interrupts */ 104 arm_reg_write(UART_BASE + UART_ICR, 0x7ff); 105 106 /* set the baud rate */ 107 arm_reg_write(UART_BASE + UART_IBRD, 1); 108 arm_reg_write(UART_BASE + UART_FBRD, 40); 109 110 /* select 8-bit, enable FIFOs */ 111 arm_reg_write(UART_BASE + UART_LCRH, UART_LCRH_WLEN_8 | UART_LCRH_FEN); 112 113 /* enable UART */ 114 arm_reg_write(UART_BASE + UART_CR, UART_CR_UARTEN | UART_CR_TXE | 115 UART_CR_RXE); 116 } 117 118 void 119 bcm2835_uart_putc(uint8_t c) 120 { 121 while (arm_reg_read(UART_BASE + UART_FR) & UART_FR_TXFF) 122 ; 123 arm_reg_write(UART_BASE + UART_DR, c & 0x7f); 124 if (c == '\n') 125 bcm2835_uart_putc('\r'); 126 } 127 128 uint8_t 129 bcm2835_uart_getc(void) 130 { 131 while (arm_reg_read(UART_BASE + UART_FR) & UART_FR_RXFE) 132 ; 133 return (arm_reg_read(UART_BASE + UART_DR) & 0x7f); 134 } 135 136 int 137 bcm2835_uart_isc(void) 138 { 139 return ((arm_reg_read(UART_BASE + UART_FR) & UART_FR_RXFE) == 0); 140 }