|
@@ -312,6 +312,8 @@ struct flash_info {
|
|
|
int (*config)(struct stfsm *);
|
|
|
};
|
|
|
|
|
|
+static int stfsm_n25q_config(struct stfsm *fsm);
|
|
|
+
|
|
|
static struct flash_info flash_types[] = {
|
|
|
/*
|
|
|
* ST Microelectronics/Numonyx --
|
|
@@ -354,9 +356,10 @@ static struct flash_info flash_types[] = {
|
|
|
FLASH_FLAG_WRITE_1_2_2 | \
|
|
|
FLASH_FLAG_WRITE_1_1_4 | \
|
|
|
FLASH_FLAG_WRITE_1_4_4)
|
|
|
- { "n25q128", 0x20ba18, 0, 64 * 1024, 256, N25Q_FLAG, 108, NULL },
|
|
|
+ { "n25q128", 0x20ba18, 0, 64 * 1024, 256, N25Q_FLAG, 108,
|
|
|
+ stfsm_n25q_config },
|
|
|
{ "n25q256", 0x20ba19, 0, 64 * 1024, 512,
|
|
|
- N25Q_FLAG | FLASH_FLAG_32BIT_ADDR, 108, NULL },
|
|
|
+ N25Q_FLAG | FLASH_FLAG_32BIT_ADDR, 108, stfsm_n25q_config },
|
|
|
|
|
|
/*
|
|
|
* Spansion S25FLxxxP
|
|
@@ -493,6 +496,8 @@ static struct seq_rw_config n25q_read4_configs[] = {
|
|
|
{0x00, 0, 0, 0, 0, 0x00, 0, 0},
|
|
|
};
|
|
|
|
|
|
+static struct stfsm_seq stfsm_seq_read; /* Dynamically populated */
|
|
|
+static struct stfsm_seq stfsm_seq_write; /* Dynamically populated */
|
|
|
static struct stfsm_seq stfsm_seq_en_32bit_addr;/* Dynamically populated */
|
|
|
|
|
|
static struct stfsm_seq stfsm_seq_read_jedec = {
|
|
@@ -840,6 +845,71 @@ static int stfsm_search_prepare_rw_seq(struct stfsm *fsm,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int stfsm_n25q_config(struct stfsm *fsm)
|
|
|
+{
|
|
|
+ uint32_t flags = fsm->info->flags;
|
|
|
+ uint8_t vcr;
|
|
|
+ int ret = 0;
|
|
|
+ bool soc_reset;
|
|
|
+
|
|
|
+ /* Configure 'READ' sequence */
|
|
|
+ if (flags & FLASH_FLAG_32BIT_ADDR)
|
|
|
+ ret = stfsm_search_prepare_rw_seq(fsm, &stfsm_seq_read,
|
|
|
+ n25q_read4_configs);
|
|
|
+ else
|
|
|
+ ret = stfsm_search_prepare_rw_seq(fsm, &stfsm_seq_read,
|
|
|
+ n25q_read3_configs);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(fsm->dev,
|
|
|
+ "failed to prepare READ sequence with flags [0x%08x]\n",
|
|
|
+ flags);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Configure 'WRITE' sequence (default configs) */
|
|
|
+ ret = stfsm_search_prepare_rw_seq(fsm, &stfsm_seq_write,
|
|
|
+ default_write_configs);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(fsm->dev,
|
|
|
+ "preparing WRITE sequence using flags [0x%08x] failed\n",
|
|
|
+ flags);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* * Configure 'ERASE_SECTOR' sequence */
|
|
|
+ stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector);
|
|
|
+
|
|
|
+ /* Configure 32-bit address support */
|
|
|
+ if (flags & FLASH_FLAG_32BIT_ADDR) {
|
|
|
+ stfsm_n25q_en_32bit_addr_seq(&stfsm_seq_en_32bit_addr);
|
|
|
+
|
|
|
+ soc_reset = stfsm_can_handle_soc_reset(fsm);
|
|
|
+ if (soc_reset || !fsm->booted_from_spi) {
|
|
|
+ /*
|
|
|
+ * If we can handle SoC resets, we enable 32-bit
|
|
|
+ * address mode pervasively
|
|
|
+ */
|
|
|
+ stfsm_enter_32bit_addr(fsm, 1);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * If not, enable/disable for WRITE and ERASE
|
|
|
+ * operations (READ uses special commands)
|
|
|
+ */
|
|
|
+ fsm->configuration = (CFG_WRITE_TOGGLE_32BIT_ADDR |
|
|
|
+ CFG_ERASESEC_TOGGLE_32BIT_ADDR);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Configure device to use 8 dummy cycles
|
|
|
+ */
|
|
|
+ vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED |
|
|
|
+ N25Q_VCR_WRAP_CONT);
|
|
|
+ stfsm_wrvcr(fsm, vcr);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *const jedec)
|
|
|
{
|
|
|
const struct stfsm_seq *seq = &stfsm_seq_read_jedec;
|
|
@@ -1073,6 +1143,16 @@ static int stfsm_probe(struct platform_device *pdev)
|
|
|
if (info->sector_size * info->n_sectors > 0x1000000)
|
|
|
info->flags |= FLASH_FLAG_32BIT_ADDR;
|
|
|
|
|
|
+ /*
|
|
|
+ * Configure READ/WRITE/ERASE sequences according to platform and
|
|
|
+ * device flags.
|
|
|
+ */
|
|
|
+ if (info->config) {
|
|
|
+ ret = info->config(fsm);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
fsm->mtd.dev.parent = &pdev->dev;
|
|
|
fsm->mtd.type = MTD_NORFLASH;
|
|
|
fsm->mtd.writesize = 4;
|