main.c revision 1.2 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.1 nisimura unsigned char hdr[0x26];
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.1 nisimura * field of offset [0x24:25];
240 1.1 nisimura * - NetBSD 02 06
241 1.1 nisimura * - Linux 02 00 (2.4) or 02 02 (2.6)
242 1.1 nisimura */
243 1.1 nisimura lseek(fd, (off_t)0, SEEK_SET);
244 1.1 nisimura read(fd, &hdr, sizeof(hdr));
245 1.1 nisimura elfpriv = *(unsigned short *)&hdr[0x24];
246 1.1 nisimura
247 1.1 nisimura entry = (void *)marks[MARK_ENTRY];
248 1.1 nisimura if (elfpriv == 0x0602) {
249 1.1 nisimura struct btinfo_symtab bi_syms;
250 1.1 nisimura
251 1.1 nisimura bi_syms.nsym = marks[MARK_NSYM];
252 1.1 nisimura bi_syms.ssym = (void*)marks[MARK_SYM];
253 1.1 nisimura bi_syms.esym = (void*)marks[MARK_END];
254 1.1 nisimura bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
255 1.1 nisimura if (bi_path.bootpath[0] != 0)
256 1.1 nisimura bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
257 1.1 nisimura bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
258 1.1 nisimura if (bi_net.devname[0] != 0 )
259 1.1 nisimura bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
260 1.1 nisimura } else {
261 1.1 nisimura printf("Loaded object is not NetBSD ARM ELF");
262 1.1 nisimura _rtt();
263 1.1 nisimura }
264 1.1 nisimura
265 1.1 nisimura printf("entry=%p, nsym=%lu, ssym=%p, esym=%p\n",
266 1.1 nisimura (void *)marks[MARK_ENTRY],
267 1.1 nisimura marks[MARK_NSYM],
268 1.1 nisimura (void *)marks[MARK_SYM],
269 1.1 nisimura (void *)marks[MARK_END]);
270 1.1 nisimura (*entry)(bootinfo);
271 1.1 nisimura
272 1.1 nisimura printf("exec returned, restarting...\n");
273 1.1 nisimura _rtt();
274 1.1 nisimura }
275 1.1 nisimura
276 1.1 nisimura void
277 1.1 nisimura uart_init(uint32_t pclk)
278 1.1 nisimura {
279 1.1 nisimura /* Setup UART0 clocking: Use PCLK */
280 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UBRDIV) =
281 1.1 nisimura (pclk/(UART_BAUDRATE*16)) - 1;
282 1.1 nisimura
283 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UCON) =
284 1.1 nisimura UCON_TXMODE_INT | UCON_RXMODE_INT;
285 1.1 nisimura
286 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_ULCON) =
287 1.1 nisimura ULCON_PARITY_NONE | ULCON_LENGTH_8;
288 1.1 nisimura
289 1.1 nisimura *(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UFCON) =
290 1.1 nisimura UFCON_TXTRIGGER_0 | UFCON_TXFIFO_RESET | UFCON_FIFO_ENABLE;
291 1.1 nisimura }
292 1.1 nisimura
293 1.1 nisimura static uint32_t countdown_duration;
294 1.1 nisimura
295 1.1 nisimura static
296 1.1 nisimura void time_init(uint32_t pclk)
297 1.1 nisimura {
298 1.1 nisimura /* Configure timer0 to be as slow as possible:
299 1.1 nisimura Prescaler = 255
300 1.1 nisimura Divider = 16
301 1.1 nisimura */
302 1.1 nisimura
303 1.1 nisimura /* First, configure the prescaler */
304 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG0) = 0xff;
305 1.1 nisimura
306 1.1 nisimura /* Next, the divider */
307 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG1) |=
308 1.1 nisimura (TCFG1_MUX_DIV16 <<TCFG1_MUX_SHIFT(0)) & TCFG1_MUX_MASK(0);
309 1.1 nisimura
310 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
311 1.1 nisimura TCON_MANUALUPDATE(0);
312 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
313 1.1 nisimura 0xffff;
314 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
315 1.1 nisimura TCON_START(0);
316 1.1 nisimura
317 1.1 nisimura
318 1.1 nisimura /* Timer count down duration */
319 1.1 nisimura countdown_duration = 65535/(pclk/256/16);
320 1.1 nisimura timer_inc_rate = pclk/256/16;
321 1.1 nisimura // printf("Countdown duration is: %ds\n", countdown_duration);
322 1.1 nisimura #if 0
323 1.1 nisimura {
324 1.1 nisimura /* Timer test */
325 1.1 nisimura time_t time, old_time;
326 1.1 nisimura
327 1.1 nisimura while(1) {
328 1.1 nisimura time = old_time = getsecs();
329 1.1 nisimura do {
330 1.1 nisimura time = getsecs();
331 1.1 nisimura } while(time == old_time);
332 1.1 nisimura printf("Count %u\n", (int)time);
333 1.1 nisimura }
334 1.1 nisimura }
335 1.1 nisimura #endif
336 1.1 nisimura }
337 1.1 nisimura
338 1.1 nisimura time_t
339 1.1 nisimura getsecs()
340 1.1 nisimura {
341 1.1 nisimura time_t secs = getusecs()/1000000;
342 1.1 nisimura return secs;
343 1.1 nisimura }
344 1.1 nisimura
345 1.1 nisimura time_t
346 1.1 nisimura getusecs() {
347 1.1 nisimura uint32_t count;
348 1.1 nisimura //do {
349 1.1 nisimura count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
350 1.1 nisimura //} while( count > 65500);
351 1.1 nisimura
352 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
353 1.1 nisimura TCON_MANUALUPDATE(0);
354 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
355 1.1 nisimura 0xffff;
356 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
357 1.1 nisimura TCON_START(0);
358 1.1 nisimura
359 1.1 nisimura wallclock += ((65535-count)*1000000) / timer_inc_rate;
360 1.1 nisimura
361 1.1 nisimura return wallclock;
362 1.1 nisimura }
363 1.1 nisimura
364 1.1 nisimura void
365 1.1 nisimura usleep(int us) {
366 1.1 nisimura uint32_t count;
367 1.1 nisimura uint32_t target_clock = wallclock+us;
368 1.1 nisimura
369 1.1 nisimura while( wallclock < target_clock) {
370 1.1 nisimura do {
371 1.1 nisimura count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
372 1.1 nisimura } while( count > 65500);
373 1.1 nisimura
374 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
375 1.1 nisimura TCON_MANUALUPDATE(0);
376 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
377 1.1 nisimura 0xffff;
378 1.1 nisimura *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
379 1.1 nisimura TCON_START(0);
380 1.1 nisimura
381 1.1 nisimura wallclock += ((65535-count)*1000000) / timer_inc_rate;
382 1.1 nisimura }
383 1.1 nisimura }
384 1.1 nisimura
385 1.1 nisimura
386 1.1 nisimura void
387 1.1 nisimura mini2440_panic()
388 1.1 nisimura {
389 1.1 nisimura int i, l;
390 1.1 nisimura int v;
391 1.1 nisimura while(1) {
392 1.1 nisimura CLEAR_LEDS();
393 1.1 nisimura for(l=0; l<0xffffff; l++) {
394 1.1 nisimura v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
395 1.1 nisimura }
396 1.1 nisimura for(i=1; i<=4; i++) {
397 1.1 nisimura LED_ON(i);
398 1.1 nisimura }
399 1.1 nisimura for(l=0; l<0xffffff; l++) {
400 1.1 nisimura v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
401 1.1 nisimura }
402 1.1 nisimura }
403 1.1 nisimura }
404 1.1 nisimura
405 1.1 nisimura void
406 1.1 nisimura s3c24x0_clock_freq2(vaddr_t clkman_base, int *fclk, int *hclk, int *pclk)
407 1.1 nisimura {
408 1.1 nisimura uint32_t pllcon, divn, camdivn;
409 1.1 nisimura int mdiv, pdiv, sdiv;
410 1.1 nisimura uint32_t f, h, p;
411 1.1 nisimura
412 1.1 nisimura pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
413 1.1 nisimura divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
414 1.1 nisimura camdivn = *(volatile uint32_t *)(clkman_base + CLKMAN_CAMDIVN);
415 1.1 nisimura
416 1.1 nisimura mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
417 1.1 nisimura pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
418 1.1 nisimura sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
419 1.1 nisimura
420 1.1 nisimura f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv)) * 2;
421 1.1 nisimura h = f;
422 1.1 nisimura
423 1.1 nisimura /* HDIVN of CLKDIVN can have 4 distinct values */
424 1.1 nisimura switch( (divn & CLKDIVN_HDIVN_MASK) >> CLKDIVN_HDIVN_SHIFT )
425 1.1 nisimura {
426 1.1 nisimura case 0:
427 1.1 nisimura /* 00b: HCLK = FCLK/1*/
428 1.1 nisimura break;
429 1.1 nisimura case 1:
430 1.1 nisimura /* 01b: HCLK = FCLK/2*/
431 1.1 nisimura h /= 2;
432 1.1 nisimura break;
433 1.1 nisimura case 2:
434 1.1 nisimura /* 10b: HCLK = FCLK/4 when CAMDIVN[9] (HCLK4_HALF) = 0
435 1.1 nisimura * HCLK = FCLK/8 when CAMDIVN[9] (HCLK4_HALF) = 1 */
436 1.1 nisimura if( camdivn & CLKCAMDIVN_HCLK4_HALF )
437 1.1 nisimura h /= 8;
438 1.1 nisimura else
439 1.1 nisimura h /= 4;
440 1.1 nisimura break;
441 1.1 nisimura case 3:
442 1.1 nisimura /* 11b: HCLK = FCLK/3 when CAMDIVN[8] (HCLK3_HALF) = 0
443 1.1 nisimura * HCLK = FCLK/6 when CAMDIVN[8] (HCLK3_HALF) = 1 */
444 1.1 nisimura if( camdivn & CLKCAMDIVN_HCLK3_HALF )
445 1.1 nisimura h /= 6;
446 1.1 nisimura else
447 1.1 nisimura h /= 3;
448 1.1 nisimura break;
449 1.1 nisimura }
450 1.1 nisimura
451 1.1 nisimura p = h;
452 1.1 nisimura
453 1.1 nisimura if (divn & CLKDIVN_PDIVN)
454 1.1 nisimura p /= 2;
455 1.1 nisimura
456 1.1 nisimura if (fclk) *fclk = f;
457 1.1 nisimura if (hclk) *hclk = h;
458 1.1 nisimura if (pclk) *pclk = p;
459 1.1 nisimura }
460 1.1 nisimura
461 1.1 nisimura void
462 1.1 nisimura putchar(int c)
463 1.1 nisimura {
464 1.1 nisimura uint32_t stat;
465 1.1 nisimura
466 1.1 nisimura if (c == '\n')
467 1.1 nisimura putchar('\r');
468 1.1 nisimura
469 1.1 nisimura do {
470 1.1 nisimura stat = CSR_READ(S3C2440_UART_BASE(0) + SSCOM_UTRSTAT);
471 1.1 nisimura } while ((stat & UTRSTAT_TXEMPTY) == 0);
472 1.1 nisimura
473 1.1 nisimura CSR_WRITE(S3C2440_UART_BASE(0) + SSCOM_UTXH, c);
474 1.1 nisimura }
475 1.1 nisimura
476 1.1 nisimura void
477 1.1 nisimura _rtt()
478 1.1 nisimura {
479 1.1 nisimura int cpsr_save, tmp;
480 1.1 nisimura /* Disable interrupts */
481 1.1 nisimura __asm volatile("mrs %0, cpsr;"
482 1.1 nisimura "orr %1, %0, %2;"
483 1.1 nisimura "msr cpsr_c, %1;"
484 1.1 nisimura : "=r" (cpsr_save), "=r" (tmp)
485 1.1 nisimura : "I" (I32_bit)
486 1.1 nisimura );
487 1.1 nisimura
488 1.1 nisimura /* Disable MMU */
489 1.1 nisimura __asm volatile("mrc p15, 0, %0, c1, c0, 0;"
490 1.1 nisimura "bic %0, %0, %1;"
491 1.1 nisimura "mcr p15, 0, %0, c1, c0, 0;"
492 1.1 nisimura : "=r" (tmp)
493 1.1 nisimura : "I" (CPU_CONTROL_MMU_ENABLE)
494 1.1 nisimura );
495 1.1 nisimura
496 1.1 nisimura /* Configure watchdog to fire now */
497 1.1 nisimura *(volatile uint32_t *)(S3C2440_WDT_BASE + WDT_WTCON) =
498 1.1 nisimura (0 << WTCON_PRESCALE_SHIFT) | WTCON_ENABLE |
499 1.1 nisimura WTCON_CLKSEL_16 | WTCON_ENRST;
500 1.1 nisimura }
501 1.1 nisimura
502 1.1 nisimura void
503 1.1 nisimura bi_init(void *addr)
504 1.1 nisimura {
505 1.1 nisimura struct btinfo_magic bi_magic;
506 1.1 nisimura
507 1.1 nisimura memset(addr, 0, BOOTINFO_MAXSIZE);
508 1.1 nisimura bi_next = (char*) addr;
509 1.1 nisimura bi_size = 0;
510 1.1 nisimura
511 1.1 nisimura bi_magic.magic = BOOTINFO_MAGIC;
512 1.1 nisimura bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
513 1.1 nisimura }
514 1.1 nisimura
515 1.1 nisimura
516 1.1 nisimura void
517 1.1 nisimura bi_add(void *new, int type, int size)
518 1.1 nisimura {
519 1.1 nisimura struct btinfo_common *bi;
520 1.1 nisimura
521 1.1 nisimura if (bi_size + size > BOOTINFO_MAXSIZE)
522 1.1 nisimura return;
523 1.1 nisimura
524 1.1 nisimura bi = new;
525 1.1 nisimura bi->next = size;
526 1.1 nisimura bi->type = type;
527 1.1 nisimura memcpy(bi_next, new, size);
528 1.1 nisimura bi_next += size;
529 1.1 nisimura }
530 1.1 nisimura
531 1.1 nisimura static void
532 1.1 nisimura parse_mac_address(const char *str, uint8_t *enaddr)
533 1.1 nisimura {
534 1.1 nisimura int i;
535 1.1 nisimura char *next = (char*)str;
536 1.1 nisimura
537 1.1 nisimura for(i=0;i<6;i++) {
538 1.1 nisimura str = next;
539 1.1 nisimura enaddr[i] = (unsigned char)strtoll(str, &next, 16);
540 1.1 nisimura if( *next == ':' ) {
541 1.1 nisimura next++;
542 1.1 nisimura } else {
543 1.1 nisimura break;
544 1.1 nisimura }
545 1.1 nisimura }
546 1.1 nisimura }
547 1.2 nisimura
548 1.2 nisimura static void
549 1.2 nisimura brdsetup(void)
550 1.2 nisimura {
551 1.2 nisimura /*
552 1.2 nisimura * MINI2440 pin usage summary
553 1.2 nisimura *
554 1.2 nisimura * B5 output LED1 control
555 1.2 nisimura * B6 output LED2 control
556 1.2 nisimura * B7 output LED3 control
557 1.2 nisimura * B8 output LED4 control
558 1.2 nisimura * G0 EINT8 K1 button
559 1.2 nisimura * G3 EINT11 K2 button
560 1.2 nisimura * G5 EINT13 K3 button
561 1.2 nisimura * G6 EINT14 K4 button
562 1.2 nisimura * G7 EINT15 K5 button
563 1.2 nisimura * G11 EINT19 K6 button
564 1.2 nisimura * F7 EINT7 DM9000 interrupt
565 1.2 nisimura * G12 EINT20 camera interrupt
566 1.2 nisimura * G8 input SD card presense detect
567 1.2 nisimura * H8 input SD write protect sense
568 1.2 nisimura * B0 TOUT0 buzzer PWM
569 1.2 nisimura * B1 TOUT1 LCD backlight PWM
570 1.2 nisimura * B2 output UDA1341 audio L3MODE
571 1.2 nisimura * B3 output UDA1341 audio L3DATA
572 1.2 nisimura * B4 output UDA1341 audio L3LOCK
573 1.2 nisimura *
574 1.2 nisimura * A21, A11, G15, G14, G13: not used.
575 1.2 nisimura *
576 1.2 nisimura * i input sense
577 1.2 nisimura * o output control
578 1.2 nisimura * 2 function 2
579 1.2 nisimura * 3 function 3
580 1.2 nisimura * 0 output control (A only)
581 1.2 nisimura * 1 function 1 (A only)
582 1.2 nisimura * ./x no function, not connected or don't-care
583 1.2 nisimura *
584 1.2 nisimura * A ........ .1x11111 1111x111 11111111
585 1.2 nisimura * B .....22o ooooooo2
586 1.2 nisimura * C 22222222 22222222
587 1.2 nisimura * D 22222222 22222222
588 1.2 nisimura * E 22222222 22222222
589 1.2 nisimura * F ........ 22222222
590 1.2 nisimura * G xxx2222i 22232322
591 1.2 nisimura * H .....22i 22222222
592 1.2 nisimura * J ...22222 22222222
593 1.2 nisimura */
594 1.2 nisimura iomux('A', "........ .1x11111 1111x111 11111111");
595 1.2 nisimura iomux('B', ".....22o ooooooo2");
596 1.2 nisimura iomux('C', "22222222 22222222");
597 1.2 nisimura iomux('D', "22222222 22222222");
598 1.2 nisimura iomux('E', "22222222 22222222");
599 1.2 nisimura iomux('F', "........ 22222222");
600 1.2 nisimura iomux('G', "xxx2222i 22232322");
601 1.2 nisimura iomux('H', ".....22i 22222222");
602 1.2 nisimura iomux('J', "...22222 22222222");
603 1.2 nisimura
604 1.2 nisimura /* mask all possible external interrupt source [23:3] */
605 1.2 nisimura CSR_WRITE(S3C2440_GPIO_BASE + GPIO_EINTMASK, ~0);
606 1.2 nisimura }
607 1.2 nisimura
608 1.2 nisimura static void
609 1.2 nisimura iomux(int grp, const char *cnf)
610 1.2 nisimura {
611 1.2 nisimura uint32_t con;
612 1.2 nisimura int sft, i, v;
613 1.2 nisimura
614 1.2 nisimura con = v = 0;
615 1.2 nisimura sft = (grp != 'A') ? 2 : 1;
616 1.2 nisimura for (i = 0; cnf[i] != '\0'; i++) {
617 1.2 nisimura switch (cnf[i]) {
618 1.2 nisimura case 'i':
619 1.2 nisimura case '0':
620 1.2 nisimura case '.':
621 1.2 nisimura case 'x':
622 1.2 nisimura v = 0; break;
623 1.2 nisimura case 'o':
624 1.2 nisimura case '1':
625 1.2 nisimura v = 1; break;
626 1.2 nisimura case '2':
627 1.2 nisimura v = 2; break;
628 1.2 nisimura case '3':
629 1.2 nisimura v = 3; break;
630 1.2 nisimura default:
631 1.2 nisimura continue;
632 1.2 nisimura }
633 1.2 nisimura con = (con << sft) | v;
634 1.2 nisimura }
635 1.2 nisimura CSR_WRITE(S3C2440_GPIO_BASE + 0x10 * (grp - 'A'), con);
636 1.2 nisimura }
637