Home | History | Annotate | Line # | Download | only in boot2440
main.c revision 1.1
      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.1  nisimura 
     88  1.1  nisimura extern void* dm9k_init(unsigned int tag, void *macaddr);
     89  1.1  nisimura 
     90  1.1  nisimura /* External variables */
     91  1.1  nisimura extern char bootprog_name[], bootprog_rev[];
     92  1.1  nisimura 
     93  1.1  nisimura /* External functions */
     94  1.1  nisimura extern void netif_match(unsigned int tag, uint8_t *macaddr);
     95  1.1  nisimura /*  extern int sdif_init(unsigned int tag);*/
     96  1.1  nisimura 
     97  1.1  nisimura /* Global variables */
     98  1.1  nisimura int pclk;
     99  1.1  nisimura struct btinfo_rootdevice	bi_rdev;
    100  1.1  nisimura 
    101  1.1  nisimura /* This is not very flexible, as only one net device is allowed */
    102  1.1  nisimura struct btinfo_net		bi_net;
    103  1.1  nisimura 
    104  1.1  nisimura struct btinfo_bootpath		bi_path;
    105  1.1  nisimura 
    106  1.1  nisimura void
    107  1.1  nisimura main(int argc, char *argv[])
    108  1.1  nisimura {
    109  1.1  nisimura 	int fclk, hclk;
    110  1.1  nisimura 	int fd;
    111  1.1  nisimura 	unsigned long marks[MARK_MAX];
    112  1.1  nisimura 	unsigned char hdr[0x26];
    113  1.1  nisimura 	void (*entry)(void*);
    114  1.1  nisimura 	unsigned elfpriv;
    115  1.1  nisimura 	char *bootfile;
    116  1.1  nisimura 	char *bf;
    117  1.1  nisimura 	bool kernel_loaded;
    118  1.1  nisimura 	uint8_t enaddr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    119  1.1  nisimura 
    120  1.1  nisimura 	/* Give some indication that main() has been reached */
    121  1.1  nisimura 	CLEAR_LEDS();
    122  1.1  nisimura 	LED_ON(4);
    123  1.1  nisimura 
    124  1.1  nisimura 	/* Next, we setup the clock of the S3C2440 such that we are not
    125  1.1  nisimura 	   dependent on any other bootloader in this regard.
    126  1.1  nisimura 	   Target FCLK is 405MHz, and we assume an input crystal of 12MHz
    127  1.1  nisimura 	*/
    128  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_CLKMAN_BASE+CLKMAN_MPLLCON) =
    129  1.1  nisimura 		((0x7F << PLLCON_MDIV_SHIFT) & PLLCON_MDIV_MASK) |
    130  1.1  nisimura 		((2 << PLLCON_PDIV_SHIFT) & PLLCON_PDIV_MASK) |
    131  1.1  nisimura 		((1 << PLLCON_SDIV_SHIFT) & PLLCON_SDIV_MASK);
    132  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_CLKMAN_BASE+CLKMAN_UPLLCON) =
    133  1.1  nisimura 		((0x38 << PLLCON_MDIV_SHIFT) & PLLCON_MDIV_MASK) |
    134  1.1  nisimura 		((2 << PLLCON_PDIV_SHIFT) & PLLCON_PDIV_MASK) |
    135  1.1  nisimura 		((2 << PLLCON_SDIV_SHIFT) & PLLCON_SDIV_MASK);
    136  1.1  nisimura 
    137  1.1  nisimura 	LED_ON(1);
    138  1.1  nisimura 
    139  1.1  nisimura 	s3c24x0_clock_freq2(S3C2440_CLKMAN_BASE, &fclk, &hclk, &pclk);
    140  1.1  nisimura 
    141  1.1  nisimura 	uart_init(pclk);
    142  1.1  nisimura 	time_init(pclk);
    143  1.1  nisimura 
    144  1.1  nisimura 	/* Let the user know we are alive */
    145  1.1  nisimura 	printf("\n");
    146  1.1  nisimura 	printf(">> %s boot2440, revision %s\n", bootprog_name, bootprog_rev);
    147  1.1  nisimura 
    148  1.1  nisimura 	bootinfo = (void*) BOOTINFO_ADDR;
    149  1.1  nisimura 	bi_init(bootinfo);
    150  1.1  nisimura 
    151  1.1  nisimura 	bi_net.devname[0] = 0;
    152  1.1  nisimura 	bi_path.bootpath[0] = 0;
    153  1.1  nisimura 
    154  1.1  nisimura 	/* Try to get boot arguments from any previous boot-loader */
    155  1.1  nisimura 	{
    156  1.1  nisimura 		struct btinfo_bootstring ba;
    157  1.1  nisimura 		int j, i;
    158  1.1  nisimura 
    159  1.1  nisimura 		printf("Argument count: %d\n", argc);
    160  1.1  nisimura 
    161  1.1  nisimura 		j = 0;
    162  1.1  nisimura 		for (i = 0; i < argc; i++) {
    163  1.1  nisimura 			if (j == MAX_BOOT_STRING-1) {
    164  1.1  nisimura 				ba.bootstring[j] = '\0';
    165  1.1  nisimura 				continue;
    166  1.1  nisimura 			}
    167  1.1  nisimura 			if (strncmp(argv[i], "mac=", 4) == 0) {
    168  1.1  nisimura 				parse_mac_address(argv[i]+4, enaddr);
    169  1.1  nisimura 			} else {
    170  1.1  nisimura 				if (j != 0)
    171  1.1  nisimura 					ba.bootstring[j++] = ' ';
    172  1.1  nisimura 
    173  1.1  nisimura 				strncpy(ba.bootstring+j, argv[i], MAX_BOOT_STRING-j);
    174  1.1  nisimura 				j += strlen(argv[i]);
    175  1.1  nisimura 			}
    176  1.1  nisimura 		}
    177  1.1  nisimura 
    178  1.1  nisimura 		printf("Boot string: %s\n", ba.bootstring);
    179  1.1  nisimura 
    180  1.1  nisimura 		bi_add(&ba, BTINFO_BOOTSTRING, sizeof(ba));
    181  1.1  nisimura 	}
    182  1.1  nisimura 
    183  1.1  nisimura 	LED_ON(3);
    184  1.1  nisimura 
    185  1.1  nisimura 	if (argc > 1) {
    186  1.1  nisimura 		bf = argv[argc-1];
    187  1.1  nisimura 	} else {
    188  1.1  nisimura 		bf = default_boot;
    189  1.1  nisimura 	}
    190  1.1  nisimura 
    191  1.1  nisimura 	/* Detect networking devices */
    192  1.1  nisimura 	netif_match(0, enaddr);
    193  1.1  nisimura 
    194  1.1  nisimura 	kernel_loaded = FALSE;
    195  1.1  nisimura 	do {
    196  1.1  nisimura 		bootfile = strsep(&bf, ";");
    197  1.1  nisimura 		printf("Trying \"%s\"...\n", bootfile);
    198  1.1  nisimura 		fd = open(bootfile, 0);
    199  1.1  nisimura 		if (fd < 0) {
    200  1.1  nisimura 			printf("Failed: %d\n", errno);
    201  1.1  nisimura 			close(fd);
    202  1.1  nisimura 			continue;
    203  1.1  nisimura 		}
    204  1.1  nisimura 
    205  1.1  nisimura 		if (fdloadfile(fd, marks, LOAD_ALL) == 0) {
    206  1.1  nisimura 			kernel_loaded = TRUE;
    207  1.1  nisimura 			break;
    208  1.1  nisimura 		}
    209  1.1  nisimura 	} while(bf != NULL);
    210  1.1  nisimura 
    211  1.1  nisimura 	if (!kernel_loaded) {
    212  1.1  nisimura 		panic("Failed to load kernel\n");
    213  1.1  nisimura 		_rtt();
    214  1.1  nisimura 	}
    215  1.1  nisimura 
    216  1.1  nisimura #if 1
    217  1.1  nisimura 	/* Set MAC address of the 'dme' net device, if
    218  1.1  nisimura 	 * it isn't set already */
    219  1.1  nisimura 	if (bi_net.devname[0] == 0) {
    220  1.1  nisimura 		uint8_t en[6] = {DM9000MAC};
    221  1.1  nisimura 		snprintf(bi_net.devname, sizeof(bi_net.devname), "dme");
    222  1.1  nisimura 		bi_net.cookie = 0;
    223  1.1  nisimura 
    224  1.1  nisimura 		memcpy(bi_net.mac_address, en, sizeof(bi_net.mac_address));
    225  1.1  nisimura 	}
    226  1.1  nisimura #endif
    227  1.1  nisimura 	/*
    228  1.1  nisimura 	 * ARM ELF header has a distinctive value in "private flags"
    229  1.1  nisimura 	 * field of offset [0x24:25];
    230  1.1  nisimura 	 * - NetBSD 02 06
    231  1.1  nisimura 	 * - Linux  02 00 (2.4) or 02 02 (2.6)
    232  1.1  nisimura 	 */
    233  1.1  nisimura 	lseek(fd, (off_t)0, SEEK_SET);
    234  1.1  nisimura 	read(fd, &hdr, sizeof(hdr));
    235  1.1  nisimura 	elfpriv = *(unsigned short *)&hdr[0x24];
    236  1.1  nisimura 
    237  1.1  nisimura 	entry = (void *)marks[MARK_ENTRY];
    238  1.1  nisimura 	if (elfpriv == 0x0602) {
    239  1.1  nisimura 		struct btinfo_symtab bi_syms;
    240  1.1  nisimura 
    241  1.1  nisimura 		bi_syms.nsym = marks[MARK_NSYM];
    242  1.1  nisimura 		bi_syms.ssym = (void*)marks[MARK_SYM];
    243  1.1  nisimura 		bi_syms.esym = (void*)marks[MARK_END];
    244  1.1  nisimura 		bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
    245  1.1  nisimura 		if (bi_path.bootpath[0] != 0)
    246  1.1  nisimura 		  bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
    247  1.1  nisimura 		bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
    248  1.1  nisimura 		if (bi_net.devname[0] != 0 )
    249  1.1  nisimura 			bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
    250  1.1  nisimura 	} else {
    251  1.1  nisimura 		printf("Loaded object is not NetBSD ARM ELF");
    252  1.1  nisimura 		_rtt();
    253  1.1  nisimura 	}
    254  1.1  nisimura 
    255  1.1  nisimura 	printf("entry=%p, nsym=%lu, ssym=%p, esym=%p\n",
    256  1.1  nisimura 	       (void *)marks[MARK_ENTRY],
    257  1.1  nisimura 	       marks[MARK_NSYM],
    258  1.1  nisimura 	       (void *)marks[MARK_SYM],
    259  1.1  nisimura 	       (void *)marks[MARK_END]);
    260  1.1  nisimura 	(*entry)(bootinfo);
    261  1.1  nisimura 
    262  1.1  nisimura 	printf("exec returned, restarting...\n");
    263  1.1  nisimura 	_rtt();
    264  1.1  nisimura }
    265  1.1  nisimura 
    266  1.1  nisimura void
    267  1.1  nisimura uart_init(uint32_t pclk)
    268  1.1  nisimura {
    269  1.1  nisimura 	/* Setup UART0 clocking: Use PCLK */
    270  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UBRDIV) =
    271  1.1  nisimura 		(pclk/(UART_BAUDRATE*16)) - 1;
    272  1.1  nisimura 
    273  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UCON) =
    274  1.1  nisimura 		UCON_TXMODE_INT | UCON_RXMODE_INT;
    275  1.1  nisimura 
    276  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_ULCON) =
    277  1.1  nisimura 		ULCON_PARITY_NONE | ULCON_LENGTH_8;
    278  1.1  nisimura 
    279  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_UART_BASE(0)+SSCOM_UFCON) =
    280  1.1  nisimura 		UFCON_TXTRIGGER_0 | UFCON_TXFIFO_RESET | UFCON_FIFO_ENABLE;
    281  1.1  nisimura }
    282  1.1  nisimura 
    283  1.1  nisimura static uint32_t countdown_duration;
    284  1.1  nisimura 
    285  1.1  nisimura static
    286  1.1  nisimura void time_init(uint32_t pclk)
    287  1.1  nisimura {
    288  1.1  nisimura 	/* Configure timer0 to be as slow as possible:
    289  1.1  nisimura 	   Prescaler = 255
    290  1.1  nisimura 	   Divider = 16
    291  1.1  nisimura 	 */
    292  1.1  nisimura 
    293  1.1  nisimura 	/* First, configure the prescaler */
    294  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG0) = 0xff;
    295  1.1  nisimura 
    296  1.1  nisimura 	/* Next, the divider */
    297  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCFG1) |=
    298  1.1  nisimura 		(TCFG1_MUX_DIV16 <<TCFG1_MUX_SHIFT(0)) & TCFG1_MUX_MASK(0);
    299  1.1  nisimura 
    300  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    301  1.1  nisimura 			TCON_MANUALUPDATE(0);
    302  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
    303  1.1  nisimura 			0xffff;
    304  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    305  1.1  nisimura 			TCON_START(0);
    306  1.1  nisimura 
    307  1.1  nisimura 
    308  1.1  nisimura 	/* Timer count down duration */
    309  1.1  nisimura 	countdown_duration = 65535/(pclk/256/16);
    310  1.1  nisimura 	timer_inc_rate = pclk/256/16;
    311  1.1  nisimura 	//	printf("Countdown duration is: %ds\n", countdown_duration);
    312  1.1  nisimura #if 0
    313  1.1  nisimura 	{
    314  1.1  nisimura 		/* Timer test */
    315  1.1  nisimura 		time_t time, old_time;
    316  1.1  nisimura 
    317  1.1  nisimura 		while(1) {
    318  1.1  nisimura 			time = old_time = getsecs();
    319  1.1  nisimura 			do {
    320  1.1  nisimura 				time = getsecs();
    321  1.1  nisimura 			} while(time == old_time);
    322  1.1  nisimura 			printf("Count %u\n", (int)time);
    323  1.1  nisimura 		}
    324  1.1  nisimura 	}
    325  1.1  nisimura #endif
    326  1.1  nisimura }
    327  1.1  nisimura 
    328  1.1  nisimura time_t
    329  1.1  nisimura getsecs()
    330  1.1  nisimura {
    331  1.1  nisimura 	time_t secs = getusecs()/1000000;
    332  1.1  nisimura 	return secs;
    333  1.1  nisimura }
    334  1.1  nisimura 
    335  1.1  nisimura time_t
    336  1.1  nisimura getusecs() {
    337  1.1  nisimura 	uint32_t count;
    338  1.1  nisimura 	//do {
    339  1.1  nisimura 		count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
    340  1.1  nisimura //} while( count > 65500);
    341  1.1  nisimura 
    342  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    343  1.1  nisimura 		TCON_MANUALUPDATE(0);
    344  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
    345  1.1  nisimura 		0xffff;
    346  1.1  nisimura 	*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    347  1.1  nisimura 		TCON_START(0);
    348  1.1  nisimura 
    349  1.1  nisimura 	wallclock += ((65535-count)*1000000) / timer_inc_rate;
    350  1.1  nisimura 
    351  1.1  nisimura 	return wallclock;
    352  1.1  nisimura }
    353  1.1  nisimura 
    354  1.1  nisimura void
    355  1.1  nisimura usleep(int us) {
    356  1.1  nisimura 	uint32_t count;
    357  1.1  nisimura 	uint32_t target_clock = wallclock+us;
    358  1.1  nisimura 
    359  1.1  nisimura 	while( wallclock < target_clock) {
    360  1.1  nisimura 		do {
    361  1.1  nisimura 			count = *(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0));
    362  1.1  nisimura 		} while( count > 65500);
    363  1.1  nisimura 
    364  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    365  1.1  nisimura 			TCON_MANUALUPDATE(0);
    366  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCNTB(0)) =
    367  1.1  nisimura 			0xffff;
    368  1.1  nisimura 		*(volatile uint32_t*)(S3C2440_TIMER_BASE+TIMER_TCON) =
    369  1.1  nisimura 			TCON_START(0);
    370  1.1  nisimura 
    371  1.1  nisimura 		wallclock += ((65535-count)*1000000) / timer_inc_rate;
    372  1.1  nisimura 	}
    373  1.1  nisimura }
    374  1.1  nisimura 
    375  1.1  nisimura 
    376  1.1  nisimura void
    377  1.1  nisimura mini2440_panic()
    378  1.1  nisimura {
    379  1.1  nisimura 	int i, l;
    380  1.1  nisimura 	int v;
    381  1.1  nisimura 	while(1) {
    382  1.1  nisimura 		CLEAR_LEDS();
    383  1.1  nisimura 		for(l=0; l<0xffffff; l++) {
    384  1.1  nisimura 			v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
    385  1.1  nisimura 		}
    386  1.1  nisimura 		for(i=1; i<=4; i++) {
    387  1.1  nisimura 			LED_ON(i);
    388  1.1  nisimura 		}
    389  1.1  nisimura 		for(l=0; l<0xffffff; l++) {
    390  1.1  nisimura 			v = *((int*)(S3C2440_TIMER_BASE+TIMER_TCNTO(0)));
    391  1.1  nisimura 		}
    392  1.1  nisimura 	}
    393  1.1  nisimura }
    394  1.1  nisimura 
    395  1.1  nisimura void
    396  1.1  nisimura s3c24x0_clock_freq2(vaddr_t clkman_base, int *fclk, int *hclk, int *pclk)
    397  1.1  nisimura {
    398  1.1  nisimura 	uint32_t pllcon, divn, camdivn;
    399  1.1  nisimura 	int mdiv, pdiv, sdiv;
    400  1.1  nisimura 	uint32_t f, h, p;
    401  1.1  nisimura 
    402  1.1  nisimura 	pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
    403  1.1  nisimura 	divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
    404  1.1  nisimura 	camdivn = *(volatile uint32_t *)(clkman_base + CLKMAN_CAMDIVN);
    405  1.1  nisimura 
    406  1.1  nisimura 	mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
    407  1.1  nisimura 	pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
    408  1.1  nisimura 	sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
    409  1.1  nisimura 
    410  1.1  nisimura 	f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv)) * 2;
    411  1.1  nisimura 	h = f;
    412  1.1  nisimura 
    413  1.1  nisimura 	/* HDIVN of CLKDIVN can have 4 distinct values */
    414  1.1  nisimura 	switch( (divn & CLKDIVN_HDIVN_MASK) >> CLKDIVN_HDIVN_SHIFT )
    415  1.1  nisimura 		{
    416  1.1  nisimura 		case 0:
    417  1.1  nisimura 			/* 00b: HCLK = FCLK/1*/
    418  1.1  nisimura 			break;
    419  1.1  nisimura 		case 1:
    420  1.1  nisimura 			/* 01b: HCLK = FCLK/2*/
    421  1.1  nisimura 			h /= 2;
    422  1.1  nisimura 			break;
    423  1.1  nisimura 		case 2:
    424  1.1  nisimura 			/* 10b: HCLK = FCLK/4 when CAMDIVN[9] (HCLK4_HALF) = 0
    425  1.1  nisimura 			 *      HCLK = FCLK/8 when CAMDIVN[9] (HCLK4_HALF) = 1 */
    426  1.1  nisimura 			if( camdivn & CLKCAMDIVN_HCLK4_HALF )
    427  1.1  nisimura 				h /= 8;
    428  1.1  nisimura 			else
    429  1.1  nisimura 				h /= 4;
    430  1.1  nisimura 			break;
    431  1.1  nisimura 		case 3:
    432  1.1  nisimura 			/* 11b: HCLK = FCLK/3 when CAMDIVN[8] (HCLK3_HALF) = 0
    433  1.1  nisimura 			 *      HCLK = FCLK/6 when CAMDIVN[8] (HCLK3_HALF) = 1 */
    434  1.1  nisimura 			if( camdivn & CLKCAMDIVN_HCLK3_HALF )
    435  1.1  nisimura 				h /= 6;
    436  1.1  nisimura 			else
    437  1.1  nisimura 				h /= 3;
    438  1.1  nisimura 			break;
    439  1.1  nisimura 		}
    440  1.1  nisimura 
    441  1.1  nisimura 	p = h;
    442  1.1  nisimura 
    443  1.1  nisimura 	if (divn & CLKDIVN_PDIVN)
    444  1.1  nisimura 		p /= 2;
    445  1.1  nisimura 
    446  1.1  nisimura 	if (fclk) *fclk = f;
    447  1.1  nisimura 	if (hclk) *hclk = h;
    448  1.1  nisimura 	if (pclk) *pclk = p;
    449  1.1  nisimura }
    450  1.1  nisimura 
    451  1.1  nisimura void
    452  1.1  nisimura putchar(int c)
    453  1.1  nisimura {
    454  1.1  nisimura 	uint32_t stat;
    455  1.1  nisimura 
    456  1.1  nisimura 	if (c == '\n')
    457  1.1  nisimura 		putchar('\r');
    458  1.1  nisimura 
    459  1.1  nisimura 	do {
    460  1.1  nisimura 		stat = CSR_READ(S3C2440_UART_BASE(0) + SSCOM_UTRSTAT);
    461  1.1  nisimura 	} while ((stat & UTRSTAT_TXEMPTY) == 0);
    462  1.1  nisimura 
    463  1.1  nisimura 	CSR_WRITE(S3C2440_UART_BASE(0) + SSCOM_UTXH, c);
    464  1.1  nisimura }
    465  1.1  nisimura 
    466  1.1  nisimura void
    467  1.1  nisimura _rtt()
    468  1.1  nisimura {
    469  1.1  nisimura 	int cpsr_save, tmp;
    470  1.1  nisimura 	/* Disable interrupts */
    471  1.1  nisimura 	__asm volatile("mrs %0, cpsr;"
    472  1.1  nisimura 		       "orr %1, %0, %2;"
    473  1.1  nisimura 		       "msr cpsr_c, %1;"
    474  1.1  nisimura 		       : "=r" (cpsr_save), "=r" (tmp)
    475  1.1  nisimura 		       : "I" (I32_bit)
    476  1.1  nisimura 		       );
    477  1.1  nisimura 
    478  1.1  nisimura 	/* Disable MMU */
    479  1.1  nisimura 	__asm volatile("mrc p15, 0, %0, c1, c0, 0;"
    480  1.1  nisimura 		       "bic %0, %0, %1;"
    481  1.1  nisimura 		       "mcr p15, 0, %0, c1, c0, 0;"
    482  1.1  nisimura 		       : "=r" (tmp)
    483  1.1  nisimura 		       : "I" (CPU_CONTROL_MMU_ENABLE)
    484  1.1  nisimura 		       );
    485  1.1  nisimura 
    486  1.1  nisimura 	/* Configure watchdog to fire now */
    487  1.1  nisimura 	*(volatile uint32_t *)(S3C2440_WDT_BASE + WDT_WTCON) =
    488  1.1  nisimura 		(0 << WTCON_PRESCALE_SHIFT) | WTCON_ENABLE |
    489  1.1  nisimura 		WTCON_CLKSEL_16 | WTCON_ENRST;
    490  1.1  nisimura }
    491  1.1  nisimura 
    492  1.1  nisimura void
    493  1.1  nisimura bi_init(void *addr)
    494  1.1  nisimura {
    495  1.1  nisimura 	struct btinfo_magic bi_magic;
    496  1.1  nisimura 
    497  1.1  nisimura 	memset(addr, 0, BOOTINFO_MAXSIZE);
    498  1.1  nisimura 	bi_next = (char*) addr;
    499  1.1  nisimura 	bi_size = 0;
    500  1.1  nisimura 
    501  1.1  nisimura 	bi_magic.magic = BOOTINFO_MAGIC;
    502  1.1  nisimura 	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
    503  1.1  nisimura }
    504  1.1  nisimura 
    505  1.1  nisimura 
    506  1.1  nisimura void
    507  1.1  nisimura bi_add(void *new, int type, int size)
    508  1.1  nisimura {
    509  1.1  nisimura 	struct btinfo_common *bi;
    510  1.1  nisimura 
    511  1.1  nisimura 	if (bi_size + size > BOOTINFO_MAXSIZE)
    512  1.1  nisimura 		return;
    513  1.1  nisimura 
    514  1.1  nisimura 	bi = new;
    515  1.1  nisimura 	bi->next = size;
    516  1.1  nisimura 	bi->type = type;
    517  1.1  nisimura 	memcpy(bi_next, new, size);
    518  1.1  nisimura 	bi_next += size;
    519  1.1  nisimura }
    520  1.1  nisimura 
    521  1.1  nisimura static void
    522  1.1  nisimura parse_mac_address(const char *str, uint8_t *enaddr)
    523  1.1  nisimura {
    524  1.1  nisimura 	int i;
    525  1.1  nisimura 	char *next = (char*)str;
    526  1.1  nisimura 
    527  1.1  nisimura 	for(i=0;i<6;i++) {
    528  1.1  nisimura 		str = next;
    529  1.1  nisimura 		enaddr[i] = (unsigned char)strtoll(str, &next, 16);
    530  1.1  nisimura 		if( *next == ':' ) {
    531  1.1  nisimura 			next++;
    532  1.1  nisimura 		} else {
    533  1.1  nisimura 			break;
    534  1.1  nisimura 		}
    535  1.1  nisimura 	}
    536  1.1  nisimura }
    537