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