[U-Boot] [RFC PATCH 1/6] mtd: spi: Port SPI NOR framework from Linux
Vignesh R
vigneshr at ti.com
Thu Nov 29 17:26:04 UTC 2018
Hi Boris,
On 29/11/18 9:34 PM, Boris Brezillon wrote:
> On Wed, 28 Nov 2018 22:56:02 +0530
> Vignesh R <vigneshr at ti.com> wrote:
>
>> +#if defined(CONFIG_DM_SPI) && defined(CONFIG_SPI_MEM)
>> +#define spi_nor_mem_exec_op spi_mem_exec_op
>> +#else
>> +/*
>> + * This function is to support transition to DM_SPI. Will be removed
>> + * once all boards are converted to DM_SPI
>> + */
>> +
>> +static int spi_nor_mem_exec_op(struct spi_slave *slave,
>> + const struct spi_mem_op *op)
>> +{
>> + unsigned int pos = 0;
>> + const u8 *tx_buf = NULL;
>> + u8 *rx_buf = NULL;
>> + u8 *op_buf;
>> + int op_len;
>> + u32 flag;
>> + int ret;
>> + int i;
>> +
>> + if (op->data.nbytes) {
>> + if (op->data.dir == SPI_MEM_DATA_IN)
>> + rx_buf = op->data.buf.in;
>> + else
>> + tx_buf = op->data.buf.out;
>> + }
>> +
>> + op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
>> + op_buf = calloc(1, op_len);
>> +
>> + ret = spi_claim_bus(slave);
>> + if (ret < 0)
>> + return ret;
>> +
>> + op_buf[pos++] = op->cmd.opcode;
>> +
>> + if (op->addr.nbytes) {
>> + for (i = 0; i < op->addr.nbytes; i++)
>> + op_buf[pos + i] = op->addr.val >>
>> + (8 * (op->addr.nbytes - i - 1));
>> +
>> + pos += op->addr.nbytes;
>> + }
>> +
>> + if (op->dummy.nbytes)
>> + memset(op_buf + pos, 0xff, op->dummy.nbytes);
>> +
>> + /* 1st transfer: opcode + address + dummy cycles */
>> + flag = SPI_XFER_BEGIN;
>> + /* Make sure to set END bit if no tx or rx data messages follow */
>> + if (!tx_buf && !rx_buf)
>> + flag |= SPI_XFER_END;
>> +
>> + ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag);
>> + if (ret)
>> + return ret;
>> +
>> + /* 2nd transfer: rx or tx data path */
>> + if (tx_buf || rx_buf) {
>> + ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
>> + rx_buf, SPI_XFER_END);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + spi_release_bus(slave);
>> +
>> + for (i = 0; i < pos; i++)
>> + debug("%02x ", op_buf[i]);
>> + debug("| [%dB %s] ",
>> + tx_buf || rx_buf ? op->data.nbytes : 0,
>> + tx_buf || rx_buf ? (tx_buf ? "out" : "in") : "-");
>> + for (i = 0; i < op->data.nbytes; i++)
>> + debug("%02x ", tx_buf ? tx_buf[i] : rx_buf[i]);
>> + debug("[ret %d]\n", ret);
>> +
>> + free(op_buf);
>> +
>> + if (ret < 0)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +#endif
>
> I'd recommend putting this alternate spi_mem_exec_op() implementation
> in drivers/spi/. Either you create a drivers/spi/spi-mem-no-dm.c file
> or you add #ifdef CONFIG_DM_SPI #else #endif sections directly in
> drivers/spi/spi-mem.c.
>
I thought about that, but then I saw spi-mem.c is under DM_SPI and
DM_SPI migration series by Jagan and thought that this code wont be
needing this at all. Anyways, will move this to drivers/spi next time
around.
>> +const struct flash_info spi_nor_ids[] = {
>> +#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
>> + /* Atmel -- some are (confusingly) marketed as "DataFlash" */
>> + { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
>> + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
>> +
>> + { "at45db011d", INFO(0x1f2200, 0, 64 * 1024, 4, SECT_4K) },
>> + { "at45db021d", INFO(0x1f2300, 0, 64 * 1024, 8, SECT_4K) },
>> + { "at45db041d", INFO(0x1f2400, 0, 64 * 1024, 8, SECT_4K) },
>> + { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
>> + { "at45db161d", INFO(0x1f2600, 0, 64 * 1024, 32, SECT_4K) },
>> + { "at45db321d", INFO(0x1f2700, 0, 64 * 1024, 64, SECT_4K) },
>> + { "at45db641d", INFO(0x1f2800, 0, 64 * 1024, 128, SECT_4K) },
>> + { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
>> +#endif
>
> If you're really short in space (for the SPL build), you might want to
> consider fined-grained selection of the chips you want to support. One
> more reason to do that is that board manufacturers usually source SPI
> NOR parts from different vendors for the same design. With a
> per-manufacturer selection logic, you'll have to enable several of them
> to have an SPL that works on all variants.
>
> I didn't try, but you might be able to place each NOR chip in its own
> section and decide which one to keep at link time (will require some
> macros to define flash_info entries + a linker script to decide which
> sections you want to discard/keep at link time).
>
IIUC, you are proposing per board linker script that will select/choose
which flash parts would to be supported by that board's SPL?
> Note that I'd be okay to convert Linux flash_info table to the new
> macro usage if you choose to do that.
>
> Just a quick example:
>
> #define SPI_FLASH_INFO(_name, ...)
> ll_entry_declare(struct flash_info, _name, spi_nor_ids) = {
> .name = #_name,
> __VAR_ARGS__
> };
>
--
Regards
Vignesh
More information about the U-Boot
mailing list