Loading drivers/mtd/spi-nor/core.c +25 −52 Original line number Diff line number Diff line Loading @@ -7,16 +7,17 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ #include <linux/err.h> #include <linux/errno.h> #include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/math64.h> #include <linux/module.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> #include <linux/mutex.h> #include <linux/of_platform.h> #include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/sched/task_stack.h> #include <linux/sizes.h> Loading Loading @@ -639,32 +640,26 @@ static bool spi_nor_use_parallel_locking(struct spi_nor *nor) static int spi_nor_rww_start_rdst(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; int ret = -EAGAIN; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd) goto busy; return -EAGAIN; rww->ongoing_io = true; rww->ongoing_rd = true; ret = 0; busy: mutex_unlock(&nor->lock); return ret; return 0; } static void spi_nor_rww_end_rdst(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); rww->ongoing_io = false; rww->ongoing_rd = false; mutex_unlock(&nor->lock); } static int spi_nor_lock_rdst(struct spi_nor *nor) Loading Loading @@ -1212,26 +1207,21 @@ static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len, static bool spi_nor_rww_start_io(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; bool start = false; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io) goto busy; return false; rww->ongoing_io = true; start = true; busy: mutex_unlock(&nor->lock); return start; return true; } static void spi_nor_rww_end_io(struct spi_nor *nor) { mutex_lock(&nor->lock); guard(mutex)(&nor->lock); nor->rww.ongoing_io = false; mutex_unlock(&nor->lock); } static int spi_nor_lock_device(struct spi_nor *nor) Loading @@ -1254,32 +1244,27 @@ static void spi_nor_unlock_device(struct spi_nor *nor) static bool spi_nor_rww_start_exclusive(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; bool start = false; mutex_lock(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) goto busy; return false; rww->ongoing_io = true; rww->ongoing_rd = true; rww->ongoing_pe = true; start = true; busy: mutex_unlock(&nor->lock); return start; return true; } static void spi_nor_rww_end_exclusive(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); rww->ongoing_io = false; rww->ongoing_rd = false; rww->ongoing_pe = false; mutex_unlock(&nor->lock); } int spi_nor_prep_and_lock(struct spi_nor *nor) Loading Loading @@ -1316,30 +1301,26 @@ static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len) { struct spi_nor_rww *rww = &nor->rww; unsigned int used_banks = 0; bool started = false; u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) goto busy; return false; spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) { if (rww->used_banks & BIT(bank)) goto busy; return false; used_banks |= BIT(bank); } rww->used_banks |= used_banks; rww->ongoing_pe = true; started = true; busy: mutex_unlock(&nor->lock); return started; return true; } static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) Loading @@ -1348,15 +1329,13 @@ static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) rww->used_banks &= ~BIT(bank); rww->ongoing_pe = false; mutex_unlock(&nor->lock); } static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len) Loading Loading @@ -1393,19 +1372,18 @@ static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) { struct spi_nor_rww *rww = &nor->rww; unsigned int used_banks = 0; bool started = false; u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd) goto busy; return false; spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) { if (rww->used_banks & BIT(bank)) goto busy; return false; used_banks |= BIT(bank); } Loading @@ -1413,11 +1391,8 @@ static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) rww->used_banks |= used_banks; rww->ongoing_io = true; rww->ongoing_rd = true; started = true; busy: mutex_unlock(&nor->lock); return started; return true; } static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) Loading @@ -1426,7 +1401,7 @@ static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) Loading @@ -1434,8 +1409,6 @@ static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) rww->ongoing_io = false; rww->ongoing_rd = false; mutex_unlock(&nor->lock); } static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len) Loading drivers/mtd/spi-nor/macronix.c +31 −0 Original line number Diff line number Diff line Loading @@ -45,8 +45,26 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor, return 0; } static int macronix_qpp4b_post_sfdp_fixups(struct spi_nor *nor) { /* PP_1_1_4_4B is supported but missing in 4BAIT. */ struct spi_nor_flash_parameter *params = nor->params; params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], SPINOR_OP_PP_1_1_4_4B, SNOR_PROTO_1_1_4); return 0; } static const struct spi_nor_fixups mx25l25635_fixups = { .post_bfpt = mx25l25635_post_bfpt_fixups, .post_sfdp = macronix_qpp4b_post_sfdp_fixups, }; static const struct spi_nor_fixups macronix_qpp4b_fixups = { .post_sfdp = macronix_qpp4b_post_sfdp_fixups, }; static const struct flash_info macronix_nor_parts[] = { Loading Loading @@ -102,11 +120,17 @@ static const struct flash_info macronix_nor_parts[] = { .size = SZ_64M, .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x20, 0x1b), .name = "mx66l1g45g", .size = SZ_128M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixups = ¯onix_qpp4b_fixups, }, { /* MX66L2G45G */ .id = SNOR_ID(0xc2, 0x20, 0x1c), .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x23, 0x14), .name = "mx25v8035f", Loading Loading @@ -148,18 +172,25 @@ static const struct flash_info macronix_nor_parts[] = { .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x25, 0x3a), .name = "mx66u51235f", .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { /* MX66U1G45G */ .id = SNOR_ID(0xc2, 0x25, 0x3b), .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x25, 0x3c), .name = "mx66u2g45g", .size = SZ_256M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x26, 0x18), .name = "mx25l12855e", Loading drivers/mtd/spi-nor/otp.c +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ */ #include <linux/log2.h> #include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> Loading drivers/mtd/spi-nor/swp.c +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (C) 2005, Intec Automation Inc. * Copyright (C) 2014, Freescale Semiconductor, Inc. */ #include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> Loading drivers/mtd/spi-nor/winbond.c +88 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ #define WINBOND_NOR_OP_RDEAR 0xc8 /* Read Extended Address Register */ #define WINBOND_NOR_OP_WREAR 0xc5 /* Write Extended Address Register */ #define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ #define WINBOND_NOR_WREAR_OP(buf) \ SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_WREAR, 0), \ Loading @@ -17,6 +18,12 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, buf, 0)) #define WINBOND_NOR_SELDIE_OP(buf) \ SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 0), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, buf, 0)) static int w25q128_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, Loading Loading @@ -66,6 +73,79 @@ static const struct spi_nor_fixups w25q256_fixups = { .post_bfpt = w25q256_post_bfpt_fixups, }; /** * winbond_nor_select_die() - Set active die. * @nor: pointer to 'struct spi_nor'. * @die: die to set active. * * Certain Winbond chips feature more than a single die. This is mostly hidden * to the user, except that some chips may experience time deviation when * modifying the status bits between dies, which in some corner cases may * produce problematic races. Being able to explicitly select a die to check its * state in this case may be useful. * * Return: 0 on success, -errno otherwise. */ static int winbond_nor_select_die(struct spi_nor *nor, u8 die) { int ret; nor->bouncebuf[0] = die; if (nor->spimem) { struct spi_mem_op op = WINBOND_NOR_SELDIE_OP(nor->bouncebuf); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { ret = spi_nor_controller_ops_write_reg(nor, WINBOND_NOR_OP_SELDIE, nor->bouncebuf, 1); } if (ret) dev_dbg(nor->dev, "error %d selecting die %d\n", ret, die); return ret; } static int winbond_nor_multi_die_ready(struct spi_nor *nor) { int ret, i; for (i = 0; i < nor->params->n_dice; i++) { ret = winbond_nor_select_die(nor, i); if (ret) return ret; ret = spi_nor_sr_ready(nor); if (ret <= 0) return ret; } return 1; } static int winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor) { /* * SFDP supports dice numbers, but this information is only available in * optional additional tables which are not provided by these chips. * Dice number has an impact though, because these devices need extra * care when reading the busy bit. */ nor->params->n_dice = nor->params->size / SZ_64M; nor->params->ready = winbond_nor_multi_die_ready; return 0; } static const struct spi_nor_fixups winbond_nor_multi_die_fixups = { .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, }; static const struct flash_info winbond_nor_parts[] = { { .id = SNOR_ID(0xef, 0x30, 0x10), Loading Loading @@ -146,6 +226,10 @@ static const struct flash_info winbond_nor_parts[] = { .name = "w25q512jvq", .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, { /* W25Q01JV */ .id = SNOR_ID(0xef, 0x40, 0x21), .fixups = &winbond_nor_multi_die_fixups, }, { .id = SNOR_ID(0xef, 0x50, 0x12), .name = "w25q20bw", Loading Loading @@ -221,6 +305,10 @@ static const struct flash_info winbond_nor_parts[] = { }, { .id = SNOR_ID(0xef, 0x70, 0x19), .name = "w25q256jvm", }, { /* W25Q02JV */ .id = SNOR_ID(0xef, 0x70, 0x22), .fixups = &winbond_nor_multi_die_fixups, }, { .id = SNOR_ID(0xef, 0x71, 0x19), .name = "w25m512jv", Loading Loading
drivers/mtd/spi-nor/core.c +25 −52 Original line number Diff line number Diff line Loading @@ -7,16 +7,17 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ #include <linux/err.h> #include <linux/errno.h> #include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/math64.h> #include <linux/module.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> #include <linux/mutex.h> #include <linux/of_platform.h> #include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/sched/task_stack.h> #include <linux/sizes.h> Loading Loading @@ -639,32 +640,26 @@ static bool spi_nor_use_parallel_locking(struct spi_nor *nor) static int spi_nor_rww_start_rdst(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; int ret = -EAGAIN; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd) goto busy; return -EAGAIN; rww->ongoing_io = true; rww->ongoing_rd = true; ret = 0; busy: mutex_unlock(&nor->lock); return ret; return 0; } static void spi_nor_rww_end_rdst(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); rww->ongoing_io = false; rww->ongoing_rd = false; mutex_unlock(&nor->lock); } static int spi_nor_lock_rdst(struct spi_nor *nor) Loading Loading @@ -1212,26 +1207,21 @@ static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len, static bool spi_nor_rww_start_io(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; bool start = false; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io) goto busy; return false; rww->ongoing_io = true; start = true; busy: mutex_unlock(&nor->lock); return start; return true; } static void spi_nor_rww_end_io(struct spi_nor *nor) { mutex_lock(&nor->lock); guard(mutex)(&nor->lock); nor->rww.ongoing_io = false; mutex_unlock(&nor->lock); } static int spi_nor_lock_device(struct spi_nor *nor) Loading @@ -1254,32 +1244,27 @@ static void spi_nor_unlock_device(struct spi_nor *nor) static bool spi_nor_rww_start_exclusive(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; bool start = false; mutex_lock(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) goto busy; return false; rww->ongoing_io = true; rww->ongoing_rd = true; rww->ongoing_pe = true; start = true; busy: mutex_unlock(&nor->lock); return start; return true; } static void spi_nor_rww_end_exclusive(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); rww->ongoing_io = false; rww->ongoing_rd = false; rww->ongoing_pe = false; mutex_unlock(&nor->lock); } int spi_nor_prep_and_lock(struct spi_nor *nor) Loading Loading @@ -1316,30 +1301,26 @@ static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len) { struct spi_nor_rww *rww = &nor->rww; unsigned int used_banks = 0; bool started = false; u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) goto busy; return false; spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) { if (rww->used_banks & BIT(bank)) goto busy; return false; used_banks |= BIT(bank); } rww->used_banks |= used_banks; rww->ongoing_pe = true; started = true; busy: mutex_unlock(&nor->lock); return started; return true; } static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) Loading @@ -1348,15 +1329,13 @@ static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) rww->used_banks &= ~BIT(bank); rww->ongoing_pe = false; mutex_unlock(&nor->lock); } static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len) Loading Loading @@ -1393,19 +1372,18 @@ static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) { struct spi_nor_rww *rww = &nor->rww; unsigned int used_banks = 0; bool started = false; u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd) goto busy; return false; spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) { if (rww->used_banks & BIT(bank)) goto busy; return false; used_banks |= BIT(bank); } Loading @@ -1413,11 +1391,8 @@ static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) rww->used_banks |= used_banks; rww->ongoing_io = true; rww->ongoing_rd = true; started = true; busy: mutex_unlock(&nor->lock); return started; return true; } static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) Loading @@ -1426,7 +1401,7 @@ static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) u8 first, last; int bank; mutex_lock(&nor->lock); guard(mutex)(&nor->lock); spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); for (bank = first; bank <= last; bank++) Loading @@ -1434,8 +1409,6 @@ static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) rww->ongoing_io = false; rww->ongoing_rd = false; mutex_unlock(&nor->lock); } static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len) Loading
drivers/mtd/spi-nor/macronix.c +31 −0 Original line number Diff line number Diff line Loading @@ -45,8 +45,26 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor, return 0; } static int macronix_qpp4b_post_sfdp_fixups(struct spi_nor *nor) { /* PP_1_1_4_4B is supported but missing in 4BAIT. */ struct spi_nor_flash_parameter *params = nor->params; params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], SPINOR_OP_PP_1_1_4_4B, SNOR_PROTO_1_1_4); return 0; } static const struct spi_nor_fixups mx25l25635_fixups = { .post_bfpt = mx25l25635_post_bfpt_fixups, .post_sfdp = macronix_qpp4b_post_sfdp_fixups, }; static const struct spi_nor_fixups macronix_qpp4b_fixups = { .post_sfdp = macronix_qpp4b_post_sfdp_fixups, }; static const struct flash_info macronix_nor_parts[] = { Loading Loading @@ -102,11 +120,17 @@ static const struct flash_info macronix_nor_parts[] = { .size = SZ_64M, .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x20, 0x1b), .name = "mx66l1g45g", .size = SZ_128M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixups = ¯onix_qpp4b_fixups, }, { /* MX66L2G45G */ .id = SNOR_ID(0xc2, 0x20, 0x1c), .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x23, 0x14), .name = "mx25v8035f", Loading Loading @@ -148,18 +172,25 @@ static const struct flash_info macronix_nor_parts[] = { .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x25, 0x3a), .name = "mx66u51235f", .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { /* MX66U1G45G */ .id = SNOR_ID(0xc2, 0x25, 0x3b), .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x25, 0x3c), .name = "mx66u2g45g", .size = SZ_256M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, .fixup_flags = SPI_NOR_4B_OPCODES, .fixups = ¯onix_qpp4b_fixups, }, { .id = SNOR_ID(0xc2, 0x26, 0x18), .name = "mx25l12855e", Loading
drivers/mtd/spi-nor/otp.c +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ */ #include <linux/log2.h> #include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> Loading
drivers/mtd/spi-nor/swp.c +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (C) 2005, Intec Automation Inc. * Copyright (C) 2014, Freescale Semiconductor, Inc. */ #include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/spi-nor.h> Loading
drivers/mtd/spi-nor/winbond.c +88 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ #define WINBOND_NOR_OP_RDEAR 0xc8 /* Read Extended Address Register */ #define WINBOND_NOR_OP_WREAR 0xc5 /* Write Extended Address Register */ #define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ #define WINBOND_NOR_WREAR_OP(buf) \ SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_WREAR, 0), \ Loading @@ -17,6 +18,12 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, buf, 0)) #define WINBOND_NOR_SELDIE_OP(buf) \ SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 0), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(1, buf, 0)) static int w25q128_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, Loading Loading @@ -66,6 +73,79 @@ static const struct spi_nor_fixups w25q256_fixups = { .post_bfpt = w25q256_post_bfpt_fixups, }; /** * winbond_nor_select_die() - Set active die. * @nor: pointer to 'struct spi_nor'. * @die: die to set active. * * Certain Winbond chips feature more than a single die. This is mostly hidden * to the user, except that some chips may experience time deviation when * modifying the status bits between dies, which in some corner cases may * produce problematic races. Being able to explicitly select a die to check its * state in this case may be useful. * * Return: 0 on success, -errno otherwise. */ static int winbond_nor_select_die(struct spi_nor *nor, u8 die) { int ret; nor->bouncebuf[0] = die; if (nor->spimem) { struct spi_mem_op op = WINBOND_NOR_SELDIE_OP(nor->bouncebuf); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { ret = spi_nor_controller_ops_write_reg(nor, WINBOND_NOR_OP_SELDIE, nor->bouncebuf, 1); } if (ret) dev_dbg(nor->dev, "error %d selecting die %d\n", ret, die); return ret; } static int winbond_nor_multi_die_ready(struct spi_nor *nor) { int ret, i; for (i = 0; i < nor->params->n_dice; i++) { ret = winbond_nor_select_die(nor, i); if (ret) return ret; ret = spi_nor_sr_ready(nor); if (ret <= 0) return ret; } return 1; } static int winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor) { /* * SFDP supports dice numbers, but this information is only available in * optional additional tables which are not provided by these chips. * Dice number has an impact though, because these devices need extra * care when reading the busy bit. */ nor->params->n_dice = nor->params->size / SZ_64M; nor->params->ready = winbond_nor_multi_die_ready; return 0; } static const struct spi_nor_fixups winbond_nor_multi_die_fixups = { .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, }; static const struct flash_info winbond_nor_parts[] = { { .id = SNOR_ID(0xef, 0x30, 0x10), Loading Loading @@ -146,6 +226,10 @@ static const struct flash_info winbond_nor_parts[] = { .name = "w25q512jvq", .size = SZ_64M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, { /* W25Q01JV */ .id = SNOR_ID(0xef, 0x40, 0x21), .fixups = &winbond_nor_multi_die_fixups, }, { .id = SNOR_ID(0xef, 0x50, 0x12), .name = "w25q20bw", Loading Loading @@ -221,6 +305,10 @@ static const struct flash_info winbond_nor_parts[] = { }, { .id = SNOR_ID(0xef, 0x70, 0x19), .name = "w25q256jvm", }, { /* W25Q02JV */ .id = SNOR_ID(0xef, 0x70, 0x22), .fixups = &winbond_nor_multi_die_fixups, }, { .id = SNOR_ID(0xef, 0x71, 0x19), .name = "w25m512jv", Loading