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