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

📄 flash.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
字号:
/*	$Id: flash.c,v 1.7 2003/06/10 14:44:49 pefo Exp $ *//* * Copyright (c) 2000 Opsycon AB  (www.opsycon.se) * Copyright (c) 2000 Rtmx, Inc   (www.rtmx.com) *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed for Rtmx, Inc by *	Opsycon Open System Consulting AB, Sweden. * 4. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include <stdio.h>#include <string.h> #include <stdlib.h>#include <machine/pio.h>#include <pmon.h>#include <pflash.h>#include <dev/pflash_tgt.h>extern void delay __P((int));#ifndef PFLASH_MAX_TIMEOUT#define PFLASH_MAX_TIMEOUT 16000#endif/* *   FLASH Programming functions. * *   Handle flash programing aspects such as different types *   organizations and actual HW design organization/interleaving. *   Combinations can be endless but an attempt to make something *   more MI may be done later when the variations become clear. */static quad_t widedata;#define	SETWIDE(x) do {						\			u_int32_t __a = x;			\			__a |= __a << 8;			\			__a |= __a << 16;			\			widedata = (quad_t)__a << 32 | __a;	\		} while(0)/* *  Inlineable function to Auto Select Device */static __inline voidfl_autoselect(struct fl_map *map){	switch(map->fl_map_bus) {	case FL_BUS_8:		outb((map->fl_map_base + AMD_CMDOFFS1), 0xAA);		outb((map->fl_map_base + AMD_CMDOFFS2), 0x55);		outb((map->fl_map_base + AMD_CMDOFFS1), FL_AUTOSEL);		break;	case FL_BUS_16_ON_8:		outb((map->fl_map_base + AMD_CMDOFFS2), 0xAA);		outb((map->fl_map_base + AMD_CMDOFFS1), 0x55);		outb((map->fl_map_base + AMD_CMDOFFS2), FL_AUTOSEL);		break;	case FL_BUS_16:		SETWIDE(0xaa);		outw(map->fl_map_base + (0x5555 << 2), widedata);		SETWIDE(0x55);		outw(map->fl_map_base + (0xaaaa << 2), widedata);		SETWIDE(FL_AUTOSEL);		outw(map->fl_map_base + (0x5555 << 2), widedata);		break;	case FL_BUS_32:		SETWIDE(0xaa);		outl(map->fl_map_base + (0x5555 << 4), widedata);		SETWIDE(0x55);		outl(map->fl_map_base + (0xaaaa << 4), widedata);		SETWIDE(FL_AUTOSEL);		outl(map->fl_map_base + (0x5555 << 4), widedata);		break;	case FL_BUS_64:	case FL_BUS_8_ON_64:		SETWIDE(0xAA);		movequad((void *)map->fl_map_base + (0x5555 << 3), &widedata);		SETWIDE(0x55);		movequad((void *)map->fl_map_base + (0x2AAA << 3), &widedata);		SETWIDE(FL_AUTOSEL);		movequad((void *)map->fl_map_base + (0x5555 << 3), &widedata);		break;	}}/* *  Inlineable function to Generic Reset the Chip */static __inline voidfl_reset(struct fl_map *map){	switch(map->fl_map_bus) {	case FL_BUS_8:	case FL_BUS_16_ON_8:		outb((map->fl_map_base), 0x90);		outb((map->fl_map_base), 0x00);		break;        case FL_BUS_16:                SETWIDE(FL_RESET);                outw(map->fl_map_base, widedata);                break;        case FL_BUS_32:                SETWIDE(FL_RESET);                outl(map->fl_map_base, widedata);                break;       	case FL_BUS_64:	case FL_BUS_8_ON_64:                SETWIDE(FL_RESET);		movequad((void *)map->fl_map_base, &widedata);		break;	}}/* *  Find what flash map address nelongs to. */struct fl_map *fl_find_map(void *base){	struct fl_map *map;	for(map = tgt_flashmap(); map->fl_map_size != 0; map++) {		if(map->fl_map_base > (u_int32_t)base ||		   (map->fl_map_base + map->fl_map_size - 1) < (u_int32_t)base) {			continue;	/* Not this one */		}		else {			return(map);		}	}	return((struct fl_map *)NULL);}		/* *  Try to figure out what kind of flash there is on given address. */struct fl_device *fl_devident(void *base, struct fl_map **m){	struct fl_device *dev;	struct fl_map *map;	char mfgid, chipid;	/* If we can't write to flash, we can't identify */	if(!tgt_flashwrite_enable()) {		return((struct fl_device *)NULL);	}	map = fl_find_map(base);	if(map != NULL) {		fl_autoselect(map);		switch(map->fl_map_bus) {		case FL_BUS_8:		case FL_BUS_16_ON_8:			mfgid = inb(map->fl_map_base);			chipid = inb(map->fl_map_base+1);			if(chipid == mfgid) { /* intel 16 bit flash mem */				chipid = inb(map->fl_map_base+3);			}			break;		case FL_BUS_8_ON_64:			mfgid = inb(map->fl_map_base);			chipid = inb(map->fl_map_base+8);			break;		case FL_BUS_16:			mfgid = inw(map->fl_map_base);			chipid = inw(map->fl_map_base+2);			break;		case FL_BUS_32:			mfgid = inl(map->fl_map_base);			chipid = inl(map->fl_map_base+4);			break;		case FL_BUS_64:			mfgid = inw(map->fl_map_base);			chipid = inw(map->fl_map_base+8);			break;		}		fl_reset(map);		/* Lookup device type using manufacturer and device id */		for(dev = &fl_known_dev[0]; dev->fl_name != 0; dev++) {			if(dev->fl_mfg == mfgid && dev->fl_id == chipid) {				tgt_flashwrite_disable();				if(m) {					*m = map;				}				return(dev);	/* GOT IT! */			}		}                printf("Mfg %2x, Id %2x\n", mfgid, chipid);	}		tgt_flashwrite_disable();	return((struct fl_device *)NULL);}/* *  Erase the flash device(s) addressed. */intfl_erase_device(void *base, int size, int verbose){	struct fl_map *map;	struct fl_device *dev;	int mask, ok, block;	int timeout;		if(tgt_flashwrite_enable() == 0) {		return(-2);	/* Flash can't be write enabled */	}	dev = fl_devident(base, &map);	if(dev == NULL) {		return(-3);	/* No flash device found at address */	}	/*	 * Sanity checks!	 */	if(size == -1 && (int)base == map->fl_map_base) {		size = map->fl_map_size;	/* Entire flash */	}        if(dev->fl_varsecsize != NULL) {                int offset = (int)(base - map->fl_map_base) + map->fl_map_offset;                int totalsize;                for(block=0, totalsize=0; totalsize < offset; block++) {                        totalsize += dev->fl_varsecsize[block] * map->fl_map_chips;                }                mask = ((dev->fl_varsecsize[block] * map->fl_map_width / map->fl_map_chips) - 1);                if((int)base & mask) {                        size += (int)base & mask;                        base = (void *)((int)base & ~mask);                } else if((size + ((int)base - map->fl_map_base)) > map->fl_map_size) {                        return(-4);	/* End beyound end of flash */                }                base -= map->fl_map_base;        } else {                mask = ((dev->fl_secsize * map->fl_map_width / map->fl_map_chips) - 1);                if((int)base & mask) {                        size += (int)base & mask;                        base = (void *)((int)base & ~mask);                } else if((size + ((int)base - map->fl_map_base)) > map->fl_map_size) {                        return(-4);	/* End beyound end of flash */                }                base -= map->fl_map_base;                block = (int)base / map->fl_map_chips / dev->fl_secsize;                size = (size + mask) & ~mask; /* Round up to catch entire flash */        }                tgt_flashwrite_enable();        	while(size > 0) {		int boffs = (int)base;		if(size == map->fl_map_size &&			dev->fl_cap & (FL_CAP_DE|FL_CAP_A7)) {			/*			 * Erase entire devices using the BULK erase feature			 */			if(verbose) {				printf("Erasing all FLASH blocks. ");			}			(*dev->functions->erase_chip)(map, dev);			size = 0;		}		else {			/*			 * Not entire flash or no BULK erase feature. We			 * use sector/block erase.			 */			if(verbose) {				printf("\rErasing FLASH block %3d      \b\b\b\b\b", block);			}			if((*dev->functions->erase_sector)(map, dev, boffs) != 0) {				printf("\nError: Failed to enter erase mode\n");				(*dev->functions->erase_suspend)(map, dev);				(*dev->functions->reset)(map, dev);				return(-4);			}                        if(dev->fl_varsecsize != NULL) {                                base += dev->fl_varsecsize[block] * map->fl_map_chips;                                size -= dev->fl_varsecsize[block] * map->fl_map_chips;                                block++;                        } else {                                base += dev->fl_secsize * map->fl_map_chips;                                size -= dev->fl_secsize * map->fl_map_chips;                                block++;                        }		}		delay(1000);		for(timeout = 0 ;		    ((ok = (*dev->functions->isbusy)(map, dev, 0xffffffff, boffs, TRUE)) == 1)				&& (timeout < PFLASH_MAX_TIMEOUT); timeout++) {			if(verbose) {				delay(1000);				dotik(256, 0);			}		}		delay(1000);		if(!(timeout < PFLASH_MAX_TIMEOUT)) {			(*dev->functions->erase_suspend)(map, dev);		}		(*dev->functions->reset)(map, dev);		if(verbose) {			if(!(timeout < PFLASH_MAX_TIMEOUT)) {/* XXX if timed out what should really happen here? This doesn't look right. */				printf("\b\b, command timed out!\n");			} else {				printf("\b Done.\n");			}		}	}	tgt_flashwrite_disable();	return(ok);}/* *  Program a flash device. Assumed that the area is erased already. */intfl_program_device(void *fl_base, void *data_base, int data_size, int verbose){	struct fl_map *map;	struct fl_device *dev;	int ok;	int i, off;		if(tgt_flashwrite_enable() == 0) {		return(-2);	/* Flash can't be write enabled */	}	dev = fl_devident(fl_base, &map);	if(dev == NULL) {		tgt_flashwrite_disable();		return(-3);	/* No flash device found at address */	}	if(data_size == -1 || (int)data_base == -1) {		return(-4);		/* Bad parameters */	}	if((data_size + ((int)fl_base - map->fl_map_base)) > map->fl_map_size) {		return(-4);	/* Size larger than device array */	}	off = (int)(fl_base - map->fl_map_base) + map->fl_map_offset;	if(verbose) {		printf("Programming FLASH. ");	}	tgt_flashwrite_enable();	for(i = 0; i < data_size; i += map->fl_map_width) {		ok = (*dev->functions->program)(map, dev, (int)off, data_base);		switch(map->fl_map_bus) {		case FL_BUS_8:		case FL_BUS_8_ON_64:		case FL_BUS_16_ON_8:			off++;			data_base++;			break;		case FL_BUS_16:			data_base += 2;			off += 2;			break;		case FL_BUS_32:			data_base += 4;			off += 4;			break;		case FL_BUS_64:			data_base += 8;			off += 8;			break; 		}		if(verbose) {			dotik(256, 0);		}	}	(*dev->functions->reset)(map, dev);	if(verbose) {		printf("\b Done.\n");	}		tgt_flashwrite_disable();	return(ok);}/* *  Verify flash contents to ram contents. */intfl_verify_device(void *fl_base, void *data_base, int data_size, int verbose){	struct fl_map *map;	struct fl_device *dev;	void *fl_last;	int ok;	int i;	dev = fl_devident(fl_base, &map);	if(dev == NULL) {		return(-3);	/* No flash device found at address */	}	if(data_size == -1 || (int)data_base == -1) {		return(-4);		/* Bad parameters */	}	if((data_size + ((int)fl_base - map->fl_map_base)) > map->fl_map_size) {		return(-4);	/* Size larger than device array */	}	if(verbose) {		printf("Verifying FLASH. ");	}	for(i = 0; i < data_size; i += map->fl_map_width) {		fl_last = fl_base;		switch(map->fl_map_bus) {		case FL_BUS_8:		case FL_BUS_16_ON_8:			ok = (*((u_char *)fl_base)++ == *((u_char *)data_base)++);			break;		case FL_BUS_16:			ok = (*((u_short *)fl_base)++ == *((u_short *)data_base)++);			break;		case FL_BUS_32:			ok = (*((u_int *)fl_base)++ == *((u_int *)data_base)++);			break;		case FL_BUS_64:			movequad(&widedata, fl_base);			ok = (bcmp(data_base, (void *)&widedata, 8) == 0);			data_base += 8;			fl_base += 8;			break; 		case FL_BUS_8_ON_64:			ok = (*((u_char *)map->fl_map_base +				   (((int)fl_base - map->fl_map_base) << 3)) ==				*(u_char *)data_base++);			fl_base++;			break;		}		if(verbose & !ok) {			printf(" error offset %p\n", fl_last);			break;		}		else if(verbose) {			dotik(32, 0);		}	}	if(verbose && ok) {		printf("\b No Errors found.\n");	}		return(ok);}/* *  List the various FLASH devices found. */voidfl_query_info(){	struct fl_map *map;	struct fl_device *dev;	printf("Available FLASH memory\n");	printf("   Start      Size    Width  Sectorsize  Type\n");	/*	0x0000ffff 0x0000ffff  4*8   0x00010000  Am29f040   */	for(map = tgt_flashmap(); map->fl_map_size != 0; map++) {		dev = fl_devident((void *)map->fl_map_base, NULL);		if(dev == NULL) {			continue;	/* Empty socket ? */		}		printf("0x%08x 0x%08x %2d*8   0x%08x   %-10s\n",			map->fl_map_base, map->fl_map_size, map->fl_map_width,			dev->fl_secsize * map->fl_map_chips, dev->fl_name);	}	printf("\n");}

⌨️ 快捷键说明

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