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 }