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
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
↓ 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;
63 66
64 67 return *ptr;
65 68 }
66 69
67 70 static __GNU_INLINE void arm_reg_write(uint32_t reg, uint32_t val)
↓ 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') {
89 92 fakeload_backend_putc(*str);
↓ 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
167 157 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
↓ 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