main.c revision 1.5 1 1.1 nisimura /*-
2 1.1 nisimura * Copyright (c) 2012 The NetBSD Foundation, Inc.
3 1.1 nisimura * All rights reserved.
4 1.1 nisimura *
5 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation
6 1.1 nisimura * by Paul Fleischer <paul (at) xpg.dk>
7 1.1 nisimura *
8 1.1 nisimura * Redistribution and use in source and binary forms, with or without
9 1.1 nisimura * modification, are permitted provided that the following conditions
10 1.1 nisimura * are met:
11 1.1 nisimura * 1. Redistributions of source code must retain the above copyright
12 1.1 nisimura * notice, this list of conditions and the following disclaimer.
13 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 nisimura * notice, this list of conditions and the following disclaimer in the
15 1.1 nisimura * documentation and/or other materials provided with the distribution.
16 1.1 nisimura *
17 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE.
28 1.1 nisimura */
29 1.1 nisimura #include <sys/types.h>
30 1.1 nisimura
31 1.1 nisimura #include <arm/armreg.h>
32 1.1 nisimura #include <arm/s3c2xx0/s3c2440reg.h>
33 1.1 nisimura
34 1.1 nisimura #include <netinet/in.h>
35 1.1 nisimura #include <netinet/in_systm.h>
36 1.1 nisimura
37 1.1 nisimura #include <lib/libkern/libkern.h>
38 1.1 nisimura #include <lib/libsa/stand.h>
39 1.1 nisimura #include <lib/libsa/loadfile.h>
40 1.1 nisimura #include <lib/libsa/iodesc.h>
41 1.1 nisimura
42 1.1 nisimura #include <arch/evbarm/mini2440/mini2440_bootinfo.h>
43 1.1 nisimura
44 1.1 nisimura #define CSR_READ(reg) \
45 1.1 nisimura *(volatile uint32_t *)(reg)
46 1.1 nisimura #define CSR_WRITE(reg, val) do { \
47 1.1 nisimura *(volatile uint32_t *)((reg)) = val; \
48 1.1 nisimura } while (0)
49 1.1 nisimura
50 1.1 nisimura #define UART_BAUDRATE 115200
51 1.1 nisimura #define S3C2XX0_XTAL_CLK 12000000
52 1.1 nisimura #define BOOTINFO_ADDR 0x31500000
53 1.1 nisimura
54 1.1 nisimura /* Macros to turn on/off LEDs. Numbering is 1-4. */
55 1.1 nisimura #define LED_REG (volatile uint16_t*)(S3C2440_GPIO_BASE+GPIO_PBDAT)
56 1.1 nisimura #define CLEAR_LEDS() *LED_REG = *LED_REG | 0x1e0
57 1.1 nisimura #define LED_ON(led) *LED_REG = *LED_REG & ( ~(1<<(led+4)) & 0x1E0 )
58 1.1 nisimura #define LED_OFF(led) *LED_REG = *LED_REG | ( ~(1<<(led+4)) & 0x1E0 )
59 1.1 nisimura
60 1.1 nisimura /* Local variables */
61 1.1 nisimura static time_t wallclock = 0;
62 1.1 nisimura static uint32_t timer_inc_rate;
63 1.1 nisimura void *bootinfo;
64 1.1 nisimura int bi_size;
65 1.1 nisimura char *bi_next;
66 1.1 nisimura
67 1.1 nisimura #define STR_EXPAND(tok) #tok
68 1.1 nisimura #define STR(tok) STR_EXPAND(tok)
69 1.1 nisimura
70 1.1 nisimura #if defined(DEFAULT_BOOTFILE)
71 1.1 nisimura static char *default_boot=STR(DEFAULT_BOOTFILE);
72 1.1 nisimura #else
73 1.1 nisimura static char *default_boot="net:";
74 1.1 nisimura #endif
75 1.1 nisimura
76 1.1 nisimura time_t getsecs();
77 1.1 nisimura time_t getusecs();
78 1.1 nisimura
79 1.1 nisimura /* Local functions */
80 1.1 nisimura static void s3c24x0_clock_freq2(vaddr_t clkman_base, int *fclk, int *hclk,
81 1.1 nisimura int *pclk);
82 1.1 nisimura static void uart_init(uint32_t pclk);
83 1.1 nisimura static void time_init(uint32_t pclk);
84 1.1 nisimura static void bi_init(void *addr);
85 1.1 nisimura static void bi_add(void *new, int type, int size);
86 1.1 nisimura static void parse_mac_address(const char *str, uint8_t *enaddr);
87 1.2 nisimura static void brdsetup(void);
88 1.2 nisimura static void iomux(int, const char *);
89 1.1 nisimura
90 1.1 nisimura extern void* dm9k_init(unsigned int tag, void *macaddr);
91 1.1 nisimura
92 1.1 nisimura /* External variables */
93 1.1 nisimura extern char bootprog_name[], bootprog_rev[];
94 1.1 nisimura
95 1.1 nisimura /* External functions */
96 1.1 nisimura extern void netif_match(unsigned int tag, uint8_t *macaddr);
97 1.1 nisimura /* extern int sdif_init(unsigned int tag);*/
98 1.1 nisimura
99 1.1 nisimura /* Global variables */
100 1.2 nisimura uint32_t socmodel;
101 1.1 nisimura int pclk;
102 1.1 nisimura struct btinfo_rootdevice bi_rdev;
103 1.1 nisimura
104 1.1 nisimura /* This is not very flexible, as only one net device is allowed */
105 1.1 nisimura struct btinfo_net bi_net;
106 1.1 nisimura
107 1.1 nisimura struct btinfo_bootpath bi_path;
108 1.1 nisimura
109 1.1 nisimura void
110 1.1 nisimura main(int argc, char *argv[])
111 1.1 nisimura {
112 1.1 nisimura int fclk, hclk;
113 1.1 nisimura int fd;
114 1.1 nisimura unsigned long marks[MARK_MAX];
115 1.5 skrll unsigned char hdr[0x28];
116 1.1 nisimura void (*entry)(void*);
117 1.1 nisimura unsigned elfpriv;
118 1.1 nisimura char *bootfile;
119 1.1 nisimura char *bf;
120 1.1 nisimura bool kernel_loaded;
121 1.1 nisimura uint8_t enaddr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
122 1.1 nisimura
123 1.2 nisimura socmodel = CSR_READ(S3C2440_GPIO_BASE + GPIO_GSTATUS1);
124 1.2 nisimura
125 1.2 nisimura brdsetup();
126 1.2 nisimura
127 1.1 nisimura /* Give some indication that main() has been reached */
128 1.1 nisimura CLEAR_LEDS();
129 1.1 nisimura LED_ON(4);
130 1.1 nisimura
131 1.1 nisimura /* Next, we setup the clock of the S3C2440 such that we are not
132 1.1 nisimura dependent on any other bootloader in this regard.
133 1.1 nisimura Target FCLK is 405MHz, and we assume an input crystal of 12MHz
134 1.1 nisimura */
135 1.1 nisimura *(volatile uint32_t*)(S3C2440_CLKMAN_BASE+CLKMAN_MPLLCON) =
136 1.1 nisimura ((0x7F << PLLCON_MDIV_SHIFT) & PLLCON_MDIV_MASK) |
137 1.1 nisimura ((2 << PLLCON_PDIV_SHIFT) & PLLCON_PDIV_MASK) |
138 1.1 nisimura ((1 << PLLCON_SDIV_SHIFT) & PLLCON_SDIV_MASK);
139 1.1 nisimura *(volatile uint32_t*)(S3C2440_CLKMAN_BASE+CLKMAN_UPLLCON) =
140 1.1 nisimura ((0x38 << PLLCON_MDIV_SHIFT) & PLLCON_MDIV_MASK) |
141 1.1 nisimura ((2 << PLLCON_PDIV_SHIFT) & PLLCON_PDIV_MASK) |
142 1.1 nisimura ((2 << PLLCON_SDIV_SHIFT) & PLLCON_SDIV_MASK);
143 1.1 nisimura
144 1.1 nisimura LED_ON(1);
145 1.1 nisimura
146 1.1 nisimura s3c24x0_clock_freq2(S3C2440_CLKMAN_BASE, &fclk, &hclk, &pclk);
147 1.1 nisimura
148 1.1 nisimura uart_init(pclk);
149 1.1 nisimura time_init(pclk);
150 1.1 nisimura
151 1.1 nisimura /* Let the user know we are alive */
152 1.1 nisimura printf("\n");
153 1.1 nisimura printf(">> %s boot2440, revision %s\n", bootprog_name, bootprog_rev);
154 1.2 nisimura printf("SoC model:");
155 1.2 nisimura switch (socmodel) {
156 1.2 nisimura case 0x32440000:
157 1.2 nisimura printf(" S3C2440"); break;
158 1.2 nisimura case 0x32440001:
159 1.2 nisimura printf(" S3C2440A"); break;
160 1.2 nisimura }
161 1.2 nisimura printf(" (chipid %08x)\n", socmodel);
162 1.1 nisimura
163 1.1 nisimura bootinfo = (void*) BOOTINFO_ADDR;
164 1.1 nisimura bi_init(bootinfo);
165 1.1 nisimura
166 1.1 nisimura bi_net.devname[0] = 0;
167 1.1 nisimura bi_path.bootpath[0] = 0;
168 1.1 nisimura
169 1.1 nisimura /* Try to get boot arguments from any previous boot-loader */
170 1.1 nisimura {
171 1.1 nisimura struct btinfo_bootstring ba;
172 1.1 nisimura int j, i;
173 1.1 nisimura
174 1.1 nisimura j = 0;
175 1.1 nisimura for (i = 0; i < argc; i++) {
176 1.1 nisimura if (j == MAX_BOOT_STRING-1) {
177 1.1 nisimura ba.bootstring[j] = '\0';
178 1.1 nisimura continue;
179 1.1 nisimura }
180 1.1 nisimura if (strncmp(argv[i], "mac=", 4) == 0) {
181 1.1 nisimura parse_mac_address(argv[i]+4, enaddr);
182 1.1 nisimura } else {
183 1.1 nisimura if (j != 0)
184 1.1 nisimura ba.bootstring[j++] = ' ';
185 1.1 nisimura
186 1.1 nisimura strncpy(ba.bootstring+j, argv[i], MAX_BOOT_STRING-j);
187 1.1 nisimura j += strlen(argv[i]);
188 1.1 nisimura }
189 1.1 nisimura }
190 1.1 nisimura bi_add(&ba, BTINFO_BOOTSTRING, sizeof(ba));
191 1.1 nisimura }
192 1.1 nisimura
193 1.1 nisimura LED_ON(3);
194 1.1 nisimura
195 1.1 nisimura if (argc > 1) {
196 1.1 nisimura bf = argv[argc-1];
197 1.1 nisimura } else {
198 1.1 nisimura bf = default_boot;
199 1.1 nisimura }
200 1.1 nisimura
201 1.1 nisimura /* Detect networking devices */
202 1.1 nisimura netif_match(0, enaddr);
203 1.1 nisimura
204 1.1 nisimura kernel_loaded = FALSE;
205 1.1 nisimura do {
206 1.1 nisimura bootfile = strsep(&bf, ";");
207 1.1 nisimura printf("Trying \"%s\"...\n", bootfile);
208 1.1 nisimura fd = open(bootfile, 0);
209 1.1 nisimura if (fd < 0) {
210 1.1 nisimura printf("Failed: %d\n", errno);
211 1.1 nisimura close(fd);
212 1.1 nisimura continue;
213 1.1 nisimura }
214 1.1 nisimura
215 1.1 nisimura if (fdloadfile(fd, marks, LOAD_ALL) == 0) {
216 1.1 nisimura kernel_loaded = TRUE;
217 1.1 nisimura break;
218 1.1 nisimura }
219 1.1 nisimura } while(bf != NULL);
220 1.1 nisimura
221 1.1 nisimura if (!kernel_loaded) {
222 1.1 nisimura panic("Failed to load kernel\n");
223 1.1 nisimura _rtt();
224 1.1 nisimura }
225 1.1 nisimura
226 1.1 nisimura #if 1
227 1.1 nisimura /* Set MAC address of the 'dme' net device, if
228 1.1 nisimura * it isn't set already */
229 1.1 nisimura if (bi_net.devname[0] == 0) {
230 1.1 nisimura uint8_t en[6] = {DM9000MAC};
231 1.1 nisimura snprintf(bi_net.devname, sizeof(bi_net.devname), "dme");
232 1.1 nisimura bi_net.cookie = 0;
233 1.1 nisimura
234 1.1 nisimura memcpy(bi_net.mac_address, en, sizeof(bi_net.mac_address));
235 1.1 nisimura }
236 1.1 nisimura #endif
237 1.1 nisimura /*
238 1.1 nisimura * ARM ELF header has a distinctive value in "private flags"
239 1.5 skrll * field of offset [0x24-x027];
240 1.5 skrll * - NetBSD 02 06 (oarm)
241 1.1 nisimura * - Linux 02 00 (2.4) or 02 02 (2.6)
242 1.5 skrll * - NetBSD 02 00 00 05 (earm)
243 1.1 nisimura */
244 1.1 nisimura lseek(fd, (off_t)0, SEEK_SET);
245 1.1 nisimura read(fd, &hdr, sizeof(hdr));
246 1.3 christos memcpy(&elfpriv, &hdr[0x24], sizeof(elfpriv));
247 1.1 nisimura
248 1.1 nisimura entry = (void *)marks[MARK_ENTRY];
249 1.5 skrll if (elfpriv == 0x0602 || elfpriv == 0x5000002) {
250 1.1 nisimura struct btinfo_symtab bi_syms;
251 1.1 nisimura
252 1.1 nisimura bi_syms.nsym = marks[MARK_NSYM];
253 1.1 nisimura bi_syms.ssym = (void*)marks[MARK_SYM];
254 1.1 nisimura bi_syms.esym = (void*)marks[MARK_END];
255 1.1 nisimura bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
256 1.1 nisimura if (bi_path.bootpath[0] != 0)
257 1.1 nisimura bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
258 1.1 nisimura bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
259 1.1 nisimura if (bi_net.devname[0] != 0 )
260 1.1 nisimura bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
261 1.1 nisimura } else {
262 1.1 nisimura printf("Loaded object is not NetBSD ARM ELF");
263 1.1 nisimura _rtt();
264 1.1 nisimura }
265 1.1 nisimura
266 1.1 nisimura printf("entry=%p, nsym=%lu, ssym=%p, esym=%p\n",
267 1.1 nisimura (void *)marks[MARK_ENTRY],
268 1.1 nisimura marks[MARK_NSYM],
269 1.1 nisimura (void *)marks[MARK_SYM],
270 1.1 nisimura (void *)marks[MARK_END]);
271 1.1 nisimura (*entry)(bootinfo);
272 1.1 nisimura
273 1.1 nisimura printf("exec returned, restarting...\n");
274 1.1 nisimura _rtt();
275 1.1 nisimura }
276 1.1 nisimura
277 1.1 nisimura void
278 1.1 nisimura uart_init(uint32_t pclk)
279 1.1 nisimura {
280 1.1 nisimura /* Setup UART0 clocking: Use PCLK */
281 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UBRDIV) =
282 1.1 nisimura (pclk/(UART_BAUDRATE*16)) - 1;
283 1.1 nisimura
284 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UCON) =
285 1.1 nisimura UCON_TXMODE_INT | UCON_RXMODE_INT;
286 1.1 nisimura
287 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_ULCON) =
288 1.1 nisimura ULCON_PARITY_NONE | ULCON_LENGTH_8;
289 1.1 nisimura
290 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UFCON) =
291 1.1 nisimura UFCON_TXTRIGGER_0 | UFCON_TXFIFO_RESET | UFCON_FIFO_ENABLE;
292 1.1 nisimura }
293 1.1 nisimura
294 1.1 nisimura static uint32_t countdown_duration;
295 1.1 nisimura
296 1.1 nisimura static
297 1.1 nisimura void time_init(uint32_t pclk)
298 1.1 nisimura {
299 1.1 nisimura /* Configure timer0 to be as slow as possible:
300 1.1 nisimura Prescaler = 255
301 1.1 nisimura Divider = 16
302 1.1 nisimura */
303 1.1 nisimura
304 1.1 nisimura /* First, configure the prescaler */
305 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG0) = 0xff;
306 1.1 nisimura
307 1.1 nisimura /* Next, the divider */
308 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG1) |=
309 1.1 nisimura (TCFG1_MUX_DIV16 <<TCFG1_MUX_SHIFT(0)) & TCFG1_MUX_MASK(0);
310 1.1 nisimura
311 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
312 1.1 nisimura TCON_MANUALUPDATE(0);
313 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
314 1.1 nisimura 0xffff;
315 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
316 1.1 nisimura TCON_START(0);
317 1.1 nisimura
318 1.1 nisimura
319 1.1 nisimura /* Timer count down duration */
320 1.1 nisimura countdown_duration = 65535/(pclk/256/16);
321 1.1 nisimura timer_inc_rate = pclk/256/16;
322 1.1 nisimura // printf("Countdown duration is: %ds\n", countdown_duration);
323 1.1 nisimura #if 0
324 1.1 nisimura {
325 1.1 nisimura /* Timer test */
326 1.1 nisimura time_t time, old_time;
327 1.1 nisimura
328 1.1 nisimura while(1) {
329 1.1 nisimura time = old_time = getsecs();
330 1.1 nisimura do {
331 1.1 nisimura time = getsecs();
332 1.1 nisimura } while(time == old_time);
333 1.1 nisimura printf("Count %u\n", (int)time);
334 1.1 nisimura }
335 1.1 nisimura }
336 1.1 nisimura #endif
337 1.1 nisimura }
338 1.1 nisimura
339 1.1 nisimura time_t
340 1.1 nisimura getsecs()
341 1.1 nisimura {
342 1.1 nisimura time_t secs = getusecs()/1000000;
343 1.1 nisimura return secs;
344 1.1 nisimura }
345 1.1 nisimura
346 1.1 nisimura time_t
347 1.1 nisimura getusecs() {
348 1.1 nisimura uint32_t count;
349 1.1 nisimura //do {
350 1.1 nisimura count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
351 1.1 nisimura //} while( count > 65500);
352 1.1 nisimura
353 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
354 1.1 nisimura TCON_MANUALUPDATE(0);
355 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
356 1.1 nisimura 0xffff;
357 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
358 1.1 nisimura TCON_START(0);
359 1.1 nisimura
360 1.1 nisimura wallclock += ((65535-count)*1000000) / timer_inc_rate;
361 1.1 nisimura
362 1.1 nisimura return wallclock;
363 1.1 nisimura }
364 1.1 nisimura
365 1.1 nisimura void
366 1.1 nisimura usleep(int us) {
367 1.1 nisimura uint32_t count;
368 1.1 nisimura uint32_t target_clock = wallclock+us;
369 1.1 nisimura
370 1.1 nisimura while( wallclock < target_clock) {
371 1.1 nisimura do {
372 1.1 nisimura count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
373 1.1 nisimura } while( count > 65500);
374 1.1 nisimura
375 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
376 1.1 nisimura TCON_MANUALUPDATE(0);
377 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
378 1.1 nisimura 0xffff;
379 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
380 1.1 nisimura TCON_START(0);
381 1.1 nisimura
382 1.1 nisimura wallclock += ((65535-count)*1000000) / timer_inc_rate;
383 1.1 nisimura }
384 1.1 nisimura }
385 1.1 nisimura
386 1.1 nisimura
387 1.1 nisimura void
388 1.1 nisimura mini2440_panic()
389 1.1 nisimura {
390 1.1 nisimura int i, l;
391 1.1 nisimura int v;
392 1.1 nisimura while(1) {
393 1.1 nisimura CLEAR_LEDS();
394 1.1 nisimura for(l=0; l<0xffffff; l++) {
395 1.1 nisimura v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
396 1.1 nisimura }
397 1.1 nisimura for(i=1; i<=4; i++) {
398 1.1 nisimura LED_ON(i);
399 1.1 nisimura }
400 1.1 nisimura for(l=0; l<0xffffff; l++) {
401 1.1 nisimura v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
402 1.1 nisimura }
403 1.3 christos __USE(v);
404 1.1 nisimura }
405 1.1 nisimura }
406 1.1 nisimura
407 1.1 nisimura void
408 1.1 nisimura s3c24x0_clock_freq2(vaddr_t clkman_base, int *fclk, int *hclk, int *pclk)
409 1.1 nisimura {
410 1.1 nisimura uint32_t pllcon, divn, camdivn;
411 1.1 nisimura int mdiv, pdiv, sdiv;
412 1.1 nisimura uint32_t f, h, p;
413 1.1 nisimura
414 1.1 nisimura pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
415 1.1 nisimura divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
416 1.1 nisimura camdivn = *(volatile uint32_t *)(clkman_base + CLKMAN_CAMDIVN);
417 1.1 nisimura
418 1.1 nisimura mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
419 1.1 nisimura pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
420 1.1 nisimura sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
421 1.1 nisimura
422 1.1 nisimura f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv)) * 2;
423 1.1 nisimura h = f;
424 1.1 nisimura
425 1.1 nisimura /* HDIVN of CLKDIVN can have 4 distinct values */
426 1.1 nisimura switch( (divn & CLKDIVN_HDIVN_MASK) >> CLKDIVN_HDIVN_SHIFT )
427 1.1 nisimura {
428 1.1 nisimura case 0:
429 1.1 nisimura /* 00b: HCLK = FCLK/1*/
430 1.1 nisimura break;
431 1.1 nisimura case 1:
432 1.1 nisimura /* 01b: HCLK = FCLK/2*/
433 1.1 nisimura h /= 2;
434 1.1 nisimura break;
435 1.1 nisimura case 2:
436 1.1 nisimura /* 10b: HCLK = FCLK/4 when CAMDIVN[9] (HCLK4_HALF) = 0
437 1.1 nisimura * HCLK = FCLK/8 when CAMDIVN[9] (HCLK4_HALF) = 1 */
438 1.1 nisimura if( camdivn & CLKCAMDIVN_HCLK4_HALF )
439 1.1 nisimura h /= 8;
440 1.1 nisimura else
441 1.1 nisimura h /= 4;
442 1.1 nisimura break;
443 1.1 nisimura case 3:
444 1.1 nisimura /* 11b: HCLK = FCLK/3 when CAMDIVN[8] (HCLK3_HALF) = 0
445 1.1 nisimura * HCLK = FCLK/6 when CAMDIVN[8] (HCLK3_HALF) = 1 */
446 1.1 nisimura if( camdivn & CLKCAMDIVN_HCLK3_HALF )
447 1.1 nisimura h /= 6;
448 1.1 nisimura else
449 1.1 nisimura h /= 3;
450 1.1 nisimura break;
451 1.1 nisimura }
452 1.1 nisimura
453 1.1 nisimura p = h;
454 1.1 nisimura
455 1.1 nisimura if (divn & CLKDIVN_PDIVN)
456 1.1 nisimura p /= 2;
457 1.1 nisimura
458 1.1 nisimura if (fclk) *fclk = f;
459 1.1 nisimura if (hclk) *hclk = h;
460 1.1 nisimura if (pclk) *pclk = p;
461 1.1 nisimura }
462 1.1 nisimura
463 1.1 nisimura void
464 1.1 nisimura putchar(int c)
465 1.1 nisimura {
466 1.1 nisimura uint32_t stat;
467 1.1 nisimura
468 1.1 nisimura if (c == '\n')
469 1.1 nisimura putchar('\r');
470 1.1 nisimura
471 1.1 nisimura do {
472 1.1 nisimura stat = CSR_READ(S3C2440_UART_BASE(0) + SSCOM_UTRSTAT);
473 1.1 nisimura } while ((stat & UTRSTAT_TXEMPTY) == 0);
474 1.1 nisimura
475 1.1 nisimura CSR_WRITE(S3C2440_UART_BASE(0) + SSCOM_UTXH, c);
476 1.1 nisimura }
477 1.1 nisimura
478 1.1 nisimura void
479 1.1 nisimura _rtt()
480 1.1 nisimura {
481 1.1 nisimura int cpsr_save, tmp;
482 1.1 nisimura /* Disable interrupts */
483 1.1 nisimura __asm volatile("mrs %0, cpsr;"
484 1.1 nisimura "orr %1, %0, %2;"
485 1.1 nisimura "msr cpsr_c, %1;"
486 1.1 nisimura : "=r" (cpsr_save), "=r" (tmp)
487 1.1 nisimura : "I" (I32_bit)
488 1.1 nisimura );
489 1.1 nisimura
490 1.1 nisimura /* Disable MMU */
491 1.1 nisimura __asm volatile("mrc p15, 0, %0, c1, c0, 0;"
492 1.1 nisimura "bic %0, %0, %1;"
493 1.1 nisimura "mcr p15, 0, %0, c1, c0, 0;"
494 1.1 nisimura : "=r" (tmp)
495 1.1 nisimura : "I" (CPU_CONTROL_MMU_ENABLE)
496 1.1 nisimura );
497 1.1 nisimura
498 1.1 nisimura /* Configure watchdog to fire now */
499 1.1 nisimura *(volatile uint32_t *)(S3C2440_WDT_BASE + WDT_WTCON) =
500 1.1 nisimura (0 << WTCON_PRESCALE_SHIFT) | WTCON_ENABLE |
501 1.1 nisimura WTCON_CLKSEL_16 | WTCON_ENRST;
502 1.4 joerg __builtin_unreachable();
503 1.1 nisimura }
504 1.1 nisimura
505 1.1 nisimura void
506 1.1 nisimura bi_init(void *addr)
507 1.1 nisimura {
508 1.1 nisimura struct btinfo_magic bi_magic;
509 1.1 nisimura
510 1.1 nisimura memset(addr, 0, BOOTINFO_MAXSIZE);
511 1.1 nisimura bi_next = (char*) addr;
512 1.1 nisimura bi_size = 0;
513 1.1 nisimura
514 1.1 nisimura bi_magic.magic = BOOTINFO_MAGIC;
515 1.1 nisimura bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
516 1.1 nisimura }
517 1.1 nisimura
518 1.1 nisimura
519 1.1 nisimura void
520 1.1 nisimura bi_add(void *new, int type, int size)
521 1.1 nisimura {
522 1.1 nisimura struct btinfo_common *bi;
523 1.1 nisimura
524 1.1 nisimura if (bi_size + size > BOOTINFO_MAXSIZE)
525 1.1 nisimura return;
526 1.1 nisimura
527 1.1 nisimura bi = new;
528 1.1 nisimura bi->next = size;
529 1.1 nisimura bi->type = type;
530 1.1 nisimura memcpy(bi_next, new, size);
531 1.1 nisimura bi_next += size;
532 1.1 nisimura }
533 1.1 nisimura
534 1.1 nisimura static void
535 1.1 nisimura parse_mac_address(const char *str, uint8_t *enaddr)
536 1.1 nisimura {
537 1.1 nisimura int i;
538 1.1 nisimura char *next = (char*)str;
539 1.1 nisimura
540 1.1 nisimura for(i=0;i<6;i++) {
541 1.1 nisimura str = next;
542 1.1 nisimura enaddr[i] = (unsigned char)strtoll(str, &next, 16);
543 1.1 nisimura if( *next == ':' ) {
544 1.1 nisimura next++;
545 1.1 nisimura } else {
546 1.1 nisimura break;
547 1.1 nisimura }
548 1.1 nisimura }
549 1.1 nisimura }
550 1.2 nisimura
551 1.2 nisimura static void
552 1.2 nisimura brdsetup(void)
553 1.2 nisimura {
554 1.2 nisimura /*
555 1.2 nisimura * MINI2440 pin usage summary
556 1.2 nisimura *
557 1.2 nisimura * B5 output LED1 control
558 1.2 nisimura * B6 output LED2 control
559 1.2 nisimura * B7 output LED3 control
560 1.2 nisimura * B8 output LED4 control
561 1.2 nisimura * G0 EINT8 K1 button
562 1.2 nisimura * G3 EINT11 K2 button
563 1.2 nisimura * G5 EINT13 K3 button
564 1.2 nisimura * G6 EINT14 K4 button
565 1.2 nisimura * G7 EINT15 K5 button
566 1.2 nisimura * G11 EINT19 K6 button
567 1.2 nisimura * F7 EINT7 DM9000 interrupt
568 1.2 nisimura * G12 EINT20 camera interrupt
569 1.2 nisimura * G8 input SD card presense detect
570 1.2 nisimura * H8 input SD write protect sense
571 1.2 nisimura * B0 TOUT0 buzzer PWM
572 1.2 nisimura * B1 TOUT1 LCD backlight PWM
573 1.2 nisimura * B2 output UDA1341 audio L3MODE
574 1.2 nisimura * B3 output UDA1341 audio L3DATA
575 1.2 nisimura * B4 output UDA1341 audio L3LOCK
576 1.2 nisimura *
577 1.2 nisimura * A21, A11, G15, G14, G13: not used.
578 1.2 nisimura *
579 1.2 nisimura * i input sense
580 1.2 nisimura * o output control
581 1.2 nisimura * 2 function 2
582 1.2 nisimura * 3 function 3
583 1.2 nisimura * 0 output control (A only)
584 1.2 nisimura * 1 function 1 (A only)
585 1.2 nisimura * ./x no function, not connected or don't-care
586 1.2 nisimura *
587 1.2 nisimura * A ........ .1x11111 1111x111 11111111
588 1.2 nisimura * B .....22o ooooooo2
589 1.2 nisimura * C 22222222 22222222
590 1.2 nisimura * D 22222222 22222222
591 1.2 nisimura * E 22222222 22222222
592 1.2 nisimura * F ........ 22222222
593 1.2 nisimura * G xxx2222i 22232322
594 1.2 nisimura * H .....22i 22222222
595 1.2 nisimura * J ...22222 22222222
596 1.2 nisimura */
597 1.2 nisimura iomux('A', "........ .1x11111 1111x111 11111111");
598 1.2 nisimura iomux('B', ".....22o ooooooo2");
599 1.2 nisimura iomux('C', "22222222 22222222");
600 1.2 nisimura iomux('D', "22222222 22222222");
601 1.2 nisimura iomux('E', "22222222 22222222");
602 1.2 nisimura iomux('F', "........ 22222222");
603 1.2 nisimura iomux('G', "xxx2222i 22232322");
604 1.2 nisimura iomux('H', ".....22i 22222222");
605 1.2 nisimura iomux('J', "...22222 22222222");
606 1.2 nisimura
607 1.2 nisimura /* mask all possible external interrupt source [23:3] */
608 1.2 nisimura CSR_WRITE(S3C2440_GPIO_BASE + GPIO_EINTMASK, ~0);
609 1.2 nisimura }
610 1.2 nisimura
611 1.2 nisimura static void
612 1.2 nisimura iomux(int grp, const char *cnf)
613 1.2 nisimura {
614 1.2 nisimura uint32_t con;
615 1.2 nisimura int sft, i, v;
616 1.2 nisimura
617 1.2 nisimura con = v = 0;
618 1.2 nisimura sft = (grp != 'A') ? 2 : 1;
619 1.2 nisimura for (i = 0; cnf[i] != '\0'; i++) {
620 1.2 nisimura switch (cnf[i]) {
621 1.2 nisimura case 'i':
622 1.2 nisimura case '0':
623 1.2 nisimura case '.':
624 1.2 nisimura case 'x':
625 1.2 nisimura v = 0; break;
626 1.2 nisimura case 'o':
627 1.2 nisimura case '1':
628 1.2 nisimura v = 1; break;
629 1.2 nisimura case '2':
630 1.2 nisimura v = 2; break;
631 1.2 nisimura case '3':
632 1.2 nisimura v = 3; break;
633 1.2 nisimura default:
634 1.2 nisimura continue;
635 1.2 nisimura }
636 1.2 nisimura con = (con << sft) | v;
637 1.2 nisimura }
638 1.2 nisimura CSR_WRITE(S3C2440_GPIO_BASE + 0x10 * (grp - 'A'), con);
639 1.2 nisimura }
640