From 3811a28a607e40f5291e45d7c57da6b0700fb821 Mon Sep 17 00:00:00 2001 From: Pai Peng Date: Wed, 3 Jul 2019 10:44:14 -0700 Subject: Add the functions to read and write EAR. EAR (extended address register) is used to access addresses above 16MiB when 3-byte address mode is used. These two functions allow to write to and read from EAR to set up what addresses to access in 3-byte mode. For example, for a 64MiB EEPROM: EAR value Addresses to access 0 0x0000000 - 0x0FFFFFF 1 0x1000000 - 0x1FFFFFF 2 0x2000000 - 0x2FFFFFF 3 0x3000000 - 0x3FFFFFF BUG=b:132252340 BRANCH=none TEST=manual Testing: 1. Writing to EAR returns successfully. 2. Writing different values to EAR, verify that accessing EERPOM in 3-byte mode is to the correct address, e.g., when EAR=2, accessing 0x0FFFFFF is actually to 0x2FFFFFF. Change-Id: I2a8bde7fc4b9069afc80a81042fb47359bffa015 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1688150 Reviewed-by: Daisuke Nojiri Tested-by: Pai Peng Commit-Queue: Pai Peng --- common/spi_nor.c | 97 ++++++++++++++++++++++++++++++++++++++++++------------- include/spi_nor.h | 34 ++++++++++++------- 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/common/spi_nor.c b/common/spi_nor.c index 3bec5cd6a6..09f5b28bdd 100644 --- a/common/spi_nor.c +++ b/common/spi_nor.c @@ -17,10 +17,10 @@ #include "watchdog.h" #ifdef CONFIG_SPI_NOR_DEBUG -#define DEBUG_CPRINTS_DEVICE(spi_nor_device, string, args...) \ - cprints(CC_SPI, "SPI NOR %s: " string, spi_nor_device->name, ## args) +#define CPRINTS(dev, string, args...) \ + cprints(CC_SPI, "SPI NOR %s: " string, (dev)->name, ## args) #else -#define DEBUG_CPRINTS_DEVICE(spi_nor_device, string, args...) +#define CPRINTS(dev, string, args...) #endif /* Time to sleep while serial NOR flash write is in progress. */ @@ -89,6 +89,62 @@ static int spi_nor_write_enable(const struct spi_nor_device_t *spi_nor_device) return rv; } +/** + * Read from the extended address register. + * @param spi_nor_device The Serial NOR Flash device to use. + * @param value The value to read to. + * @return ec_error_list (non-zero on error and timeout). + */ +static int spi_nor_read_ear(const struct spi_nor_device_t *spi_nor_device, + uint8_t *value) +{ + uint8_t command = SPI_NOR_OPCODE_RDEAR; + + return spi_transaction(&spi_devices[spi_nor_device->spi_master], + &command, sizeof(command), value, 1); +} + +int spi_nor_write_ear(const struct spi_nor_device_t *spi_nor_device, + const uint8_t value) +{ + uint8_t buf[2]; + int rv; + uint8_t ear; + + mutex_lock(&driver_mutex); + + rv = spi_nor_write_enable(spi_nor_device); + if (rv) { + CPRINTS(spi_nor_device, "Failed to write enable"); + goto err_free; + } + + buf[0] = SPI_NOR_OPCODE_WREAR; + buf[1] = value; + + rv = spi_transaction(&spi_devices[spi_nor_device->spi_master], + buf, sizeof(buf), NULL, 0); + if (rv) { + CPRINTS(spi_nor_device, "Failed to write EAR, rv=%d", rv); + goto err_free; + } + + rv = spi_nor_read_ear(spi_nor_device, &ear); + if (rv) + goto err_free; + + if (ear != value) { + CPRINTS(spi_nor_device, + "Write EAR error: write=%d, read=%d", value, ear); + rv = EC_ERROR_UNKNOWN; /* WEL not set but should be. */ + goto err_free; + } + +err_free: + mutex_unlock(&driver_mutex); + return rv; +} + /** * Block until the Serial NOR Flash clears the BUSY/WIP bit in its status reg. */ @@ -232,7 +288,7 @@ static int locate_sfdp_basic_parameter_table( * compatible, older basic parameter tables which are compatible with * this driver in the parameter headers. */ if (!SFDP_HEADER_DW1_SFDP_SIGNATURE_VALID(dw1)) { - DEBUG_CPRINTS_DEVICE(spi_nor_device, "SFDP signature invalid"); + CPRINTS(spi_nor_device, "SFDP signature invalid"); return EC_ERROR_UNKNOWN; } @@ -240,15 +296,14 @@ static int locate_sfdp_basic_parameter_table( SFDP_GET_BITFIELD(SFDP_HEADER_DW2_SFDP_MAJOR, dw2); *out_sfdp_minor_rev = SFDP_GET_BITFIELD(SFDP_HEADER_DW2_SFDP_MINOR, dw2); - DEBUG_CPRINTS_DEVICE(spi_nor_device, "SFDP v%d.%d discovered", - *out_sfdp_major_rev, *out_sfdp_minor_rev); + CPRINTS(spi_nor_device, "SFDP v%d.%d discovered", + *out_sfdp_major_rev, *out_sfdp_minor_rev); /* NPH is 0-based, so add 1. */ number_parameter_headers = SFDP_GET_BITFIELD(SFDP_HEADER_DW2_NPH, dw2) + 1; - DEBUG_CPRINTS_DEVICE(spi_nor_device, - "There are %d SFDP parameter headers", - number_parameter_headers); + CPRINTS(spi_nor_device, "There are %d SFDP parameter headers", + number_parameter_headers); /* Search for the newest, compatible basic flash parameter table. */ *out_table_major_rev = 0; @@ -302,15 +357,13 @@ static int locate_sfdp_basic_parameter_table( } if (!table_found) { - DEBUG_CPRINTS_DEVICE( - spi_nor_device, + CPRINTS(spi_nor_device, "No compatible Basic Flash Parameter Table found"); return EC_ERROR_UNKNOWN; } - DEBUG_CPRINTS_DEVICE(spi_nor_device, - "Using Basic Flash Parameter Table v%d.%d", - *out_sfdp_major_rev, *out_sfdp_minor_rev); + CPRINTS(spi_nor_device, "Using Basic Flash Parameter Table v%d.%d", + *out_sfdp_major_rev, *out_sfdp_minor_rev); return EC_SUCCESS; } @@ -489,8 +542,7 @@ int spi_nor_init(void) mutex_lock(&driver_mutex); spi_nor_device->capacity = capacity; spi_nor_device->page_size = page_size; - DEBUG_CPRINTS_DEVICE( - spi_nor_device, + CPRINTS(spi_nor_device, "Updated to SFDP params: %dKiB w/ %dB pages", spi_nor_device->capacity >> 10, spi_nor_device->page_size); @@ -549,9 +601,8 @@ int spi_nor_set_4b_mode(struct spi_nor_device_t *spi_nor_device, enter_4b_addressing_mode; } - DEBUG_CPRINTS_DEVICE(spi_nor_device, - "Entered %s Addressing Mode", - enter_4b_addressing_mode ? "4-Byte" : "3-Byte"); + CPRINTS(spi_nor_device, "Entered %s Addressing Mode", + enter_4b_addressing_mode ? "4-Byte" : "3-Byte"); /* Release the driver mutex. */ mutex_unlock(&driver_mutex); @@ -681,10 +732,10 @@ int spi_nor_erase(const struct spi_nor_device_t *spi_nor_device, } if (!read_left) { /* Sector/block already erased. */ - DEBUG_CPRINTS_DEVICE(spi_nor_device, - "Skipping erase [%x:%x] " - "(already erased)", - offset, erase_size); + CPRINTS(spi_nor_device, + "Skipping erase [%x:%x] " + "(already erased)", + offset, erase_size); offset += erase_size; size -= erase_size; continue; diff --git a/include/spi_nor.h b/include/spi_nor.h index 4bf8d853f2..77347399d7 100644 --- a/include/spi_nor.h +++ b/include/spi_nor.h @@ -61,16 +61,18 @@ extern const unsigned int spi_nor_devices_used; /* Industry standard Serial NOR Flash opcodes. All other opcodes are part * specific and require SFDP discovery. */ -#define SPI_NOR_OPCODE_WRITE_STATUS 0x01 /* Write Status Register (1 Byte) */ -#define SPI_NOR_OPCODE_PAGE_PROGRAM 0x02 /* Page program */ -#define SPI_NOR_OPCODE_SLOW_READ 0x03 /* Read data (low frequency) */ +#define SPI_NOR_OPCODE_WRITE_STATUS 0x01 /* Write Status Register (1 Byte) */ +#define SPI_NOR_OPCODE_PAGE_PROGRAM 0x02 /* Page program */ +#define SPI_NOR_OPCODE_SLOW_READ 0x03 /* Read data (low frequency) */ #define SPI_NOR_OPCODE_WRITE_DISABLE 0x04 -#define SPI_NOR_OPCODE_READ_STATUS 0x05 /* Read Status Register */ -#define SPI_NOR_OPCODE_WRITE_ENABLE 0x06 -#define SPI_NOR_OPCODE_FAST_READ 0x0b /* Read data (high frequency) */ -#define SPI_NOR_OPCODE_SFDP 0x5a /* Read JEDEC SFDP */ -#define SPI_NOR_OPCODE_JEDEC_ID 0x9f /* Read JEDEC ID */ -#define SPI_NOR_OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define SPI_NOR_OPCODE_READ_STATUS 0x05 /* Read Status Register */ +#define SPI_NOR_OPCODE_WRITE_ENABLE 0x06 +#define SPI_NOR_OPCODE_FAST_READ 0x0b /* Read data (high frequency) */ +#define SPI_NOR_OPCODE_SFDP 0x5a /* Read JEDEC SFDP */ +#define SPI_NOR_OPCODE_JEDEC_ID 0x9f /* Read JEDEC ID */ +#define SPI_NOR_OPCODE_WREAR 0xc5 /* Write extended address register */ +#define SPI_NOR_OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define SPI_NOR_OPCODE_RDEAR 0xc8 /* Read extended address register */ /* Flags for SPI_NOR_OPCODE_READ_STATUS */ #define SPI_NOR_STATUS_REGISTER_WIP BIT(0) /* Write in progres */ @@ -78,13 +80,13 @@ extern const unsigned int spi_nor_devices_used; /* If needed in the future this driver can be extended to discover SFDP * advertised erase sizes and opcodes for SFDP v1.0+. */ -#define SPI_NOR_DRIVER_SPECIFIED_OPCODE_4KIB_ERASE 0x20 +#define SPI_NOR_DRIVER_SPECIFIED_OPCODE_4KIB_ERASE 0x20 #define SPI_NOR_DRIVER_SPECIFIED_OPCODE_64KIB_ERASE 0xd8 /* If needed in the future this driver can be extended to discover 4B entry and * exit methods for SFDP v1.5+. */ #define SPI_NOR_DRIVER_SPECIFIED_OPCODE_ENTER_4B 0xb7 -#define SPI_NOR_DRIVER_SPECIFIED_OPCODE_EXIT_4B 0xe9 +#define SPI_NOR_DRIVER_SPECIFIED_OPCODE_EXIT_4B 0xe9 /* JEDEC JEP106AR specifies 9 Manufacturer ID banks, read 12 to be sure. */ #define SPI_NOR_JEDEC_ID_BANKS 12 @@ -168,4 +170,14 @@ int spi_nor_erase(const struct spi_nor_device_t *spi_nor_device, int spi_nor_write(const struct spi_nor_device_t *spi_nor_device, uint32_t offset, size_t size, const uint8_t *data); +/** + * Write to the extended address register. + * @param spi_nor_device The Serial NOR Flash device to use. + * @param value The value to write. + * @return ec_error_list (non-zero on error and timeout). + */ +int spi_nor_write_ear(const struct spi_nor_device_t *spi_nor_device, + const uint8_t value); + + #endif /* __CROS_EC_SPI_NOR_H */ -- cgit v1.2.1