linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Add Wondermedia Serial Flash controller support
@ 2013-01-23  8:01 Tony Prisk
  2013-01-23  8:01 ` [PATCH v3 1/2] mtd: Add a common JEDEC flash device table Tony Prisk
  2013-01-23  8:01 ` [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller Tony Prisk
  0 siblings, 2 replies; 5+ messages in thread
From: Tony Prisk @ 2013-01-23  8:01 UTC (permalink / raw)
  To: dwmw2
  Cc: linux-kernel, linux-arm-kernel, vt8500-wm8505-linux-kernel,
	linux-mtd, dedekind1, Tony Prisk

v3 Changes:
As requested by Artem Bityutskiy, I have seperated out the flash chip data into
a seperate file (flash_jedec.(h/c)) which should be expandable by other drivers
as needed.

I have also cleared up some of the sparse warnings that were being generated,
but need some help with the last one:
+drivers/mtd/devices/wmt_sflash.c:442:24: warning: cast removes address space of expression [sparse]
which relates to this line:
+	u32 addr_to = (u32)info->sf_base_virt + to;

What is the correct way to get the value of ->sf_base_virt without generating
a sparse warning? sf_base_virt is void __iomem *.

Tony Prisk (2):
  mtd: Add a common JEDEC flash device table
  mtd: vt8500: Add support for Wondermedia Serial Flash Controller

 drivers/mtd/devices/Kconfig       |   10 +
 drivers/mtd/devices/Makefile      |    3 +-
 drivers/mtd/devices/flash_jedec.c |   96 ++++++
 drivers/mtd/devices/flash_jedec.h |   30 ++
 drivers/mtd/devices/wmt_sflash.c  |  585 +++++++++++++++++++++++++++++++++++++
 5 files changed, 723 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/devices/flash_jedec.c
 create mode 100644 drivers/mtd/devices/flash_jedec.h
 create mode 100644 drivers/mtd/devices/wmt_sflash.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table
  2013-01-23  8:01 [PATCH v3 0/2] Add Wondermedia Serial Flash controller support Tony Prisk
@ 2013-01-23  8:01 ` Tony Prisk
  2013-01-23  9:00   ` Matthieu CASTET
  2013-01-23  8:01 ` [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller Tony Prisk
  1 sibling, 1 reply; 5+ messages in thread
From: Tony Prisk @ 2013-01-23  8:01 UTC (permalink / raw)
  To: dwmw2
  Cc: linux-kernel, linux-arm-kernel, vt8500-wm8505-linux-kernel,
	linux-mtd, dedekind1, Tony Prisk

This patch adds a common JEDEC flash device table which can be
expanded on as more features are required.

A simple match function is also included to query the table for
a match based on the JEDEC id.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/mtd/devices/flash_jedec.c |   96 +++++++++++++++++++++++++++++++++++++
 drivers/mtd/devices/flash_jedec.h |   30 ++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 drivers/mtd/devices/flash_jedec.c
 create mode 100644 drivers/mtd/devices/flash_jedec.h

diff --git a/drivers/mtd/devices/flash_jedec.c b/drivers/mtd/devices/flash_jedec.c
new file mode 100644
index 0000000..c0b2272
--- /dev/null
+++ b/drivers/mtd/devices/flash_jedec.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "flash_jedec.h"
+
+/*
+ * Device Manufacturer IDs
+ * Please keep sorted by manufacturer ID
+ */
+#define MFR_SPANSION		0X01
+#define MFR_EON			0X1C
+#define MFR_ATMEL		0X1F
+#define MFR_MICRON		0X20	/* Also Numonyx & STM */
+#define MFR_INTEL		0x89
+#define MFR_FUDAN		0XA1
+#define MFR_SST			0XBF
+#define MFR_MXIC		0XC2
+#define MFR_WINBOND		0XEF
+
+#define _ID(m, d)	((m << 16) | d)
+
+/*
+ * Flash device information
+ * Please keep sorted by manufacturer id, then device id
+ */
+static struct flash_device_info flash_devices[] = {
+	/* Spansion */
+	{ "s25fl016", _ID(MFR_SPANSION, 0x0214), 2048 },
+	{ "s25fl064", _ID(MFR_SPANSION, 0x0216), 8192 },
+	/* EON */
+	{ "en25p16", _ID(MFR_EON, 0x2015), 2048 },
+	{ "en25p64", _ID(MFR_EON, 0x2017), 8192 },
+	{ "en25f40", _ID(MFR_EON, 0x3113),  512 },
+	{ "en25f16", _ID(MFR_EON, 0x3115), 2048 },
+	/* ATMEL */
+	{ "at25df041a", _ID(MFR_ATMEL, 0x4401), 512 },
+	/* Micron, STM & Numonyx */
+	{ "stm25p16", _ID(MFR_MICRON, 0x2015), 2048 },
+	{ "stm25p64", _ID(MFR_MICRON, 0x2017), 8192 },
+	/* Fudan */
+	{ "fm25f04", _ID(MFR_FUDAN, 0x3113), 512 },
+	/* SST */
+	{ "sst25vf016b", _ID(MFR_SST, 0x2541), 2048 },
+	/* Macronix - MXIC */
+	{ "mx25l512",   _ID(MFR_MXIC, 0x2010),    64 },
+	{ "mx25l4005",  _ID(MFR_MXIC, 0x2013),   512 },
+	{ "mx25l1605",  _ID(MFR_MXIC, 0x2015),  2048 },
+	{ "mx25l3205",  _ID(MFR_MXIC, 0x2016),  4096 },
+	{ "mx25l6405",  _ID(MFR_MXIC, 0x2017),  8192 },
+	{ "mx25l12805", _ID(MFR_MXIC, 0x2018), 16384 },
+	{ "mx25l1635",  _ID(MFR_MXIC, 0x2415),  2048 },
+	{ "mx25l3235",  _ID(MFR_MXIC, 0x5E16),  4096 },
+	/* Winbond */
+	{ "w25x40", _ID(MFR_WINBOND, 0x3013),   512 },
+	{ "w25x16", _ID(MFR_WINBOND, 0x3015),  2048 },
+	{ "w25x32", _ID(MFR_WINBOND, 0x3016),  4096 },
+	{ "w25x64", _ID(MFR_WINBOND, 0x3017),  8192 },
+};
+
+/*
+ * jedec_match_device - match a jedec id against the flash_devices table
+ * @jedecid: JEDEC formatted id to match
+ *	bits 16..24: manufacturer id
+ *	bits  0..15: device id
+ * Returns a valid flash_device_info* or ERR_PTR(-ENODEV) if an entry is
+ * not found
+ */
+struct flash_device_info *jedec_match_device(u32 jedec_id)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(flash_devices); i++)
+		if (flash_devices[i].jedec_id == jedec_id)
+			return &flash_devices[i];
+
+	return ERR_PTR(-ENODEV);
+}
diff --git a/drivers/mtd/devices/flash_jedec.h b/drivers/mtd/devices/flash_jedec.h
new file mode 100644
index 0000000..27b978a
--- /dev/null
+++ b/drivers/mtd/devices/flash_jedec.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MTD_FLASH_JEDEC
+#define __MTD_FLASH_JEDEC
+
+struct flash_device_info {
+	const char	*name;
+	u32		jedec_id;
+	u32		size_kb;
+};
+
+extern struct flash_device_info *jedec_match_device(u32 jedec_id);
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller
  2013-01-23  8:01 [PATCH v3 0/2] Add Wondermedia Serial Flash controller support Tony Prisk
  2013-01-23  8:01 ` [PATCH v3 1/2] mtd: Add a common JEDEC flash device table Tony Prisk
@ 2013-01-23  8:01 ` Tony Prisk
  1 sibling, 0 replies; 5+ messages in thread
From: Tony Prisk @ 2013-01-23  8:01 UTC (permalink / raw)
  To: dwmw2
  Cc: linux-kernel, linux-arm-kernel, vt8500-wm8505-linux-kernel,
	linux-mtd, dedekind1, Tony Prisk

This patch adds support for the Wondermedia serial flash controller
found on WM8505, WM8650 and WM8850 SoCs.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/mtd/devices/Kconfig      |   10 +
 drivers/mtd/devices/Makefile     |    3 +-
 drivers/mtd/devices/wmt_sflash.c |  585 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 597 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/devices/wmt_sflash.c

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 27f80cd..dbabb08 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -128,6 +128,16 @@ config MTD_BCM47XXSFLASH
 	  registered by bcma as platform devices. This enables driver for
 	  serial flash memories (only read-only mode is implemented).
 
+config MTD_WMT_SFLASH
+	tristate "WonderMedia Serial Flash Support"
+	depends on ARCH_VT8500
+	help
+	  Enable this option to provide support for the Wondermedia SoC serial
+	  flash controller.
+
+	  Select M to build this driver as a module. The module will be called
+	  'wmt_sflash'.
+
 config MTD_SLRAM
 	tristate "Uncached system RAM"
 	help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 395733a..79af2f6 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
 obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o
 obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
+obj-$(CONFIG_MTD_WMT_SFLASH)	+= wmt_sflash.o flash_jedec.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 
-CFLAGS_docg3.o			+= -I$(src)
\ No newline at end of file
+CFLAGS_docg3.o			+= -I$(src)
diff --git a/drivers/mtd/devices/wmt_sflash.c b/drivers/mtd/devices/wmt_sflash.c
new file mode 100644
index 0000000..d3adf7a
--- /dev/null
+++ b/drivers/mtd/devices/wmt_sflash.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#include <linux/mtd/mtd.h>
+
+#include "flash_jedec.h"
+
+
+/* controller only supports erase size of 64KB */
+#define WMT_ERASESIZE			0x10000
+
+/* Serial Flash controller register offsets */
+#define SF_CHIP_SEL_0_CFG		0x000
+#define SF_CHIP_SEL_1_CFG		0x008
+#define SF_SPI_INTF_CFG			0x040
+#define SF_SPI_RD_WR_CTR		0x050
+#define SF_SPI_WR_EN_CTR		0x060
+#define SF_SPI_ER_CTR			0x070
+#define SF_SPI_ER_START_ADDR		0x074
+#define SF_SPI_ERROR_STATUS		0x080
+#define SF_SPI_MEM_0_SR_ACC		0x100
+#define SF_SPI_MEM_1_SR_ACC		0x110
+#define SF_SPI_PDWN_CTR_0		0x180
+#define SF_SPI_PDWN_CTR_1		0x190
+#define SF_SPI_PROG_CMD_CTR		0x200
+#define SF_SPI_USER_CMD_VAL		0x210
+#define SF_SPI_PROG_CMD_WBF		0x300	/* 64 bytes */
+#define SF_SPI_PROG_CMD_RBF		0x380	/* 64 bytes */
+
+/* SF_SPI_WR_EN_CTR bit fields */
+#define SF_CS0_WR_EN			BIT(0)
+#define SF_CS1_WR_EN			BIT(1)
+
+/* SF_SPI_ER_CTR bit fields */
+#define SF_SEC_ER_EN			BIT(31)
+
+/* SF_SPI_ERROR_STATUS bit fields */
+#define SF_ERR_TIMEOUT			BIT(31)
+#define SF_ERR_WR_PROT_ERR		BIT(5)
+#define SF_ERR_MEM_REGION_ERR		BIT(4)
+#define SF_ERR_PWR_DWN_ACC_ERR		BIT(3)
+#define SF_ERR_PCMD_OP_ERR		BIT(2)
+#define SF_ERR_PCMD_ACC_ERR		BIT(1)
+#define SF_ERR_MASLOCK_ERR		BIT(0)
+
+/*
+ * Serial Flash device manufacturers
+ * Please keep sorted by manufacturers ID
+ */
+#define MFR_SPANSION		0x01
+#define MFR_EON			0x1C
+#define MFR_ATMEL		0x1F
+#define MFR_NUMONYX		0x20
+#define MFR_FUDAN		0xA1
+#define MFR_SST			0xBF
+#define MFR_MXIC		0xC2
+#define MFR_WINBOND		0xEF
+
+/*
+ * SF Device Models
+ * Please keep in the same order as the manufacturers table
+ */
+
+/* Spansion */
+#define SPAN_FL016A		0x0214 /* 2 MB */
+#define SPAN_FL064A		0x0216 /* 8 MB */
+
+/* Eon */
+#define EON_25P16		0x2015 /* 2 MB */
+#define EON_25P64		0x2017 /* 8 MB */
+#define EON_25F40		0x3113 /* 512 KB */
+#define EON_25F16		0x3115 /* 2 MB */
+
+/* Atmel */
+#define AT_25DF041A		0x4401 /* 512KB */
+
+/* Numonyx */
+#define	NX_25P16		0x2015 /* 2 MB */
+#define	NX_25P64		0x2017 /* 8 MB */
+
+/* Fudan Microelectronics Group */
+#define FM_25F04		0x3113 /* 512 KB */
+
+/* SST */
+#define SST_VF016B		0x2541 /* 2 MB */
+
+/* MXIC */
+#define	MX_L512			0x2010 /* 64 KB , 4KB*/
+#define MX_L4005A		0x2013 /* 512 KB */
+#define	MX_L1605D		0x2015 /* 2 MB */
+#define	MX_L3205D		0x2016 /* 4 MB */
+#define	MX_L6405D		0x2017 /* 8 MB */
+#define	MX_L1635D		0x2415 /* 2 MB */
+#define	MX_L3235D		0x5E16 /* 4 MB */
+#define	MX_L12805D		0x2018 /* 16 MB */
+
+/* WinBond */
+#define WB_W25X40BV		0x3013	/* 512 KB */
+#define WB_X16A			0x3015	/* 2 MB */
+#define WB_X32			0x3016	/* 4 MB */
+#define WB_X64			0x3017	/* 8 MB */
+
+
+#define SF_ID(mfr, mdl)		((mfr << 16) | mdl)
+
+#define FLASH_UNKNOWN		0x00ffffff
+
+struct wmt_sf_chip {
+	u32	id;
+	u32	size;
+	u32	addr_phys;
+	u32	ccr;
+};
+
+struct wmt_sf_data {
+	struct mtd_info		*sf_mtd;
+	struct clk		*sf_clk;
+	struct device		*dev;
+
+	struct wmt_sf_chip	chip[2];
+
+	void __iomem		*base;		/* register virt base */
+
+	void __iomem		*sf_base_virt;	/* mem-mapped sf virt base */
+	u32			sf_base_phys;	/* mem-mapped sf phys base */
+	u32			sf_total_size;
+};
+
+static void sf_calc_ccr(struct wmt_sf_chip *chip)
+{
+	unsigned int cnt = 0, size;
+
+	size = chip->size;
+	while (size) {
+		size >>= 1;
+		cnt++;
+	}
+	cnt -= 16;
+	cnt = cnt << 8;
+	chip->ccr = (chip->addr_phys | cnt);
+}
+
+static int wmt_sf_init_hw(struct wmt_sf_data *info)
+{
+	u32 strap;
+	u32 phys_addr;
+	struct device_node *np;
+	struct flash_device_info *flash;
+	void __iomem *gpio_base;
+
+	np = of_find_compatible_node(NULL, NULL, "wm,wm8650-gpio");
+	if (!np) {
+		dev_err(info->dev, "Unable to find GPIO node\n");
+		return -1;
+	}
+
+	gpio_base = of_iomap(np, 0);
+	if (!gpio_base) {
+		dev_err(info->dev, "Failed to map gpio memory\n");
+		return -1;
+	}
+
+	strap = readl_relaxed(gpio_base + 0x100);
+	iounmap(gpio_base);
+
+	if ((strap & 0x06) == 0) {
+		phys_addr = 0xFFFFFFFF;
+		writel(0x00000011, info->base + SF_SPI_RD_WR_CTR);
+		writel(0xFF800800, info->base + SF_CHIP_SEL_0_CFG);
+		writel(0x00030000, info->base + SF_SPI_INTF_CFG);
+	} else {
+		phys_addr = 0xEFFFFFFF;
+		writel(0x00000011, info->base + SF_SPI_RD_WR_CTR);
+		writel(0xEF800800, info->base + SF_CHIP_SEL_0_CFG);
+		writel(0x00030000, info->base + SF_SPI_INTF_CFG);
+	}
+
+	info->chip[0].id = FLASH_UNKNOWN;
+	info->chip[1].id = FLASH_UNKNOWN;
+
+	/* Read serial flash ID */
+	writel(0x11, info->base + SF_SPI_RD_WR_CTR);
+	info->chip[0].id = readl(info->base + SF_SPI_MEM_0_SR_ACC);
+	writel(0x01, info->base + SF_SPI_RD_WR_CTR);
+
+	writel(0x11, info->base + SF_SPI_RD_WR_CTR);
+	info->chip[1].id = readl(info->base + SF_SPI_MEM_1_SR_ACC);
+	writel(0x01, info->base + SF_SPI_RD_WR_CTR);
+
+	flash = jedec_match_device(info->chip[0].id);
+	if (IS_ERR(flash)) {
+		dev_err(info->dev, "Unknown flash id (%08x)\n",
+			info->chip[0].id);
+		return -1;
+	}
+
+	info->chip[0].size = flash->size_kb * 1024;
+	info->chip[0].addr_phys = phys_addr - info->chip[0].size + 1;
+	if (info->chip[0].addr_phys & 0xffff) {
+		dev_err(info->dev, "Chip 0 start address must align to 64KB\n");
+		return -1;
+	}
+	info->sf_base_phys = info->chip[0].addr_phys;
+	info->sf_total_size = info->chip[0].size;
+	pr_info("SFC: Chip 0 @ %08x (size: %d)\n", info->chip[0].addr_phys,
+							info->chip[0].size);
+
+	sf_calc_ccr(&info->chip[0]);
+	writel(info->chip[0].ccr, info->base + SF_CHIP_SEL_0_CFG);
+
+	if (info->chip[1].id != FLASH_UNKNOWN) {
+		flash = jedec_match_device(info->chip[1].id);
+		if (IS_ERR(flash)) {
+			dev_err(info->dev, "Unknown flash id (%08x)\n",
+				info->chip[1].id);
+			return -1;
+		}
+
+		info->chip[0].size = flash->size_kb * 1024;
+		info->chip[1].addr_phys = info->chip[0].addr_phys -
+							info->chip[1].size;
+		if (info->chip[1].addr_phys & 0xffff) {
+			dev_err(info->dev, "Chip 1 start address must align to 64KB\n");
+			info->chip[1].id = FLASH_UNKNOWN;
+			return 0;
+		}
+		info->sf_base_phys = info->chip[1].addr_phys;
+		info->sf_total_size += info->chip[1].size;
+		pr_info("SFC: Chip 1 @ %08x (size: %d)\n",
+				info->chip[1].addr_phys, info->chip[1].size);
+
+		sf_calc_ccr(&info->chip[1]);
+		writel(info->chip[1].ccr, info->base + SF_CHIP_SEL_1_CFG);
+	}
+
+	return 0;
+}
+
+static int sf_check_error(struct device *dev, u32 code)
+{
+	if (code & SF_ERR_TIMEOUT) {
+		dev_err(dev, "Serial flash timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	if (code & SF_ERR_WR_PROT_ERR) {
+		dev_err(dev, "Serial flash write-protected\n");
+		return -EIO;
+	}
+
+	if (code & SF_ERR_MEM_REGION_ERR) {
+		dev_err(dev, "Serial flash memory region error\n");
+		return -EIO;
+	}
+
+	if (code & SF_ERR_PWR_DWN_ACC_ERR) {
+		dev_err(dev, "Serial flash power down access error\n");
+		return -EIO;
+	}
+
+	if (code & SF_ERR_PCMD_OP_ERR)	{
+		dev_err(dev, "Serial flash program CMD OP error\n");
+		return -EIO;
+	}
+
+	if (code & SF_ERR_PCMD_ACC_ERR) {
+		dev_err(dev, "Serial flash program CMD OP access error\n");
+		return -EIO;
+	}
+
+	if (code & SF_ERR_MASLOCK_ERR) {
+		dev_err(dev, "Serial flash master lock error\n");
+		return -EIO;
+	}
+
+	/* no error */
+	return 0;
+}
+
+static int sf_spi_read_status(struct wmt_sf_data *info, int chip)
+{
+	u32 timeout = 0x30000000;
+	u32 temp;
+	int err;
+
+	do {
+		if (chip == 0)
+			temp = readl_relaxed(info->base + SF_SPI_MEM_0_SR_ACC);
+		else
+			temp = readl_relaxed(info->base + SF_SPI_MEM_1_SR_ACC);
+
+		if ((temp & 0x1) == 0x0)
+			break;
+
+		err = sf_check_error(info->dev,
+				     readl(info->base + SF_SPI_ERROR_STATUS));
+		if (err) {
+			writel(0x3f, info->base + SF_SPI_ERROR_STATUS);
+			return err;
+		}
+		timeout--;
+	} while (timeout);
+
+	if (timeout == 0) {
+		dev_err(info->dev, "spi request timed-out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int sf_sector_erase(struct wmt_sf_data *info, u32 addr)
+{
+	int chip;
+	u32 val;
+
+	if ((info->sf_base_phys + addr) < info->chip[0].addr_phys) {
+		chip = 0;
+		writel(SF_CS0_WR_EN, info->base + SF_SPI_WR_EN_CTR);
+	} else {
+		chip = 1;
+		writel(SF_CS1_WR_EN, info->base + SF_SPI_WR_EN_CTR);
+	}
+
+	addr &= ~(info->sf_mtd->erasesize - 1);
+	writel(addr, info->base + SF_SPI_ER_START_ADDR);
+
+	writel(SF_SEC_ER_EN, info->base + SF_SPI_ER_CTR);
+
+	val = sf_spi_read_status(info, chip);
+
+	writel(0, info->base + SF_SPI_WR_EN_CTR);
+	return val;
+}
+
+static int sf_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct wmt_sf_data *info = mtd->priv;
+	int ret;
+
+	ret = clk_enable(info->sf_clk);
+	if (ret)
+		return ret;
+
+	ret = sf_sector_erase(info, (u32)instr->addr);
+	if (ret) {
+		clk_disable(info->sf_clk);
+		return ret;
+	}
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	clk_disable(info->sf_clk);
+	return 0;
+}
+
+static int sf_read(struct mtd_info *mtd, loff_t from, size_t len,
+			 size_t *retlen, u_char *buf)
+{
+	struct wmt_sf_data *info = mtd->priv;
+	int ret;
+
+	ret = clk_enable(info->sf_clk);
+	if (ret)
+		return ret;
+
+	if (sf_spi_read_status(info, 0))
+		return -EBUSY;
+	if (sf_spi_read_status(info, 1))
+		return -EBUSY;
+
+	if (from + len > mtd->size) {
+		dev_err(info->dev, "Request out of bounds (from=%llu, len=%d)\n",
+								from, len);
+		return -EINVAL;
+	}
+
+	memcpy_fromio(buf, info->sf_base_virt + from, len);
+	*retlen = len;
+
+	clk_disable(info->sf_clk);
+	return 0;
+}
+
+static int sf_sector_write(struct wmt_sf_data *info, loff_t to, size_t len,
+			   const u_char *buf)
+{
+	int ret;
+	int data_size;
+	u32 count;
+	u32 addr_to = (u32)info->sf_base_virt + to;
+
+	ret = clk_enable(info->sf_clk);
+	if (ret)
+		return ret;
+
+	if (sf_spi_read_status(info, 0))
+		return -EBUSY;
+	if (sf_spi_read_status(info, 1))
+		return -EBUSY;
+
+	writel(SF_CS0_WR_EN | SF_CS1_WR_EN, info->base + SF_SPI_WR_EN_CTR);
+
+	count = 0;
+	while (len) {
+		data_size = (len >= 4) ? 4 : 1;
+		memcpy_toio(((void *)(addr_to + count)), buf + count,
+								data_size);
+		count += data_size;
+		len -= data_size;
+
+		if (len) {
+			data_size = (len >= 4) ? 4 : 1;
+			memcpy_toio(((void *)(addr_to + count)), buf + count,
+								data_size);
+			count += data_size;
+			len -= data_size;
+		}
+
+		ret = sf_spi_read_status(info, 0);
+		if (ret) {
+			clk_disable(info->sf_clk);
+			return ret;
+		}
+	}
+
+	writel(0, info->base + SF_SPI_WR_EN_CTR);
+
+	clk_disable(info->sf_clk);
+
+	return count;
+}
+
+static int sf_write(struct mtd_info *mtd, loff_t to, size_t len,
+				size_t *retlen, const u_char *buf)
+{
+	struct wmt_sf_data *info = mtd->priv;
+
+	*retlen = sf_sector_write(info, to, len, buf);
+
+	return 0;
+}
+
+static int mtdsf_init_device(struct device *dev, struct mtd_info *mtd,
+					unsigned long size, char *name)
+{
+	mtd->name = name;
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->size = size;
+	mtd->erasesize = WMT_ERASESIZE;
+	mtd->owner = THIS_MODULE;
+	mtd->_erase = sf_erase;
+	mtd->_read = sf_read;
+	mtd->_write = sf_write;
+	mtd->writesize = 1;
+
+	if (mtd_device_register(mtd, NULL, 0)) {
+		dev_err(dev, "Erroring adding MTD device\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int wmt_sf_probe(struct platform_device *pdev)
+{
+	struct wmt_sf_data	*info;
+	struct device_node	*np = pdev->dev.of_node;
+	int err;
+
+	if (!np) {
+		dev_err(&pdev->dev, "Invalid devicetree node\n");
+		return -EINVAL;
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&pdev->dev, "Failed to get memory for SF info\n");
+		return -ENOMEM;
+	}
+
+	info->dev = &pdev->dev;
+
+	info->base = of_iomap(np, 0);
+	if (!info->base) {
+		dev_err(&pdev->dev, "Failed to map register memory\n");
+		return -ENOMEM;
+	}
+
+	info->sf_clk = of_clk_get(np, 0);
+	if (!info->sf_clk) {
+		dev_err(&pdev->dev, "Failed to get clock from device tree\n");
+		return -EINVAL;
+	}
+
+	err = clk_prepare_enable(info->sf_clk);
+	if (err)
+		return err;
+
+	err = wmt_sf_init_hw(info);
+	clk_disable(info->sf_clk);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to initialize SF hardware\n");
+		return -EIO;
+	}
+
+	info->sf_base_virt = devm_ioremap(&pdev->dev, info->sf_base_phys,
+					  info->sf_total_size);
+	if (!info->sf_base_virt) {
+		dev_err(&pdev->dev, "Failed to map serial flash memory\n");
+		return -ENOMEM;
+	}
+
+	info->sf_mtd = devm_kzalloc(&pdev->dev, sizeof(struct mtd_info),
+								GFP_KERNEL);
+	if (!info->sf_mtd) {
+		dev_err(&pdev->dev, "Failed to allocate SFMTD memory\n");
+		return -ENOMEM;
+	}
+
+	err = mtdsf_init_device(info->dev, info->sf_mtd, info->sf_total_size,
+						"Wondermedia SF Device");
+	if (err)
+		return err;
+
+	info->sf_mtd->priv = info;
+	dev_set_drvdata(&pdev->dev, info);
+
+	pr_info("Wondermedia Serial Flash Controller initialized\n");
+
+	return 0;
+}
+
+static int wmt_sf_remove(struct platform_device *pdev)
+{
+	struct wmt_sf_data *info = dev_get_drvdata(&pdev->dev);
+
+	mtd_device_unregister(info->sf_mtd);
+
+	return 0;
+}
+
+static const struct of_device_id wmt_dt_ids[] = {
+	{ .compatible = "wm,wm8505-sf", },
+	{}
+};
+
+static struct platform_driver wmt_sf_driver = {
+	.probe		= wmt_sf_probe,
+	.remove		= wmt_sf_remove,
+	.driver		= {
+		.name	= "wmt-sf",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(wmt_dt_ids),
+	},
+};
+
+module_platform_driver(wmt_sf_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("Wondermedia SoC Serial Flash driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/2] mtd: Add a common JEDEC flash device table
  2013-01-23  8:01 ` [PATCH v3 1/2] mtd: Add a common JEDEC flash device table Tony Prisk
@ 2013-01-23  9:00   ` Matthieu CASTET
  2013-01-23 18:28     ` Tony Prisk
  0 siblings, 1 reply; 5+ messages in thread
From: Matthieu CASTET @ 2013-01-23  9:00 UTC (permalink / raw)
  To: Tony Prisk
  Cc: dwmw2, dedekind1, linux-kernel, linux-mtd,
	vt8500-wm8505-linux-kernel, linux-arm-kernel

Tony Prisk a écrit :
> This patch adds a common JEDEC flash device table which can be
> expanded on as more features are required.
> 
> A simple match function is also included to query the table for
> a match based on the JEDEC id.

Why don't you use id from include/linux/mtd/cfi.h that is used by flash driver
like drivers/mtd/devices/m25p80.c ?


#define CFI_MFR_AMD     0x0001
#define CFI_MFR_AMIC        0x0037
#define CFI_MFR_ATMEL       0x001F
#define CFI_MFR_EON     0x001C
#define CFI_MFR_FUJITSU     0x0004
#define CFI_MFR_HYUNDAI     0x00AD
#define CFI_MFR_INTEL       0x0089
#define CFI_MFR_MACRONIX    0x00C2
#define CFI_MFR_NEC     0x0010
#define CFI_MFR_PMC     0x009D
#define CFI_MFR_SAMSUNG     0x00EC
#define CFI_MFR_SHARP       0x00B0
#define CFI_MFR_SST     0x00BF
#define CFI_MFR_ST      0x0020 /* STMicroelectronics */
#define CFI_MFR_TOSHIBA     0x0098
#define CFI_MFR_WINBOND     0x00DA


> 
> Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
> ---
>  drivers/mtd/devices/flash_jedec.c |   96 +++++++++++++++++++++++++++++++++++++
>  drivers/mtd/devices/flash_jedec.h |   30 ++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/mtd/devices/flash_jedec.c
>  create mode 100644 drivers/mtd/devices/flash_jedec.h
> 
> diff --git a/drivers/mtd/devices/flash_jedec.c b/drivers/mtd/devices/flash_jedec.c
> new file mode 100644
> index 0000000..c0b2272
> --- /dev/null
> +++ b/drivers/mtd/devices/flash_jedec.c
> @@ -0,0 +1,96 @@
> +/*
> + * Copyright Tony Prisk <linux@prisktech.co.nz>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/bug.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +
> +#include "flash_jedec.h"
> +
> +/*
> + * Device Manufacturer IDs
> + * Please keep sorted by manufacturer ID
> + */
> +#define MFR_SPANSION		0X01
> +#define MFR_EON			0X1C
> +#define MFR_ATMEL		0X1F
> +#define MFR_MICRON		0X20	/* Also Numonyx & STM */
> +#define MFR_INTEL		0x89
> +#define MFR_FUDAN		0XA1
> +#define MFR_SST			0XBF
> +#define MFR_MXIC		0XC2
> +#define MFR_WINBOND		0XEF
> +
> +#define _ID(m, d)	((m << 16) | d)
> +
> +/*
> + * Flash device information
> + * Please keep sorted by manufacturer id, then device id
> + */
> +static struct flash_device_info flash_devices[] = {
> +	/* Spansion */
> +	{ "s25fl016", _ID(MFR_SPANSION, 0x0214), 2048 },
> +	{ "s25fl064", _ID(MFR_SPANSION, 0x0216), 8192 },
> +	/* EON */
> +	{ "en25p16", _ID(MFR_EON, 0x2015), 2048 },
> +	{ "en25p64", _ID(MFR_EON, 0x2017), 8192 },
> +	{ "en25f40", _ID(MFR_EON, 0x3113),  512 },
> +	{ "en25f16", _ID(MFR_EON, 0x3115), 2048 },
> +	/* ATMEL */
> +	{ "at25df041a", _ID(MFR_ATMEL, 0x4401), 512 },
> +	/* Micron, STM & Numonyx */
> +	{ "stm25p16", _ID(MFR_MICRON, 0x2015), 2048 },
> +	{ "stm25p64", _ID(MFR_MICRON, 0x2017), 8192 },
> +	/* Fudan */
> +	{ "fm25f04", _ID(MFR_FUDAN, 0x3113), 512 },
> +	/* SST */
> +	{ "sst25vf016b", _ID(MFR_SST, 0x2541), 2048 },
> +	/* Macronix - MXIC */
> +	{ "mx25l512",   _ID(MFR_MXIC, 0x2010),    64 },
> +	{ "mx25l4005",  _ID(MFR_MXIC, 0x2013),   512 },
> +	{ "mx25l1605",  _ID(MFR_MXIC, 0x2015),  2048 },
> +	{ "mx25l3205",  _ID(MFR_MXIC, 0x2016),  4096 },
> +	{ "mx25l6405",  _ID(MFR_MXIC, 0x2017),  8192 },
> +	{ "mx25l12805", _ID(MFR_MXIC, 0x2018), 16384 },
> +	{ "mx25l1635",  _ID(MFR_MXIC, 0x2415),  2048 },
> +	{ "mx25l3235",  _ID(MFR_MXIC, 0x5E16),  4096 },
> +	/* Winbond */
> +	{ "w25x40", _ID(MFR_WINBOND, 0x3013),   512 },
> +	{ "w25x16", _ID(MFR_WINBOND, 0x3015),  2048 },
> +	{ "w25x32", _ID(MFR_WINBOND, 0x3016),  4096 },
> +	{ "w25x64", _ID(MFR_WINBOND, 0x3017),  8192 },
> +};
> +
> +/*
> + * jedec_match_device - match a jedec id against the flash_devices table
> + * @jedecid: JEDEC formatted id to match
> + *	bits 16..24: manufacturer id
> + *	bits  0..15: device id
> + * Returns a valid flash_device_info* or ERR_PTR(-ENODEV) if an entry is
> + * not found
> + */
> +struct flash_device_info *jedec_match_device(u32 jedec_id)
> +{
> +	int i;
> +	for (i = 0; i < ARRAY_SIZE(flash_devices); i++)
> +		if (flash_devices[i].jedec_id == jedec_id)
> +			return &flash_devices[i];
> +
> +	return ERR_PTR(-ENODEV);
> +}
> diff --git a/drivers/mtd/devices/flash_jedec.h b/drivers/mtd/devices/flash_jedec.h
> new file mode 100644
> index 0000000..27b978a
> --- /dev/null
> +++ b/drivers/mtd/devices/flash_jedec.h
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright Tony Prisk <linux@prisktech.co.nz>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __MTD_FLASH_JEDEC
> +#define __MTD_FLASH_JEDEC
> +
> +struct flash_device_info {
> +	const char	*name;
> +	u32		jedec_id;
> +	u32		size_kb;
> +};
> +
> +extern struct flash_device_info *jedec_match_device(u32 jedec_id);
> +
> +#endif


-- 
Matthieu Castet
Ingénieur Développement Logiciel
Parrot SA
174 Quai de Jemmapes
75010 Paris, France

Tél: +33 (0) 1 48 03 74 78
Fax: +33 (0) 1 48 03 06 66
Email: matthieu.castet@parrot.fr
http://www.parrot.biz

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/2] mtd: Add a common JEDEC flash device table
  2013-01-23  9:00   ` Matthieu CASTET
@ 2013-01-23 18:28     ` Tony Prisk
  0 siblings, 0 replies; 5+ messages in thread
From: Tony Prisk @ 2013-01-23 18:28 UTC (permalink / raw)
  To: vt8500-wm8505-linux-kernel
  Cc: dwmw2, dedekind1, linux-kernel, linux-mtd, linux-arm-kernel

On Wed, 2013-01-23 at 10:00 +0100, Matthieu CASTET wrote:
> Tony Prisk a écrit :
> > This patch adds a common JEDEC flash device table which can be
> > expanded on as more features are required.
> > 
> > A simple match function is also included to query the table for
> > a match based on the JEDEC id.
> 
> Why don't you use id from include/linux/mtd/cfi.h that is used by flash driver
> like drivers/mtd/devices/m25p80.c ?
> 

Thanks - have changed for v4.

Regards
Tony P


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-01-23 18:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-23  8:01 [PATCH v3 0/2] Add Wondermedia Serial Flash controller support Tony Prisk
2013-01-23  8:01 ` [PATCH v3 1/2] mtd: Add a common JEDEC flash device table Tony Prisk
2013-01-23  9:00   ` Matthieu CASTET
2013-01-23 18:28     ` Tony Prisk
2013-01-23  8:01 ` [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller Tony Prisk

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).