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 }