| @@ -1,223 +1,225 @@ | | | @@ -1,223 +1,225 @@ |
1 | /* $NetBSD: awin_board.c,v 1.6 2013/09/09 17:53:36 matt Exp $ */ | | 1 | /* $NetBSD: awin_board.c,v 1.7 2014/02/20 21:46:14 matt Exp $ */ |
2 | /*- | | 2 | /*- |
3 | * Copyright (c) 2012 The NetBSD Foundation, Inc. | | 3 | * Copyright (c) 2012 The NetBSD Foundation, Inc. |
4 | * All rights reserved. | | 4 | * All rights reserved. |
5 | * | | 5 | * |
6 | * This code is derived from software contributed to The NetBSD Foundation | | 6 | * This code is derived from software contributed to The NetBSD Foundation |
7 | * by Matt Thomas of 3am Software Foundry. | | 7 | * by Matt Thomas of 3am Software Foundry. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | * POSSIBILITY OF SUCH DAMAGE. | | 28 | * POSSIBILITY OF SUCH DAMAGE. |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | #include "opt_allwinner.h" | | 31 | #include "opt_allwinner.h" |
32 | | | 32 | |
33 | #define _ARM32_BUS_DMA_PRIVATE | | 33 | #define _ARM32_BUS_DMA_PRIVATE |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | | | 36 | |
37 | __KERNEL_RCSID(1, "$NetBSD: awin_board.c,v 1.6 2013/09/09 17:53:36 matt Exp $"); | | 37 | __KERNEL_RCSID(1, "$NetBSD: awin_board.c,v 1.7 2014/02/20 21:46:14 matt Exp $"); |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/bus.h> | | 40 | #include <sys/bus.h> |
41 | #include <sys/cpu.h> | | 41 | #include <sys/cpu.h> |
42 | #include <sys/device.h> | | 42 | #include <sys/device.h> |
43 | | | 43 | |
44 | #include <prop/proplib.h> | | 44 | #include <prop/proplib.h> |
45 | | | 45 | |
46 | #include <net/if.h> | | 46 | #include <net/if.h> |
47 | #include <net/if_ether.h> | | 47 | #include <net/if_ether.h> |
48 | | | 48 | |
49 | #include <arm/mainbus/mainbus.h> | | 49 | #include <arm/mainbus/mainbus.h> |
50 | | | 50 | |
51 | #include <arm/allwinner/awin_reg.h> | | 51 | #include <arm/allwinner/awin_reg.h> |
52 | #include <arm/allwinner/awin_var.h> | | 52 | #include <arm/allwinner/awin_var.h> |
53 | | | 53 | |
| | | 54 | #include <arm/cortex/gtmr_var.h> |
| | | 55 | |
54 | bus_space_handle_t awin_core_bsh; | | 56 | bus_space_handle_t awin_core_bsh; |
55 | | | 57 | |
56 | struct arm32_bus_dma_tag awin_dma_tag = { | | 58 | struct arm32_bus_dma_tag awin_dma_tag = { |
57 | _BUS_DMAMAP_FUNCS, | | 59 | _BUS_DMAMAP_FUNCS, |
58 | _BUS_DMAMEM_FUNCS, | | 60 | _BUS_DMAMEM_FUNCS, |
59 | _BUS_DMATAG_FUNCS, | | 61 | _BUS_DMATAG_FUNCS, |
60 | }; | | 62 | }; |
61 | | | 63 | |
62 | #ifdef AWIN_CONSOLE_EARLY | | 64 | #ifdef AWIN_CONSOLE_EARLY |
63 | #include <dev/ic/ns16550reg.h> | | 65 | #include <dev/ic/ns16550reg.h> |
64 | #include <dev/ic/comreg.h> | | 66 | #include <dev/ic/comreg.h> |
65 | #include <dev/cons.h> | | 67 | #include <dev/cons.h> |
66 | | | 68 | |
67 | static volatile uint32_t *uart_base; | | 69 | static volatile uint32_t *uart_base; |
68 | | | 70 | |
69 | static int | | 71 | static int |
70 | awin_cngetc(dev_t dv) | | 72 | awin_cngetc(dev_t dv) |
71 | { | | 73 | { |
72 | if ((uart_base[com_lsr] & LSR_RXRDY) == 0) | | 74 | if ((uart_base[com_lsr] & LSR_RXRDY) == 0) |
73 | return -1; | | 75 | return -1; |
74 | | | 76 | |
75 | return uart_base[com_data] & 0xff; | | 77 | return uart_base[com_data] & 0xff; |
76 | } | | 78 | } |
77 | | | 79 | |
78 | static void | | 80 | static void |
79 | awin_cnputc(dev_t dv, int c) | | 81 | awin_cnputc(dev_t dv, int c) |
80 | { | | 82 | { |
81 | int timo = 150000; | | 83 | int timo = 150000; |
82 | | | 84 | |
83 | while ((uart_base[com_lsr] & LSR_TXRDY) == 0 && --timo > 0) | | 85 | while ((uart_base[com_lsr] & LSR_TXRDY) == 0 && --timo > 0) |
84 | ; | | 86 | ; |
85 | | | 87 | |
86 | uart_base[com_data] = c & 0xff; | | 88 | uart_base[com_data] = c & 0xff; |
87 | | | 89 | |
88 | timo = 150000; | | 90 | timo = 150000; |
89 | while ((uart_base[com_lsr] & LSR_TSRE) == 0 && --timo > 0) | | 91 | while ((uart_base[com_lsr] & LSR_TSRE) == 0 && --timo > 0) |
90 | ; | | 92 | ; |
91 | } | | 93 | } |
92 | | | 94 | |
93 | static struct consdev awin_earlycons = { | | 95 | static struct consdev awin_earlycons = { |
94 | .cn_putc = awin_cnputc, | | 96 | .cn_putc = awin_cnputc, |
95 | .cn_getc = awin_cngetc, | | 97 | .cn_getc = awin_cngetc, |
96 | .cn_pollc = nullcnpollc, | | 98 | .cn_pollc = nullcnpollc, |
97 | }; | | 99 | }; |
98 | #endif /* AWIN_CONSOLE_EARLY */ | | 100 | #endif /* AWIN_CONSOLE_EARLY */ |
99 | | | 101 | |
100 | static void | | 102 | static void |
101 | awin_cpu_clk(void) | | 103 | awin_cpu_clk(void) |
102 | { | | 104 | { |
103 | struct cpu_info * const ci = curcpu(); | | 105 | struct cpu_info * const ci = curcpu(); |
104 | const uint32_t cpu0_cfg = bus_space_read_4(&awin_bs_tag, awin_core_bsh, | | 106 | const uint32_t cpu0_cfg = bus_space_read_4(&awin_bs_tag, awin_core_bsh, |
105 | AWIN_CCM_OFFSET + AWIN_CPU_AHB_APB0_CFG_REG); | | 107 | AWIN_CCM_OFFSET + AWIN_CPU_AHB_APB0_CFG_REG); |
106 | const u_int cpu_clk_sel = __SHIFTIN(cpu0_cfg, AWIN_CPU_CLK_SRC_SEL); | | 108 | const u_int cpu_clk_sel = __SHIFTIN(cpu0_cfg, AWIN_CPU_CLK_SRC_SEL); |
107 | switch (__SHIFTOUT(cpu_clk_sel, AWIN_CPU_CLK_SRC_SEL)) { | | 109 | switch (__SHIFTOUT(cpu_clk_sel, AWIN_CPU_CLK_SRC_SEL)) { |
108 | case AWIN_CPU_CLK_SRC_SEL_LOSC: | | 110 | case AWIN_CPU_CLK_SRC_SEL_LOSC: |
109 | ci->ci_data.cpu_cc_freq = 32768; | | 111 | ci->ci_data.cpu_cc_freq = 32768; |
110 | break; | | 112 | break; |
111 | case AWIN_CPU_CLK_SRC_SEL_OSC24M: | | 113 | case AWIN_CPU_CLK_SRC_SEL_OSC24M: |
112 | ci->ci_data.cpu_cc_freq = AWIN_REF_FREQ; | | 114 | ci->ci_data.cpu_cc_freq = AWIN_REF_FREQ; |
113 | break; | | 115 | break; |
114 | case AWIN_CPU_CLK_SRC_SEL_PLL1: { | | 116 | case AWIN_CPU_CLK_SRC_SEL_PLL1: { |
115 | const uint32_t pll1_cfg = bus_space_read_4(&awin_bs_tag, | | 117 | const uint32_t pll1_cfg = bus_space_read_4(&awin_bs_tag, |
116 | awin_core_bsh, AWIN_CCM_OFFSET + AWIN_PLL1_CFG_REG); | | 118 | awin_core_bsh, AWIN_CCM_OFFSET + AWIN_PLL1_CFG_REG); |
117 | u_int p = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_OUT_EXP_DIVP); | | 119 | u_int p = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_OUT_EXP_DIVP); |
118 | u_int n = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_N); | | 120 | u_int n = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_N); |
119 | u_int k = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_K) + 1; | | 121 | u_int k = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_K) + 1; |
120 | u_int m = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_M) + 1; | | 122 | u_int m = __SHIFTOUT(pll1_cfg, AWIN_PLL_CFG_FACTOR_M) + 1; |
121 | ci->ci_data.cpu_cc_freq = | | 123 | ci->ci_data.cpu_cc_freq = |
122 | ((uint64_t)AWIN_REF_FREQ * (n ? n : 1) * k / m) >> p; | | 124 | ((uint64_t)AWIN_REF_FREQ * (n ? n : 1) * k / m) >> p; |
123 | break; | | 125 | break; |
124 | } | | 126 | } |
125 | case AWIN_CPU_CLK_SRC_SEL_200MHZ: | | 127 | case AWIN_CPU_CLK_SRC_SEL_200MHZ: |
126 | ci->ci_data.cpu_cc_freq = 200000000; | | 128 | ci->ci_data.cpu_cc_freq = 200000000; |
127 | break; | | 129 | break; |
128 | } | | 130 | } |
129 | } | | 131 | } |
130 | | | 132 | |
131 | void | | 133 | void |
132 | awin_bootstrap(vaddr_t iobase, vaddr_t uartbase) | | 134 | awin_bootstrap(vaddr_t iobase, vaddr_t uartbase) |
133 | { | | 135 | { |
134 | int error; | | 136 | int error; |
135 | | | 137 | |
136 | #ifdef AWIN_CONSOLE_EARLY | | 138 | #ifdef AWIN_CONSOLE_EARLY |
137 | uart_base = (volatile uint32_t *)uartbase; | | 139 | uart_base = (volatile uint32_t *)uartbase; |
138 | cn_tab = &awin_earlycons; | | 140 | cn_tab = &awin_earlycons; |
139 | printf("Early console started\n"); | | 141 | printf("Early console started\n"); |
140 | #endif | | 142 | #endif |
141 | | | 143 | |
142 | error = bus_space_map(&awin_bs_tag, AWIN_CORE_PBASE, | | 144 | error = bus_space_map(&awin_bs_tag, AWIN_CORE_PBASE, |
143 | AWIN_CORE_SIZE, 0, &awin_core_bsh); | | 145 | AWIN_CORE_SIZE, 0, &awin_core_bsh); |
144 | if (error) | | 146 | if (error) |
145 | panic("%s: failed to map a[12]0 %s registers: %d", | | 147 | panic("%s: failed to map a[12]0 %s registers: %d", |
146 | __func__, "io", error); | | 148 | __func__, "io", error); |
147 | KASSERT(awin_core_bsh == iobase); | | 149 | KASSERT(awin_core_bsh == iobase); |
148 | | | 150 | |
149 | #ifdef VERBOSE_INIT_ARM | | 151 | #ifdef VERBOSE_INIT_ARM |
150 | printf("CPU Speed is"); | | 152 | printf("CPU Speed is"); |
151 | #endif | | 153 | #endif |
152 | awin_cpu_clk(); | | 154 | awin_cpu_clk(); |
153 | #ifdef VERBOSE_INIT_ARM | | 155 | #ifdef VERBOSE_INIT_ARM |
154 | printf(" %"PRIu64"\n", curcpu()->ci_data.cpu_cc_freq); | | 156 | printf(" %"PRIu64"\n", curcpu()->ci_data.cpu_cc_freq); |
155 | #endif | | 157 | #endif |
156 | | | 158 | |
157 | #ifdef VERBOSE_INIT_ARM | | 159 | #ifdef VERBOSE_INIT_ARM |
158 | printf("Determining GPIO configuration"); | | 160 | printf("Determining GPIO configuration"); |
159 | #endif | | 161 | #endif |
160 | awin_gpio_init(); | | 162 | awin_gpio_init(); |
161 | #ifdef VERBOSE_INIT_ARM | | 163 | #ifdef VERBOSE_INIT_ARM |
162 | printf("\n"); | | 164 | printf("\n"); |
163 | #endif | | 165 | #endif |
164 | } | | 166 | } |
165 | | | 167 | |
166 | #ifdef MULTIPROCESSOR | | 168 | #ifdef MULTIPROCESSOR |
167 | void | | 169 | void |
168 | awin_cpu_hatch(struct cpu_info *ci) | | 170 | awin_cpu_hatch(struct cpu_info *ci) |
169 | { | | 171 | { |
170 | gtmr_init_cpu_clock(ci); | | 172 | gtmr_init_cpu_clock(ci); |
171 | } | | 173 | } |
172 | #endif | | 174 | #endif |
173 | | | 175 | |
174 | psize_t | | 176 | psize_t |
175 | awin_memprobe(void) | | 177 | awin_memprobe(void) |
176 | { | | 178 | { |
177 | const uint32_t dcr = bus_space_read_4(&awin_bs_tag, awin_core_bsh, | | 179 | const uint32_t dcr = bus_space_read_4(&awin_bs_tag, awin_core_bsh, |
178 | AWIN_DRAM_OFFSET + AWIN_DRAM_DCR_REG); | | 180 | AWIN_DRAM_OFFSET + AWIN_DRAM_DCR_REG); |
179 | | | 181 | |
180 | psize_t memsize = __SHIFTOUT(dcr, AWIN_DRAM_DCR_IO_WIDTH); | | 182 | psize_t memsize = __SHIFTOUT(dcr, AWIN_DRAM_DCR_IO_WIDTH); |
181 | memsize <<= __SHIFTOUT(dcr, AWIN_DRAM_DCR_CHIP_DENSITY) + 28 - 3; | | 183 | memsize <<= __SHIFTOUT(dcr, AWIN_DRAM_DCR_CHIP_DENSITY) + 28 - 3; |
182 | #ifdef VERBOSE_INIT_ARM | | 184 | #ifdef VERBOSE_INIT_ARM |
183 | printf("sdram_config = %#x, memsize = %uMB\n", dcr, | | 185 | printf("sdram_config = %#x, memsize = %uMB\n", dcr, |
184 | (u_int)(memsize >> 20)); | | 186 | (u_int)(memsize >> 20)); |
185 | #endif | | 187 | #endif |
186 | return memsize; | | 188 | return memsize; |
187 | } | | 189 | } |
188 | | | 190 | |
189 | void | | 191 | void |
190 | awin_pll6_enable(void) | | 192 | awin_pll6_enable(void) |
191 | { | | 193 | { |
192 | bus_space_tag_t bst = &awin_bs_tag; | | 194 | bus_space_tag_t bst = &awin_bs_tag; |
193 | bus_space_handle_t bsh = awin_core_bsh; | | 195 | bus_space_handle_t bsh = awin_core_bsh; |
194 | | | 196 | |
195 | /* | | 197 | /* |
196 | * SATA needs PLL6 to be a 100MHz clock. | | 198 | * SATA needs PLL6 to be a 100MHz clock. |
197 | */ | | 199 | */ |
198 | const uint32_t ocfg = bus_space_read_4(bst, bsh, | | 200 | const uint32_t ocfg = bus_space_read_4(bst, bsh, |
199 | AWIN_CCM_OFFSET + AWIN_PLL6_CFG_REG); | | 201 | AWIN_CCM_OFFSET + AWIN_PLL6_CFG_REG); |
200 | const u_int k = __SHIFTOUT(ocfg, AWIN_PLL_CFG_FACTOR_K); | | 202 | const u_int k = __SHIFTOUT(ocfg, AWIN_PLL_CFG_FACTOR_K); |
201 | | | 203 | |
202 | /* | | 204 | /* |
203 | * Output freq is 24MHz * n * k / m / 6. | | 205 | * Output freq is 24MHz * n * k / m / 6. |
204 | * To get to 100MHz, k & m must be equal and n must be 25. | | 206 | * To get to 100MHz, k & m must be equal and n must be 25. |
205 | */ | | 207 | */ |
206 | uint32_t ncfg = ocfg; | | 208 | uint32_t ncfg = ocfg; |
207 | ncfg &= ~(AWIN_PLL_CFG_FACTOR_M|AWIN_PLL_CFG_FACTOR_N); | | 209 | ncfg &= ~(AWIN_PLL_CFG_FACTOR_M|AWIN_PLL_CFG_FACTOR_N); |
208 | ncfg &= ~(AWIN_PLL_CFG_BYPASS); | | 210 | ncfg &= ~(AWIN_PLL_CFG_BYPASS); |
209 | ncfg |= __SHIFTIN(k, AWIN_PLL_CFG_FACTOR_M); | | 211 | ncfg |= __SHIFTIN(k, AWIN_PLL_CFG_FACTOR_M); |
210 | ncfg |= __SHIFTIN(25, AWIN_PLL_CFG_FACTOR_N); | | 212 | ncfg |= __SHIFTIN(25, AWIN_PLL_CFG_FACTOR_N); |
211 | ncfg |= AWIN_PLL_CFG_ENABLE | AWIN_PLL6_CFG_SATA_CLK_EN; | | 213 | ncfg |= AWIN_PLL_CFG_ENABLE | AWIN_PLL6_CFG_SATA_CLK_EN; |
212 | if (ncfg != ocfg) { | | 214 | if (ncfg != ocfg) { |
213 | bus_space_write_4(bst, bsh, | | 215 | bus_space_write_4(bst, bsh, |
214 | AWIN_CCM_OFFSET + AWIN_PLL6_CFG_REG, ncfg); | | 216 | AWIN_CCM_OFFSET + AWIN_PLL6_CFG_REG, ncfg); |
215 | } | | 217 | } |
216 | #if 0 | | 218 | #if 0 |
217 | printf(" [pll6=%#x->%#x:n=%ju k=%ju m=%ju] ", | | 219 | printf(" [pll6=%#x->%#x:n=%ju k=%ju m=%ju] ", |
218 | ocfg, ncfg, | | 220 | ocfg, ncfg, |
219 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_N), | | 221 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_N), |
220 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_K), | | 222 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_K), |
221 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_M)); | | 223 | __SHIFTOUT(ncfg, AWIN_PLL_CFG_FACTOR_M)); |
222 | #endif | | 224 | #endif |
223 | } | | 225 | } |