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.)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/armv6/bcm2835/loader/bcm2835_ldep.c
          +++ new/usr/src/uts/armv6/bcm2835/loader/bcm2835_ldep.c
↓ open down ↓ 10 lines elided ↑ open up ↑
  11   11  
  12   12  /*
  13   13   * Copyright (c) 2013 Joyent, Inc.  All rights reserved.
  14   14   * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  15   15   */
  16   16  
  17   17  #include <sys/elf.h>
  18   18  #include <sys/atag.h>
  19   19  
  20   20  /*
  21      - * The primary serial console that we end up using is not in fact a normal UART,
  22      - * but is instead actually a mini-uart that shares interrupts and registers with
  23      - * the SPI masters as well. While the RPi also supports another more traditional
  24      - * UART, that isn't what we are actually hooking up to generally with the
  25      - * adafruit cable. We already wasted our time having to figure that out. -_-
       21 + * The primary serial console that we end up using is the normal UART, not
       22 + * the mini-uart that shares interrupts and registers with the SPI masters
       23 + * as well.
  26   24   */
  27   25  
  28      -#define AUX_BASE        0x20215000
  29      -#define AUX_ENABLES     0x4
  30      -#define AUX_MU_IO_REG   0x40
  31      -#define AUX_MU_IER_REG  0x44
  32      -#define AUX_MU_IIR_REG  0x48
  33      -#define AUX_MU_LCR_REG  0x4C
  34      -#define AUX_MU_MCR_REG  0x50
  35      -#define AUX_MU_LSR_REG  0x54
  36      -#define AUX_MU_CNTL_REG 0x60
  37      -#define AUX_MU_BAUD     0x68
       26 +#define UART_BASE               0x20201000
       27 +#define UART_DR                 0x0
       28 +#define UART_FR                 0x18
       29 +#define UART_IBRD               0x24
       30 +#define UART_FBRD               0x28
       31 +#define UART_LCRH               0x2c
       32 +#define UART_CR                 0x30
       33 +#define UART_ICR                0x44
       34 +
       35 +#define UART_FR_RXFE            0x10            /* RX fifo empty */
       36 +#define UART_FR_TXFF            0x20            /* TX fifo full */
       37 +
       38 +#define UART_LCRH_FEN           0x00000010      /* fifo enable */
       39 +#define UART_LCRH_WLEN_8        0x00000060      /* 8 bits */
       40 +
       41 +#define UART_CR_UARTEN          0x001           /* uart enable */
       42 +#define UART_CR_TXE             0x100           /* TX enable */
       43 +#define UART_CR_RXE             0x200           /* RX enable */
  38   44  
  39      -#define AUX_MU_RX_READY 0x01
  40      -#define AUX_MU_TX_READY 0x20
  41   45  
  42   46  /*
  43      - * For the mini UART, all we care about are pins 14 and 15 for the UART.
  44      - * Specifically, alt5 for GPIO14 is TXD1 and GPIO15 is RXD1. Those are
  45      - * controlled by FSEL1.
       47 + * All we care about are pins 14 and 15 for the UART.  Specifically, alt0
       48 + * for GPIO14 is TXD0 and GPIO15 is RXD0. Those are controlled by FSEL1.
  46   49   */
  47   50  #define GPIO_BASE       0x20200000
  48   51  #define GPIO_FSEL1      0x4
  49   52  #define GPIO_PUD        0x94
  50   53  #define GPIO_PUDCLK0    0x98
  51   54  
  52      -#define GPIO_SEL_ALT5   0x2
       55 +#define GPIO_SEL_ALT0   0x4
  53   56  #define GPIO_UART_MASK  0xfffc0fff
  54   57  #define GPIO_UART_TX_SHIFT      12
  55   58  #define GPIO_UART_RX_SHIFT      15
  56   59  
  57   60  #define GPIO_PUD_DISABLE        0x0
  58   61  #define GPIO_PUDCLK_UART        0x0000c000
  59   62  
  60   63  static __GNU_INLINE uint32_t arm_reg_read(uint32_t reg)
  61   64  {
  62   65          volatile uint32_t *ptr = (volatile uint32_t *)reg;
↓ open down ↓ 5 lines elided ↑ open up ↑
  68   71  {
  69   72          volatile uint32_t *ptr = (volatile uint32_t *)reg;
  70   73  
  71   74          *ptr = val;
  72   75  }
  73   76  
  74   77  /*
  75   78   * A simple nop
  76   79   */
  77   80  static void
  78      -bcm2835_miniuart_nop(void)
       81 +uart_nop(void)
  79   82  {
  80   83          __asm__ volatile("mov r0, r0\n" : : :);
  81   84  }
  82   85  
  83   86  void fakeload_backend_putc(int);
  84   87  
  85   88  static void
  86   89  fakeload_puts(const char *str)
  87   90  {
  88   91          while (*str != '\0') {
↓ open down ↓ 1 lines elided ↑ open up ↑
  90   93                  str++;
  91   94          }
  92   95  }
  93   96  
  94   97  void
  95   98  fakeload_backend_init(void)
  96   99  {
  97  100          uint32_t v;
  98  101          int i;
  99  102  
 100      -        /* Enable the mini UAT */
 101      -        arm_reg_write(AUX_BASE + AUX_ENABLES, 0x1);
 102      -
 103      -        /* Disable interrupts */
 104      -        arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0);
 105      -
 106      -        /* Disable the RX and TX */
 107      -        arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x0);
 108      -
 109      -        /*
 110      -         * Enable 8-bit word length. External sources tell us the PRM is buggy
 111      -         * here and that even though bit 1 is reserved, we need to actually set
 112      -         * it to get 8-bit words.
 113      -         */
 114      -        arm_reg_write(AUX_BASE + AUX_MU_LCR_REG, 0x3);
 115      -
 116      -        /* Set RTS high */
 117      -        arm_reg_write(AUX_BASE + AUX_MU_MCR_REG, 0x0);
 118      -
 119      -        /* Disable interrupts */
 120      -        arm_reg_write(AUX_BASE + AUX_MU_IER_REG, 0x0);
 121      -
 122      -        /* Set baud rate */
 123      -        arm_reg_write(AUX_BASE + AUX_MU_IIR_REG, 0xc6);
 124      -        arm_reg_write(AUX_BASE + AUX_MU_BAUD, 0x10e);
      103 +        /* disable UART */
      104 +        arm_reg_write(UART_BASE + UART_CR, 0);
 125  105  
 126  106          /* TODO: Factor out the gpio bits */
 127  107          v = arm_reg_read(GPIO_BASE + GPIO_FSEL1);
 128  108          v &= GPIO_UART_MASK;
 129      -        v |= GPIO_SEL_ALT5 << GPIO_UART_RX_SHIFT;
 130      -        v |= GPIO_SEL_ALT5 << GPIO_UART_TX_SHIFT;
      109 +        v |= GPIO_SEL_ALT0 << GPIO_UART_RX_SHIFT;
      110 +        v |= GPIO_SEL_ALT0 << GPIO_UART_TX_SHIFT;
 131  111          arm_reg_write(GPIO_BASE + GPIO_FSEL1, v);
 132  112  
 133  113          arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE);
 134  114          for (i = 0; i < 150; i++)
 135      -                bcm2835_miniuart_nop();
      115 +                uart_nop();
 136  116          arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART);
 137  117          for (i = 0; i < 150; i++)
 138      -                bcm2835_miniuart_nop();
 139      -        // XXX: GPIO_PUD_DISABLE again?
      118 +                uart_nop();
 140  119          arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0);
 141  120  
 142      -        /* Finally, go back and enable RX and TX */
 143      -        arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x3);
      121 +        /* clear all interrupts */
      122 +        arm_reg_write(UART_BASE + UART_ICR, 0x7ff);
      123 +
      124 +        /* set the baud rate */
      125 +        arm_reg_write(UART_BASE + UART_IBRD, 1);
      126 +        arm_reg_write(UART_BASE + UART_FBRD, 40);
      127 +
      128 +        /* select 8-bit, enable FIFOs */
      129 +        arm_reg_write(UART_BASE + UART_LCRH, UART_LCRH_WLEN_8 | UART_LCRH_FEN);
      130 +
      131 +        /* enable UART */
      132 +        arm_reg_write(UART_BASE + UART_CR, UART_CR_UARTEN | UART_CR_TXE |
      133 +            UART_CR_RXE);
 144  134  }
 145  135  
 146  136  void
 147  137  fakeload_backend_putc(int c)
 148  138  {
 149  139          if (c == '\n')
 150  140                  fakeload_backend_putc('\r');
 151  141  
 152      -        for (;;) {
 153      -                if (arm_reg_read(AUX_BASE + AUX_MU_LSR_REG) & AUX_MU_TX_READY)
 154      -                        break;
 155      -        }
 156      -        arm_reg_write(AUX_BASE + AUX_MU_IO_REG, c & 0x7f);
      142 +        while (arm_reg_read(UART_BASE + UART_FR) & UART_FR_TXFF)
      143 +                ;
      144 +        arm_reg_write(UART_BASE + UART_DR, c & 0x7f);
      145 +        if (c == '\n')
      146 +                fakeload_backend_putc('\r');
 157  147  }
 158  148  
 159  149  /*
 160  150   * Add a map for the uart.
 161  151   */
 162  152  void
 163  153  fakeload_backend_addmaps(atag_header_t *chain)
 164  154  {
 165  155          atag_illumos_mapping_t aim;
 166  156  
↓ open down ↓ 1 lines elided ↑ open up ↑
 168  158          aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
 169  159          aim.aim_paddr = GPIO_BASE;
 170  160          aim.aim_vaddr = GPIO_BASE;
 171  161          aim.aim_vlen = 0x1000;
 172  162          aim.aim_plen = 0x1000;
 173  163          aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
 174  164          atag_append(chain, &aim.aim_header);
 175  165  
 176  166          aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
 177  167          aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
 178      -        aim.aim_paddr = AUX_BASE;
 179      -        aim.aim_vaddr = AUX_BASE;
      168 +        aim.aim_paddr = UART_BASE;
      169 +        aim.aim_vaddr = UART_BASE;
 180  170          aim.aim_vlen = 0x1000;
 181  171          aim.aim_plen = 0x1000;
 182  172          aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
 183  173          atag_append(chain, &aim.aim_header);
 184  174  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX