📄 flash_amd.c
字号:
/* $Id: flash_amd.c,v 1.6 2003/05/21 09:15:48 pefo Exp $ *//* * Copyright (c) 2001 ipUnplugged AB (www.ipunplugged.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 by * ipUnplugged 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));int fl_erase_chip_amd __P((struct fl_map *, struct fl_device *));int fl_erase_sector_amd __P((struct fl_map *, struct fl_device *, int ));int fl_isbusy_amd __P((struct fl_map *, struct fl_device *, int, int, int));int fl_reset_amd __P((struct fl_map *, struct fl_device *));int fl_erase_suspend_amd __P((struct fl_map *, struct fl_device *));int fl_erase_resume_amd __P((struct fl_map *, struct fl_device *));int fl_program_amd __P((struct fl_map *, struct fl_device *, int , unsigned char *));struct fl_functions fl_func_amd = {fl_erase_chip_amd, fl_erase_sector_amd, fl_isbusy_amd, fl_reset_amd, fl_erase_suspend_amd, fl_program_amd};/* * 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 Unlock Bypass */static __inline void fl_unlock_bypass_amd __P((struct fl_map *));static __inline voidfl_unlock_bypass_amd(map) 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), 0x20); 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), 0x20); 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 Bypass */static __inline void fl_unlock_bypass_reset_amd __P((struct fl_map *));static __inline voidfl_unlock_bypass_reset_amd(map) 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_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 Bypass */static __inline void fl_unlock_bypass_program_amd __P((struct fl_map *, int , int ));static __inline voidfl_unlock_bypass_program_amd(map, pa, pd) struct fl_map *map; int pa; int pd;{ 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); break; case FL_BUS_16_ON_8: outb((map->fl_map_base + AMD_CMDOFFS2), 0xaa); outb((map->fl_map_base + AMD_CMDOFFS1), 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; }}/* * Function to erase sector */intfl_erase_sector_amd(map, dev, offset) struct fl_map *map; struct fl_device *dev; int offset;{ 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_ERASE); outb((map->fl_map_base + AMD_CMDOFFS1), 0xAA); outb((map->fl_map_base + AMD_CMDOFFS2), 0x55); outb((map->fl_map_base + offset), FL_SECT); 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_ERASE); outb((map->fl_map_base + AMD_CMDOFFS2), 0xAA); outb((map->fl_map_base + AMD_CMDOFFS1), 0x55); outb((map->fl_map_base + offset), FL_SECT); 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; } return(0);}/* * Function to Program */intfl_program_amd(map, dev, pa, pd) struct fl_map *map; struct fl_device *dev; int pa; unsigned char *pd;{ int stat; 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), 0xA0); outb((map->fl_map_base + pa), *pd); 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), 0xA0); outb((map->fl_map_base + pa), *pd); break; 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(*pd); movequad((void *)map->fl_map_base + (pa << 3), &widedata); break; case FL_BUS_64: break; /* Leave this for now */ } do { stat = fl_isbusy_amd(map, dev, *pd, pa, FALSE); } while(stat == 1); return(0);}/* * Function to erase chip */intfl_erase_chip_amd(map, dev) struct fl_map *map; struct fl_device *dev;{ 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_ERASE); outb((map->fl_map_base + AMD_CMDOFFS1), 0xaa); outb((map->fl_map_base + AMD_CMDOFFS2), 0x55); outb((map->fl_map_base + AMD_CMDOFFS1), FL_ERASE_CHIP); 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_ERASE); outb((map->fl_map_base + AMD_CMDOFFS2), 0xaa); outb((map->fl_map_base + AMD_CMDOFFS1), 0x55); outb((map->fl_map_base + AMD_CMDOFFS2), FL_ERASE_CHIP); 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; } return(0);}/* * Function to suspend erase sector */intfl_erase_suspend_amd(map, dev) struct fl_map *map; struct fl_device *dev;{ switch(map->fl_map_bus) { case FL_BUS_8: case FL_BUS_16_ON_8: outb(map->fl_map_base, FL_SUSPEND); 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; } return(0);}/* * Function to resume erase sector */intfl_erase_resume_amd(map, dev) struct fl_map *map; struct fl_device *dev;{ switch(map->fl_map_bus) { case FL_BUS_8: case FL_BUS_16_ON_8: outb(map->fl_map_base, FL_RESUME); 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; } return(0);}/* * Function to "reset" flash, eg return to read mode. */intfl_reset_amd(map, dev) struct fl_map *map; struct fl_device *dev;{ switch(map->fl_map_bus) { case FL_BUS_8: case FL_BUS_16_ON_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: break; } return(0);}/* * Function to poll flash BUSY if available. * returns 1 if busy, 0 if OK, -1 if error. */intfl_isbusy_amd(map, dev, what, offset, erase) struct fl_device *dev; struct fl_map *map; int what; int offset; int erase;{ int busy; switch(map->fl_map_bus) { case FL_BUS_8_ON_64: offset = offset << 3; /* Fallthrough */ case FL_BUS_8: case FL_BUS_16_ON_8: /* Data polling * algorithm is in Figure 6 */#if defined(CPC700) || defined(OCELOT_G) if(erase) { int d; d = inb(map->fl_map_base + offset); d ^= inb(map->fl_map_base + offset + 1); if((d & 0x40) == 0) { /* Not toggling */ busy = 0; } else { if(!(inb(map->fl_map_base + offset) & 0x20)) { busy = 1; /* Check again */ } else { d = inb(map->fl_map_base + offset); d ^= inb(map->fl_map_base + offset + 1); if((d & 0x40) == 1) { busy = 1; } else { busy = -1; } } } } else { int d; d = inb(map->fl_map_base + offset); if(((d ^ what) & 0x80) == 0) { busy = 0; /* Done */ } else if((d & 0x20) == 0) { busy = 1; /* Busy */ } else { d = inb(map->fl_map_base + offset); if(((d ^ what) & 0x80) == 0) { busy = 0; /* Done */ } else { busy = -1; /* Poll error */ } } } #else while (1) { u_int8_t poll1, poll2; poll1 = inb(map->fl_map_base + offset); poll2 = inb(map->fl_map_base + offset); if ((poll1 ^ poll2) & 0x40) { /* toggle */ if (poll2 & 0x20) { /* DQ5 = 1 */ /* read twice */ poll1 = inb(map->fl_map_base + offset); poll2 = inb(map->fl_map_base + offset); if ((poll1 ^ poll2) & 0x40) { /* toggle */ busy = -1; break; } else { busy = 0; break; /* program completed */ } } else { poll1 = poll2; continue; } } else { busy = 0; break; /* program completed */ } }#endif break; default: /* Not supported but sorted out much earlier */ } return(busy);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -