www.pudn.com > 4k_bootloader.rar > main.c




#define COMMAND_LINE_SIZE         1024
#define SZ_64M                  0x04000000
#define DRAM_SIZE		     SZ_64M
/*#define DRAM_BASE               0x30000000 */
#define KERNEL_ROM_ADDR				0x00030000       /*kernel zImage ÔÚ  nand flash ÖеÄλÖÃ.  */
#define KERNEL_SIZE       0x001d0000

#define MACH_TYPE 193

#define MT_SMC_S3C2410 3
#define LINUX_KERNEL_OFFSET	0x8000
#define LINUX_PARAM_OFFSET	0x100
#define SZ_4K                           0x00001000

#define LINUX_PAGE_SIZE		SZ_4K
#define LINUX_PAGE_SHIFT	12
#define LINUX_ZIMAGE_MAGIC	0x016f2818

int printk(const char *fmt, ...);

/* This is the old deprecated way to pass parameters to the kernel */
struct param_struct {
union {
struct {
unsigned long page_size; /* 0 */
unsigned long nr_pages; /* 4 */
unsigned long ramdisk_size; /* 8 */
unsigned long flags; /* 12 */
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
unsigned long rootdev; /* 16 */
unsigned long video_num_cols; /* 20 */
unsigned long video_num_rows; /* 24 */
unsigned long video_x; /* 28 */
unsigned long video_y; /* 32 */
unsigned long memc_control_reg; /* 36 */
unsigned char sounddefault; /* 40 */
unsigned char adfsdrives; /* 41 */
unsigned char bytes_per_char_h; /* 42 */
unsigned char bytes_per_char_v; /* 43 */
unsigned long pages_in_bank[4]; /* 44 */
unsigned long pages_in_vram; /* 60 */
unsigned long initrd_start; /* 64 */
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
union {
char paths[8][128];
struct {
unsigned long magic;
char n[1024 - sizeof(unsigned long)];
} s;
} u2;
char commandline[COMMAND_LINE_SIZE];
};








#define UART_CTL_BASE		0x50000000
#define oUTRSTAT		0x10	
#define oUTXHL			0x20	

#define __REGl(x)	(*(volatile unsigned long *)(x))
#define __REGb(x)	(*(volatile unsigned char *)(x))

#define bUART(x, Nb)		__REGl(UART_CTL_BASE + (x)*0x4000 + (Nb))
#define bUARTb(x, Nb)		__REGb(UART_CTL_BASE + (x)*0x4000 + (Nb))

#define UTRSTAT0		bUART(0, oUTRSTAT)
#define UTXH0			bUARTb(0, oUTXHL)
#define UTRSTAT_TX_EMPTY	(1 << 2)

#define SERIAL_WRITE_READY()	((UTRSTAT0) & UTRSTAT_TX_EMPTY)
#define SERIAL_WRITE_CHAR(c)	((UTXH0) = (c))

#define PROC_SERIAL_PUTC(c)	\
	({ while (!SERIAL_WRITE_READY()); \
	   SERIAL_WRITE_CHAR(c); })

void putc(char c)
{
	PROC_SERIAL_PUTC(c);
}


