public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Marek Vasut <marex@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] mtd: add altera quadspi driver
Date: Wed, 4 Nov 2015 17:18:35 +0100	[thread overview]
Message-ID: <201511041718.35613.marex@denx.de> (raw)
In-Reply-To: <1446652570.3963.10.camel@clsee-VirtualBox>

On Wednesday, November 04, 2015 at 04:56:10 PM, Chin Liang See wrote:
> On Tue, 2015-11-03 at 21:22 +0800, thomas at wytron.com.tw wrote:
> > Add Altera Generic Quad SPI Controller support. The controller
> > converts SPI NOR flash to parallel flash interface. So it is
> > not like other SPI flash, but rather like CFI flash.
> > 
> > Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> > ---
> > 
> >  doc/device-tree-bindings/mtd/altera_qspi.txt |  35 +++
> >  drivers/mtd/Kconfig                          |   9 +
> >  drivers/mtd/Makefile                         |   1 +
> >  drivers/mtd/altera_qspi.c                    | 312
> >  +++++++++++++++++++++++++++ 4 files changed, 357 insertions(+)
> >  create mode 100644 doc/device-tree-bindings/mtd/altera_qspi.txt
> >  create mode 100644 drivers/mtd/altera_qspi.c
> >  ...
> > 
> > diff --git a/drivers/mtd/altera_qspi.c b/drivers/mtd/altera_qspi.c
> > new file mode 100644
> > index 0000000..06bc53e
> > --- /dev/null
> > +++ b/drivers/mtd/altera_qspi.c
> > @@ -0,0 +1,312 @@
> > +/*
> > + * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
> > + *
> > + * SPDX-License-Identifier:	GPL-2.0+
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <errno.h>
> > +#include <fdt_support.h>
> > +#include <flash.h>
> > +#include <mtd.h>
> > +#include <asm/io.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
> > +
> > +/*
> > + * The QUADSPI_MEM_OP register is used to do memory protect and erase
> > operations + */
> > +#define QUADSPI_MEM_OP_BULK_ERASE		0x00000001
> > +#define QUADSPI_MEM_OP_SECTOR_ERASE		0x00000002
> > +#define QUADSPI_MEM_OP_SECTOR_PROTECT		0x00000003
> > +
> > +/*
> > + * The QUADSPI_ISR register is used to determine whether an invalid
> > write or + * erase operation trigerred an interrupt
> > + */
> > +#define QUADSPI_ISR_ILLEGAL_ERASE		BIT(0)
> > +#define QUADSPI_ISR_ILLEGAL_WRITE		BIT(1)
> > +
> > +struct altera_qspi_regs {
> > +	u32	rd_status;
> > +	u32	rd_sid;
> > +	u32	rd_rdid;
> > +	u32	mem_op;
> > +	u32	isr;
> > +	u32	imr;
> > +	u32	chip_select;
> > +};
> > +
> > +struct altera_qspi_platdata {
> > +	struct altera_qspi_regs *regs;
> > +	void *base;
> > +	unsigned long size;
> > +};
> > +
> > +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];	/* FLASH chips 
info
> > */ +
> > +void flash_print_info(flash_info_t *info)
> > +{
> > +	printf("Altera QSPI flash  Size: %ld MB in %d Sectors\n",
> > +	       info->size >> 20, info->sector_count);
> > +}
> > +
> > +int flash_erase(flash_info_t *info, int s_first, int s_last)
> > +{
> > +	struct mtd_info *mtd = info->mtd;
> > +	struct erase_info instr;
> > +	int ret;
> > +
> > +	memset(&instr, 0, sizeof(instr));
> > +	instr.addr = mtd->erasesize * s_first;
> > +	instr.len = mtd->erasesize * (s_last + 1 - s_first);
> > +	ret = mtd_erase(mtd, &instr);
> > +	if (ret)
> > +		return ERR_NOT_ERASED;
> > +
> > +	return 0;
> > +}
> > +
> > +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
> > +{
> > +	struct mtd_info *mtd = info->mtd;
> > +	struct udevice *dev = mtd->dev;
> > +	struct altera_qspi_platdata *pdata = dev_get_platdata(dev);
> > +	ulong base = (ulong)pdata->base;
> > +	loff_t to = addr - base;
> > +	size_t retlen;
> > +	int ret;
> > +
> > +	ret = mtd_write(mtd, to, cnt, &retlen, src);
> > +	if (ret)
> > +		return ERR_NOT_ERASED;
> > +
> > +	return 0;
> > +}
> > +
> > +unsigned long flash_init(void)
> > +{
> > +	struct udevice *dev;
> > +
> > +	/* probe every MTD device */
> > +	for (uclass_first_device(UCLASS_MTD, &dev);
> > +	     dev;
> > +	     uclass_next_device(&dev)) {
> > +	}
> > +
> > +	return flash_info[0].size;
> > +}
> > +
> > +static int altera_qspi_erase(struct mtd_info *mtd, struct erase_info
> > *instr) +{
> > +	struct udevice *dev = mtd->dev;
> > +	struct altera_qspi_platdata *pdata = dev_get_platdata(dev);
> > +	struct altera_qspi_regs *regs = pdata->regs;
> > +	size_t addr = instr->addr;
> > +	size_t len = instr->len;
> > +	size_t end = addr + len;
> > +	u32 sect;
> > +	u32 stat;
> > +
> > +	instr->state = MTD_ERASING;
> > +	addr &= ~(mtd->erasesize - 1); /* get lower aligned address */
> > +	while (addr < end) {
> > +		sect = addr / mtd->erasesize;
> > +		sect <<= 8;
> > +		sect |= QUADSPI_MEM_OP_SECTOR_ERASE;
> > +		debug("erase %08x\n", sect);
> > +		writel(sect, &regs->mem_op);
> > +		stat = readl(&regs->isr);
> > +		if (stat & QUADSPI_ISR_ILLEGAL_ERASE) {
> > +			/* erase failed, sector might be protected */
> > +			debug("erase %08x fail %x\n", sect, stat);
> > +			writel(stat, &regs->isr); /* clear isr */
> > +			instr->state = MTD_ERASE_FAILED;
> > +			return -EIO;
> > +		}
> > +		addr += mtd->erasesize;
> > +	}
> > +	instr->state = MTD_ERASE_DONE;
> > +	mtd_erase_callback(instr);
> > +
> > +	return 0;
> > +}
> > +
> > +static int altera_qspi_read(struct mtd_info *mtd, loff_t from, size_t
> > len, +			    size_t *retlen, u_char *buf)
> > +{
> > +	struct udevice *dev = mtd->dev;
> > +	struct altera_qspi_platdata *pdata = dev_get_platdata(dev);
> > +
> > +	memcpy(buf, pdata->base + from, len);
> > +	*retlen = len;
> > +
> > +	return 0;
> > +}
> > +
> > +static inline u32 add_byte(u32 data, u8 byte, int shift)
> > +{
> > +	data &= ~(0xff << shift);
> > +	data |= byte << shift;
> > +	return data;
> > +}
> > +
> > +static int altera_qspi_write_word(struct mtd_info *mtd, loff_t to,
> > +				  u32 data)
> > +{
> > +	struct udevice *dev = mtd->dev;
> > +	struct altera_qspi_platdata *pdata = dev_get_platdata(dev);
> > +	struct altera_qspi_regs *regs = pdata->regs;
> > +	u32 pos = (u32)to;
> > +	u32 stat;
> > +
> > +	/* write to flash 32 bits at a time */
> > +	writel(data, pdata->base + pos);
> > +	/* check whether write triggered a illegal write interrupt */
> > +	stat = readl(&regs->isr);
> > +	if (stat & QUADSPI_ISR_ILLEGAL_WRITE) {
> > +		/* write failed, sector might be protected */
> > +		debug("write %08x fail %x\n", pos, stat);
> > +		writel(stat, &regs->isr); /* clear isr */
> > +		return -EIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int altera_qspi_write(struct mtd_info *mtd, loff_t to, size_t
> > len, +			     size_t *retlen, const u_char *buf)
> > +{
> > +	const u_char *end = buf + len;
> > +	unsigned shift;
> > +	u32 data;
> > +	int ret;
> > +
> > +	shift = (to & (sizeof(u32) - 1)) * 8; /* first shift to add byte */
> > +	to &= ~(sizeof(u32) - 1); /* get lower aligned address */
> > +	while (buf < end) {
> > +		data = 0xffffffff; /* pad data */
> > +		while (buf < end && shift < 32) {
> > +			/* add byte from buf */
> > +			data = add_byte(data, *buf++, shift);
> > +			shift += 8;
> > +		}
> > +		ret = altera_qspi_write_word(mtd, to, data);
> > +		if (ret)
> > +			return ret;
> > +		to += sizeof(u32);
> > +		shift = 0;
> > +	}
> > +	*retlen = len;
> > +
> > +	return 0;
> > +}
> > +
> 
> Hi Thomas,
> 
> Thanks for the patch.
> 
> I notice you are writing in word style which might have concern in
> performance. As the burst count can go up to 64, we can write larger
> data through memcpy. This will avoid redundancy of data header (opcode +
> address + dummy).

You cannot do that, memcpy works on memory while write*() operators work
on I/O. You should use readsl() and friends then.

  reply	other threads:[~2015-11-04 16:18 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-03 13:22 [U-Boot] [PATCH] mtd: add altera quadspi driver Thomas Chou
2015-11-03 17:44 ` Marek Vasut
2015-11-03 17:49   ` Jagan Teki
2015-11-03 17:52     ` Marek Vasut
2015-11-03 17:56       ` Jagan Teki
2015-11-03 18:11         ` Marek Vasut
2015-11-04  2:36   ` Thomas Chou
2015-11-04  3:45     ` Marek Vasut
2015-11-04  4:45       ` Thomas Chou
2015-11-04  5:15         ` Marek Vasut
2015-11-04  5:33           ` Thomas Chou
2015-11-04 14:02             ` Marek Vasut
2015-11-04 15:56 ` Chin Liang See
2015-11-04 16:18   ` Marek Vasut [this message]
2015-11-05  2:49     ` Chin Liang See
2015-11-05  2:53       ` Marek Vasut
2015-11-05  3:05         ` Chin Liang See
2015-11-05  4:26           ` Thomas Chou
2015-11-05  4:36             ` Marek Vasut
2015-11-05  8:47 ` [U-Boot] [PATCH v2 1/2] nios2: add memcpy_fromio and memcpy_toio Thomas Chou
2015-11-05  8:47   ` [U-Boot] [PATCH v2 2/2] mtd: add altera quadspi driver Thomas Chou
2015-11-05 14:25     ` Jagan Teki
2015-11-05 14:45       ` Thomas Chou
2015-11-05 14:57         ` Jagan Teki
2015-11-05 15:51           ` Marek Vasut
2015-11-06  8:11             ` Jagan Teki
2015-11-06 13:45               ` Marek Vasut
2015-11-06  0:18           ` Thomas Chou
2015-11-06  8:07             ` Jagan Teki
2015-11-06  9:28               ` Thomas Chou
2015-11-06  9:52                 ` Jagan Teki
2015-11-06 11:48                   ` Jagan Teki
2015-11-06 13:32                     ` Thomas Chou
2015-11-07  8:07 ` [U-Boot] [PATCH v3] " Thomas Chou

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=201511041718.35613.marex@denx.de \
    --to=marex@denx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox