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

📄 pflash.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
字号:
/*	$Id: pflash.c,v 1.1 2001/12/12 10:15:24 patrik 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 "pflash_tgt.h"extern void delay __P((int));/* *   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. *//* *  Flash devices known by this code. */#define __KB 1024struct fl_device fl_known_dev[] = {  { "Am29F040", 0x01, 0xa4, FL_PROTO_AMD, FL_CAP_DE,  512*__KB, 64*__KB },  { "ST29F040", 0x20, 0xe2, FL_PROTO_AMD, FL_CAP_DE,  512*__KB, 64*__KB },  { "i28F016",  0x89, 0xaa, FL_PROTO_INT,         0, 2048*__KB, 64*__KB },  { "i28F016SA",0x89, 0xa0, FL_PROTO_INT, FL_CAP_A7, 2048*__KB, 64*__KB },  { "i28F160",  0xb0, 0xd0, FL_PROTO_INT, FL_CAP_DE, 2048*__KB, 64*__KB },  { "i28F320",  0xb0, 0xd4, FL_PROTO_INT, FL_CAP_DE, 4096*__KB, 64*__KB },/* Wierd... but this is what we get from the 320 on the Palomar-II */  { "i28F320x", 0x89, 0x14, FL_PROTO_INT, FL_CAP_DE, 4096*__KB, 64*__KB },  { 0 },};#undef __KBquad_t unlock_aa = 0xaaaaaaaaaaaaaaaa;quad_t unlock_55 = 0x5555555555555555;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 unlock flash. */static __inline void fl_unlock __P((struct fl_map *));static __inline voidfl_unlock(map)	struct fl_map *map;{	switch(map->fl_map_bus) {	case FL_BUS_8:		outb((map->fl_map_base + 0x5555), 0xaa);		outb((map->fl_map_base + 0x2aaa), 0x55);		break;	case FL_BUS_64:		break;	/* Leave this for now */	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);		break;	}}/* *  Inlineable function to unlock and send command to flash. */static __inline void fl_command_amd __P((struct fl_map *, int, int));static __inline voidfl_command_amd(map, command, offset)	struct fl_map *map;	int command;	int offset;{	fl_unlock(map);	switch(map->fl_map_bus) {	case FL_BUS_8:		outb((map->fl_map_base + offset), command);		break;	case FL_BUS_64:	case FL_BUS_8_ON_64:		SETWIDE(command);		movequad((void *)map->fl_map_base + (offset << 3), &widedata);		break;	}}/* *  Inlineable function to send INT command to flash. */static __inline void fl_command_int __P((struct fl_map *, int, int));static __inline voidfl_command_int(map, command, offset)	struct fl_map *map;	int command;	int offset;{	delay(5);	switch(map->fl_map_bus) {	case FL_BUS_8:		outb(map->fl_map_base + offset, command);		break;	case FL_BUS_64:		SETWIDE(command);		movequad((void *)(map->fl_map_base + offset), &widedata);		break;	}}/* *  Inlineable function to "reset" flash, eg return to read mode. */static __inline void fl_reset __P((struct fl_map *));static __inline voidfl_reset(map)	struct fl_map *map;{	switch(map->fl_map_bus) {	case FL_BUS_8:		outb((map->fl_map_base), FL_RESET);		break;	case FL_BUS_8_ON_64:		SETWIDE(FL_RESET);		movequad((void *)map->fl_map_base, &widedata);		break;	case FL_BUS_64:		fl_command_int(map, FL_INT_READ, 0);		break;	}}/* *  Generic function to poll flash BUSY if available. *  returns 1 if busy, 0 if OK, -1 if error. */intfl_isbusy(map, dev, what, offset)	struct fl_device *dev;	struct fl_map *map;	int what;{	u_char *p;	int d;	switch(dev->fl_proto) {	case FL_PROTO_AMD:		switch(map->fl_map_bus) {		case FL_BUS_8_ON_64:			offset = offset << 3;			/* Fallthrough */		case FL_BUS_8:			d = inb(map->fl_map_base + offset);			if(((d ^ what) & 0x80) == 0) {				d = 0;	/* Done */			}			else if((d & 0x20) == 0) {				d = 1;	/* Busy */			}			else {				d = inb(map->fl_map_base + offset);				if(((d ^ what) & 0x80) == 0) {					d = 0;	/* Done */				}				else {					d = -1;	/* Poll error */				}			}			break;		default:			/* Not supported but sorted out much earlier */		}		break;	case FL_PROTO_INT:		switch(map->fl_map_bus) {		case FL_BUS_8:			d = !(inb(map->fl_map_base) & FL_INT_BUSY);			break;		case FL_BUS_64:			movequad(&widedata, (void *)map->fl_map_base);			p = (u_char *)&widedata;			d = !((p[1] & p[3] & p[5] & p[7]) & FL_INT_BUSY);			break;		}		break;	}	return(d);}/* *  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;	map = tgt_flashmap();	/* 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_command_amd(map, FL_AUTOSEL, AMD_CMDOFFS);		switch(map->fl_map_bus) {		case FL_BUS_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_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;	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 */	}	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 */	}	tgt_flashwrite_enable();	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 */	while(size > 0) {		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. ");			}			switch(dev->fl_proto) {			case FL_PROTO_AMD:				fl_command_amd(map, FL_ERASE, AMD_CMDOFFS);				fl_command_amd(map, FL_CHIP, AMD_CMDOFFS);				break;			case FL_PROTO_INT:				if(dev->fl_cap & FL_CAP_A7) {					fl_command_int(map, FL_INT_FCE_A7, 0);				}				else {					fl_command_int(map, FL_INT_FCE, 0);				}				fl_command_int(map, FL_INT_CNF, 0);				break;			}			size = 0;		}		else {			/*			 * Not entire flash or no BULK erase feature. We			 * use sector/block erase.			 * This code does not handle boot block style devs			 * like the 28F160B3T yet.			 */			if(verbose) {				printf("Erasing FLASH block %2d ", block);			}			switch(dev->fl_proto) {			case FL_PROTO_AMD:				fl_command_amd(map, FL_ERASE, AMD_CMDOFFS);				fl_command_amd(map, FL_SECT, (int)base);				break;			case FL_PROTO_INT:				fl_command_int(map, FL_INT_BE, 0);				fl_command_int(map, FL_INT_CNF, (int)base);				break;			}			block++;			base += dev->fl_secsize * map->fl_map_chips;			size -= dev->fl_secsize * map->fl_map_chips;		}		delay(1000);		while((ok = fl_isbusy(map, dev, 0xffffffff, 0)) == 1) {			if(verbose) {				delay(1000);				dotik(256, 0);			}		}		delay(1000);		switch(dev->fl_proto) {		case FL_PROTO_AMD:			fl_reset(map);			break;		case FL_PROTO_INT:			fl_command_int(map, FL_INT_CLR, 0);			fl_command_int(map, FL_INT_READ, 0);			break;		}		if(verbose) {			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, d, 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 */	}	if(verbose) {		printf("Programming FLASH. ");	}	tgt_flashwrite_enable();	for(i = 0; i < data_size; i += map->fl_map_width) {		switch(dev->fl_proto) {		case FL_PROTO_AMD:			off = (int)fl_base - map->fl_map_base;			d = *(u_char *)data_base++;			fl_command_amd(map, FL_PGM, AMD_CMDOFFS);			switch(map->fl_map_bus) {			case FL_BUS_8:				outb(fl_base, d);				fl_base++;				break;			case FL_BUS_8_ON_64:				SETWIDE(d);				movequad((void *)map->fl_map_base + (((int)fl_base - map->fl_map_base) << 3), &widedata);				fl_base++;				break;			}			break;		case FL_PROTO_INT:			fl_command_int(map, FL_INT_PGM, 0);			switch(map->fl_map_bus) {			case FL_BUS_8:				*(u_char *)fl_base++ = *(u_char *)data_base++;				break;			case FL_BUS_64:				bcopy(data_base, (void *)&widedata, 8);				movequad(fl_base, &widedata);				data_base += 8;				fl_base += 8;				break; 			}			break;		}		if(verbose) {			dotik(32, 0);		}		while((ok = fl_isbusy(map, dev, d, off)) == 1) {		}	}	switch(dev->fl_proto) {	case FL_PROTO_AMD:		fl_reset(map);		break;	case FL_PROTO_INT:		fl_command_int(map, FL_INT_CLR, 0);		fl_command_int(map, FL_INT_READ, 0);		break;	}	if(verbose) {		printf("\b Done.\n");	}		tgt_flashwrite_disable();	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");	/*	0000ffff 0000ffff  4*8   00010000  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("%08x %08x %2d*8   %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");}/* *  Flash programming functionality. */const Optdesc flash_opts[] = {	{ "-q",	"display info about flash memory" },	{ "-e",	"erase flash" },	{ 0 }};intcmd_flash(ac, av)	int ac;	char *av[];{extern int optind;	int	c;	int	opt_erase = 0;	u_int32_t base_addr;	u_int32_t offset;	u_int32_t flashsize = -1;	if(tgt_flashwrite_enable() == 0) {		printf("FLASH can't be write enabled by PMON/2000. Please\n");		printf("consult the HW manual on how to enable writing!\n");		return(0);	}	tgt_flashwrite_disable();	if(ac == 1) {	/* No arguments given, display flash info */		fl_query_info();		return(0);	}	optind = 0;	while((c = getopt(ac, av, "eq")) != EOF) {		switch(c) {		case 'e':		/* Erase */			opt_erase = 1;			break;		case 'q':		/* query info */			fl_query_info();			return(0);	/* Don't bother with the rest */		}	}	if(optind >= ac) {		return(-1);	/* Argument error */	}	if(!get_rsa(&base_addr, av[optind++])) {		return(-1);	}	if(optind < ac && !get_rsa (&flashsize, av[optind++])) {		return(-1);	}	if(optind < ac && !get_rsa (&offset, av[optind++])) {		return(-1);	}	if(opt_erase) {		c = fl_erase_device((void *)base_addr, flashsize, TRUE);		switch(c) {		case -4:			printf("Bad address and/or size for erase!\n");			break;		case -3:			printf("No FLASH memory on that address!\n");			break;		case -1:			printf("Erase status failed!\n");			break;		}	}	else if(optind >= 4) {		c = fl_program_device((void *)base_addr, (void *)offset, flashsize, TRUE);		switch(c) {		case -4:			printf("Bad address and/or size!\n");			break;		case -3:			printf("No FLASH memory on that address!\n");			break;		case -1:			printf("Programming failed!\n");			break;		}	}	return(0);}/* *  Command table registration *  ========================== */extern const Optdesc  flash_opts[];static const Cmd Cmds[] ={	{"Misc"},	{"flash",	"[-qe] addr size data",			flash_opts,			"program flash memory",			cmd_flash, 1, 5,			0},	{0, 0}};static void init_cmd __P((void)) __attribute__ ((constructor));voidinit_cmd(){	cmdlist_expand(Cmds, 1);}

⌨️ 快捷键说明

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