[PATCH V3 36/63] ST SPEAr : FSMC (Flexible Static Memory Controller) NOR interface driver

Viresh Kumar viresh.kumar at st.com
Mon Dec 20 03:25:56 EST 2010


From: Vipin Kumar <vipin.kumar at st.com>

SPEAr1300 SoC supports FSMC to interface with various memories
(NOR/NAND/SRAM). This patch adds the support for FSMC over NOR interface.

The driver being used is driver/mtd/maps/physmap.c

Signed-off-by: Vipin Kumar <vipin.kumar at st.com>
Signed-off-by: shiraz hashim <shiraz.hashim at st.com>
Signed-off-by: Viresh Kumar <viresh.kumar at st.com>
---
 arch/arm/mach-spear13xx/Makefile               |    2 +-
 arch/arm/mach-spear13xx/fsmc-nor.c             |   85 ++++++++++++++++++++++++
 arch/arm/mach-spear13xx/include/mach/generic.h |    1 +
 arch/arm/mach-spear13xx/spear1300_evb.c        |   17 +++++
 arch/arm/mach-spear13xx/spear1310_evb.c        |   17 +++++
 arch/arm/mach-spear13xx/spear13xx.c            |   20 ++++++
 arch/arm/plat-spear/include/plat/fsmc.h        |   15 ++++
 include/linux/mtd/fsmc.h                       |    2 +
 8 files changed, 158 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-spear13xx/fsmc-nor.c

diff --git a/arch/arm/mach-spear13xx/Makefile b/arch/arm/mach-spear13xx/Makefile
index 838405a..9312fcd 100644
--- a/arch/arm/mach-spear13xx/Makefile
+++ b/arch/arm/mach-spear13xx/Makefile
@@ -3,7 +3,7 @@
 #
 
 # common files
-obj-y					+= spear13xx.o clock.o
+obj-y					+= spear13xx.o clock.o fsmc-nor.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_LOCAL_TIMERS)		+= localtimer.o
 obj-$(CONFIG_PCIEPORTBUS)		+= pcie.o
