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 (c) 2013 Joyent, Inc.  All rights reserved.
  14  * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  15  */
  16 
  17 #include <sys/elf.h>
  18 #include <sys/atag.h>
  19 
  20 /*
  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.
  24  */
  25 
  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 */
  44 
  45 
  46 /*
  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.
  49  */
  50 #define GPIO_BASE       0x20200000
  51 #define GPIO_FSEL1      0x4
  52 #define GPIO_PUD        0x94
  53 #define GPIO_PUDCLK0    0x98
  54 
  55 #define GPIO_SEL_ALT0   0x4
  56 #define GPIO_UART_MASK  0xfffc0fff
  57 #define GPIO_UART_TX_SHIFT      12
  58 #define GPIO_UART_RX_SHIFT      15
  59 
  60 #define GPIO_PUD_DISABLE        0x0
  61 #define GPIO_PUDCLK_UART        0x0000c000
  62 
  63 static __GNU_INLINE uint32_t arm_reg_read(uint32_t reg)
  64 {
  65         volatile uint32_t *ptr = (volatile uint32_t *)reg;
  66 
  67         return *ptr;
  68 }
  69 
  70 static __GNU_INLINE void arm_reg_write(uint32_t reg, uint32_t val)
  71 {
  72         volatile uint32_t *ptr = (volatile uint32_t *)reg;
  73 
  74         *ptr = val;
  75 }
  76 
  77 /*
  78  * A simple nop
  79  */
  80 static void
  81 uart_nop(void)
  82 {
  83         __asm__ volatile("mov r0, r0\n" : : :);
  84 }
  85 
  86 void fakeload_backend_putc(int);
  87 
  88 static void
  89 fakeload_puts(const char *str)
  90 {
  91         while (*str != '\0') {
  92                 fakeload_backend_putc(*str);
  93                 str++;
  94         }
  95 }
  96 
  97 void
  98 fakeload_backend_init(void)
  99 {
 100         uint32_t v;
 101         int i;
 102 
 103         /* disable UART */
 104         arm_reg_write(UART_BASE + UART_CR, 0);
 105 
 106         /* TODO: Factor out the gpio bits */
 107         v = arm_reg_read(GPIO_BASE + GPIO_FSEL1);
 108         v &= GPIO_UART_MASK;
 109         v |= GPIO_SEL_ALT0 << GPIO_UART_RX_SHIFT;
 110         v |= GPIO_SEL_ALT0 << GPIO_UART_TX_SHIFT;
 111         arm_reg_write(GPIO_BASE + GPIO_FSEL1, v);
 112 
 113         arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE);
 114         for (i = 0; i < 150; i++)
 115                 uart_nop();
 116         arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART);
 117         for (i = 0; i < 150; i++)
 118                 uart_nop();
 119         arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0);
 120 
 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);
 134 }
 135 
 136 void
 137 fakeload_backend_putc(int c)
 138 {
 139         if (c == '\n')
 140                 fakeload_backend_putc('\r');
 141 
 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');
 147 }
 148 
 149 /*
 150  * Add a map for the uart.
 151  */
 152 void
 153 fakeload_backend_addmaps(atag_header_t *chain)
 154 {
 155         atag_illumos_mapping_t aim;
 156 
 157         aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
 158         aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
 159         aim.aim_paddr = GPIO_BASE;
 160         aim.aim_vaddr = GPIO_BASE;
 161         aim.aim_vlen = 0x1000;
 162         aim.aim_plen = 0x1000;
 163         aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
 164         atag_append(chain, &aim.aim_header);
 165 
 166         aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
 167         aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
 168         aim.aim_paddr = UART_BASE;
 169         aim.aim_vaddr = UART_BASE;
 170         aim.aim_vlen = 0x1000;
 171         aim.aim_plen = 0x1000;
 172         aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
 173         atag_append(chain, &aim.aim_header);
 174 }