summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPai Peng <paipeng@google.com>2019-07-03 10:44:14 -0700
committerCommit Bot <commit-bot@chromium.org>2019-07-17 20:18:55 +0000
commit3811a28a607e40f5291e45d7c57da6b0700fb821 (patch)
tree0c7c0dc2777940a600c55aded6df4d8b542f80d3
parente425f0d7ef7f6e56b783e20a35709fbb1cc2e2b7 (diff)
downloadchrome-ec-3811a28a607e40f5291e45d7c57da6b0700fb821.tar.gz
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 <dnojiri@chromium.org> Tested-by: Pai Peng <paipeng@google.com> Commit-Queue: Pai Peng <paipeng@google.com>
-rw-r--r--common/spi_nor.c97
-rw-r--r--include/spi_nor.h34
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. */
@@ -90,6 +90,62 @@ static int spi_nor_write_enable(const struct spi_nor_device_t *spi_nor_device)
}
/**
+ * 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.
*/
static int spi_nor_wait(const struct spi_nor_device_t *spi_nor_device)
@@ -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 */