* [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).