Home | History | Annotate | Line # | Download | only in boot2440
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