diff --git a/arch/arm/mach-spear13xx/fsmc-nor.c b/arch/arm/mach-spear13xx/fsmc-nor.c
new file mode 100644
index 0000000..03234b6
--- /dev/null
+++ b/arch/arm/mach-spear13xx/fsmc-nor.c
@@ -0,0 +1,85 @@
+/*
+ * arch/arm/mach-spear13xx/fsmc-nor.c
+ *
+ * FSMC (Flexible Static Memory Controller) interface for NOR
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Vipin Kumar<vipin.kumar at st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <plat/fsmc.h>
+
+int __init fsmc_nor_init(struct platform_device *pdev, unsigned long base,
+		u32 bank, u32 width)
+{
+	void __iomem *fsmc_nor_base;
+	struct fsmc_regs *regs;
+	struct clk *clk;
+	int ret;
+	u32 ctrl;
+
+	if (bank > (FSMC_MAX_NOR_BANKS - 1))
+		return -EINVAL;
+
+	fsmc_nor_base = ioremap(base, FSMC_NOR_REG_SIZE);
+	if (!fsmc_nor_base)
+		return -ENOMEM;
+
+	clk = clk_get(NULL, "fsmc");
+	if (IS_ERR(clk)) {
+		iounmap(fsmc_nor_base);
+		return PTR_ERR(clk);
+	}
+
+	ret = clk_enable(clk);
+	if (ret) {
+		iounmap(fsmc_nor_base);
+		return ret;
+	}
+
+	regs = (struct fsmc_regs *)fsmc_nor_base;
+
+	ctrl = WAIT_ENB | WRT_ENABLE | WPROT | NOR_DEV | BANK_ENABLE;
+
+	switch (width) {
+	case FSMC_FLASH_WIDTH8:
+		ctrl |= WIDTH_8;
+		break;
+
+	case FSMC_FLASH_WIDTH16:
+		ctrl |= WIDTH_16;
+		break;
+
+	case FSMC_FLASH_WIDTH32:
+		ctrl |= WIDTH_32;
+		break;
+
+	default:
+		ctrl |= WIDTH_8;
+		break;
+	}
+
+	writel(ctrl, &regs->nor_bank_regs[bank].ctrl);
+	writel(0x0FFFFFFF, &regs->nor_bank_regs[bank].ctrl_tim);
+	writel(ctrl | RSTPWRDWN, &regs->nor_bank_regs[bank].ctrl);
+
+	iounmap(fsmc_nor_base);
+
+	return 0;
+}
+
+void __init fsmc_init_board_info(struct platform_device *pdev,
+		struct mtd_partition *partitions, unsigned int nr_partitions,
+		unsigned int width)
+{
+	fsmc_nor_set_plat_data(pdev, partitions, nr_partitions, width);
+}
diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h
index 5cbf131..d719039 100644
--- a/arch/arm/mach-spear13xx/include/mach/generic.h
+++ b/arch/arm/mach-spear13xx/include/mach/generic.h
@@ -34,6 +34,7 @@ extern struct amba_device spear13xx_ssp_device;
 extern struct amba_device spear13xx_uart_device;
 extern struct platform_device spear13xx_ehci0_device;
 extern struct platform_device spear13xx_ehci1_device;
+extern struct platform_device spear13xx_fsmc_nor_device;
 extern struct platform_device spear13xx_i2c_device;
 extern struct platform_device spear13xx_kbd_device;
 extern struct platform_device spear13xx_nand_device;
diff --git a/arch/arm/mach-spear13xx/spear1300_evb.c b/arch/arm/mach-spear13xx/spear1300_evb.c
index f39555e..b6ee08a 100644
--- a/arch/arm/mach-spear13xx/spear1300_evb.c
+++ b/arch/arm/mach-spear13xx/spear1300_evb.c
@@ -22,10 +22,20 @@
 #include <mach/generic.h>
 #include <mach/spear.h>
 #include <mach/pcie.h>
+#include <plat/fsmc.h>
 #include <plat/keyboard.h>
 #include <plat/fsmc.h>
 #include <plat/spi.h>
 
+#define PARTITION(n, off, sz)	{.name = n, .offset = off, .size = sz}
+
+static struct mtd_partition partition_info[] = {
+	PARTITION("X-loader", 0, 1 * 0x20000),
+	PARTITION("U-Boot", 0x20000, 3 * 0x20000),
+	PARTITION("Kernel", 0x80000, 24 * 0x20000),
+	PARTITION("Root File System", 0x380000, 84 * 0x20000),
+};
+
 static struct amba_device *amba_devs[] __initdata = {
 	&spear13xx_gpio_device[0],
 	&spear13xx_gpio_device[1],
@@ -112,6 +122,13 @@ static void __init spear1300_evb_init(void)
 	enable_pcie0_clk();
 	pcie_init(&spear1300_pcie_port_is_host);
 #endif
+	/* initialize fsmc related data in fsmc plat data */
+	fsmc_init_board_info(&spear13xx_fsmc_nor_device, partition_info,
+			ARRAY_SIZE(partition_info), FSMC_FLASH_WIDTH8);
+
+	/* Initialize fsmc regiters */
+	fsmc_nor_init(&spear13xx_fsmc_nor_device, SPEAR13XX_FSMC_BASE, 0,
+			FSMC_FLASH_WIDTH8);
 
 	/* Add Platform Devices */
 	platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
diff --git a/arch/arm/mach-spear13xx/spear1310_evb.c b/arch/arm/mach-spear13xx/spear1310_evb.c
index 0c190b7..84069b6 100644
--- a/arch/arm/mach-spear13xx/spear1310_evb.c
+++ b/arch/arm/mach-spear13xx/spear1310_evb.c
@@ -26,6 +26,15 @@
 #include <plat/fsmc.h>
 #include <plat/spi.h>
 
