/*

  Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.

  Copyright (C) 2015, 2016  kai <kmx@posteo.net>
  Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022  Kai Mertens <kmx@posteo.net>

  This file is part of Zerocat Chipflasher.

  Zerocat Chipflasher is free software: you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  Zerocat Chipflasher is distributed in the hope that it will be
  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Zerocat Chipflasher.
  If not, see <http://www.gnu.org/licenses/>.


***/


/*

  Documentation
  =============


  Brief
  -----

  Database of supported chips. These chips are usually found on
  motherboards, which are compatible with coreboot and libreboot.


***/


struct CHIPSPEC_t chipspec[] = {
  /*

    CHIPSPEC_t Member Description
    =============================

    .id_JEDEC      = (MSB) 0x00, Manufacturer ID, Memory Type, Memory Density (LSB)
    .names         = possible chip names for specified id_JEDEC, i.e. MX25L1605D.
    .size          = total chip size in bytes
    .cmdset        = featured commands, selection
    .is_writable   = register bit info: writable?
    .is_static     = register bit info: static or volatile?
    .is_otp        = register bit info: one time programmable?
    .bits          = register bit names (maintain tabulator characters!)

  ***/


  /*
  {
    //  SPI Chip Template
    //  =================
    //
    //  - Size is: 68 bytes
    //  - Edit to your needs and add to Database
    //  - Maintain CHIPSPEC_ARRAYSIZE
    //  - Take care that compiled binary won't grow too much

    //max. 19 characters:   "0123456789012345678"
    .id_JEDEC             = ID_JEDEC_UNKNOWN,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    .names                = "",
    .size                 = SIZE_0,
    .cmdset               = BASIC_SPI,

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "" HT "" HT "" HT "" HT "" HT "" HT "" HT "",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_static            = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },
  */

  {
    /*

      EN25QH32
      ========

      Datasheets
      ----------

      www.eonssi.com, Rev. E, Issue Date: 2012/01/30


      Commands in Use
      ---------------

      0x01, Write Status Register
      0x02, Page Program
      0x03, Read Data
      0x04, Write Disable / Exit OTP Mode
      0x05, Read Status Register
      0x06, Write Enable
      0x20, Sector Erase (4K)
      0x60, Chip Erase
      0x90, Manufacturer Device ID
      0x9f, Read Identification
      0xab, Release from Deep Power-down, Read Device ID
      0xb9, Deep Power Down
      0xc7, Chip Erase
      0xd8, Block Erase (64K)


      Commands, not used
      ------------------

      0x0b, Fast Read
      0x38, EQPI
      0x3a, Enter OTP Mode
      0x3b, Dual Output Fast Read
      0x5a, Read SFDP Mode and Unique ID Number
      0x66, RSTEN
      0x99, RST
      0xbb, Dual I/O Fast Read
      0xeb, Quad I/O Fast Read
      0xff, RSTQIO


    ***/


    .id_JEDEC             = ID_JEDEC_EN25QH32,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "EN25QH32",
    .size                 = SIZE_32MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //  0: SRP/LB = Status Register Protect / OTP Lock Bit
    //  0: shall bit 6 be disabled to reduce risk of wrong usage by user?
    //
    //Index 3:      Security Register (N/A)
    //
    .bits                 = {
      "SRP/LB" HT "WHDIS" HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b11111100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b11111100,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b10000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      EN25QH64
      ========

      Datasheets
      ----------

      www.eonssi.com, Rev. J, Issue Date: 2013/12/27


      Commands in Use
      ---------------

      0x01, Write Status Register
      0x02, Page Program
      0x03, Read Data
      0x04, Write Disable / Exit OTP Mode
      0x05, Read Status Register
      0x06, Write Enable
      0x20, Sector Erase (4K)
      0x60, Chip Erase
      0x90, Manufacturer Device ID
      0x9f, Read Identification
      0xab, Release from Deep Power-down, Read Device ID
      0xb9, Deep Power Down
      0xc7, Chip Erase
      0xd8, Block Erase (64K)


      Commands, not used
      ------------------

      0x0b, Fast Read
      0x38, EQPI
      0x3a, Enter OTP Mode
      0x3b, Dual Output Fast Read
      0x5a, Read SFDP Mode and Unique ID Number
      0x66, RSTEN
      0x99, RST
      0xbb, Dual I/O Fast Read
      0xeb, Quad I/O Fast Read
      0xff, RSTQIO


    ***/


    .id_JEDEC             = ID_JEDEC_EN25QH64,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "EN25QH64",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //  0: SRP/LB = Status Register Protect / OTP Lock Bit
    //  0: shall bit 6 be disabled to reduce risk of wrong usage by user?
    //
    //Index 3:      Security Register (N/A)
    //
    .bits                 = {
      "SRP/LB" HT "WHDIS" HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b11111100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b11111100,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b10000000,
      0,
      0,
      0,
    },
  },

  {
    /*

      AT26DF161
      =========

      Datasheet
      ---------

      http://www.gaw.ru/pdf/Atmel/at26/AT26DF161.pdf


      Notes
      -----

      Status Register: Only bit 7 is modifyable by user.


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x3c, Read Sector Protection Registers


    ***/


    .id_JEDEC             = ID_JEDEC_AT26DF161,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "AT26DF161",
    .size                 = SIZE_16MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X00_NOP)
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X36_PS)
                            | (1 << X39_US)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Status and Configuration Registers
    //Security Register (N/A)
    .bits                 = {
      "SPRL" HT "-" HT "-" HT "WPP" HT "SWP1" HT "SWP0" HT "WEL" HT "BUSY",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10000000,
      0,
      0,
      0,
    },
    .is_static            = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      AT26DF321
      =========

