⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 board.c

📁 嵌入式ARM的一些源代码
💻 C
字号:
/*
 * (C) Copyright 2000
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <ppcboot.h>
#include <command.h>
#include <malloc.h>
#include <devices.h>
#if (CONFIG_COMMANDS & CFG_CMD_IDE)
#include <ide.h>
#endif
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
#include <kgdb.h>
#endif
#include <version.h>

static char *failed = "*** failed ***\n";

/*
 * Begin and End of memory area for malloc(), and current "brk"
 */
static	ulong	mem_malloc_start = 0;
static	ulong	mem_malloc_end	 = 0;
static	ulong	mem_malloc_brk	 = 0;

/*
 * The Malloc area is immediately below the monitor copy in DRAM
 */
static void mem_malloc_init (ulong dest_addr)
{
	mem_malloc_end	 = dest_addr;
	mem_malloc_start = dest_addr - CFG_MALLOC_LEN;
	mem_malloc_brk = mem_malloc_start;

	memset ((void *)mem_malloc_start, 0, mem_malloc_end - mem_malloc_start);
}

void *sbrk (ptrdiff_t increment)
{
	ulong old = mem_malloc_brk;
	ulong new = old + increment;

	if ((new < mem_malloc_start) ||
	    (new > mem_malloc_end) ) {
		return (NULL);
	}
	mem_malloc_brk = new;
	return ((void *)old);
}

char *
strmhz(char *buf, long hz)
{
    int l, n;
#if defined(CFG_CLKS_IN_HZ)
    int m;
#endif

    n = hz / 1000000L;

    l = sprintf(buf, "%d", n);

#if defined(CFG_CLKS_IN_HZ)
    m = (hz % 1000000L) / 1000L;

    if (m != 0)
	sprintf(buf+l, ".%03d", m);
#endif

    return (buf);
}

/*
 * Breath some life into the board...
 *
 * Initialize an SMC for serial comms, and carry out some hardware
 * tests.
 *
 * The first part of initialization is running from Flash memory;
 * its main purpose is to initialize the RAM so that we
 * can relocate the monitor code to RAM.
 */