+#define PARTITION(n, off, sz)	{.name = n, .offset = off, .size = sz}
+
+static struct mtd_partition partition_info[] = {
+	PARTITION("X-loader", 0, 1 * 0x20000),
+	PARTITION("U-Boot", 0x20000, 3 * 0x20000),
+	PARTITION("Kernel", 0x80000, 24 * 0x20000),
+	PARTITION("Root File System", 0x380000, 84 * 0x20000),
+};
+
 static struct amba_device *amba_devs[] __initdata = {
 	/* spear13xx specific devices */
 	&spear13xx_gpio_device[0],
@@ -123,6 +132,14 @@ static void __init spear1310_evb_init(void)
 	fsmc_nor_init(&spear13xx_fsmc_nor_device, SPEAR13XX_FSMC_BASE, 0,
 			FSMC_FLASH_WIDTH8);
 
+	/* initialize fsmc related data in fsmc plat data */
+	fsmc_init_board_info(&spear13xx_fsmc_nor_device, partition_info,
+			ARRAY_SIZE(partition_info), FSMC_FLASH_WIDTH8);
+
+	/* Initialize fsmc regiters */
+	fsmc_nor_init(&spear13xx_fsmc_nor_device, SPEAR13XX_FSMC_BASE, 0,
+			FSMC_FLASH_WIDTH8);
+
 #ifdef CONFIG_PCIEPORTBUS
 	/* Enable PCIE0 clk */
 	enable_pcie0_clk();
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index 630e004..a218d15 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/amba/pl022.h>
 #include <linux/amba/pl061.h>
+#include <linux/mtd/physmap.h>
 #include <linux/ptrace.h>
 #include <linux/io.h>
 #include <linux/mtd/fsmc.h>
@@ -130,6 +131,25 @@ struct platform_device spear13xx_i2c_device = {
 	.resource = i2c_resources,
 };
 
+/* fsmc nor flash device registeration */
+static struct physmap_flash_data fsmc_norflash_data;
+
+static struct resource fsmc_nor_resources[] = {
+	{
+		.start	= SPEAR13XX_FSMC_MEM_BASE,
+		.end	= SPEAR13XX_FSMC_MEM_BASE + SZ_16M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device spear13xx_fsmc_nor_device = {
+	.name	= "physmap-flash",
+	.id	= -1,
+	.resource = fsmc_nor_resources,
+	.num_resources = ARRAY_SIZE(fsmc_nor_resources),
+	.dev.platform_data = &fsmc_norflash_data,
+};
+
 /* nand device registeration */
 void __init nand_mach_init(u32 busw)
 {
diff --git a/arch/arm/plat-spear/include/plat/fsmc.h b/arch/arm/plat-spear/include/plat/fsmc.h
index 364a79b..3b460d7 100644
--- a/arch/arm/plat-spear/include/plat/fsmc.h
+++ b/arch/arm/plat-spear/include/plat/fsmc.h
@@ -14,6 +14,7 @@
 #ifndef __PLAT_FSMC_H
 #define __PLAT_FSMC_H
 
+#include <linux/mtd/physmap.h>
 #include <linux/mtd/fsmc.h>
 
 /* This function is used to set platform data field of pdev->dev */
@@ -33,4 +34,18 @@ static inline void fsmc_nand_set_plat_data(struct platform_device *pdev,
 	plat_data->width = width;
 }
 
+static inline void fsmc_nor_set_plat_data(struct platform_device *pdev,
+		struct mtd_partition *partitions, unsigned int nr_partitions,
+		unsigned int width)
+{
+	struct physmap_flash_data *plat_data;
+	plat_data = dev_get_platdata(&pdev->dev);
+
+	if (partitions) {
+		plat_data->parts = partitions;
+		plat_data->nr_parts = nr_partitions;
+	}
+
+	plat_data->width = width;
+}
 #endif /* __PLAT_FSMC_H */
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
index e210b87..fce5cf0 100644
--- a/include/linux/mtd/fsmc.h
+++ b/include/linux/mtd/fsmc.h
@@ -44,6 +44,7 @@
 
 #define FSMC_FLASH_WIDTH8	1
 #define FSMC_FLASH_WIDTH16	2
+#define FSMC_FLASH_WIDTH32	4
 
 struct fsmc_nor_bank_regs {
 	uint32_t ctrl;
@@ -56,6 +57,7 @@ struct fsmc_nor_bank_regs {
 #define NOR_DEV			(2 << 2)
 #define WIDTH_8			(0 << 4)
 #define WIDTH_16		(1 << 4)
+#define WIDTH_32		(2 << 4)
 #define RSTPWRDWN		(1 << 6)
 #define WPROT			(1 << 7)
 #define WRT_ENABLE		(1 << 12)
-- 
1.7.2.2




More information about the linux-arm-kernel mailing list