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 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. -_-
26 */
27
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
38
39 #define AUX_MU_RX_READY 0x01
40 #define AUX_MU_TX_READY 0x20
41
42 /*
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.
46 */
47 #define GPIO_BASE 0x20200000
48 #define GPIO_FSEL1 0x4
49 #define GPIO_PUD 0x94
50 #define GPIO_PUDCLK0 0x98
51
52 #define GPIO_SEL_ALT5 0x2
53 #define GPIO_UART_MASK 0xfffc0fff
54 #define GPIO_UART_TX_SHIFT 12
55 #define GPIO_UART_RX_SHIFT 15
56
57 #define GPIO_PUD_DISABLE 0x0
58 #define GPIO_PUDCLK_UART 0x0000c000
59
60 static __GNU_INLINE uint32_t arm_reg_read(uint32_t reg)
61 {
62 volatile uint32_t *ptr = (volatile uint32_t *)reg;
63
64 return *ptr;
65 }
66
67 static __GNU_INLINE void arm_reg_write(uint32_t reg, uint32_t val)
68 {
69 volatile uint32_t *ptr = (volatile uint32_t *)reg;
70
71 *ptr = val;
72 }
73
74 /*
75 * A simple nop
76 */
77 static void
78 bcm2835_miniuart_nop(void)
79 {
80 __asm__ volatile("mov r0, r0\n" : : :);
81 }
82
83 void fakeload_backend_putc(int);
84
85 static void
86 fakeload_puts(const char *str)
87 {
88 while (*str != '\0') {
89 fakeload_backend_putc(*str);
90 str++;
91 }
92 }
93
94 void
95 fakeload_backend_init(void)
96 {
97 uint32_t v;
98 int i;
99
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);
125
126 /* TODO: Factor out the gpio bits */
127 v = arm_reg_read(GPIO_BASE + GPIO_FSEL1);
128 v &= GPIO_UART_MASK;
129 v |= GPIO_SEL_ALT5 << GPIO_UART_RX_SHIFT;
130 v |= GPIO_SEL_ALT5 << GPIO_UART_TX_SHIFT;
131 arm_reg_write(GPIO_BASE + GPIO_FSEL1, v);
132
133 arm_reg_write(GPIO_BASE + GPIO_PUD, GPIO_PUD_DISABLE);
134 for (i = 0; i < 150; i++)
135 bcm2835_miniuart_nop();
136 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, GPIO_PUDCLK_UART);
137 for (i = 0; i < 150; i++)
138 bcm2835_miniuart_nop();
139 // XXX: GPIO_PUD_DISABLE again?
140 arm_reg_write(GPIO_BASE + GPIO_PUDCLK0, 0);
141
142 /* Finally, go back and enable RX and TX */
143 arm_reg_write(AUX_BASE + AUX_MU_CNTL_REG, 0x3);
144 }
145
146 void
147 fakeload_backend_putc(int c)
148 {
149 if (c == '\n')
150 fakeload_backend_putc('\r');
151
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);
157 }
158
159 /*
160 * Add a map for the uart.
161 */
162 void
163 fakeload_backend_addmaps(atag_header_t *chain)
164 {
165 atag_illumos_mapping_t aim;
166
167 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
168 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
169 aim.aim_paddr = GPIO_BASE;
170 aim.aim_vaddr = GPIO_BASE;
171 aim.aim_vlen = 0x1000;
172 aim.aim_plen = 0x1000;
173 aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
174 atag_append(chain, &aim.aim_header);
175
176 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE;
177 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING;
178 aim.aim_paddr = AUX_BASE;
179 aim.aim_vaddr = AUX_BASE;
180 aim.aim_vlen = 0x1000;
181 aim.aim_plen = 0x1000;
182 aim.aim_mapflags = PF_R | PF_W | PF_NORELOC | PF_DEVICE;
183 atag_append(chain, &aim.aim_header);
184 }
|
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 }
|