 void putnstr(const char *str, int n)
{
	if (str == "")
		return;

	while (n && *str != '\0') {
		putc(*str);
		str++;
		n--;
	}
}


int strlen(const char* str)
{
int i=0;
while(*str++) i++;
return i;
} 



void putstr(const char *str)
{
	putnstr(str, strlen(str));
}   








#define MAX_PART_NAME             16
typedef struct mtd_partiton {
        char name[MAX_PART_NAME];       /* partition name */
        unsigned long offset;
        unsigned long size;
        unsigned long flag;
} mtd_partition_t;


#define MF_BONFS          0x00000004

mtd_partition_t default_mtd_partitions[] = {
        {
                name:           "vi",
                offset:         0,
                size:           0x00020000,
                flag:           0
        }, {
                name:           "param",
                offset:         0x00020000,
                size:           0x00010000,
                flag:           0
        }, {
                name:           "kernel",
                offset:         0x00030000,
                size:           0x001d0000,
                flag:           0
        }, {
                name:           "root",
                offset:         0x00200000,
                size:           0x02300000,
                flag:           MF_BONFS
        },{
					 name:				"yaffs",
					 offset:				0x02500000,
					 size:				0x01b00000,
					 flag:				0
}
};


#define SZ_1M                           0x00100000
#define SZ_16K                          0x00004000
#define SZ_64M                          0x04000000

#define DRAM_BASE0		0x30000000      /* base address of dram bank 0 */
#define DRAM_BASE		DRAM_BASE0
#define DRAM_SIZE		SZ_64M
#define VIVI_RAM_SIZE		SZ_1M

#define VIVI_RAM_BASE		(DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)
#define HEAP_SIZE		SZ_1M

#define HEAP_BASE		(VIVI_RAM_BASE - HEAP_SIZE)
#define MMU_TABLE_SIZE		SZ_16K

#define MTD_PART_SIZE		SZ_16K
#define PARAMETER_TLB_SIZE	SZ_16K
#define LINUX_CMD_SIZE		SZ_16K

#define MMU_TABLE_BASE		(HEAP_BASE - MMU_TABLE_SIZE)
#define VIVI_PRIV_SIZE		(MTD_PART_SIZE + PARAMETER_TLB_SIZE + LINUX_CMD_SIZE)
#define VIVI_PRIV_RAM_BASE        (MMU_TABLE_BASE - VIVI_PRIV_SIZE)

#define MTD_PART_OFFSET		0x00000000
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
int default_nb_part = ARRAY_SIZE(default_mtd_partitions);
int *nb_mtd_parts = (int *)(VIVI_PRIV_RAM_BASE + MTD_PART_OFFSET + 8);
const char mtd_part_magic[8] = {'V', 'I', 'V', 'I', 'M', 'T', 'D', 'P'};

int get_default_mtd_partition(void)
{     
	
	char *src_parts = (char *)&default_mtd_partitions;
	char *dst_parts = (char *)(VIVI_PRIV_RAM_BASE + MTD_PART_OFFSET);
	int num = default_nb_part;
	
	putstr("begin to transfer mtd partition table \n");
	if (src_parts == "") return -1;

	/* printk("number of mtd partitions: %d\n", num); */
	*(nb_mtd_parts) = num;

	if ((sizeof(mtd_partition_t)*num + 16) > MTD_PART_SIZE) {
		/*printk("too large mtd partition table\n"); */
		return -1;
	}

	memcpy(dst_parts, mtd_part_magic, 8);	/* copy mtd magic */
	dst_parts += 16;
	/* copy partition table */
	memcpy(dst_parts, src_parts, (sizeof(mtd_partition_t)*num));	
	return 0;
}






#include 

#define __REGb(x)	(*(volatile unsigned char *)(x))
#define __REGi(x)	(*(volatile unsigned int *)(x))
#define NF_BASE		0x4e000000
#define NFCONF		__REGi(NF_BASE + 0x0)
#define NFCMD		__REGb(NF_BASE + 0x4)
#define NFADDR		__REGb(NF_BASE + 0x8)
#define NFDATA		__REGb(NF_BASE + 0xc)
#define NFSTAT		__REGb(NF_BASE + 0x10)

#define BUSY 1
inline void wait_idle(void) {
    int i;

    while(!(NFSTAT & BUSY))
      for(i=0; i<10; i++);
}

#define NAND_SECTOR_SIZE	512
#define NAND_BLOCK_MASK		(NAND_SECTOR_SIZE - 1)

/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
        return -1;	/* invalid alignment */
    }

    /* chip Enable */
    NFCONF &= ~0x800;
    for(i=0; i<10; i++);

    for(i=start_addr; i < (start_addr + size);) {
      /* READ0 */
      NFCMD = 0;

      /* Write Address */
      NFADDR = i & 0xff;
      NFADDR = (i >> 9) & 0xff;
      NFADDR = (i >> 17) & 0xff;
      NFADDR = (i >> 25) & 0xff;

      wait_idle();

      for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
	*buf = (NFDATA & 0xff);
	buf++;
      }
    }

    /* chip Disable */
    NFCONF |= 0x800;	/* chip disable */

    return 0;
}






