[U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support

Prabhakar Kushwaha
2018-01-02T10:18:13Z

Hi Jagan,

> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan Teki
> Sent: Thursday, December 28, 2017 11:42 AM
> To: u-boot at lists.denx.de
> Cc: Tom Rini <trini@konsulko.com>
> Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
>
> Some of the SPI device drivers at drivers/spi not a real
> spi controllers, Unlike normal/generic SPI controllers they
> operates only with SPI-NOR flash devices. these were technically
> termed as SPI-NOR controllers, Ex: drivers/spi/fsl_qspi.c
>
> The problem with these were resides at drivers/spi is entire
> SPI layer becomes SPI-NOR flash oriented which is absolutely
> a wrong indication where SPI layer getting effected more with
> flash operations - So this SPI-NOR core will resolve this issue
> by separating all SPI-NOR flash operations from spi layer and
> creats a generic layer called SPI-NOR core which can be used to
> interact SPI-NOR to SPI driver interface layer and the SPI-NOR
> controller driver. The idea is taken from Linux spi-nor framework.
>
> =======================================
> cmd/spinor.c
> =======================================
> mtd-uclass.c
> =======================================
> spi-nor-uclass.c
> =======================================
> spi-nor.c
> =======================================
> m25p80.c zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
> #####SPI NOR chip######
> =======================================
>

<snip>

> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <mapmem.h>
> +#include <mtd.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/math64.h>
> +#include <linux/types.h>
> +#include <linux/mtd/spi-nor.h>
> +
> +int spi_nor_scan(struct spi_nor *nor)
> +{
> + struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
> + struct mtd_ops *ops = mtd_get_ops(mtd->dev);
> + const struct spi_nor_info *info = NULL;
> + int ret;
> +
> + struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
> + upriv->spi_nor = nor;
> +
> + if (nor->init_done)
> + return 0;
> +
> + info = spi_nor_id(nor->dev);
> + if (IS_ERR_OR_NULL(info)) {
> + ret = -ENOENT;
> + goto err;
> + }
> +
> + /*
> + * Flash powers up read-only, so clear BP# bits.
> + *
> + * Note on some flash (like Macronix), QE (quad enable) bit is in the
> + * same status register as BP# bits, and we need preserve its original
> + * value during a reboot cycle as this is required by some platforms
> + * (like Intel ICH SPI controller working under descriptor mode).
> + */
> + if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> + (JEDEC_MFR(info) == SNOR_MFR_SST) ||
> + (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
> + u8 sr = 0;
> +
> + if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
> + sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
> + write_sr(nor->dev, sr);
> + }
> +
> + mtd->name = info->name;
> + mtd->priv = nor;
> + mtd->type = MTD_NORFLASH;
> + mtd->writesize = 1;
> + mtd->flags = MTD_CAP_NORFLASH;
> +
> + if (info->flags & E_FSR)
> + nor->flags |= SNOR_F_USE_FSR;
> +
> + if (info->flags & SST_WR)
> + nor->flags |= SNOR_F_SST_WRITE;
> +
> + ops->write = spi_nor_mwrite;
> +
> + /* compute the flash size */
> + nor->page_size = info->page_size;
> + /*
> + * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
> + * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
> + * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
> + * have 256b pages.
> + */
> + if (JEDEC_EXT(info) == 0x4d00) {
> + if ((JEDEC_ID(info) != 0x0215) &&
> + (JEDEC_ID(info) != 0x0216))
> + nor->page_size = 512;
> + }
> + mtd->writebufsize = nor->page_size;
> + mtd->size = info->sector_size * info->n_sectors;
> +
> +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
> + /* prefer "small sector" erase if possible */
> + if (info->flags & SECT_4K) {
> + nor->erase_opcode = SNOR_OP_BE_4K;
> + mtd->erasesize = 4096;
> + } else
> +#endif
> + {
> + nor->erase_opcode = SNOR_OP_SE;
> + mtd->erasesize = info->sector_size;
> + }
> +
> + /* Look for read opcode */
> + nor->read_opcode = SNOR_OP_READ_FAST;
> + if (nor->mode & SNOR_READ)
> + nor->read_opcode = SNOR_OP_READ;
> + else if (nor->mode & SNOR_READ_1_1_4 && info->flags & RD_QUAD)
> + nor->read_opcode = SNOR_OP_READ_1_1_4;
> + else if (nor->mode & SNOR_READ_1_1_2 && info->flags & RD_DUAL)
> + nor->read_opcode = SNOR_OP_READ_1_1_2;
> +

Are you planning to store read_protocol i.e. 1-1-1. 1-1-2, 1-4-4, 4-4-4 etc information in nor structure?
It will help low level controller driver to configure number of lines to be used during read in instruction, address and data phase.

Similar framework is present in Linux.

struct spi_nor :
* @read_proto: the SPI protocol for read operations
* @write_proto: the SPI protocol for write operations
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations

--pk