Author: allanjude
Date: Sun Mar 24 06:28:25 2019
New Revision: 345464
URL: https://svnweb.freebsd.org/changeset/base/345464

Log:
  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 <yamori...@yahoo.co.jp>
  Reviewed by:  imp, sbruno
  Differential Revision:        https://reviews.freebsd.org/D14279

Modified:
  head/sys/dev/cfi/cfi_core.c
  head/sys/dev/cfi/cfi_reg.h
  head/sys/dev/cfi/cfi_var.h

Modified: head/sys/dev/cfi/cfi_core.c
==============================================================================
--- head/sys/dev/cfi/cfi_core.c Sat Mar 23 23:44:40 2019        (r345463)
+++ head/sys/dev/cfi/cfi_core.c Sun Mar 24 06:28:25 2019        (r345464)
@@ -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. */

Modified: head/sys/dev/cfi/cfi_reg.h
==============================================================================
--- head/sys/dev/cfi/cfi_reg.h  Sat Mar 23 23:44:40 2019        (r345463)
+++ head/sys/dev/cfi/cfi_reg.h  Sun Mar 24 06:28:25 2019        (r345464)
@@ -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_ */

Modified: head/sys/dev/cfi/cfi_var.h
==============================================================================
--- head/sys/dev/cfi/cfi_var.h  Sat Mar 23 23:44:40 2019        (r345463)
+++ head/sys/dev/cfi/cfi_var.h  Sun Mar 24 06:28:25 2019        (r345464)
@@ -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[];
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to