static inline void cpu_arm920_cache_clean_invalidate_all(void)
{
__asm__(
	"	mov	r1, #0\n"
	"	mov	r1, #7 << 5\n"		  /* 8 segments */
	"1:	orr	r3, r1, #63 << 26\n"	  /* 64 entries */
	"2:	mcr	p15, 0, r3, c7, c14, 2\n" /* clean & invalidate D index */
	"	subs	r3, r3, #1 << 26\n"
	"	bcs	2b\n"			  /* entries 64 to 0 */
	"	subs	r1, r1, #1 << 5\n"
	"	bcs	1b\n"			  /* segments 7 to 0 */
	"	mcr	p15, 0, r1, c7, c5, 0\n"  /* invalidate I cache */
	"	mcr	p15, 0, r1, c7, c10, 4\n" /* drain WB */
	);
}

void cache_clean_invalidate(void)
{
	cpu_arm920_cache_clean_invalidate_all();
}



static inline void cpu_arm920_tlb_invalidate_all(void)
{
	__asm__(
		"mov	r0, #0\n"
		"mcr	p15, 0, r0, c7, c10, 4\n"	/* drain WB */
		"mcr	p15, 0, r0, c8, c7, 0\n"	/* invalidate I & D TLBs */
		);
}

void tlb_invalidate(void)
{
	cpu_arm920_tlb_invalidate_all();
}














void  call_linux(long a0, long a1, long a2)
{
	cache_clean_invalidate();
	tlb_invalidate();

__asm__(
	"mov	r0, %0\n"
	"mov	r1, %1\n"
	"mov	r2, %2\n"
	"mov	ip, #0\n"
	"mcr	p15, 0, ip, c13, c0, 0\n"	/* zero PID */
	"mcr	p15, 0, ip, c7, c7, 0\n"	/* invalidate I,D caches */
	"mcr	p15, 0, ip, c7, c10, 4\n"	/* drain write buffer */
	"mcr	p15, 0, ip, c8, c7, 0\n"	/* invalidate I,D TLBs */
	"mrc	p15, 0, ip, c1, c0, 0\n"	/* get control register */
	"bic	ip, ip, #0x0001\n"		/* disable MMU */
	"mcr	p15, 0, ip, c1, c0, 0\n"	/* write control register */
	"mov	pc, r2\n"
	"nop\n"
	"nop\n"
	: /* no outpus */
	: "r" (a0), "r" (a1), "r" (a2)
	);
}



/*
 * pram_base: base address of linux paramter
 */
static void setup_linux_param(long param_base)
{
	struct param_struct *params = (struct param_struct *)param_base; 
	char *linux_cmd;

	/*printk("Setup linux parameters at 0x%08lx\n", param_base);*/
	memset(params, 0, sizeof(struct param_struct));

	/* ²¿¿À¿Á ÇØÁà¾ß µÉ °Íµé.. ³­µð°¡ °æÇèÀûÀ¸·Î ´ëÃæ ÂïÀº °Í.. */
	params->u1.s.page_size = LINUX_PAGE_SIZE;
	params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);
#if 0
	params->u1.s.page_size = LINUX_PAGE_SIZE;
	params->u1.s.nr_pages = (dram_size >> LINUX_PAGE_SHIFT);
	params->u1.s.ramdisk_size = 0;
	params->u1.s.rootdev = rootdev;
	params->u1.s.flags = 0;

	/* TODO */
	/* If use ramdisk */
	/*
	params->u1.s.initrd_start = ?;
	params->u1.s.initrd_size = ?;
	params->u1.s.rd_start = ?;
	*/

#endif

	/* set linux command line */
	/*linux_cmd = get_linux_cmd_line();*/
	linux_cmd= "noinitrd root=/dev/mtdblock/1 init=/linuxrc confole=ttyS0";
	
	if (linux_cmd == "") {
		
	putstr("boot args is null");
	} else {
		memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
		
	putstr("loading linux boot args is ok !"); 
	}       
}








int boot_kernel(void)
{
	
	unsigned long boot_mem_base;	
	unsigned long mach_type;



unsigned long dst;
boot_mem_base = 0x30000000;
dst = 0x30008000;



mach_type = MACH_TYPE;

	

	
	setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);

/*	get_default_mtd_partition(); */
	
putstr ("MACH_TYPE = 193  \n");
	
	putstr("NOW, Booting Linux......\n");  
	call_linux(0, mach_type, dst);

	return 0;	
}
	
/*static void 
error(void)
{
	putstr("Sorry. We can not run vivi\n"); 
	for (;;) 
} */


int main(int argc, char *argv[])
{
	boot_kernel();
	
	
	return 0;
}