      Datasheet
      ---------

      Version 3633E–DFLASH–10/07

      In a certain percentage of units, the Chip Erase feature may not function
      correctly and may adversely affect device operation. Therefore, it is
      recommended that the Chip Erase commands (opcodes 60h and C7h) not be used.


      Notes
      -----

      Global protect/unprotect is supported via X01_WRSR & sr_bitmask 0b10111100.
      Write 0x00111100 in order to activate global protect.
      Write 0x00000000 in order to activate global unprotect.

      NOTE: Only bit 7 of the Status Register will be modified when using
      the Write Status Register command.


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x3c, Read Sector Protection Registers
      0x60, Chip Erase
      0xc7, Chip Erase


    ***/


    .id_JEDEC             = ID_JEDEC_AT26DF321,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "AT26DF321",
    .size                 = SIZE_32MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X36_PS)
                            | (1 << X39_US)
                            | (1 << X52_BE32K)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "SPRL" HT "-" HT "EPE" HT "WPP" HT "SWP1" HT "SWP0" HT "WEL" HT "R/B",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10000000,
      0,
      0,
      0,
    },
    .is_static            = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*
      SST25VF016B
      ===========

      Datasheet
      ---------

      http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf

      The JEDEC Read ID instruction is terminated by a low to high transition
      on CE# at any time during data output. If no other command is issued
      after executing the JEDEC Read-ID instruction, issue a 00H (NOP) command
      before going into Standby Mode. --> Our NOP Flag


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x70, Enable SO to output programming status
      0x80, Disable SO to output programming status
    */


    .id_JEDEC             = ID_JEDEC_SST25VF016B,   //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "SST25VF016B",
    .size                 = SIZE_16MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X00_NOP)
                            | (1 << X02_BP)
                            | (1 << X50_EWSR)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAD_CP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "BPL" HT "AAI" HT "-" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "BUSY",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10011100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      SST25VF080B
      ===========

      Datasheet
      ---------

      Version DS20005045C


      Notes
      -----

      After power-up, the BPL bit is reset to 0.
      Default at power-up for BP0, BP1 and BP2 is 1.

      The JEDEC Read ID instruction is terminated by a low to high transition
      on CE# at any time during data output.


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x70, Enable SO to output programming status
      0x80, Disable SO to output programming status


    ***/


    .id_JEDEC             = ID_JEDEC_SST25VF080B,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "SST25VF080B",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X50_EWSR)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAD_CP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "BPL" HT "AAI" HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "BUSY",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10011100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b00000000,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      MX25L8005
      =========

      Datasheet
      ---------

      Version REV. 2.2, OCT. 23, 2008

      Clock Frequency for READ instructions: min. 1KHz
      According to datasheet, the chip supports page programming only.


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x52, Erase Block 32K (would address a 64k block instead)


    ***/


    .id_JEDEC             = ID_JEDEC_MX25L8005,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "MX25L8005",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "SRWD" HT "-" HT "-" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10011100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b10011100,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      MX25L1605D, MX25L1606E
      ======================

      Datasheets
      ----------

      MX25L1605D:
       http://www.macronix.com/Lists/Datasheet/Attachments/4978/MX25L6405D,%203V,%2064Mb,%20v1.5.pdf
       Version REV. 1.5, APR. 29, 2009

       Some Bits are greyed out without explication.
       This chip seems to NOT have bits CP, BP3 in Status Register.

      MX25L1606E:
       P/N: PM1548 -- REV. 1.5, NOV. 06, 2013


      Notes
      -----

      MX25L1605D:
       Command XAD_CP doesn't work.
       Bits LDSO and SOTPI in SCUR seem to be always zero.
       Commands ENSO and EXSO don't work, is there no OTP region accessible?


      Commands, not used
      ------------------

      MX25L1605D:
      0x0b, Read High Frequency
      0x2f, Write Security Register
      0x70, Enable SO to output programming status
      0x80, Disable SO to output programming status
      0xad, Continuously Program Mode
      0xb1, Enter Secured OTP
      0xbb, Read Dual I/O
      0xc1, Exit Secured OTP
      0xef, REMS Dual I/O

      MX25L1606E:
      0x0b, Fast Read
      0x2f, Write SCUR
      0x3b, DREAD
      0x52, Block Erase
      0x5a, Read SFDP
      0xb1, ENSO
      0xc1, EXSO


    ***/


    .id_JEDEC             = ID_JEDEC_MX25L1605D_06E,  //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "MX25L1605D/06E",
    .size                 = SIZE_16MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X2B_RDSCUR)
                            | (1 << X2F_WRSCUR)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB1_ENSO)
                            | (1 << XC1_EXSO)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //
    //Index 3:      Security Register (accessible via RDSCUR and WRSCUR)
    //  LDSO = Lock Down Secured 512bit OTP Area, OTP
    //  SOTP = Secure OTP Indicator Bit, 1 = factory lock
    //
    .bits                 = {
//    "SRWD"  HT "CP" HT "-"    HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "WIP"  ,   //Register 0: MX25L1605D
      "SRWD"  HT "-"  HT "-"    HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "WIP"  ,   //Register 0: MX25L1606E
      NULL,                                                                           //Register 1
      NULL,                                                                           //Register 2
      "-"     HT "-"  HT "-"    HT "-"    HT "-"    HT "-"    HT "LDSO" HT "SOTP" ,   //Security Register
    },
    .is_writable          = {
//    0b10011100,       //Register 0: MX25L1605D: according to datasheets, bit5 should be writable
      0b10011100,       //Register 0: MX25L1606E: according to datasheets, bit5 should be writable
      0,
      0,
      0b00000010,       //Security Register
    },
    .is_static            = {
//    0b10011100,       //Register 0: MX25L1605D: according to datasheets, bit5 is non-volatile
      0b10011100,       //Register 0: MX25L1606E: according to datasheets, bit5 is non-volatile
      0,
      0,
      0b00000011,       //Security Register
    },
    .is_otp               = {
//    0b00000000,       //Register 0: MX25L1605D: according to datasheets, bit5 is non-volatile
      0b00000000,       //Register 0: MX25L1606E: according to datasheets, bit5 is non-volatile
      0,
      0,
      0b00000010,       //Security Register
    },

  },

  {
    /*

      MX25L3205D, MX25L3206E
      ======================

      Datasheets
      ----------

      MX25L3205D: Same as MX25L1605D.
      MX25L3206E: P/N: PM1568 --- REV. 1.5, DEC. 04, 2013


      Notes
      -----

      Unfortunately, both chips have the same JEDEC ID 0xc22016 but their command sets differ.
      Let's use congruent specs only!


      Commands, not used
      ------------------

      MX25L3205D:
      0x0b, Read High Frequency
      0x2f, Write Security Register
      0x70, Enable SO to output programming status
      0x80, Disable SO to output programming status
      0xad, CP Continuous Programming
      0xb1, Enter Secured OTP
      0xbb, Read Dual I/O
      0xc1, Exit Secured OTP
      0xef, REMS Dual I/O

      MX25L3206E:
      0x0b, Read High Frequency
      0x2f, Write Security Register
      0x3b, DREAD
      0x52, BE64K
      0x5a, Read SFDP
      0xb1, Enter Secured OTP
      0xc1, Exit Secured OTP


    ***/


    .id_JEDEC             = ID_JEDEC_MX25L3205D_06E,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "MX25L3205D/06E",
    .size                 = SIZE_32MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X2B_RDSCUR)
                            | (1 << X2F_WRSCUR)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB1_ENSO)
                            | (1 << XC1_EXSO)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (accessible via RDSCUR and WRSCUR)
    .bits                 = {
//    "SRWD"  HT "CP" HT "BP3"  HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "WIP"  ,   //Register 1: MX25L3205D
      "SRWD"  HT "-"  HT "BP3"  HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "WIP"  ,   //Register 1: MX25L3206E
      NULL,                                                                           //Register 2
      NULL,                                                                           //Register 3
      "-"     HT "-"  HT "-"    HT "-"    HT "-"    HT "-"    HT "LDSO" HT "SOTP" ,   //Security Register
    },
    .is_writable          = {
//    0b10111100,       //Register 1: MX25L3205D
      0b10111100,       //Register 1: MX25L3206E
      0,
      0,
      0b00000010,
    },
    .is_static            = {
//    0b10111100,       //Register 1: MX25L3205D
      0b10111100,       //Register 1: MX25L3206E
      0,
      0,
      0b00000011,
    },
    .is_otp               = {
//    0b00000000,       //Register 1: MX25L3205D
      0b00000000,       //Register 1: MX25L3206E
      0,
      0,
      0b00000010,
    },

  },

  {
    /*

      MX25L6405D, MX25L6406E, MX25L6445E
      ==================================

      Datasheets
      ----------

      MX25L6405D: Same as MX25L1605D.
      MX25L6406E: P/N: PM1577 --- REV. 1.8, NOV. 12, 2013
      MX25L6445E: P/N: PM1736 --- REV. 1.8, DEC. 26, 2011


      Notes
      -----

      Unfortunately, all chips have the same JEDEC ID 0xc22017 but
      their command sets differ. Let's use congruent specs only!


      Commands, not used
      ------------------

      MX25L6405D:
      0x0b, Read High Frequency
      0x2f, Write Security Register
      0x70, Enable SO to output programming status
      0x80, Disable SO to output programming status
      0xad, CP Continuous Programming
      0xb1, Enter Secured OTP
      0xbb, Read Dual I/O
      0xc1, Exit Secured OTP
      0xef, REMS Dual I/O

      MX25L6406E:
      0x0b, Read High Frequency
      0x2f, Write Security Register
      0x3b, DREAD
      0x5a, Read SFDP
      0x52, BE32K
      0xb1, Enter Secured OTP
      0xc1, Exit Secured OTP

      MX25L6445E:
      0x0d, FASTDTRD (fast Double Transfer read)
      0xbd, 2DTRD (dual I/O Double Transfer read)
      0xed, 4DTRD (quad I/O Double Transfer read)
      0x0b, FAST READ (fast read data)
      0x5a, RDSFDP (read SFDP)
      0xbb, 2READ (2x I/O read command)
      0xeb, 4READ (4x I/O read command)
      0x38, 4PP (quad page program)
      0x52, BE 32K (block erase 32K)
      0xAD, CP (continuously program mode)
      0xef, REMS2 (read ID for 2x I/O mode)
      0xdf, REMS4 (read ID for 4x I/O mode)
      0xcf, REMS4D (read ID for 4x I/O Double Transfer mode)
      0xb1, ENSO (enter secured OTP)
      0xc1, EXSO (exit secured OTP)
      0x2f, WRSCUR (write security register)
      0x70, ESRY (enable SO to output RY/BY#)
      0x80, DSRY (disable SO to output RY/BY#)
      0x30, CLSR (Clear SR Fail Flags)
      0xa3, HPM (High Performance Enable)
      0x68, WPSEL (write protection selection)
      0x36, SBLK (single block lock)
      0x39, SBULK (single block unlock)
      0x3c, RDBLOCK (block protect read)
      0x7e, GBLK (gang block lock)
      0x98, GBULK (gang block unlock)


    ***/


    .id_JEDEC             = ID_JEDEC_MX25L6445E_06E_05D,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "MX25L6445E/06E/05D",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X2B_RDSCUR)
                            | (1 << X2F_WRSCUR)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB1_ENSO)
                            | (1 << XC1_EXSO)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (accessible via RDSCUR and WRSCUR)
    .bits                 = {
//    "SRWD"  HT "CP"  HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",         //Register 1 MX25L6405D
//    "SRWD"  HT "-"   HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",         //Register 1 MX25L6406E
      "SRWD"  HT "QE"  HT "BP3" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "WIP",         //Register 1 MX25L6445E
      NULL,                                                                           //Register 2
      NULL,                                                                           //Register 3
//    "-"     HT "-"      HT "-"      HT "-"  HT "-"  HT "-"  HT "LDSO" HT "SOTP",    //Security Register MX25L6405D
//    "-"     HT "-"      HT "-"      HT "-"  HT "-"  HT "-"  HT "LDSO" HT "SOTP",    //Security Register MX25L6406E
      "WPSEL" HT "E_FAIL" HT "P_FAIL" HT "CP" HT "-"  HT "-"  HT "LDSO" HT "SOTP",    //Security Register MX25L6445E, bit7 and bit1 are OTP
    },
    .is_writable          = {
//    0b11111100,   //Register 1 MX25L6405D
//    0b10111100,   //Register 1 MX25L6406E
      0b11111100,   //Register 1 MX25L6445E
      0,            //Register 2
      0,            //Register 3
//    0b00000010,   //Security Register MX25L6405D
//    0b00000010,   //Security Register MX25L6406E
      0b10000010,   //Security Register MX25L6445E
    },
    .is_static            = {
//    0b11111100,   //Register 1 MX25L6405D
//    0b10111100,   //Register 1 MX25L6406E
      0b11111100,   //Register 1 MX25L6445E
      0,            //Register 2
      0,            //Register 3
//    0b00000011,   //Security Register MX25L6405D
//    0b00000011,   //Security Register MX25L6406E
      0b10000011,   //Security Register MX25L6445E
    },
    .is_otp               = {
//    0b00000000,   //Register 1 MX25L6405D
//    0b00000000,   //Register 1 MX25L6406E
      0b00000000,   //Register 1 MX25L6445E
      0,            //Register 2
      0,            //Register 3
//    0b00000010,   //Security Register MX25L6405D
//    0b00000010,   //Security Register MX25L6406E
      0b10000010,   //Security Register MX25L6445E
    },

  },

  {
    /*

      MX25L12835E
      ===========

      Datasheets
      ----------

      MX25L12835E: P/N: PM1676 – REV. 1.0, APR. 25, 2011


      Commands, not used
      ------------------

      0x00, NOP No Operation
      0x0b, FAST READ Fast Read Data
      0x2f, WRSCUR Write Security Register
      0x30, CLSR Clear SR Fail Flags
      0x36, SBLK Single Block Lock
      0x38, 4PP Quad Page Program
      0x39, SBULK Single Block Unlock
      0x3b, DREAD 1I / 2O Read Command
      0x3c, RDBLOCK Block Protect Read
      0x66, RSTEN Reset Enable
      0x68, WPSEL Write Protect Selection
      0x6b, QREAD
      0x70, ESRY Enable SO to output programming status
      0x77, SPL Set Burst Length
      0x7e, GBLK Gang Block Lock
      0x80, DSRY Disable SO to output programming status
      0x98, GBULK Gang Block Unlock
      0x99, RST Reset Memory
      0xb1, ENSO Enter Secured OTP
      0xbb, 2READ 2x I/O Read Command
      0xc1, EXSO Exit Secured OTP
      0xdf, REMS4 Quad I/O
      0xe7, W4READ
      0xeb, 4READ 4x I/O Read Command
      0xef, REMS2 Dual I/O


    ***/


    .id_JEDEC             = ID_JEDEC_MX25L12835E,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "MX25L12835E",
    .size                 = SIZE_128MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X2B_RDSCUR)
                            | (1 << X2F_WRSCUR)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XAD_CP)
                            | (1 << XB1_ENSO)
                            | (1 << XC1_EXSO)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (accessible via RDSCUR and WRSCUR)
    //  bit7, bit1 are OTP
    .bits                 = {
      "SRWD"  HT "QE"     HT "BP3"    HT "BP2"      HT "BP1"  HT "BP0"  HT "WEL"  HT "WIP"  ,
      NULL,
      NULL,
      "WPSEL" HT "E_FAIL" HT "P_FAIL" HT "CP_MODE"  HT "-"    HT "-"    HT "LDSO" HT "SOTP" ,
    },
    .is_writable          = {
      0b11111100,
      0,
      0,
      0b10000010,
    },
    .is_static            = {
      0b11111100,
      0,
      0,
      0b10000011,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0b10000010,   //bit7, bit1 are OTP
    },

  },

  {
    /*

      W25X40
      ======

      SERIAL FLASH MEMORY WITH 4KB SECTORS AND DUAL OUTPUT SPI


      Datasheet
      ---------

      Publication Release Date: September 22, 2006;
      Preliminary - Revision I


      Notes
      -----

      Pin #WP has no effect if SRP-Bit is zero (default).
      Other Chip Sizes: 1MBit (0xEF3011), 2MBit (0xEF3012), 8MBit (0xEF3014).


      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency

      Dual SPI:
      0x3b, Fast Read Dual Output


    ***/


    .id_JEDEC             = ID_JEDEC_W25X40,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "W25X40",
    .size                 = SIZE_4MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X90_REMS)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "SRP" HT "-" HT "TB" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "BUSY",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10111100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b10111100,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      W25X64
      ======

      Datasheet
      ---------

      Notes
      -----

      Commands, not used
      ------------------

      Standard SPI:
      0x0b, Read High Frequency


    ***/


    .id_JEDEC             = ID_JEDEC_W25X64,    //!< 0x00, Manufacturer ID, Memory Type, Memory Density
    //max. 19 characters:   "0123456789012345678"
    .names                = "W25X64",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_BP)
                            | (1 << X02_PP)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //Index 3:      Security Register (N/A)
    .bits                 = {
      "SRP" HT "-" HT "TB" HT "BP2" HT "BP1" HT "BP0" HT "WEL" HT "BUSY",
      NULL,
      NULL,
      NULL,
    },
    .is_writable          = {
      0b10111100,
      0,
      0,
      0,
    },
    .is_static            = {
      0b10111100,
      0,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0,
      0,
      0,
    },

  },

  {
    /*

      W25Q32FV
      ========

      V = 2.7V to 3.6V
      Q = Green Package with QE=1 in Status Register 2


      Datasheet
      ---------

      https://www.winbond.com/resource-files/w25q32fv%20revi%2010202015.pdf

      WARNING: If the /WP or /HOLD pins are tied directly to the power
      supply or ground during standard SPI or Dual SPI operation, the QE
      bit should never be set to a 1.


      Notes
      -----

      We are not using X50_WRSR, thus using static SR bits!


      Commands, not used:
      -------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x32, Quad Page Program
      0x36, Individual Block Lock
      0x38, Enter QPI Mode
      0x39, Individual Block Unlock
      0x3d, Read Block Lock
      0x42, Program Security Register
      0x44, Erase Security Register
      0x48, Read Security Register
      0x4b, Read Unique ID
      0x50, Write Status Register Bits as Volatiles
      0x5a, Read SFDP Register
      0x66, Enable Reset
      0x75, Erase/ Program Suspend
      0x7a, Erase/ Program Resume
      0x7e, Global Block Lock
      0x98, Global Block Unlock
      0x99, Reset Device

      Dual SPI:
      0x3b, Read High Frequency Dual Output
      0x92, Manufaturer ID, Device ID, Dual I/O
      0xbb, Read High Frequency Dual I/O

      Quad SPI:
      0x0c, Burst Read With Wrap
      0x6b, Read High Frequency Quad Output
      0x77, Set Burst With Wrap
      0x94, Manufacturer ID, Device ID, Quad I/O
      0xc0, Set Read Parameters
      0xe3, Octal Word Read Quad I/O
      0xe7, Word Read Quad I/O
      0xeb, Read High Frequency Quad I/O
      0xff, Exit QPI Mode


    ***/


    .id_JEDEC             = ID_JEDEC_W25Q32FV,    //!< 0x00ef6016 in QPI mode
    //max. 19 characters:   "0123456789012345678"
    .names                = "W25Q32FV",
    .size                 = SIZE_32MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_PP)
                            | (1 << X11_WRSR3)
                            | (1 << X15_RDSR3)
                            | (1 << X31_WRSR2)
                            | (1 << X35_RDSR2)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2:   Status and Configuration Registers
    //  1: S15 = SUS, status only
    //  1: S13..11 = OTP Lock Bits!
    //
    //Index 3:      Security Register (N/A)
    //
    .bits                 = {
      "SRP0"    HT "SEC"  HT "TB"   HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "BUSY" ,   //S7..S0
      "SUS"     HT "CMP"  HT "LB3"  HT "LB2"  HT "LB1"  HT "-"    HT "QE"   HT "SRP1" ,   //S15..S8
      "HLD/RST" HT "DRV1" HT "DRV0" HT "-"    HT "-"    HT "WPS"  HT "-"    HT "-"    ,   //S23..S16
      NULL,
    },
    .is_writable          = {
      0b11111100,
      0b01111011,
      0b11100100,
      0,
    },
    .is_static            = {
      0b11111100,
      0b01111011,
      0b11100100,
      0,
    },
    .is_otp               = {
      0b00000000,
      0b00111000,
      0b00000000,
      0,
    },

  },

  {
    /*

      W25Q64FV
      ========

      V = 2.7V to 3.6V
      Q = Green Package with QE=1 in Status Register 2


      Datasheet
      ---------

      https://www.winbond.com/resource-files/w25q64fv revr 10262016.pdf

      WARNING: If the /WP or /HOLD pins are tied directly to the power
      supply or ground during standard SPI or Dual SPI operation, the QE
      bit should never be set to a 1.


      Notes
      -----

      - We are not using X50_WRSR, thus using static SR bits!
      - How to access Register 1?


      Commands, not used:
      -------------------

      Standard SPI:
      0x0b, Read High Frequency
      0x38, Enter QPI Mode
      0x42, Program Security Register
      0x44, Erase Security Register
      0x48, Read Security Register
      0x4b, Read Unique ID
      0x50, Write Status Register Bits as Volatiles
      0x5a, Read SFDP Register
      0x66, Enable Reset
      0x75, Erase/ Program Suspend
      0x7a, Erase/ Program Resume
      0x99, Reset Device

      Dual SPI:
      0x3b, Read High Frequency Dual Output
      0x92, Manufaturer ID, Device ID, Dual I/O
      0xbb, Read High Frequency Dual I/O

      Quad SPI:
      0x0c, Burst Read With Wrap
      0x32, Quad Page Program
      0x6b, Read High Frequency Quad Output
      0x77, Set Burst With Wrap
      0x94, Manufacturer ID, Device ID, Quad I/O
      0xc0, Set Read Parameters
      0xe3, Octal Word Read Quad I/O
      0xe7, Word Read Quad I/O
      0xeb, Read High Frequency Quad I/O
      0xff, Exit QPI Mode


    ***/


    .id_JEDEC             = ID_JEDEC_W25Q64FV,    //!< 0x00ef6017 in QPI mode
    //max. 19 characters:   "0123456789012345678"
    .names                = "W25Q64FV",
    .size                 = SIZE_64MBIT,
    .cmdset               = BASIC_SPI
                            | (1 << X02_PP)
                            | (1 << X35_RDSR2)
                            | (1 << X52_BE32K)
                            | (1 << X60_CE)
                            | (1 << X90_REMS)
                            | (1 << XAB_RES)
                            | (1 << XAB_RDP)
                            | (1 << XB9_DP)
                            | (1 << XC7_CE),

    //Index 0..2: Status and Configuration Registers
    //  1: S15 = SUS, is status only
    //  1: S13..11 = OTP Lock Bits
    //
    //Index 3:    Security Register (N/A)
    //
    .bits                 = {
      "SRP0"  HT "SEC"  HT "TB"   HT "BP2"  HT "BP1"  HT "BP0"  HT "WEL"  HT "BUSY",    //Register 1: S7..S0
      "SUS"   HT "CMP"  HT "LB3"  HT "LB2"  HT "LB1"  HT "-"    HT "QE"   HT "SRP1",    //Register 2: S15..S8
      NULL,                                             //Register 3
      NULL,                                             //Security Register
    },
    .is_writable          = {
      0b11111100,     //Register 1
      0b01111011,     //Register 2
      0,              //Register 3
      0,              //Security Register
    },
    .is_static            = {
      0b11111100,
      0b01111011,
      0,
      0,
    },
    .is_otp               = {
      0b00000000,
      0b00111000,
      0,
      0,
    },

  },
};
