* [PATCH v3 0/2] Add Wondermedia Serial Flash controller support @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: dwmw2 Cc: dedekind1, linux-kernel, Tony Prisk, linux-mtd, vt8500-wm8505-linux-kernel, linux-arm-kernel 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] 15+ messages in thread
* [PATCH v3 0/2] Add Wondermedia Serial Flash controller support @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ 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] 15+ messages in thread
* [PATCH v3 0/2] Add Wondermedia Serial Flash controller support @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: linux-arm-kernel 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] 15+ messages in thread
* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table 2013-01-23 8:01 ` Tony Prisk (?) @ 2013-01-23 8:01 ` Tony Prisk -1 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: dwmw2 Cc: dedekind1, linux-kernel, Tony Prisk, linux-mtd, vt8500-wm8505-linux-kernel, linux-arm-kernel 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] 15+ messages in thread
* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ 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] 15+ messages in thread
* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: linux-arm-kernel 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] 15+ messages in thread
* Re: [PATCH v3 1/2] mtd: Add a common JEDEC flash device table 2013-01-23 8:01 ` Tony Prisk (?) @ 2013-01-23 9:00 ` Matthieu CASTET -1 siblings, 0 replies; 15+ messages in thread From: Matthieu CASTET @ 2013-01-23 9:00 UTC (permalink / raw) To: Tony Prisk Cc: dedekind1@gmail.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, vt8500-wm8505-linux-kernel@googlegroups.com, dwmw2@infradead.org, linux-arm-kernel@lists.infradead.org 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] 15+ messages in thread
* Re: [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 9:00 ` Matthieu CASTET 0 siblings, 0 replies; 15+ messages in thread From: Matthieu CASTET @ 2013-01-23 9:00 UTC (permalink / raw) To: Tony Prisk Cc: dwmw2@infradead.org, dedekind1@gmail.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, vt8500-wm8505-linux-kernel@googlegroups.com, linux-arm-kernel@lists.infradead.org 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] 15+ messages in thread
* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 9:00 ` Matthieu CASTET 0 siblings, 0 replies; 15+ messages in thread From: Matthieu CASTET @ 2013-01-23 9:00 UTC (permalink / raw) To: 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 at parrot.fr http://www.parrot.biz ^ permalink raw reply [flat|nested] 15+ 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 -1 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 18:28 UTC (permalink / raw) To: vt8500-wm8505-linux-kernel Cc: linux-mtd@lists.infradead.org, dwmw2@infradead.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, dedekind1@gmail.com 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] 15+ messages in thread
* Re: [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 18:28 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 18:28 UTC (permalink / raw) To: vt8500-wm8505-linux-kernel Cc: dwmw2@infradead.org, dedekind1@gmail.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org 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] 15+ messages in thread
* [PATCH v3 1/2] mtd: Add a common JEDEC flash device table @ 2013-01-23 18:28 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 18:28 UTC (permalink / raw) To: 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] 15+ messages in thread
* [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller 2013-01-23 8:01 ` Tony Prisk (?) @ 2013-01-23 8:01 ` Tony Prisk -1 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: dwmw2 Cc: dedekind1, linux-kernel, Tony Prisk, linux-mtd, vt8500-wm8505-linux-kernel, linux-arm-kernel 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] 15+ messages in thread
* [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ 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] 15+ messages in thread
* [PATCH v3 2/2] mtd: vt8500: Add support for Wondermedia Serial Flash Controller @ 2013-01-23 8:01 ` Tony Prisk 0 siblings, 0 replies; 15+ messages in thread From: Tony Prisk @ 2013-01-23 8:01 UTC (permalink / raw) To: linux-arm-kernel 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] 15+ messages in thread
end of thread, other threads:[~2013-01-23 18:28 UTC | newest] Thread overview: 15+ 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 ` Tony Prisk 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 ` Tony Prisk 2013-01-23 8:01 ` Tony Prisk 2013-01-23 9:00 ` Matthieu CASTET 2013-01-23 9:00 ` Matthieu CASTET 2013-01-23 9:00 ` Matthieu CASTET 2013-01-23 18:28 ` Tony Prisk 2013-01-23 18:28 ` Tony Prisk 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 2013-01-23 8:01 ` Tony Prisk 2013-01-23 8:01 ` Tony Prisk
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.