void
board_init_f (ulong bootflag)
{
    bd_t	*bd;
    ulong	reg, len, clock_mhz;
    int		board_type;
    ulong	addr_moni, addr_sp;
    ulong	dram_size;
    char	*s, *e;
    int		baudrate;
    /* Pointer to initial global data area */
    init_data_t *idata = (init_data_t *)(CFG_INIT_RAM_ADDR + CFG_INIT_DATA_OFFSET);

#if defined(CONFIG_8260)

    get_8260_clks();

#else	/* !CONFIG_8260 */

    /* CPU Clock Speed */
    idata->cpu_clk = get_gclk_freq ();		/* in  Hz */

#endif	/* CONFIG_8260 */

#if defined(CFG_CLKS_IN_HZ)
    clock_mhz = idata->cpu_clk;				/* still in Hz */
#else
    clock_mhz = idata->cpu_clk / 1000 / 1000;		/* in MHz */
#endif

    s = getenv ("baudrate");
    baudrate = s ? (int)simple_strtoul(s, NULL, 10) : CONFIG_BAUDRATE;

    /* set up serial port */
    serial_init (clock_mhz, baudrate);

    /* Initialize the console (before the relocation) */
    console_init_f ();

    /* now we can use standard printf/puts/getc/tstc functions */
    display_options();

#if defined(CONFIG_8260)
    prt_8260_rsr();
    prt_8260_clks();
#endif	/* CONFIG_8260 */

    printf ("Initializing...\n  CPU:   ");		/* Check CPU		*/

    if (checkcpu(clock_mhz) < 0) {
    	printf (failed);
	hang();
    }

    printf ("  Board: ");				/* Check Board		*/

    if ((board_type = checkboard()) < 0) {
    	printf (failed);
	hang();
    }

#ifdef CONFIG_COGENT
    /* miscellaneous platform dependent initialisations */
    if (misc_init_f() < 0) {
	printf (failed);
	hang();
    }
#endif

    /* we need the timebase for udelay() in DRAM setup */
    init_timebase ();

    printf ("  DRAM:  ");

    if ((dram_size = initdram (board_type)) > 0) {
	printf ("%2ld MB\n", dram_size >> 20);
    } else {
	printf (failed);
	hang();
    }

    /*
     * Now that we have DRAM mapped and working, we can
     * relocate the code and continue running from DRAM.
     *
     * First reserve memory for monitor code at end of DRAM.
     */
    len = get_endaddr() - CFG_MONITOR_BASE;
    if (len > CFG_MONITOR_LEN) {
	printf ("*** PPCBoot size %ld > reserved memory (%d)\n",
		len, CFG_MONITOR_LEN);
	hang();
    }
    if (CFG_MONITOR_LEN > len)
	len = CFG_MONITOR_LEN;
    /* round up to next 4 kB limit */
    len = (len + (4096 - 1)) & ~(4096 - 1);

    addr_moni = CFG_SDRAM_BASE + dram_size - len;

#ifdef DEBUG
    printf ("  Relocating to: %08lx\n", addr_moni);
#endif

    /*
     * Then we (permanently) allocate a Board Info struct.
     *
     * We leave room for the malloc() arena.
     */
    bd = (bd_t *)(addr_moni - sizeof(bd_t) - CFG_MALLOC_LEN);

#ifdef DEBUG
    printf ("  Board Info at: %08lx\n", (ulong)bd);
#endif

    /*
     * Finally, we set up a new (bigger) stack.
     *
     * Leave some safety gap for SP, force alignment on 16 byte boundary
     */
    addr_sp  = (ulong)bd - 128;
    addr_sp &= ~0xF;

#if defined(CFG_FLASH_ENV_BUF)
    /*
     * Unfortunately, some boards (like the Cogent CMA302 flash I/O
     * Module) have ridiculously large sectors (512KB) because they
     * have 8 x 8 bit wide flash chips arranged so that each chip has
     * one of the byte lanes in a 64 bit word. Not only that, the
     * Intel 28F008S5 flash chips have 64K sectors (16 of them, for
     * 1Mbyte each). So effectively, the CMA302 has 16 x 512KB
     * sectors. We need some space to store the data when programming
     * one of these flash sectors, so the only way I can think of at
     * the moment is to allocate it here, between the board data and
     * the top of the stack.
     */
    addr_sp -= CFG_FLASH_ENV_BUF;
#endif /* CFG_FLASH_ENV_BUF */

    /*
     * Save local variables to board info struct
     */

    bd->bi_memstart    = CFG_SDRAM_BASE;  /* start of  DRAM memory		*/
    bd->bi_memsize     = dram_size;	  /* size  of  DRAM memory in bytes	*/
    bd->bi_flashstart  = CFG_FLASH_BASE;  /* start of FLASH memory		*/
    bd->bi_flashsize   = 0;	 	  /* size  of FLASH memory (PRELIM)	*/
    
#if CFG_MONITOR_BASE == CFG_FLASH_BASE
    bd->bi_flashoffset = CFG_MONITOR_LEN; /* reserved area for startup monitor	*/
#else
    bd->bi_flashoffset = 0;
#endif

    bd->bi_sramstart   = 0; /* FIXME */	  /* start of  SRAM memory		*/
    bd->bi_sramsize    = 0; /* FIXME */	  /* size  of  SRAM memory		*/

#if defined(CONFIG_8xx) || defined(CONFIG_8260)
    bd->bi_immr_base   = CFG_IMMR;	  /* base  of IMMR register		*/
#endif

    bd->bi_bootflags   = bootflag;	  /* boot / reboot flag (for LynxOS)	*/

    /* IP Address */
    bd->bi_ip_addr = 0;
    s = getenv ("ipaddr");
    for (reg=0; reg<4; ++reg) {
    	ulong val = s ? simple_strtoul(s, &e, 10) : 0;
	bd->bi_ip_addr <<= 8;
	bd->bi_ip_addr  |= (val & 0xFF);
	if (s)
		s = (*e) ? e+1 : e;
    }

    s = getenv ("ethaddr");

#ifdef	CONFIG_MBX
    if (s == NULL)
	board_get_enetaddr(bd->bi_enetaddr);
    else
#endif
    for (reg=0; reg<6; ++reg) {
	bd->bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
	if (s)
		s = (*e) ? e+1 : e;
    }

    bd->bi_intfreq  = clock_mhz;		/* Internal Freq, in MHz	*/
    bd->bi_busfreq  = get_bus_freq(clock_mhz);	/* Bus Freq,      in MHz	*/
#if defined(CONFIG_8260)
# if defined(CFG_CLKS_IN_HZ)
    bd->bi_cpmfreq = idata->cpm_clk;
    bd->bi_brgfreq = idata->brg_clk;
    bd->bi_sccfreq = idata->scc_clk;
    bd->bi_vco = idata->vco_out;
# else
    bd->bi_cpmfreq = idata->cpm_clk / 1000 / 1000;
    bd->bi_brgfreq = idata->brg_clk / 1000 / 1000;
    bd->bi_sccfreq = idata->scc_clk / 1000 / 1000;
    bd->bi_vco = idata->vco_out / 1000 / 1000;
# endif
#endif	/* CONFIG_8260 */

    bd->bi_baudrate = baudrate;			/* Console Baudrate		*/

#ifdef CFG_EXTBDINFO
    strncpy(bd->bi_s_version, "1.2", sizeof(bd->bi_s_version));
    strncpy(bd->bi_r_version, PPCBOOT_VERSION, sizeof(bd->bi_r_version));

    bd->bi_procfreq = bd->bi_intfreq * 1000000; /* Processor Speed, In Hz */
    bd->bi_plb_busfreq = bd->bi_busfreq;
    bd->bi_pci_busfreq = bd->bi_busfreq;
#endif

    /* Function pointers must be added after code relocation */
#if 0
    bd->bi_mon_fnc.getc   = NULL;	/* Addr of getc() from Console	*/
    bd->bi_mon_fnc.tstc   = NULL;	/* Addr of tstc() from Console	*/
    bd->bi_mon_fnc.putc   = NULL;	/* Addr of putc()   to Console	*/
    bd->bi_mon_fnc.putstr = NULL;	/* Addr of putstr() to Console	*/
    bd->bi_mon_fnc.printf = NULL;	/* Addr of printf() to Console	*/
    bd->bi_mon_fnc.install_hdlr = NULL;
    bd->bi_mon_fnc.free_hdlr    = NULL;
    bd->bi_mon_fnc.malloc	= NULL;
    bd->bi_mon_fnc.free		= NULL;
#endif

#ifdef DEBUG
    printf ("  New Stack Pointer is: %08lx\n", addr_sp);
#endif

    relocate_code (addr_sp, bd, addr_moni);

    /* NOTREACHED - relocate_code() does not return */
}

