Commit 541d5d02 authored by Ladislav Michl's avatar Ladislav Michl Committed by Tony Lindgren

[PATCH] ARM: OMAP: NAND flash driver model

NAND flash driver model
parent 5ff4cea4
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -40,7 +41,7 @@ ...@@ -40,7 +41,7 @@
extern int omap_gpio_init(void); extern int omap_gpio_init(void);
static struct mtd_partition h2_partitions[] = { static struct mtd_partition h2_nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */ /* bootloader (U-Boot, etc) in first sector */
{ {
.name = "bootloader", .name = "bootloader",
...@@ -71,26 +72,83 @@ static struct mtd_partition h2_partitions[] = { ...@@ -71,26 +72,83 @@ static struct mtd_partition h2_partitions[] = {
} }
}; };
static struct flash_platform_data h2_flash_data = { static struct flash_platform_data h2_nor_data = {
.map_name = "cfi_probe", .map_name = "cfi_probe",
.width = 2, .width = 2,
.parts = h2_partitions, .parts = h2_nor_partitions,
.nr_parts = ARRAY_SIZE(h2_partitions), .nr_parts = ARRAY_SIZE(h2_nor_partitions),
}; };
static struct resource h2_flash_resource = { static struct resource h2_nor_resource = {
/* This is on CS3, wherever it's mapped */ /* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };
static struct platform_device h2_flash_device = { static struct platform_device h2_nor_device = {
.name = "omapflash", .name = "omapflash",
.id = 0, .id = 0,
.dev = { .dev = {
.platform_data = &h2_flash_data, .platform_data = &h2_nor_data,
}, },
.num_resources = 1, .num_resources = 1,
.resource = &h2_flash_resource, .resource = &h2_nor_resource,
};
static struct mtd_partition h2_nand_partitions[] = {
#if 0
/* REVISIT: enable these partitions if you make NAND BOOT
* work on your H2 (rev C or newer); published versions of
* x-load only support P2 and H3.
*/
{
.name = "xloader",
.offset = 0,
.size = 64 * 1024,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "bootloader",
.offset = MTDPART_OFS_APPEND,
.size = 256 * 1024,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "params",
.offset = MTDPART_OFS_APPEND,
.size = 192 * 1024,
},
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 2 * SZ_1M,
},
#endif
{
.name = "filesystem",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
},
};
/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */
static struct nand_platform_data h2_nand_data = {
.options = NAND_SAMSUNG_LP_OPTIONS,
.parts = h2_nand_partitions,
.nr_parts = ARRAY_SIZE(h2_nand_partitions),
};
static struct resource h2_nand_resource = {
.flags = IORESOURCE_MEM,
};
static struct platform_device h2_nand_device = {
.name = "omapnand",
.id = 0,
.dev = {
.platform_data = &h2_nand_data,
},
.num_resources = 1,
.resource = &h2_nand_resource,
}; };
static struct resource h2_smc91x_resources[] = { static struct resource h2_smc91x_resources[] = {
...@@ -114,7 +172,8 @@ static struct platform_device h2_smc91x_device = { ...@@ -114,7 +172,8 @@ static struct platform_device h2_smc91x_device = {
}; };
static struct platform_device *h2_devices[] __initdata = { static struct platform_device *h2_devices[] __initdata = {
&h2_flash_device, &h2_nor_device,
&h2_nand_device,
&h2_smc91x_device, &h2_smc91x_device,
}; };
...@@ -174,13 +233,34 @@ static struct omap_board_config_kernel h2_config[] = { ...@@ -174,13 +233,34 @@ static struct omap_board_config_kernel h2_config[] = {
{ OMAP_TAG_LCD, &h2_lcd_config }, { OMAP_TAG_LCD, &h2_lcd_config },
}; };
#define H2_NAND_RB_GPIO_PIN 62
static int h2_nand_dev_ready(struct nand_platform_data *data)
{
return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
}
static void __init h2_init(void) static void __init h2_init(void)
{ {
/* NOTE: revC boards support NAND-boot, which can put NOR on CS2B /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
* and NAND (either 16bit or 8bit) on CS3. * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
* notice whether a NAND chip is enabled at probe time.
*
* FIXME revC boards (and H3) support NAND-boot, with a dip switch to
* put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try
* detecting that in code here, to avoid probing every possible flash
* configuration...
*/ */
h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys(); h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys();
h2_flash_resource.end += SZ_32M - 1; h2_nor_resource.end += SZ_32M - 1;
h2_nand_resource.end = h2_nand_resource.start = OMAP_CS2B_PHYS;
h2_nand_resource.end += SZ_4K - 1;
if (!(omap_request_gpio(H2_NAND_RB_GPIO_PIN)))
h2_nand_data.dev_ready = h2_nand_dev_ready;
omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
/* MMC: card detect and WP */ /* MMC: card detect and WP */
// omap_cfg_reg(U19_ARMIO1); /* CD */ // omap_cfg_reg(U19_ARMIO1); /* CD */
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -41,7 +42,7 @@ ...@@ -41,7 +42,7 @@
extern int omap_gpio_init(void); extern int omap_gpio_init(void);
static struct mtd_partition h3_partitions[] = { static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */ /* bootloader (U-Boot, etc) in first sector */
{ {
.name = "bootloader", .name = "bootloader",
...@@ -72,26 +73,80 @@ static struct mtd_partition h3_partitions[] = { ...@@ -72,26 +73,80 @@ static struct mtd_partition h3_partitions[] = {
} }
}; };
static struct flash_platform_data h3_flash_data = { static struct flash_platform_data nor_data = {
.map_name = "cfi_probe", .map_name = "cfi_probe",
.width = 2, .width = 2,
.parts = h3_partitions, .parts = nor_partitions,
.nr_parts = ARRAY_SIZE(h3_partitions), .nr_parts = ARRAY_SIZE(nor_partitions),
}; };
static struct resource h3_flash_resource = { static struct resource nor_resource = {
/* This is on CS3, wherever it's mapped */ /* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };
static struct platform_device flash_device = { static struct platform_device nor_device = {
.name = "omapflash", .name = "omapflash",
.id = 0, .id = 0,
.dev = { .dev = {
.platform_data = &h3_flash_data, .platform_data = &nor_data,
}, },
.num_resources = 1, .num_resources = 1,
.resource = &h3_flash_resource, .resource = &nor_resource,
};
static struct mtd_partition nand_partitions[] = {
#if 0
/* REVISIT: enable these partitions if you make NAND BOOT work */
{
.name = "xloader",
.offset = 0,
.size = 64 * 1024,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "bootloader",
.offset = MTDPART_OFS_APPEND,
.size = 256 * 1024,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "params",
.offset = MTDPART_OFS_APPEND,
.size = 192 * 1024,
},
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 2 * SZ_1M,
},
#endif
{
.name = "filesystem",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
},
};
/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */
static struct nand_platform_data nand_data = {
.options = NAND_SAMSUNG_LP_OPTIONS,
.parts = nand_partitions,
.nr_parts = ARRAY_SIZE(nand_partitions),
};
static struct resource nand_resource = {
.flags = IORESOURCE_MEM,
};
static struct platform_device nand_device = {
.name = "omapnand",
.id = 0,
.dev = {
.platform_data = &nand_data,
},
.num_resources = 1,
.resource = &nand_resource,
}; };
static struct resource smc91x_resources[] = { static struct resource smc91x_resources[] = {
...@@ -139,7 +194,8 @@ static struct platform_device intlat_device = { ...@@ -139,7 +194,8 @@ static struct platform_device intlat_device = {
}; };
static struct platform_device *devices[] __initdata = { static struct platform_device *devices[] __initdata = {
&flash_device, &nor_device,
&nand_device,
&smc91x_device, &smc91x_device,
&intlat_device, &intlat_device,
}; };
...@@ -182,11 +238,36 @@ static struct omap_board_config_kernel h3_config[] = { ...@@ -182,11 +238,36 @@ static struct omap_board_config_kernel h3_config[] = {
{ OMAP_TAG_LCD, &h3_lcd_config }, { OMAP_TAG_LCD, &h3_lcd_config },
}; };
#define H3_NAND_RB_GPIO_PIN 10
static int nand_dev_ready(struct nand_platform_data *data)
{
return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
}
static void __init h3_init(void) static void __init h3_init(void)
{ {
h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys(); /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
h3_flash_resource.end += OMAP_CS3_SIZE - 1; * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
(void) platform_add_devices(devices, ARRAY_SIZE(devices)); * notice whether a NAND chip is enabled at probe time.
*
* H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND
* (which on H2 may be 16bit) on CS3. Try detecting that in code here,
* to avoid probing every possible flash configuration...
*/
nor_resource.end = nor_resource.start = omap_cs3_phys();
nor_resource.end += SZ_32M - 1;
nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS;
nand_resource.end += SZ_4K - 1;
if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN)))
nand_data.dev_ready = nand_dev_ready;
/* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */
/* GPIO10 pullup/down register, Enable pullup on GPIO10 */
omap_cfg_reg(V2_1710_GPIO10);
platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = h3_config; omap_board_config = h3_config;
omap_board_config_size = ARRAY_SIZE(h3_config); omap_board_config_size = ARRAY_SIZE(h3_config);
omap_serial_init(); omap_serial_init();
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -44,7 +45,7 @@ static struct resource smc91x_resources[] = { ...@@ -44,7 +45,7 @@ static struct resource smc91x_resources[] = {
}, },
}; };
static struct mtd_partition p2_partitions[] = { static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */ /* bootloader (U-Boot, etc) in first sector */
{ {
.name = "bootloader", .name = "bootloader",
...@@ -75,27 +76,47 @@ static struct mtd_partition p2_partitions[] = { ...@@ -75,27 +76,47 @@ static struct mtd_partition p2_partitions[] = {
}, },
}; };
static struct flash_platform_data p2_flash_data = { static struct flash_platform_data nor_data = {
.map_name = "cfi_probe", .map_name = "cfi_probe",
.width = 2, .width = 2,
.parts = p2_partitions, .parts = nor_partitions,
.nr_parts = ARRAY_SIZE(p2_partitions), .nr_parts = ARRAY_SIZE(nor_partitions),
}; };
static struct resource p2_flash_resource = { static struct resource nor_resource = {
.start = OMAP_CS0_PHYS, .start = OMAP_CS0_PHYS,
.end = OMAP_CS0_PHYS + SZ_32M - 1, .end = OMAP_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };
static struct platform_device p2_flash_device = { static struct platform_device nor_device = {
.name = "omapflash", .name = "omapflash",
.id = 0, .id = 0,
.dev = { .dev = {
.platform_data = &p2_flash_data, .platform_data = &nor_data,
}, },
.num_resources = 1, .num_resources = 1,
.resource = &p2_flash_resource, .resource = &nor_resource,
};
static struct nand_platform_data nand_data = {
.options = NAND_SAMSUNG_LP_OPTIONS,
};
static struct resource nand_resource = {
.start = OMAP_CS3_PHYS,
.end = OMAP_CS3_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
};
static struct platform_device nand_device = {
.name = "omapnand",
.id = 0,
.dev = {
.platform_data = &nand_data,
},
.num_resources = 1,
.resource = &nand_resource,
}; };
static struct platform_device smc91x_device = { static struct platform_device smc91x_device = {
...@@ -106,10 +127,18 @@ static struct platform_device smc91x_device = { ...@@ -106,10 +127,18 @@ static struct platform_device smc91x_device = {
}; };
static struct platform_device *devices[] __initdata = { static struct platform_device *devices[] __initdata = {
&p2_flash_device, &nor_device,
&nand_device,
&smc91x_device, &smc91x_device,
}; };
#define P2_NAND_RB_GPIO_PIN 62
static int nand_dev_ready(struct nand_platform_data *data)
{
return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN);
}
static struct omap_uart_config perseus2_uart_config __initdata = { static struct omap_uart_config perseus2_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1)), .enabled_uarts = ((1 << 0) | (1 << 1)),
}; };
...@@ -126,7 +155,13 @@ static struct omap_board_config_kernel perseus2_config[] = { ...@@ -126,7 +155,13 @@ static struct omap_board_config_kernel perseus2_config[] = {
static void __init omap_perseus2_init(void) static void __init omap_perseus2_init(void)
{ {
(void) platform_add_devices(devices, ARRAY_SIZE(devices)); if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN)))
nand_data.dev_ready = nand_dev_ready;
omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = perseus2_config; omap_board_config = perseus2_config;
omap_board_config_size = ARRAY_SIZE(perseus2_config); omap_board_config_size = ARRAY_SIZE(perseus2_config);
......
/* /*
* drivers/mtd/nand/omap-nand-flash.c * drivers/mtd/nand/omap-nand-flash.c
* *
* Copyright (c) 2004 Texas Instruments * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
* Jian Zhang <jzhang@ti.com>
* Copyright (c) 2004 David Brownell * Copyright (c) 2004 David Brownell
* *
* Derived from drivers/mtd/autcpu12.c
*
* Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the NAND flash device found on the
* TI H3/H2 boards. It supports 16-bit 32MiB Samsung k9f5616 chip.
*
*/ */
#include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/hardware.h> #include <asm/hardware.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/sizes.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/flash.h>
#include <asm/arch/tc.h>
#define H3_NAND_RB_GPIO_PIN 10 #include <asm/io.h>
#define H2_NAND_RB_GPIO_PIN 62 #include <asm/arch/hardware.h>
#define P2_NAND_RB_GPIO_PIN 62
#define NETSTAR_NAND_RB_GPIO_PIN 1
/*
* MTD structure for H3 board
*/
static struct mtd_info *omap_nand_mtd = NULL;
static void __iomem *omap_nand_flash_base;
/* #define DRIVER_NAME "omapnand"
* Define partitions for flash devices
*/
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition static_partition[] = { static const char *part_probes[] = { "cmdlinepart", NULL };
{ .name = "Booting Image",
.offset = 0,
.size = 64 * 1024,
.mask_flags = MTD_WRITEABLE /* force read-only */
},
{ .name = "U-Boot",
.offset = MTDPART_OFS_APPEND,
.size = 256 * 1024,
.mask_flags = MTD_WRITEABLE /* force read-only */
},
{ .name = "U-Boot Environment",
.offset = MTDPART_OFS_APPEND,
.size = 192 * 1024
},
{ .name = "Kernel",
.offset = MTDPART_OFS_APPEND,
.size = 2 * SZ_1M
},
{ .name = "File System",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
},
};
const char *part_probes[] = { "cmdlinepart", NULL, };
#endif #endif
/* H2/H3 maps two address LSBs to CLE and ALE; MSBs make CS_2B */ struct omap_nand_info {
#define MASK_CLE 0x02 struct nand_platform_data *pdata;
#define MASK_ALE 0x04 struct mtd_partition *parts;
struct mtd_info mtd;
struct nand_chip nand;
};
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*/ * NOTE: boards may use different bits for these!!
*/
#define MASK_CLE 0x02
#define MASK_ALE 0x04
static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd) static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
u32 IO_ADDR_W = (u32) this->IO_ADDR_W; unsigned long IO_ADDR_W = (unsigned long) this->IO_ADDR_W;
IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); switch (cmd) {
switch(cmd){
case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break; case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break;
case NAND_CTL_CLRCLE: IO_ADDR_W &= ~MASK_CLE; break;
case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break; case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break;
case NAND_CTL_CLRALE: IO_ADDR_W &= ~MASK_ALE; break;
} }
this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
} }
/* static int omap_nand_dev_ready(struct mtd_info *mtd)
* chip busy R/B detection
*/
static int omap_nand_ready(struct mtd_info *mtd)
{
if (machine_is_omap_h3())
return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
if (machine_is_omap_h2())
return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
if (machine_is_omap_perseus2())
return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
if (machine_is_netstar())
return omap_get_gpio_datain(NETSTAR_NAND_RB_GPIO_PIN);
return 0;
}
/* Scan to find existance of the device at omap_nand_flash_base.
This also allocates oob and data internal buffers */
static int __init probe_nand_chip(void)
{ {
struct nand_chip *this; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd);
this = (struct nand_chip *) (&omap_nand_mtd[1]);
/* Initialize structures */
memset((char *) this, 0, sizeof(struct nand_chip));
this->IO_ADDR_R = omap_nand_flash_base;
this->IO_ADDR_W = omap_nand_flash_base;
this->options = NAND_SAMSUNG_LP_OPTIONS;
this->hwcontrol = omap_nand_hwcontrol;
this->eccmode = NAND_ECC_SOFT;
/* try 16-bit chip first */
this->options |= NAND_BUSWIDTH_16;
if (nand_scan (omap_nand_mtd, 1)) {
if (machine_is_omap_h3())
return -ENXIO;
/* then try 8-bit chip for H2 */
memset((char *) this, 0, sizeof(struct nand_chip));
this->IO_ADDR_R = omap_nand_flash_base;
this->IO_ADDR_W = omap_nand_flash_base;
this->options = NAND_SAMSUNG_LP_OPTIONS;
this->hwcontrol = omap_nand_hwcontrol;
this->eccmode = NAND_ECC_SOFT;
if (nand_scan (omap_nand_mtd, 1)) {
return -ENXIO;
}
}
return 0; return info->pdata->dev_ready(info->pdata);
} }
static char nand1_name [] = "nand"; static int __devinit omap_nand_probe(struct device *dev)
/*
* Main initialization routine
*/
int __init omap_nand_init (void)
{ {
struct nand_chip *this; struct omap_nand_info *info;
struct mtd_partition *dynamic_partition = 0; struct platform_device *pdev = to_platform_device(dev);
int err = 0; struct nand_platform_data *pdata = pdev->dev.platform_data;
int nandboot = 0; struct resource *res = pdev->resource;
unsigned long size = res->end - res->start + 1;
if (!(machine_is_omap_h2() || machine_is_omap_h3() || machine_is_netstar() || machine_is_omap_perseus2())) int err;
return -ENODEV;
info = kmalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
memset(info, 0, sizeof(struct omap_nand_info));
if (!request_mem_region(res->start, size, dev->driver->name)) {
err = -EBUSY;
goto out_free_info;
}
/* Allocate memory for MTD device structure and private data */ info->nand.IO_ADDR_R = ioremap(res->start, size);
omap_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), if (!info->nand.IO_ADDR_R) {
GFP_KERNEL);
if (!omap_nand_mtd) {
printk (KERN_WARNING "Unable to allocate NAND MTD device structure.\n");
err = -ENOMEM; err = -ENOMEM;
goto out; goto out_release_mem_region;
} }
info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
info->nand.hwcontrol = omap_nand_hwcontrol;
info->nand.eccmode = NAND_ECC_SOFT;
info->nand.options = pdata->options;
if (pdata->dev_ready)
info->nand.dev_ready = omap_nand_dev_ready;
else
info->nand.chip_delay = 20;
/* Get pointer to private data */ info->mtd.name = pdev->dev.bus_id;
this = (struct nand_chip *) (&omap_nand_mtd[1]); info->mtd.priv = &info->nand;
/* Initialize structures */
memset((char *) omap_nand_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
omap_nand_mtd->priv = this;
if (machine_is_omap_h2() || machine_is_omap_perseus2()) {
/* FIXME on H2, R/B needs M7_1610_GPIO62 ... */
this->chip_delay = 15;
omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
} else if (machine_is_omap_h3()) {
if (omap_request_gpio(H3_NAND_RB_GPIO_PIN) != 0) {
printk(KERN_ERR "NAND: Unable to get GPIO pin for R/B, use delay\n");
/* 15 us command delay time */
this->chip_delay = 15;
} else {
/* GPIO10 for input. it is in GPIO1 module */
omap_set_gpio_direction(H3_NAND_RB_GPIO_PIN, 1);
/* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */ info->pdata = pdata;
/* GPIO10 pullup/down register, Enable pullup on GPIO10 */
omap_cfg_reg(V2_1710_GPIO10);
this->dev_ready = omap_nand_ready; /* DIP switches on H2 and some other boards change between 8 and 16 bit
} * bus widths for flash. Try the other width if the first try fails.
} else if (machine_is_netstar()) { */
if (omap_request_gpio(NETSTAR_NAND_RB_GPIO_PIN) != 0) { if (nand_scan(&info->mtd, 1)) {
printk(KERN_ERR "NAND: Unable to get GPIO pin for R/B, use delay\n"); info->nand.options ^= NAND_BUSWIDTH_16;
/* 15 us command delay time */ if (nand_scan(&info->mtd, 1)) {
this->chip_delay = 15;
} else {
omap_set_gpio_direction(NETSTAR_NAND_RB_GPIO_PIN, 1);
this->dev_ready = omap_nand_ready;
}
}
/* try the first address */
omap_nand_flash_base = ioremap(OMAP_NAND_FLASH_START1, SZ_4K);
omap_nand_mtd->name = nand1_name;
if (probe_nand_chip()){
nandboot = 1;
/* try the second address */
iounmap(omap_nand_flash_base);
omap_nand_flash_base = ioremap(OMAP_NAND_FLASH_START2, SZ_4K);
if (probe_nand_chip()){
iounmap(omap_nand_flash_base);
err = -ENXIO; err = -ENXIO;
goto out_mtd; goto out_iounmap;
} }
} }
info->mtd.owner = THIS_MODULE;
/* Register the partitions */
switch(omap_nand_mtd->size) {
case SZ_128M:
if (!(machine_is_netstar()))
goto out_unsupported;
/* fall through */
case SZ_64M:
if (!(machine_is_netstar() || machine_is_omap_perseus2()))
goto out_unsupported;
/* fall through */
case SZ_32M:
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
err = parse_mtd_partitions(omap_nand_mtd, part_probes, err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
&dynamic_partition, 0);
if (err > 0) if (err > 0)
err = add_mtd_partitions(omap_nand_mtd, add_mtd_partitions(&info->mtd, info->parts, err);
dynamic_partition, err); else if (err < 0 && pdata->parts)
else if (nandboot) add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
err = add_mtd_partitions(omap_nand_mtd,
static_partition,
ARRAY_SIZE(static_partition));
else else
#endif #endif
err = add_mtd_device(omap_nand_mtd); add_mtd_device(&info->mtd);
if (err)
goto out_buf;
break;
out_unsupported:
default:
printk(KERN_WARNING "Unsupported NAND device\n");
err = -ENXIO;
goto out_buf;
}
goto out; dev_set_drvdata(&pdev->dev, info);
out_buf: return 0;
nand_release (omap_nand_mtd);
if (this->dev_ready) { out_iounmap:
if (machine_is_omap_h2()) iounmap(info->nand.IO_ADDR_R);
omap_free_gpio(H2_NAND_RB_GPIO_PIN); out_release_mem_region:
else if (machine_is_omap_perseus2()) release_mem_region(res->start, size);
omap_free_gpio(P2_NAND_RB_GPIO_PIN); out_free_info:
else if (machine_is_omap_h3()) kfree(info);
omap_free_gpio(H3_NAND_RB_GPIO_PIN);
else if (machine_is_netstar())
omap_free_gpio(NETSTAR_NAND_RB_GPIO_PIN);
}
iounmap(omap_nand_flash_base);
out_mtd:
kfree (omap_nand_mtd);
out:
return err; return err;
} }
module_init(omap_nand_init); static int __devexit omap_nand_remove(struct device *dev)
/*
* Clean up routine
*/
static void __exit omap_nand_cleanup (void)
{ {
struct nand_chip *this = omap_nand_mtd->priv; struct platform_device *pdev = to_platform_device(dev);
if (this->dev_ready) { struct omap_nand_info *info = dev_get_drvdata(&pdev->dev);
if (machine_is_omap_h2())
omap_free_gpio(H2_NAND_RB_GPIO_PIN); dev_set_drvdata(&pdev->dev, NULL);
else if (machine_is_omap_h2()) /* Release NAND device, its internal structures and partitions */
omap_free_gpio(H2_NAND_RB_GPIO_PIN); nand_release(&info->mtd);
else if (machine_is_omap_h3()) iounmap(info->nand.IO_ADDR_R);
omap_free_gpio(H3_NAND_RB_GPIO_PIN); kfree(info);
else if (machine_is_netstar()) return 0;
omap_free_gpio(NETSTAR_NAND_RB_GPIO_PIN); }
}
/* nand_release frees MTD partitions, MTD structure static struct device_driver omap_nand_driver = {
and nand internal buffers*/ .name = DRIVER_NAME,
nand_release (omap_nand_mtd); .bus = &platform_bus_type,
kfree (omap_nand_mtd); .probe = omap_nand_probe,
.remove = __devexit_p(omap_nand_remove),
};
MODULE_ALIAS(DRIVER_NAME);
iounmap(omap_nand_flash_base); static int __init omap_nand_init(void)
{
return driver_register(&omap_nand_driver);
} }
module_exit(omap_nand_cleanup); static void __exit omap_nand_exit(void)
{
driver_unregister(&omap_nand_driver);
}
module_init(omap_nand_init);
module_exit(omap_nand_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jian Zhang <jzhang@ti.com>"); MODULE_AUTHOR("Jian Zhang <jzhang@ti.com> (and others)");
MODULE_DESCRIPTION("Glue layer for NAND flash on H2/H3 boards"); MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
...@@ -34,9 +34,5 @@ ...@@ -34,9 +34,5 @@
/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
#define OMAP1610_ETHR_START 0x04000300 #define OMAP1610_ETHR_START 0x04000300
/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
#endif /* __ASM_ARCH_OMAP_H2_H */ #endif /* __ASM_ARCH_OMAP_H2_H */
...@@ -30,10 +30,6 @@ ...@@ -30,10 +30,6 @@
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */ /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300 #define OMAP1710_ETHR_START 0x04000300
/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
#define MAXIRQNUM (IH_BOARD_BASE) #define MAXIRQNUM (IH_BOARD_BASE)
#define MAXFIQNUM MAXIRQNUM #define MAXFIQNUM MAXIRQNUM
#define MAXSWINUM MAXIRQNUM #define MAXSWINUM MAXIRQNUM
......
...@@ -42,8 +42,4 @@ ...@@ -42,8 +42,4 @@
#define NR_IRQS (MAXIRQNUM + 1) #define NR_IRQS (MAXIRQNUM + 1)
/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
#endif #endif
...@@ -36,4 +36,18 @@ struct flash_platform_data { ...@@ -36,4 +36,18 @@ struct flash_platform_data {
unsigned int nr_parts; unsigned int nr_parts;
}; };
/**
* struct nand_platform_data - platform data describing NAND flash banks
* @dev_ready: tests if the NAND flash is ready (READY signal is high)
* @options: bitmask for nand_chip.options
* @parts: optional array of mtd_partitions for static partitioning
* @nr_parts: number of mtd_partitions for static partitoning
*/
struct nand_platform_data {
int (*dev_ready)(struct nand_platform_data *data);
unsigned int options;
struct mtd_partition *parts;
unsigned int nr_parts;
};
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment