Fix AMD type flash write operations, and display chip information at boot

Applies to MX flash chips on AR9132 and RT3050

Submitted by:	Hiroki Mori <yamori813@yahoo.co.jp>
Reviewed by:	imp, sbruno
Differential Revision:	https://reviews.freebsd.org/D14279
This commit is contained in:
Allan Jude 2019-03-24 06:28:25 +00:00
parent 7de4780412
commit 91dfbef4aa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345464
3 changed files with 100 additions and 6 deletions

View File

@ -421,6 +421,16 @@ cfi_attach(device_t dev)
}
}
if (sc->sc_cmdset == CFI_VEND_AMD_ECS ||
sc->sc_cmdset == CFI_VEND_AMD_SCS) {
cfi_amd_write(sc, 0, AMD_ADDR_START, CFI_AMD_AUTO_SELECT);
sc->sc_manid = cfi_read(sc, 0);
sc->sc_devid = cfi_read(sc, 2);
device_printf(dev, "Manufacturer ID:%x Device ID:%x\n",
sc->sc_manid, sc->sc_devid);
cfi_write(sc, 0, CFI_BCS_READ_ARRAY2);
}
u = device_get_unit(dev);
sc->sc_nod = make_dev(&cfi_cdevsw, u, UID_ROOT, GID_WHEEL, 0600,
"%s%u", cfi_driver_name, u);
@ -500,6 +510,37 @@ cfi_detach(device_t dev)
return (0);
}
static bool
cfi_check_erase(struct cfi_softc *sc, u_int ofs, u_int sz)
{
bool result;
int i;
uint32_t val;
result = FALSE;
for (i = 0; i < sz; i += sc->sc_width) {
val = cfi_read(sc, ofs + i);
switch (sc->sc_width) {
case 1:
if (val != 0xff)
goto out;
continue;
case 2:
if (val != 0xffff)
goto out;
continue;
case 4:
if (val != 0xffffffff)
goto out;
continue;
}
}
result = TRUE;
out:
return (result);
}
static int
cfi_wait_ready(struct cfi_softc *sc, u_int ofs, sbintime_t start,
enum cfi_wait_cmd cmd)
@ -581,10 +622,12 @@ cfi_write_block(struct cfi_softc *sc)
uint32_t *x32;
} ptr, cpyprt;
register_t intr;
int error, i, neederase = 0;
int error, i, j, neederase = 0;
uint32_t st;
u_int wlen;
sbintime_t start;
u_int minsz;
uint32_t val;
/* Intel flash must be unlocked before modification */
switch (sc->sc_cmdset) {
@ -615,9 +658,27 @@ cfi_write_block(struct cfi_softc *sc)
break;
case CFI_VEND_AMD_SCS:
case CFI_VEND_AMD_ECS:
/* find minimum sector size */
minsz = sc->sc_region[0].r_blksz;
for (i = 1; i < sc->sc_regions; i++) {
if (sc->sc_region[i].r_blksz < minsz)
minsz = sc->sc_region[i].r_blksz;
}
cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START,
CFI_AMD_ERASE_SECTOR);
cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE);
cfi_amd_write(sc, sc->sc_wrofs,
sc->sc_wrofs >> (ffs(minsz) - 1),
CFI_AMD_BLOCK_ERASE);
for (i = 0; i < CFI_AMD_MAXCHK; ++i) {
if (cfi_check_erase(sc, sc->sc_wrofs,
sc->sc_wrbufsz))
break;
DELAY(10);
}
if (i == CFI_AMD_MAXCHK) {
printf("\nCFI Sector Erase time out error\n");
return (ENODEV);
}
break;
default:
/* Better safe than sorry... */
@ -749,10 +810,37 @@ cfi_write_block(struct cfi_softc *sc)
intr_restore(intr);
error = cfi_wait_ready(sc, sc->sc_wrofs, start,
CFI_TIMEOUT_WRITE);
if (error)
goto out;
if (sc->sc_cmdset == CFI_VEND_AMD_ECS ||
sc->sc_cmdset == CFI_VEND_AMD_SCS) {
for (j = 0; j < CFI_AMD_MAXCHK; ++j) {
switch (sc->sc_width) {
case 1:
val = *(ptr.x8 + i);
break;
case 2:
val = *(ptr.x16 + i / 2);
break;
case 4:
val = *(ptr.x32 + i / 4);
break;
}
if (cfi_read(sc, sc->sc_wrofs + i) == val)
break;
DELAY(10);
}
if (j == CFI_AMD_MAXCHK) {
printf("\nCFI Program Verify time out error\n");
error = ENXIO;
goto out;
}
} else {
error = cfi_wait_ready(sc, sc->sc_wrofs, start,
CFI_TIMEOUT_WRITE);
if (error)
goto out;
}
}
/* error is 0. */

View File

@ -146,10 +146,13 @@ struct cfi_qry {
#define CFI_AMD_BLOCK_ERASE 0x30
#define CFI_AMD_UNLOCK_ACK 0x55
#define CFI_AMD_ERASE_SECTOR 0x80
#define CFI_AMD_AUTO_SELECT 0x90
#define CFI_AMD_PROGRAM 0xa0
#define CFI_AMD_UNLOCK 0xaa
#define AMD_ADDR_START 0xaaa
#define AMD_ADDR_ACK 0x555
#define CFI_AMD_MAXCHK 0x10000
#endif /* _DEV_CFI_REG_H_ */

View File

@ -80,6 +80,9 @@ struct cfi_softc {
u_int sc_wrbufsz;
u_int sc_wrofs;
u_int sc_writing;
u_int sc_manid;
u_int sc_devid;
};
extern char cfi_driver_name[];