void    board_init_r  (bd_t *bd, ulong dest_addr)
{
    cmd_tbl_t	*cmdtp;
    ulong	flash_size;
    ulong	reloc_off = dest_addr - CFG_MONITOR_BASE;
    /* Pointer to initial global data area */
    init_data_t *idata = (init_data_t *)(CFG_INIT_RAM_ADDR + CFG_INIT_DATA_OFFSET);

    extern void malloc_bin_reloc (ulong);

#ifdef DEBUG
    printf("  Now running in RAM - dest_addr = 0x%08lx\n", dest_addr);
#endif

    /* Save a global pointer to the board info struct */
    bd_ptr = bd ;
    /* Set the monitor function pointer to DPAM init data */
    bd->bi_mon_fnc = &idata->bi_mon_fnc;

    /*
     * We have to relocate the command table manually
     */
    for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) {
	ulong addr;
	
	addr = (ulong)(cmdtp->cmd) + reloc_off;
#if 0
	printf ("Command \"%s\": 0x%08lx => 0x%08lx\n",
	    cmdtp->name, (ulong)(cmdtp->cmd), addr);
#endif
	cmdtp->cmd = (void (*)(struct cmd_tbl_s*,bd_t*,int,int,char*[]))addr;

	addr = (ulong)(cmdtp->name) + reloc_off;
	cmdtp->name = (char *)addr;

	if (cmdtp->usage) {
		addr = (ulong)(cmdtp->usage) + reloc_off;
		cmdtp->usage = (char *)addr;
	}
#ifdef	CFG_LONGHELP
	if (cmdtp->help) {
		addr = (ulong)(cmdtp->help) + reloc_off;
		cmdtp->help = (char *)addr;
	}
#endif
    }

    asm ("sync ; isync");

    /*
     * Setup trap handlers
     */
    trap_init(dest_addr);

    printf ("  FLASH: ");

    if ((flash_size = flash_init ()) > 0) {
    	if (flash_size >= (1 << 20)) {
		printf ("%2ld MB\n", flash_size >> 20);
	} else {
		printf ("%2ld kB\n", flash_size >> 10);
	}
    } else {
	printf (failed);
	hang();
    }
    bd->bi_flashsize = flash_size;   /* size of FLASH memory (final value)	*/

#if defined(CFG_FLASH_ENV_ADDR)
    /*
     * Protect the sector that the environment is in.
     *
     * This scheme (i.e. bi_flashoffset in the board info) cannot
     * really reflect an arbitrarily placed environment flash sector,
     * but lets just do our best, and assume that if CFG_FLASH_ENV_ADDR
     * is defined it will be in a sensible location e.g. either the
     * first sector, or the sector just after the monitor, if it is
     * in flash.
     */
    {
	ulong addr, newoff;
	flash_info_t *fip;
	int i, j;

	/* address of last byte in the environment */
	addr = CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1;

	/* make sure it is within the flash */
	if ((fip = addr2info(addr)) == NULL)
	    panic("environment address 0x%08lx is not within flash!\n", addr);

	/* move it to the sector boundary */
	for (i = 0, j = 1; j < fip->sector_count; i++, j++)
	    if (addr >= fip->start[i] && addr < fip->start[j])
		break;
	if (j == fip->sector_count)
	    addr = fip->start[0] + fip->size;
	else
	    addr = fip->start[j];

	/* adjust flashoffset if required */
	newoff = addr - bd->bi_flashstart;
	if (bd->bi_flashoffset < newoff)
	    bd->bi_flashoffset = newoff;
    }
#endif

    /* initialize higher level parts of CPU like time base and timers */
    cpu_init_r (bd);

#ifdef CONFIG_COGENT
    /* miscellaneous platform dependent initialisations */
    misc_init_r(bd);
#endif

#ifdef CONFIG_SPD823TS
    reset_phy ();
#endif

#if (CONFIG_COMMANDS & CFG_CMD_IDE)
    printf ("  IDE:   ");
    ide_init(bd);
#endif

#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
    printf ("  KGDB:  ");
    kgdb_init();
#endif

#ifdef DEBUG
    printf("Monitor relocated to 0x%08lx\n", dest_addr);
#endif

    /*
     * Enable Interrupts
     */
    interrupt_init (bd);

    udelay(20);

    set_timer(0);

    /* Insert function pointers now that we have relocated the code */

    bd->bi_mon_fnc->install_hdlr = irq_install_handler;
    bd->bi_mon_fnc->free_hdlr    = irq_free_handler;

    /* Initialize other board modules */
#ifdef CONFIG_PCMCIA
    printf("  PCMCIA: ");
    pcmcia_init();
#endif

#ifdef CONFIG_PCI_PNP
    /*
     * Do pci plug-n-play configuration
     */
    pci_init();
#endif

    bd->bi_mon_fnc->malloc = malloc;
    bd->bi_mon_fnc->free   = free;

    /* initialize malloc() area */
    mem_malloc_init (dest_addr);
    malloc_bin_reloc (reloc_off);

/** LEAVE THIS HERE **/
    /* Initialize devices */
    devices_init();

    /* Initialize the console (after the relocation and devices init) */
    console_init_r ();
    putc('\n');
/**********************/

    /* Initialization complete - start the monitor */

    main_loop (bd);

    /* NOTREACHED - start_main does not return; just in case: loop here */
    for (;;);
}

void hang(void)
{
	printf ("### ERROR ### Please RESET the board ###\n");
	for (;;);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -