Merge branch 'omap-for-v3.8/cleanup-headers-gpmc' into omap-for-v3.8/cleanup-headers
Conflicts: arch/arm/mach-omap2/board-3430sdp.c arch/arm/mach-omap2/board-h4.c arch/arm/mach-omap2/board-rx51-peripherals.c arch/arm/mach-omap2/board-rx51.c arch/arm/mach-omap2/pm34xx.c drivers/mtd/nand/omap2.c drivers/mtd/onenand/omap2.c
This commit is contained in:
Коммит
99f0b8d6b0
|
@ -34,7 +34,7 @@
|
|||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <plat/usb.h>
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
#include <plat/usb.h>
|
||||
#include "common.h"
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
#include "board-flash.h"
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include <plat/led.h>
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <plat/usb.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
|
@ -53,6 +53,7 @@
|
|||
#include "sdram-micron-mt46h32m32lf-6.h"
|
||||
#include "hsmmc.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "gpmc-nand.h"
|
||||
|
||||
#define CM_T35_GPIO_PENDOWN 57
|
||||
#define SB_T35_USB_HUB_RESET_GPIO 167
|
||||
|
@ -181,7 +182,7 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
|
|||
|
||||
static void __init cm_t35_init_nand(void)
|
||||
{
|
||||
if (gpmc_nand_init(&cm_t35_nand_data) < 0)
|
||||
if (gpmc_nand_init(&cm_t35_nand_data, NULL) < 0)
|
||||
pr_err("CM-T35: Unable to register NAND device\n");
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "common.h"
|
||||
#include <plat/usb.h>
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
|
||||
#include "am35xx.h"
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
|||
#include "control.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "am35xx-emac.h"
|
||||
#include "gpmc-nand.h"
|
||||
|
||||
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
|
||||
static struct gpio_led cm_t3517_leds[] = {
|
||||
|
@ -240,7 +241,7 @@ static struct omap_nand_platform_data cm_t3517_nand_data = {
|
|||
|
||||
static void __init cm_t3517_init_nand(void)
|
||||
{
|
||||
if (gpmc_nand_init(&cm_t3517_nand_data) < 0)
|
||||
if (gpmc_nand_init(&cm_t3517_nand_data, NULL) < 0)
|
||||
pr_err("CM-T3517: NAND initialization failed\n");
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include <asm/mach/flash.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/usb.h>
|
||||
#include <video/omapdss.h>
|
||||
|
@ -55,8 +55,11 @@
|
|||
#include "sdram-micron-mt46h32m32lf-6.h"
|
||||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
#include "board-flash.h"
|
||||
#include "common-board-devices.h"
|
||||
|
||||
#define NAND_CS 0
|
||||
|
||||
#define OMAP_DM9000_GPIO_IRQ 25
|
||||
#define OMAP3_DEVKIT_TS_GPIO 27
|
||||
|
||||
|
@ -621,8 +624,9 @@ static void __init devkit8000_init(void)
|
|||
|
||||
usb_musb_init(NULL);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
|
||||
ARRAY_SIZE(devkit8000_nand_partitions));
|
||||
board_nand_init(devkit8000_nand_partitions,
|
||||
ARRAY_SIZE(devkit8000_nand_partitions), NAND_CS,
|
||||
NAND_BUSWIDTH_16, NULL);
|
||||
omap_twl4030_audio_init("omap3beagle");
|
||||
|
||||
/* Ensure SDRC pins are mux'd for self-refresh */
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
#include <linux/io.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <linux/platform_data/mtd-onenand-omap2.h>
|
||||
#include <plat/tc.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "board-flash.h"
|
||||
#include "gpmc-onenand.h"
|
||||
#include "gpmc-nand.h"
|
||||
|
||||
#define REG_FPGA_REV 0x10
|
||||
#define REG_FPGA_DIP_SWITCH_INPUT2 0x60
|
||||
|
@ -104,36 +106,35 @@ __init board_onenand_init(struct mtd_partition *onenand_parts,
|
|||
defined(CONFIG_MTD_NAND_OMAP2_MODULE)
|
||||
|
||||
/* Note that all values in this struct are in nanoseconds */
|
||||
static struct gpmc_timings nand_timings = {
|
||||
struct gpmc_timings nand_default_timings[1] = {
|
||||
{
|
||||
.sync_clk = 0,
|
||||
|
||||
.sync_clk = 0,
|
||||
.cs_on = 0,
|
||||
.cs_rd_off = 36,
|
||||
.cs_wr_off = 36,
|
||||
|
||||
.cs_on = 0,
|
||||
.cs_rd_off = 36,
|
||||
.cs_wr_off = 36,
|
||||
.adv_on = 6,
|
||||
.adv_rd_off = 24,
|
||||
.adv_wr_off = 36,
|
||||
|
||||
.adv_on = 6,
|
||||
.adv_rd_off = 24,
|
||||
.adv_wr_off = 36,
|
||||
.we_off = 30,
|
||||
.oe_off = 48,
|
||||
|
||||
.we_off = 30,
|
||||
.oe_off = 48,
|
||||
.access = 54,
|
||||
.rd_cycle = 72,
|
||||
.wr_cycle = 72,
|
||||
|
||||
.access = 54,
|
||||
.rd_cycle = 72,
|
||||
.wr_cycle = 72,
|
||||
|
||||
.wr_access = 30,
|
||||
.wr_data_mux_bus = 0,
|
||||
.wr_access = 30,
|
||||
.wr_data_mux_bus = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct omap_nand_platform_data board_nand_data = {
|
||||
.gpmc_t = &nand_timings,
|
||||
};
|
||||
static struct omap_nand_platform_data board_nand_data;
|
||||
|
||||
void
|
||||
__init board_nand_init(struct mtd_partition *nand_parts,
|
||||
u8 nr_parts, u8 cs, int nand_type)
|
||||
__init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs,
|
||||
int nand_type, struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
board_nand_data.cs = cs;
|
||||
board_nand_data.parts = nand_parts;
|
||||
|
@ -141,7 +142,7 @@ __init board_nand_init(struct mtd_partition *nand_parts,
|
|||
board_nand_data.devsize = nand_type;
|
||||
|
||||
board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_DEFAULT;
|
||||
gpmc_nand_init(&board_nand_data);
|
||||
gpmc_nand_init(&board_nand_data, gpmc_t);
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */
|
||||
|
||||
|
@ -238,5 +239,6 @@ void __init board_flash_init(struct flash_partitions partition_info[],
|
|||
pr_err("NAND: Unable to find configuration in GPMC\n");
|
||||
else
|
||||
board_nand_init(partition_info[2].parts,
|
||||
partition_info[2].nr_parts, nandcs, nand_type);
|
||||
partition_info[2].nr_parts, nandcs,
|
||||
nand_type, nand_default_timings);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
|
||||
#define PDC_NOR 1
|
||||
#define PDC_NAND 2
|
||||
|
@ -40,12 +40,14 @@ static inline void board_flash_init(struct flash_partitions part[],
|
|||
#if defined(CONFIG_MTD_NAND_OMAP2) || \
|
||||
defined(CONFIG_MTD_NAND_OMAP2_MODULE)
|
||||
extern void board_nand_init(struct mtd_partition *nand_parts,
|
||||
u8 nr_parts, u8 cs, int nand_type);
|
||||
u8 nr_parts, u8 cs, int nand_type, struct gpmc_timings *gpmc_t);
|
||||
extern struct gpmc_timings nand_default_timings[];
|
||||
#else
|
||||
static inline void board_nand_init(struct mtd_partition *nand_parts,
|
||||
u8 nr_parts, u8 cs, int nand_type)
|
||||
u8 nr_parts, u8 cs, int nand_type, struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
}
|
||||
#define nand_default_timings NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include <plat/menelaus.h>
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "debug-devices.h"
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
@ -42,6 +41,7 @@
|
|||
#include "common.h"
|
||||
#include "mux.h"
|
||||
#include "control.h"
|
||||
#include "gpmc.h"
|
||||
|
||||
#define H4_FLASH_CS 0
|
||||
#define H4_SMC91X_CS 1
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
@ -43,6 +43,7 @@
|
|||
#include "common-board-devices.h"
|
||||
#include "board-flash.h"
|
||||
#include "control.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
#define IGEP2_SMSC911X_CS 5
|
||||
#define IGEP2_SMSC911X_GPIO 176
|
||||
|
@ -175,7 +176,7 @@ static void __init igep_flash_init(void)
|
|||
pr_info("IGEP: initializing NAND memory device\n");
|
||||
board_nand_init(igep_flash_partitions,
|
||||
ARRAY_SIZE(igep_flash_partitions),
|
||||
0, NAND_BUSWIDTH_16);
|
||||
0, NAND_BUSWIDTH_16, nand_default_timings);
|
||||
} else if (mux == IGEP_SYSBOOT_ONENAND) {
|
||||
pr_info("IGEP: initializing OneNAND memory device\n");
|
||||
board_onenand_init(igep_flash_partitions,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <mach/board-zoom.h>
|
||||
#include <plat/usb.h>
|
||||
#include "gpmc-smsc911x.h"
|
||||
|
@ -420,8 +420,8 @@ static void __init omap_ldp_init(void)
|
|||
omap_serial_init();
|
||||
omap_sdrc_init(NULL, NULL);
|
||||
usb_musb_init(NULL);
|
||||
board_nand_init(ldp_nand_partitions,
|
||||
ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
|
||||
board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
|
||||
ZOOM_NAND_CS, 0, nand_default_timings);
|
||||
|
||||
omap_hsmmc_init(mmc);
|
||||
ldp_display_init();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <plat/mmc.h>
|
||||
|
||||
#include "mux.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
#define TUSB6010_ASYNC_CS 1
|
||||
#define TUSB6010_SYNC_CS 4
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "common.h"
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/usb.h>
|
||||
#include <plat/omap_device.h>
|
||||
|
@ -49,8 +49,11 @@
|
|||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
#include "pm.h"
|
||||
#include "board-flash.h"
|
||||
#include "common-board-devices.h"
|
||||
|
||||
#define NAND_CS 0
|
||||
|
||||
/*
|
||||
* OMAP3 Beagle revision
|
||||
* Run time detection of Beagle revision is done by reading GPIO.
|
||||
|
@ -512,8 +515,9 @@ static void __init omap3_beagle_init(void)
|
|||
|
||||
usb_musb_init(NULL);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
|
||||
ARRAY_SIZE(omap3beagle_nand_partitions));
|
||||
board_nand_init(omap3beagle_nand_partitions,
|
||||
ARRAY_SIZE(omap3beagle_nand_partitions), NAND_CS,
|
||||
NAND_BUSWIDTH_16, NULL);
|
||||
omap_twl4030_audio_init("omap3beagle");
|
||||
|
||||
/* Ensure msecure is mux'd to be able to set the RTC. */
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
#include "sdram-micron-mt46h32m32lf-6.h"
|
||||
#include "hsmmc.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "board-flash.h"
|
||||
|
||||
#define NAND_CS 0
|
||||
|
||||
#define OMAP3_EVM_TS_GPIO 175
|
||||
#define OMAP3_EVM_EHCI_VBUS 22
|
||||
|
@ -731,8 +734,9 @@ static void __init omap3_evm_init(void)
|
|||
}
|
||||
usb_musb_init(&musb_board_data);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
omap_nand_flash_init(NAND_BUSWIDTH_16, omap3evm_nand_partitions,
|
||||
ARRAY_SIZE(omap3evm_nand_partitions));
|
||||
board_nand_init(omap3evm_nand_partitions,
|
||||
ARRAY_SIZE(omap3evm_nand_partitions), NAND_CS,
|
||||
NAND_BUSWIDTH_16, NULL);
|
||||
|
||||
omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL);
|
||||
omap3evm_init_smsc911x();
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <asm/mach/map.h>
|
||||
|
||||
#include "gpmc-smsc911x.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <plat/sdrc.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "sdram-micron-mt46h32m32lf-6.h"
|
||||
#include "hsmmc.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "gpmc-nand.h"
|
||||
|
||||
#define PANDORA_WIFI_IRQ_GPIO 21
|
||||
#define PANDORA_WIFI_NRESET_GPIO 23
|
||||
|
@ -602,7 +603,7 @@ static void __init omap3pandora_init(void)
|
|||
omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
usb_musb_init(NULL);
|
||||
gpmc_nand_init(&pandora_nand_data);
|
||||
gpmc_nand_init(&pandora_nand_data, NULL);
|
||||
|
||||
/* Ensure SDRC pins are mux'd for self-refresh */
|
||||
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include <asm/mach/flash.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/usb.h>
|
||||
#include <video/omapdss.h>
|
||||
|
|
|
@ -44,12 +44,13 @@
|
|||
#include <asm/system_info.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
#include "board-flash.h"
|
||||
#include "common-board-devices.h"
|
||||
|
||||
#include <asm/setup.h>
|
||||
|
@ -59,6 +60,8 @@
|
|||
#define TB_BL_PWM_TIMER 9
|
||||
#define TB_KILL_POWER_GPIO 168
|
||||
|
||||
#define NAND_CS 0
|
||||
|
||||
static unsigned long touchbook_revision;
|
||||
|
||||
static struct mtd_partition omap3touchbook_nand_partitions[] = {
|
||||
|
@ -365,8 +368,9 @@ static void __init omap3_touchbook_init(void)
|
|||
omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
|
||||
usb_musb_init(NULL);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
omap_nand_flash_init(NAND_BUSWIDTH_16, omap3touchbook_nand_partitions,
|
||||
ARRAY_SIZE(omap3touchbook_nand_partitions));
|
||||
board_nand_init(omap3touchbook_nand_partitions,
|
||||
ARRAY_SIZE(omap3touchbook_nand_partitions), NAND_CS,
|
||||
NAND_BUSWIDTH_16, NULL);
|
||||
|
||||
/* Ensure SDRC pins are mux'd for self-refresh */
|
||||
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
|
||||
|
|
|
@ -49,14 +49,17 @@
|
|||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include "mux.h"
|
||||
#include "sdram-micron-mt46h32m32lf-6.h"
|
||||
#include "hsmmc.h"
|
||||
#include "board-flash.h"
|
||||
#include "common-board-devices.h"
|
||||
|
||||
#define NAND_CS 0
|
||||
|
||||
#define OVERO_GPIO_BT_XGATE 15
|
||||
#define OVERO_GPIO_W2W_NRESET 16
|
||||
#define OVERO_GPIO_PENDOWN 114
|
||||
|
@ -495,8 +498,8 @@ static void __init overo_init(void)
|
|||
omap_serial_init();
|
||||
omap_sdrc_init(mt46h32m32lf6_sdrc_params,
|
||||
mt46h32m32lf6_sdrc_params);
|
||||
omap_nand_flash_init(0, overo_nand_partitions,
|
||||
ARRAY_SIZE(overo_nand_partitions));
|
||||
board_nand_init(overo_nand_partitions,
|
||||
ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
|
||||
usb_musb_init(NULL);
|
||||
usbhs_init(&usbhs_bdata);
|
||||
overo_spi_init();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <plat/i2c.h>
|
||||
#include <plat/mmc.h>
|
||||
#include <plat/usb.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include "common.h"
|
||||
#include <plat/serial.h>
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
|||
#include "hsmmc.h"
|
||||
#include "sdram-nokia.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
|
||||
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
#include "common.h"
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat/omap-pm.h>
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
|
@ -54,6 +53,8 @@
|
|||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
#define SYSTEM_REV_B_USES_VAUX3 0x1699
|
||||
#define SYSTEM_REV_S_USES_VAUX3 0x8
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mux.h"
|
||||
#include "gpmc.h"
|
||||
#include "pm.h"
|
||||
#include "sdram-nokia.h"
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smsc911x.h"
|
||||
|
||||
#include <mach/board-zoom.h>
|
||||
|
|
|
@ -113,8 +113,9 @@ static void __init omap_zoom_init(void)
|
|||
usbhs_init(&usbhs_bdata);
|
||||
}
|
||||
|
||||
board_nand_init(zoom_nand_partitions, ARRAY_SIZE(zoom_nand_partitions),
|
||||
ZOOM_NAND_CS, NAND_BUSWIDTH_16);
|
||||
board_nand_init(zoom_nand_partitions,
|
||||
ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS,
|
||||
NAND_BUSWIDTH_16, nand_default_timings);
|
||||
zoom_debugboard_init();
|
||||
zoom_peripherals_init();
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <linux/spi/ads7846.h>
|
||||
|
||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common-board-devices.h"
|
||||
|
@ -96,48 +95,3 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
|
|||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
|
||||
static struct omap_nand_platform_data nand_data;
|
||||
|
||||
void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
|
||||
int nr_parts)
|
||||
{
|
||||
u8 cs = 0;
|
||||
u8 nandcs = GPMC_CS_NUM + 1;
|
||||
|
||||
/* find out the chip-select on which NAND exists */
|
||||
while (cs < GPMC_CS_NUM) {
|
||||
u32 ret = 0;
|
||||
ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
|
||||
|
||||
if ((ret & 0xC00) == 0x800) {
|
||||
printk(KERN_INFO "Found NAND on CS%d\n", cs);
|
||||
if (nandcs > GPMC_CS_NUM)
|
||||
nandcs = cs;
|
||||
}
|
||||
cs++;
|
||||
}
|
||||
|
||||
if (nandcs > GPMC_CS_NUM) {
|
||||
pr_info("NAND: Unable to find configuration in GPMC\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nandcs < GPMC_CS_NUM) {
|
||||
nand_data.cs = nandcs;
|
||||
nand_data.parts = parts;
|
||||
nand_data.nr_parts = nr_parts;
|
||||
nand_data.devsize = options;
|
||||
|
||||
printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
|
||||
if (gpmc_nand_init(&nand_data) < 0)
|
||||
printk(KERN_ERR "Unable to register NAND device\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
|
||||
int nr_parts)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,5 @@ struct ads7846_platform_data;
|
|||
|
||||
void omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
|
||||
struct ads7846_platform_data *board_pdata);
|
||||
void omap_nand_flash_init(int opts, struct mtd_partition *parts, int n_parts);
|
||||
|
||||
#endif /* __OMAP_COMMON_BOARD_DEVICES__ */
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
|
||||
#include <asm/mach/flash.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "soc.h"
|
||||
#include "gpmc-nand.h"
|
||||
|
||||
/* minimum size for IO mapping */
|
||||
#define NAND_IO_SIZE 4
|
||||
|
||||
static struct resource gpmc_nand_resource[] = {
|
||||
{
|
||||
|
@ -40,41 +43,36 @@ static struct platform_device gpmc_nand_device = {
|
|||
.resource = gpmc_nand_resource,
|
||||
};
|
||||
|
||||
static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data)
|
||||
static int omap2_nand_gpmc_retime(
|
||||
struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
int err;
|
||||
|
||||
if (!gpmc_nand_data->gpmc_t)
|
||||
return 0;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.sync_clk = gpmc_nand_data->gpmc_t->sync_clk;
|
||||
t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on);
|
||||
t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on);
|
||||
t.sync_clk = gpmc_t->sync_clk;
|
||||
t.cs_on = gpmc_round_ns_to_ticks(gpmc_t->cs_on);
|
||||
t.adv_on = gpmc_round_ns_to_ticks(gpmc_t->adv_on);
|
||||
|
||||
/* Read */
|
||||
t.adv_rd_off = gpmc_round_ns_to_ticks(
|
||||
gpmc_nand_data->gpmc_t->adv_rd_off);
|
||||
t.adv_rd_off = gpmc_round_ns_to_ticks(gpmc_t->adv_rd_off);
|
||||
t.oe_on = t.adv_on;
|
||||
t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access);
|
||||
t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off);
|
||||
t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off);
|
||||
t.rd_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle);
|
||||
t.access = gpmc_round_ns_to_ticks(gpmc_t->access);
|
||||
t.oe_off = gpmc_round_ns_to_ticks(gpmc_t->oe_off);
|
||||
t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_t->cs_rd_off);
|
||||
t.rd_cycle = gpmc_round_ns_to_ticks(gpmc_t->rd_cycle);
|
||||
|
||||
/* Write */
|
||||
t.adv_wr_off = gpmc_round_ns_to_ticks(
|
||||
gpmc_nand_data->gpmc_t->adv_wr_off);
|
||||
t.adv_wr_off = gpmc_round_ns_to_ticks(gpmc_t->adv_wr_off);
|
||||
t.we_on = t.oe_on;
|
||||
if (cpu_is_omap34xx()) {
|
||||
t.wr_data_mux_bus = gpmc_round_ns_to_ticks(
|
||||
gpmc_nand_data->gpmc_t->wr_data_mux_bus);
|
||||
t.wr_access = gpmc_round_ns_to_ticks(
|
||||
gpmc_nand_data->gpmc_t->wr_access);
|
||||
t.wr_data_mux_bus = gpmc_round_ns_to_ticks(gpmc_t->wr_data_mux_bus);
|
||||
t.wr_access = gpmc_round_ns_to_ticks(gpmc_t->wr_access);
|
||||
}
|
||||
t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off);
|
||||
t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off);
|
||||
t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
|
||||
t.we_off = gpmc_round_ns_to_ticks(gpmc_t->we_off);
|
||||
t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_t->cs_wr_off);
|
||||
t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_t->wr_cycle);
|
||||
|
||||
/* Configure GPMC */
|
||||
if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
|
||||
|
@ -91,7 +89,29 @@ static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)
|
||||
static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||
{
|
||||
/* support only OMAP3 class */
|
||||
if (!cpu_is_omap34xx()) {
|
||||
pr_err("BCH ecc is not supported on this CPU\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
|
||||
* Other chips may be added if confirmed to work.
|
||||
*/
|
||||
if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) &&
|
||||
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
|
||||
pr_err("BCH 4-bit mode is not supported on this CPU\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
int err = 0;
|
||||
struct device *dev = &gpmc_nand_device.dev;
|
||||
|
@ -112,11 +132,13 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)
|
|||
gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
|
||||
gpmc_nand_resource[2].start =
|
||||
gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
|
||||
/* Set timings in GPMC */
|
||||
err = omap2_nand_gpmc_retime(gpmc_nand_data);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to set gpmc timings: %d\n", err);
|
||||
return err;
|
||||
|
||||
if (gpmc_t) {
|
||||
err = omap2_nand_gpmc_retime(gpmc_nand_data, gpmc_t);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to set gpmc timings: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable RD PIN Monitoring Reg */
|
||||
|
@ -126,6 +148,9 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)
|
|||
|
||||
gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
|
||||
|
||||
if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt))
|
||||
return -EINVAL;
|
||||
|
||||
err = platform_device_register(&gpmc_nand_device);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to register NAND device\n");
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* arch/arm/mach-omap2/gpmc-nand.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_GPMC_NAND_H
|
||||
#define __OMAP2_GPMC_NAND_H
|
||||
|
||||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
|
||||
extern int gpmc_nand_init(struct omap_nand_platform_data *d,
|
||||
struct gpmc_timings *gpmc_t);
|
||||
#else
|
||||
static inline int gpmc_nand_init(struct omap_nand_platform_data *d,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -16,15 +16,25 @@
|
|||
#include <linux/mtd/onenand_regs.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/mtd-onenand-omap2.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/mach/flash.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "soc.h"
|
||||
#include "gpmc-onenand.h"
|
||||
|
||||
#define ONENAND_IO_SIZE SZ_128K
|
||||
|
||||
#define ONENAND_FLAG_SYNCREAD (1 << 0)
|
||||
#define ONENAND_FLAG_SYNCWRITE (1 << 1)
|
||||
#define ONENAND_FLAG_HF (1 << 2)
|
||||
#define ONENAND_FLAG_VHF (1 << 3)
|
||||
|
||||
static unsigned onenand_flags;
|
||||
static unsigned latency;
|
||||
static int fclk_offset;
|
||||
|
||||
static struct omap_onenand_platform_data *gpmc_onenand_data;
|
||||
|
||||
static struct resource gpmc_onenand_resource = {
|
||||
|
@ -38,11 +48,9 @@ static struct platform_device gpmc_onenand_device = {
|
|||
.resource = &gpmc_onenand_resource,
|
||||
};
|
||||
|
||||
static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
|
||||
static struct gpmc_timings omap2_onenand_calc_async_timings(void)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
u32 reg;
|
||||
int err;
|
||||
|
||||
const int t_cer = 15;
|
||||
const int t_avdp = 12;
|
||||
|
@ -55,11 +63,6 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
|
|||
const int t_wpl = 40;
|
||||
const int t_wph = 30;
|
||||
|
||||
/* Ensure sync read and sync write are disabled */
|
||||
reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
|
||||
reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
|
||||
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.sync_clk = 0;
|
||||
t.cs_on = 0;
|
||||
|
@ -86,25 +89,30 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
|
|||
t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
|
||||
t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int gpmc_set_async_mode(int cs, struct gpmc_timings *t)
|
||||
{
|
||||
/* Configure GPMC for asynchronous read */
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
|
||||
GPMC_CONFIG1_DEVICESIZE_16 |
|
||||
GPMC_CONFIG1_MUXADDDATA);
|
||||
|
||||
err = gpmc_cs_set_timings(cs, &t);
|
||||
if (err)
|
||||
return err;
|
||||
return gpmc_cs_set_timings(cs, t);
|
||||
}
|
||||
|
||||
static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Ensure sync read and sync write are disabled */
|
||||
reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
|
||||
reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
|
||||
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_onenand_cfg(void __iomem *onenand_base, int latency,
|
||||
int sync_read, int sync_write, int hf, int vhf)
|
||||
static void set_onenand_cfg(void __iomem *onenand_base)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
|
@ -112,19 +120,19 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency,
|
|||
reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
|
||||
reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
|
||||
ONENAND_SYS_CFG1_BL_16;
|
||||
if (sync_read)
|
||||
if (onenand_flags & ONENAND_FLAG_SYNCREAD)
|
||||
reg |= ONENAND_SYS_CFG1_SYNC_READ;
|
||||
else
|
||||
reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
|
||||
if (sync_write)
|
||||
if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
|
||||
reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
|
||||
else
|
||||
reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
|
||||
if (hf)
|
||||
if (onenand_flags & ONENAND_FLAG_HF)
|
||||
reg |= ONENAND_SYS_CFG1_HF;
|
||||
else
|
||||
reg &= ~ONENAND_SYS_CFG1_HF;
|
||||
if (vhf)
|
||||
if (onenand_flags & ONENAND_FLAG_VHF)
|
||||
reg |= ONENAND_SYS_CFG1_VHF;
|
||||
else
|
||||
reg &= ~ONENAND_SYS_CFG1_VHF;
|
||||
|
@ -132,21 +140,10 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency,
|
|||
}
|
||||
|
||||
static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
|
||||
void __iomem *onenand_base, bool *clk_dep)
|
||||
void __iomem *onenand_base)
|
||||
{
|
||||
u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
|
||||
int freq = 0;
|
||||
|
||||
if (cfg->get_freq) {
|
||||
struct onenand_freq_info fi;
|
||||
|
||||
fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
|
||||
fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
|
||||
fi.ver_id = ver;
|
||||
freq = cfg->get_freq(&fi, clk_dep);
|
||||
if (freq)
|
||||
return freq;
|
||||
}
|
||||
int freq;
|
||||
|
||||
switch ((ver >> 4) & 0xf) {
|
||||
case 0:
|
||||
|
@ -172,9 +169,9 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
|
|||
return freq;
|
||||
}
|
||||
|
||||
static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
||||
void __iomem *onenand_base,
|
||||
int *freq_ptr)
|
||||
static struct gpmc_timings
|
||||
omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
||||
int freq)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
const int t_cer = 15;
|
||||
|
@ -184,29 +181,15 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
const int t_wpl = 40;
|
||||
const int t_wph = 30;
|
||||
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
|
||||
int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
|
||||
int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
|
||||
int err, ticks_cez;
|
||||
int cs = cfg->cs, freq = *freq_ptr;
|
||||
u32 reg;
|
||||
bool clk_dep = false;
|
||||
int div, fclk_offset_ns, gpmc_clk_ns;
|
||||
int ticks_cez;
|
||||
int cs = cfg->cs;
|
||||
|
||||
if (cfg->flags & ONENAND_SYNC_READ) {
|
||||
sync_read = 1;
|
||||
} else if (cfg->flags & ONENAND_SYNC_READWRITE) {
|
||||
sync_read = 1;
|
||||
sync_write = 1;
|
||||
} else
|
||||
return omap2_onenand_set_async_mode(cs, onenand_base);
|
||||
|
||||
if (!freq) {
|
||||
/* Very first call freq is not known */
|
||||
err = omap2_onenand_set_async_mode(cs, onenand_base);
|
||||
if (err)
|
||||
return err;
|
||||
freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep);
|
||||
first_time = 1;
|
||||
}
|
||||
if (cfg->flags & ONENAND_SYNC_READ)
|
||||
onenand_flags = ONENAND_FLAG_SYNCREAD;
|
||||
else if (cfg->flags & ONENAND_SYNC_READWRITE)
|
||||
onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
|
||||
|
||||
switch (freq) {
|
||||
case 104:
|
||||
|
@ -244,44 +227,31 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
t_ach = 9;
|
||||
t_aavdh = 7;
|
||||
t_rdyo = 15;
|
||||
sync_write = 0;
|
||||
onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
|
||||
div = gpmc_calc_divider(min_gpmc_clk_period);
|
||||
gpmc_clk_ns = gpmc_ticks_to_ns(div);
|
||||
if (gpmc_clk_ns < 15) /* >66Mhz */
|
||||
hf = 1;
|
||||
onenand_flags |= ONENAND_FLAG_HF;
|
||||
else
|
||||
onenand_flags &= ~ONENAND_FLAG_HF;
|
||||
if (gpmc_clk_ns < 12) /* >83Mhz */
|
||||
vhf = 1;
|
||||
if (vhf)
|
||||
onenand_flags |= ONENAND_FLAG_VHF;
|
||||
else
|
||||
onenand_flags &= ~ONENAND_FLAG_VHF;
|
||||
if (onenand_flags & ONENAND_FLAG_VHF)
|
||||
latency = 8;
|
||||
else if (hf)
|
||||
else if (onenand_flags & ONENAND_FLAG_HF)
|
||||
latency = 6;
|
||||
else if (gpmc_clk_ns >= 25) /* 40 MHz*/
|
||||
latency = 3;
|
||||
else
|
||||
latency = 4;
|
||||
|
||||
if (clk_dep) {
|
||||
if (gpmc_clk_ns < 12) { /* >83Mhz */
|
||||
t_ces = 3;
|
||||
t_avds = 4;
|
||||
} else if (gpmc_clk_ns < 15) { /* >66Mhz */
|
||||
t_ces = 5;
|
||||
t_avds = 4;
|
||||
} else if (gpmc_clk_ns < 25) { /* >40Mhz */
|
||||
t_ces = 6;
|
||||
t_avds = 5;
|
||||
} else {
|
||||
t_ces = 7;
|
||||
t_avds = 7;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_time)
|
||||
set_onenand_cfg(onenand_base, latency,
|
||||
sync_read, sync_write, hf, vhf);
|
||||
/* Set synchronous read timings */
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if (div == 1) {
|
||||
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
|
||||
|
@ -307,8 +277,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
|
||||
}
|
||||
|
||||
/* Set synchronous read timings */
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.sync_clk = min_gpmc_clk_period;
|
||||
t.cs_on = 0;
|
||||
t.adv_on = 0;
|
||||
|
@ -330,7 +298,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
ticks_cez);
|
||||
|
||||
/* Write */
|
||||
if (sync_write) {
|
||||
if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
|
||||
t.adv_wr_off = t.adv_rd_off;
|
||||
t.we_on = 0;
|
||||
t.we_off = t.cs_rd_off;
|
||||
|
@ -355,6 +323,14 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t)
|
||||
{
|
||||
unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD;
|
||||
unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE;
|
||||
|
||||
/* Configure GPMC for synchronous read */
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
|
||||
GPMC_CONFIG1_WRAPBURST_SUPP |
|
||||
|
@ -371,11 +347,45 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
GPMC_CONFIG1_DEVICETYPE_NOR |
|
||||
GPMC_CONFIG1_MUXADDDATA);
|
||||
|
||||
err = gpmc_cs_set_timings(cs, &t);
|
||||
if (err)
|
||||
return err;
|
||||
return gpmc_cs_set_timings(cs, t);
|
||||
}
|
||||
|
||||
set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf);
|
||||
static int omap2_onenand_setup_async(void __iomem *onenand_base)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
int ret;
|
||||
|
||||
omap2_onenand_set_async_mode(onenand_base);
|
||||
|
||||
t = omap2_onenand_calc_async_timings();
|
||||
|
||||
ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
omap2_onenand_set_async_mode(onenand_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
|
||||
{
|
||||
int ret, freq = *freq_ptr;
|
||||
struct gpmc_timings t;
|
||||
|
||||
if (!freq) {
|
||||
/* Very first call freq is not known */
|
||||
freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
|
||||
set_onenand_cfg(onenand_base);
|
||||
}
|
||||
|
||||
t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq);
|
||||
|
||||
ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
set_onenand_cfg(onenand_base);
|
||||
|
||||
*freq_ptr = freq;
|
||||
|
||||
|
@ -385,15 +395,22 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
|
|||
static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
|
||||
{
|
||||
struct device *dev = &gpmc_onenand_device.dev;
|
||||
unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
|
||||
int ret;
|
||||
|
||||
/* Set sync timings in GPMC */
|
||||
if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
|
||||
freq_ptr) < 0) {
|
||||
dev_err(dev, "Unable to set synchronous mode\n");
|
||||
return -EINVAL;
|
||||
ret = omap2_onenand_setup_async(onenand_base);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to set to async mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!(gpmc_onenand_data->flags & l))
|
||||
return 0;
|
||||
|
||||
ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
|
||||
if (ret)
|
||||
dev_err(dev, "unable to set to sync mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
|
@ -411,6 +428,11 @@ void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
|||
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
|
||||
}
|
||||
|
||||
if (cpu_is_omap34xx())
|
||||
gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
|
||||
else
|
||||
gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
|
||||
|
||||
err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
|
||||
(unsigned long *)&gpmc_onenand_resource.start);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* arch/arm/mach-omap2/gpmc-onenand.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_GPMC_ONENAND_H
|
||||
#define __OMAP2_GPMC_ONENAND_H
|
||||
|
||||
#include <linux/platform_data/mtd-onenand-omap2.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
|
||||
extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
|
||||
#else
|
||||
#define board_onenand_data NULL
|
||||
static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -17,7 +17,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/smc91x.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smc91x.h"
|
||||
|
||||
#include "soc.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/smsc911x.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smsc911x.h"
|
||||
|
||||
static struct resource gpmc_smsc911x_resources[] = {
|
||||
|
|
|
@ -26,16 +26,17 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <plat/gpmc.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat/sdrc.h>
|
||||
#include <plat/omap_device.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "common.h"
|
||||
#include "gpmc.h"
|
||||
|
||||
#define DEVICE_NAME "omap-gpmc"
|
||||
|
||||
|
@ -59,6 +60,9 @@
|
|||
#define GPMC_ECC_SIZE_CONFIG 0x1fc
|
||||
#define GPMC_ECC1_RESULT 0x200
|
||||
#define GPMC_ECC_BCH_RESULT_0 0x240 /* not available on OMAP2 */
|
||||
#define GPMC_ECC_BCH_RESULT_1 0x244 /* not available on OMAP2 */
|
||||
#define GPMC_ECC_BCH_RESULT_2 0x248 /* not available on OMAP2 */
|
||||
#define GPMC_ECC_BCH_RESULT_3 0x24c /* not available on OMAP2 */
|
||||
|
||||
/* GPMC ECC control settings */
|
||||
#define GPMC_ECC_CTRL_ECCCLEAR 0x100
|
||||
|
@ -75,6 +79,7 @@
|
|||
|
||||
#define GPMC_CS0_OFFSET 0x60
|
||||
#define GPMC_CS_SIZE 0x30
|
||||
#define GPMC_BCH_SIZE 0x10
|
||||
|
||||
#define GPMC_MEM_START 0x00000000
|
||||
#define GPMC_MEM_END 0x3FFFFFFF
|
||||
|
@ -137,7 +142,6 @@ static struct resource gpmc_mem_root;
|
|||
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
static unsigned int gpmc_cs_map; /* flag for cs which are initialized */
|
||||
static int gpmc_ecc_used = -EINVAL; /* cs using ecc engine */
|
||||
static struct device *gpmc_dev;
|
||||
static int gpmc_irq;
|
||||
static resource_size_t phys_base, mem_size;
|
||||
|
@ -158,22 +162,6 @@ static u32 gpmc_read_reg(int idx)
|
|||
return __raw_readl(gpmc_base + idx);
|
||||
}
|
||||
|
||||
static void gpmc_cs_write_byte(int cs, int idx, u8 val)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
|
||||
reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
|
||||
__raw_writeb(val, reg_addr);
|
||||
}
|
||||
|
||||
static u8 gpmc_cs_read_byte(int cs, int idx)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
|
||||
reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
|
||||
return __raw_readb(reg_addr);
|
||||
}
|
||||
|
||||
void gpmc_cs_write_reg(int cs, int idx, u32 val)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
|
@ -288,7 +276,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
|
|||
return -1
|
||||
#endif
|
||||
|
||||
int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
|
||||
int gpmc_calc_divider(unsigned int sync_clk)
|
||||
{
|
||||
int div;
|
||||
u32 l;
|
||||
|
@ -308,7 +296,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
|
|||
int div;
|
||||
u32 l;
|
||||
|
||||
div = gpmc_cs_calc_divider(cs, t->sync_clk);
|
||||
div = gpmc_calc_divider(t->sync_clk);
|
||||
if (div < 0)
|
||||
return div;
|
||||
|
||||
|
@ -508,44 +496,6 @@ void gpmc_cs_free(int cs)
|
|||
}
|
||||
EXPORT_SYMBOL(gpmc_cs_free);
|
||||
|
||||
/**
|
||||
* gpmc_read_status - read access request to get the different gpmc status
|
||||
* @cmd: command type
|
||||
* @return status
|
||||
*/
|
||||
int gpmc_read_status(int cmd)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
u32 regval = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case GPMC_GET_IRQ_STATUS:
|
||||
status = gpmc_read_reg(GPMC_IRQSTATUS);
|
||||
break;
|
||||
|
||||
case GPMC_PREFETCH_FIFO_CNT:
|
||||
regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
|
||||
status = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
|
||||
break;
|
||||
|
||||
case GPMC_PREFETCH_COUNT:
|
||||
regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
|
||||
status = GPMC_PREFETCH_STATUS_COUNT(regval);
|
||||
break;
|
||||
|
||||
case GPMC_STATUS_BUFFER:
|
||||
regval = gpmc_read_reg(GPMC_STATUS);
|
||||
/* 1 : buffer is available to write */
|
||||
status = regval & GPMC_STATUS_BUFF_EMPTY;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "gpmc_read_status: Not supported\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_read_status);
|
||||
|
||||
/**
|
||||
* gpmc_cs_configure - write request to configure gpmc
|
||||
* @cs: chip select number
|
||||
|
@ -614,121 +564,10 @@ int gpmc_cs_configure(int cs, int cmd, int wval)
|
|||
}
|
||||
EXPORT_SYMBOL(gpmc_cs_configure);
|
||||
|
||||
/**
|
||||
* gpmc_nand_read - nand specific read access request
|
||||
* @cs: chip select number
|
||||
* @cmd: command type
|
||||
*/
|
||||
int gpmc_nand_read(int cs, int cmd)
|
||||
{
|
||||
int rval = -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case GPMC_NAND_DATA:
|
||||
rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "gpmc_read_nand_ctrl: Not supported\n");
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_nand_read);
|
||||
|
||||
/**
|
||||
* gpmc_nand_write - nand specific write request
|
||||
* @cs: chip select number
|
||||
* @cmd: command type
|
||||
* @wval: value to write
|
||||
*/
|
||||
int gpmc_nand_write(int cs, int cmd, int wval)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case GPMC_NAND_COMMAND:
|
||||
gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
|
||||
break;
|
||||
|
||||
case GPMC_NAND_ADDRESS:
|
||||
gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
|
||||
break;
|
||||
|
||||
case GPMC_NAND_DATA:
|
||||
gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "gpmc_write_nand_ctrl: Not supported\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_nand_write);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* gpmc_prefetch_enable - configures and starts prefetch transfer
|
||||
* @cs: cs (chip select) number
|
||||
* @fifo_th: fifo threshold to be used for read/ write
|
||||
* @dma_mode: dma mode enable (1) or disable (0)
|
||||
* @u32_count: number of bytes to be transferred
|
||||
* @is_write: prefetch read(0) or write post(1) mode
|
||||
*/
|
||||
int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
|
||||
unsigned int u32_count, int is_write)
|
||||
{
|
||||
|
||||
if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) {
|
||||
pr_err("gpmc: fifo threshold is not supported\n");
|
||||
return -1;
|
||||
} else if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
|
||||
/* Set the amount of bytes to be prefetched */
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
|
||||
|
||||
/* Set dma/mpu mode, the prefetch read / post write and
|
||||
* enable the engine. Set which cs is has requested for.
|
||||
*/
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, ((cs << CS_NUM_SHIFT) |
|
||||
PREFETCH_FIFOTHRESHOLD(fifo_th) |
|
||||
ENABLE_PREFETCH |
|
||||
(dma_mode << DMA_MPU_MODE) |
|
||||
(0x1 & is_write)));
|
||||
|
||||
/* Start the prefetch engine */
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
|
||||
} else {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_prefetch_enable);
|
||||
|
||||
/**
|
||||
* gpmc_prefetch_reset - disables and stops the prefetch engine
|
||||
*/
|
||||
int gpmc_prefetch_reset(int cs)
|
||||
{
|
||||
u32 config1;
|
||||
|
||||
/* check if the same module/cs is trying to reset */
|
||||
config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
|
||||
if (((config1 >> CS_NUM_SHIFT) & 0x7) != cs)
|
||||
return -EINVAL;
|
||||
|
||||
/* Stop the PFPW engine */
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
|
||||
|
||||
/* Reset/disable the PFPW engine */
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_prefetch_reset);
|
||||
|
||||
void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
|
||||
{
|
||||
int i;
|
||||
|
||||
reg->gpmc_status = gpmc_base + GPMC_STATUS;
|
||||
reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
|
||||
GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
|
||||
|
@ -744,7 +583,17 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
|
|||
reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
|
||||
reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
|
||||
reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
|
||||
reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0;
|
||||
|
||||
for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
|
||||
reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
|
||||
GPMC_BCH_SIZE * i;
|
||||
reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
|
||||
GPMC_BCH_SIZE * i;
|
||||
reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
|
||||
GPMC_BCH_SIZE * i;
|
||||
reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
|
||||
GPMC_BCH_SIZE * i;
|
||||
}
|
||||
}
|
||||
|
||||
int gpmc_get_client_irq(unsigned irq_config)
|
||||
|
@ -1079,267 +928,3 @@ void omap3_gpmc_restore_context(void)
|
|||
}
|
||||
}
|
||||
#endif /* CONFIG_ARCH_OMAP3 */
|
||||
|
||||
/**
|
||||
* gpmc_enable_hwecc - enable hardware ecc functionality
|
||||
* @cs: chip select number
|
||||
* @mode: read/write mode
|
||||
* @dev_width: device bus width(1 for x16, 0 for x8)
|
||||
* @ecc_size: bytes for which ECC will be generated
|
||||
*/
|
||||
int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* check if ecc module is in used */
|
||||
if (gpmc_ecc_used != -EINVAL)
|
||||
return -EINVAL;
|
||||
|
||||
gpmc_ecc_used = cs;
|
||||
|
||||
/* clear ecc and enable bits */
|
||||
gpmc_write_reg(GPMC_ECC_CONTROL,
|
||||
GPMC_ECC_CTRL_ECCCLEAR |
|
||||
GPMC_ECC_CTRL_ECCREG1);
|
||||
|
||||
/* program ecc and result sizes */
|
||||
val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
|
||||
gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
|
||||
|
||||
switch (mode) {
|
||||
case GPMC_ECC_READ:
|
||||
case GPMC_ECC_WRITE:
|
||||
gpmc_write_reg(GPMC_ECC_CONTROL,
|
||||
GPMC_ECC_CTRL_ECCCLEAR |
|
||||
GPMC_ECC_CTRL_ECCREG1);
|
||||
break;
|
||||
case GPMC_ECC_READSYN:
|
||||
gpmc_write_reg(GPMC_ECC_CONTROL,
|
||||
GPMC_ECC_CTRL_ECCCLEAR |
|
||||
GPMC_ECC_CTRL_ECCDISABLE);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
|
||||
val = (dev_width << 7) | (cs << 1) | (0x1);
|
||||
gpmc_write_reg(GPMC_ECC_CONFIG, val);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_enable_hwecc);
|
||||
|
||||
/**
|
||||
* gpmc_calculate_ecc - generate non-inverted ecc bytes
|
||||
* @cs: chip select number
|
||||
* @dat: data pointer over which ecc is computed
|
||||
* @ecc_code: ecc code buffer
|
||||
*
|
||||
* Using non-inverted ECC is considered ugly since writing a blank
|
||||
* page (padding) will clear the ECC bytes. This is not a problem as long
|
||||
* no one is trying to write data on the seemingly unused page. Reading
|
||||
* an erased page will produce an ECC mismatch between generated and read
|
||||
* ECC bytes that has to be dealt with separately.
|
||||
*/
|
||||
int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
unsigned int val = 0x0;
|
||||
|
||||
if (gpmc_ecc_used != cs)
|
||||
return -EINVAL;
|
||||
|
||||
/* read ecc result */
|
||||
val = gpmc_read_reg(GPMC_ECC1_RESULT);
|
||||
*ecc_code++ = val; /* P128e, ..., P1e */
|
||||
*ecc_code++ = val >> 16; /* P128o, ..., P1o */
|
||||
/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
|
||||
*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
|
||||
|
||||
gpmc_ecc_used = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP3
|
||||
|
||||
/**
|
||||
* gpmc_init_hwecc_bch - initialize hardware BCH ecc functionality
|
||||
* @cs: chip select number
|
||||
* @nsectors: how many 512-byte sectors to process
|
||||
* @nerrors: how many errors to correct per sector (4 or 8)
|
||||
*
|
||||
* This function must be executed before any call to gpmc_enable_hwecc_bch.
|
||||
*/
|
||||
int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors)
|
||||
{
|
||||
/* check if ecc module is in use */
|
||||
if (gpmc_ecc_used != -EINVAL)
|
||||
return -EINVAL;
|
||||
|
||||
/* support only OMAP3 class */
|
||||
if (!cpu_is_omap34xx()) {
|
||||
printk(KERN_ERR "BCH ecc is not supported on this CPU\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
|
||||
* Other chips may be added if confirmed to work.
|
||||
*/
|
||||
if ((nerrors == 4) &&
|
||||
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
|
||||
printk(KERN_ERR "BCH 4-bit mode is not supported on this CPU\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (nsectors > 8) {
|
||||
printk(KERN_ERR "BCH cannot process %d sectors (max is 8)\n",
|
||||
nsectors);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_init_hwecc_bch);
|
||||
|
||||
/**
|
||||
* gpmc_enable_hwecc_bch - enable hardware BCH ecc functionality
|
||||
* @cs: chip select number
|
||||
* @mode: read/write mode
|
||||
* @dev_width: device bus width(1 for x16, 0 for x8)
|
||||
* @nsectors: how many 512-byte sectors to process
|
||||
* @nerrors: how many errors to correct per sector (4 or 8)
|
||||
*/
|
||||
int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
|
||||
int nerrors)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* check if ecc module is in use */
|
||||
if (gpmc_ecc_used != -EINVAL)
|
||||
return -EINVAL;
|
||||
|
||||
gpmc_ecc_used = cs;
|
||||
|
||||
/* clear ecc and enable bits */
|
||||
gpmc_write_reg(GPMC_ECC_CONTROL, 0x1);
|
||||
|
||||
/*
|
||||
* When using BCH, sector size is hardcoded to 512 bytes.
|
||||
* Here we are using wrapping mode 6 both for reading and writing, with:
|
||||
* size0 = 0 (no additional protected byte in spare area)
|
||||
* size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
|
||||
*/
|
||||
gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, (32 << 22) | (0 << 12));
|
||||
|
||||
/* BCH configuration */
|
||||
val = ((1 << 16) | /* enable BCH */
|
||||
(((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
|
||||
(0x06 << 8) | /* wrap mode = 6 */
|
||||
(dev_width << 7) | /* bus width */
|
||||
(((nsectors-1) & 0x7) << 4) | /* number of sectors */
|
||||
(cs << 1) | /* ECC CS */
|
||||
(0x1)); /* enable ECC */
|
||||
|
||||
gpmc_write_reg(GPMC_ECC_CONFIG, val);
|
||||
gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_enable_hwecc_bch);
|
||||
|
||||
/**
|
||||
* gpmc_calculate_ecc_bch4 - Generate 7 ecc bytes per sector of 512 data bytes
|
||||
* @cs: chip select number
|
||||
* @dat: The pointer to data on which ecc is computed
|
||||
* @ecc: The ecc output buffer
|
||||
*/
|
||||
int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc)
|
||||
{
|
||||
int i;
|
||||
unsigned long nsectors, reg, val1, val2;
|
||||
|
||||
if (gpmc_ecc_used != cs)
|
||||
return -EINVAL;
|
||||
|
||||
nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
|
||||
|
||||
for (i = 0; i < nsectors; i++) {
|
||||
|
||||
reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
|
||||
|
||||
/* Read hw-computed remainder */
|
||||
val1 = gpmc_read_reg(reg + 0);
|
||||
val2 = gpmc_read_reg(reg + 4);
|
||||
|
||||
/*
|
||||
* Add constant polynomial to remainder, in order to get an ecc
|
||||
* sequence of 0xFFs for a buffer filled with 0xFFs; and
|
||||
* left-justify the resulting polynomial.
|
||||
*/
|
||||
*ecc++ = 0x28 ^ ((val2 >> 12) & 0xFF);
|
||||
*ecc++ = 0x13 ^ ((val2 >> 4) & 0xFF);
|
||||
*ecc++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
|
||||
*ecc++ = 0x39 ^ ((val1 >> 20) & 0xFF);
|
||||
*ecc++ = 0x96 ^ ((val1 >> 12) & 0xFF);
|
||||
*ecc++ = 0xac ^ ((val1 >> 4) & 0xFF);
|
||||
*ecc++ = 0x7f ^ ((val1 & 0xF) << 4);
|
||||
}
|
||||
|
||||
gpmc_ecc_used = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch4);
|
||||
|
||||
/**
|
||||
* gpmc_calculate_ecc_bch8 - Generate 13 ecc bytes per block of 512 data bytes
|
||||
* @cs: chip select number
|
||||
* @dat: The pointer to data on which ecc is computed
|
||||
* @ecc: The ecc output buffer
|
||||
*/
|
||||
int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc)
|
||||
{
|
||||
int i;
|
||||
unsigned long nsectors, reg, val1, val2, val3, val4;
|
||||
|
||||
if (gpmc_ecc_used != cs)
|
||||
return -EINVAL;
|
||||
|
||||
nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
|
||||
|
||||
for (i = 0; i < nsectors; i++) {
|
||||
|
||||
reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
|
||||
|
||||
/* Read hw-computed remainder */
|
||||
val1 = gpmc_read_reg(reg + 0);
|
||||
val2 = gpmc_read_reg(reg + 4);
|
||||
val3 = gpmc_read_reg(reg + 8);
|
||||
val4 = gpmc_read_reg(reg + 12);
|
||||
|
||||
/*
|
||||
* Add constant polynomial to remainder, in order to get an ecc
|
||||
* sequence of 0xFFs for a buffer filled with 0xFFs.
|
||||
*/
|
||||
*ecc++ = 0xef ^ (val4 & 0xFF);
|
||||
*ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
|
||||
*ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
|
||||
*ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
|
||||
*ecc++ = 0xed ^ (val3 & 0xFF);
|
||||
*ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
|
||||
*ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
|
||||
*ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
|
||||
*ecc++ = 0x97 ^ (val2 & 0xFF);
|
||||
*ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
|
||||
*ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
|
||||
*ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
|
||||
*ecc++ = 0xb5 ^ (val1 & 0xFF);
|
||||
}
|
||||
|
||||
gpmc_ecc_used = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch8);
|
||||
|
||||
#endif /* CONFIG_ARCH_OMAP3 */
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef __OMAP2_GPMC_H
|
||||
#define __OMAP2_GPMC_H
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
/* Maximum Number of Chip Selects */
|
||||
#define GPMC_CS_NUM 8
|
||||
|
||||
|
@ -32,15 +34,6 @@
|
|||
#define GPMC_SET_IRQ_STATUS 0x00000004
|
||||
#define GPMC_CONFIG_WP 0x00000005
|
||||
|
||||
#define GPMC_GET_IRQ_STATUS 0x00000006
|
||||
#define GPMC_PREFETCH_FIFO_CNT 0x00000007 /* bytes available in FIFO for r/w */
|
||||
#define GPMC_PREFETCH_COUNT 0x00000008 /* remaining bytes to be read/write*/
|
||||
#define GPMC_STATUS_BUFFER 0x00000009 /* 1: buffer is available to write */
|
||||
|
||||
#define GPMC_NAND_COMMAND 0x0000000a
|
||||
#define GPMC_NAND_ADDRESS 0x0000000b
|
||||
#define GPMC_NAND_DATA 0x0000000c
|
||||
|
||||
#define GPMC_ENABLE_IRQ 0x0000000d
|
||||
|
||||
/* ECC commands */
|
||||
|
@ -76,25 +69,10 @@
|
|||
#define GPMC_DEVICETYPE_NOR 0
|
||||
#define GPMC_DEVICETYPE_NAND 2
|
||||
#define GPMC_CONFIG_WRITEPROTECT 0x00000010
|
||||
#define GPMC_STATUS_BUFF_EMPTY 0x00000001
|
||||
#define WR_RD_PIN_MONITORING 0x00600000
|
||||
#define GPMC_PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
|
||||
#define GPMC_PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
|
||||
#define GPMC_IRQ_FIFOEVENTENABLE 0x01
|
||||
#define GPMC_IRQ_COUNT_EVENT 0x02
|
||||
|
||||
#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
|
||||
#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
|
||||
|
||||
enum omap_ecc {
|
||||
/* 1-bit ecc: stored at end of spare area */
|
||||
OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
|
||||
OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
|
||||
/* 1-bit ecc: stored at beginning of spare area as romcode */
|
||||
OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
|
||||
OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
|
||||
OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that all values in this struct are in nanoseconds except sync_clk
|
||||
|
@ -133,22 +111,6 @@ struct gpmc_timings {
|
|||
u16 wr_data_mux_bus; /* WRDATAONADMUXBUS */
|
||||
};
|
||||
|
||||
struct gpmc_nand_regs {
|
||||
void __iomem *gpmc_status;
|
||||
void __iomem *gpmc_nand_command;
|
||||
void __iomem *gpmc_nand_address;
|
||||
void __iomem *gpmc_nand_data;
|
||||
void __iomem *gpmc_prefetch_config1;
|
||||
void __iomem *gpmc_prefetch_config2;
|
||||
void __iomem *gpmc_prefetch_control;
|
||||
void __iomem *gpmc_prefetch_status;
|
||||
void __iomem *gpmc_ecc_config;
|
||||
void __iomem *gpmc_ecc_control;
|
||||
void __iomem *gpmc_ecc_size_config;
|
||||
void __iomem *gpmc_ecc1_result;
|
||||
void __iomem *gpmc_bch_result0;
|
||||
};
|
||||
|
||||
extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
|
||||
extern int gpmc_get_client_irq(unsigned irq_config);
|
||||
|
||||
|
@ -160,31 +122,14 @@ extern unsigned long gpmc_get_fclk_period(void);
|
|||
|
||||
extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
|
||||
extern u32 gpmc_cs_read_reg(int cs, int idx);
|
||||
extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
|
||||
extern int gpmc_calc_divider(unsigned int sync_clk);
|
||||
extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
|
||||
extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
|
||||
extern void gpmc_cs_free(int cs);
|
||||
extern int gpmc_cs_set_reserved(int cs, int reserved);
|
||||
extern int gpmc_cs_reserved(int cs);
|
||||
extern int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
|
||||
unsigned int u32_count, int is_write);
|
||||
extern int gpmc_prefetch_reset(int cs);
|
||||
extern void omap3_gpmc_save_context(void);
|
||||
extern void omap3_gpmc_restore_context(void);
|
||||
extern int gpmc_read_status(int cmd);
|
||||
extern int gpmc_cs_configure(int cs, int cmd, int wval);
|
||||
extern int gpmc_nand_read(int cs, int cmd);
|
||||
extern int gpmc_nand_write(int cs, int cmd, int wval);
|
||||
|
||||
int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
|
||||
int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP3
|
||||
int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors);
|
||||
int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
|
||||
int nerrors);
|
||||
int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc);
|
||||
int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc);
|
||||
#endif /* CONFIG_ARCH_OMAP3 */
|
||||
|
||||
#endif
|
|
@ -40,12 +40,12 @@
|
|||
#include "powerdomain.h"
|
||||
#include <plat/sdrc.h>
|
||||
#include <plat/prcm.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat-omap/dma-omap.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "cm2xxx_3xxx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
#include "gpmc.h"
|
||||
#include "prm-regbits-34xx.h"
|
||||
|
||||
#include "prm2xxx_3xxx.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <linux/usb/musb.h>
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
#include "gpmc.h"
|
||||
|
||||
#include "mux.h"
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#endif
|
||||
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
#define DRIVER_NAME "omap2-nand"
|
||||
|
@ -106,10 +105,16 @@
|
|||
#define CS_MASK 0x7
|
||||
#define ENABLE_PREFETCH (0x1 << 7)
|
||||
#define DMA_MPU_MODE_SHIFT 2
|
||||
#define ECCSIZE0_SHIFT 12
|
||||
#define ECCSIZE1_SHIFT 22
|
||||
#define ECC1RESULTSIZE 0x1
|
||||
#define ECCCLEAR 0x100
|
||||
#define ECC1 0x1
|
||||
#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
|
||||
#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
|
||||
#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
|
||||
#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
|
||||
#define STATUS_BUFF_EMPTY 0x00000001
|
||||
|
||||
#define OMAP24XX_DMA_GPMC 4
|
||||
|
||||
|
@ -271,7 +276,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = readl(info->reg.gpmc_status) &
|
||||
GPMC_STATUS_BUFF_EMPTY;
|
||||
STATUS_BUFF_EMPTY;
|
||||
} while (!status);
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +314,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
|
|||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = readl(info->reg.gpmc_status) &
|
||||
GPMC_STATUS_BUFF_EMPTY;
|
||||
STATUS_BUFF_EMPTY;
|
||||
} while (!status);
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +355,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
} else {
|
||||
do {
|
||||
r_count = readl(info->reg.gpmc_prefetch_status);
|
||||
r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
|
||||
r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
|
||||
r_count = r_count >> 2;
|
||||
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
|
||||
p += r_count;
|
||||
|
@ -397,7 +402,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
} else {
|
||||
while (len) {
|
||||
w_count = readl(info->reg.gpmc_prefetch_status);
|
||||
w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
|
||||
w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
|
||||
w_count = w_count >> 1;
|
||||
for (i = 0; (i < w_count) && len; i++, len -= 2)
|
||||
iowrite16(*p++, info->nand.IO_ADDR_W);
|
||||
|
@ -409,7 +414,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
do {
|
||||
cpu_relax();
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
val = PREFETCH_STATUS_COUNT(val);
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
|
@ -495,7 +500,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
|
|||
do {
|
||||
cpu_relax();
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
val = PREFETCH_STATUS_COUNT(val);
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
|
@ -558,7 +563,7 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
|
|||
u32 bytes;
|
||||
|
||||
bytes = readl(info->reg.gpmc_prefetch_status);
|
||||
bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes);
|
||||
bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
|
||||
bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */
|
||||
if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
|
||||
if (this_irq == info->gpmc_irq_count)
|
||||
|
@ -684,7 +689,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
|
|||
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
|
||||
do {
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
val = PREFETCH_STATUS_COUNT(val);
|
||||
cpu_relax();
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
|
@ -998,7 +1003,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
cond_resched();
|
||||
}
|
||||
|
||||
status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
|
||||
status = readb(info->reg.gpmc_nand_data);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1031,19 +1036,45 @@ static int omap_dev_ready(struct mtd_info *mtd)
|
|||
static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
|
||||
{
|
||||
int nerrors;
|
||||
unsigned int dev_width;
|
||||
unsigned int dev_width, nsectors;
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
u32 val;
|
||||
|
||||
nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4;
|
||||
dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
|
||||
nsectors = 1;
|
||||
/*
|
||||
* Program GPMC to perform correction on one 512-byte sector at a time.
|
||||
* Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and
|
||||
* gives a slight (5%) performance gain (but requires additional code).
|
||||
*/
|
||||
(void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors);
|
||||
|
||||
writel(ECC1, info->reg.gpmc_ecc_control);
|
||||
|
||||
/*
|
||||
* When using BCH, sector size is hardcoded to 512 bytes.
|
||||
* Here we are using wrapping mode 6 both for reading and writing, with:
|
||||
* size0 = 0 (no additional protected byte in spare area)
|
||||
* size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
|
||||
*/
|
||||
val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT);
|
||||
writel(val, info->reg.gpmc_ecc_size_config);
|
||||
|
||||
/* BCH configuration */
|
||||
val = ((1 << 16) | /* enable BCH */
|
||||
(((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
|
||||
(0x06 << 8) | /* wrap mode = 6 */
|
||||
(dev_width << 7) | /* bus width */
|
||||
(((nsectors-1) & 0x7) << 4) | /* number of sectors */
|
||||
(info->gpmc_cs << 1) | /* ECC CS */
|
||||
(0x1)); /* enable ECC */
|
||||
|
||||
writel(val, info->reg.gpmc_ecc_config);
|
||||
|
||||
/* clear ecc and enable bits */
|
||||
writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1057,7 +1088,32 @@ static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat,
|
|||
{
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code);
|
||||
unsigned long nsectors, val1, val2;
|
||||
int i;
|
||||
|
||||
nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
|
||||
|
||||
for (i = 0; i < nsectors; i++) {
|
||||
|
||||
/* Read hw-computed remainder */
|
||||
val1 = readl(info->reg.gpmc_bch_result0[i]);
|
||||
val2 = readl(info->reg.gpmc_bch_result1[i]);
|
||||
|
||||
/*
|
||||
* Add constant polynomial to remainder, in order to get an ecc
|
||||
* sequence of 0xFFs for a buffer filled with 0xFFs; and
|
||||
* left-justify the resulting polynomial.
|
||||
*/
|
||||
*ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF);
|
||||
*ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF);
|
||||
*ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
|
||||
*ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF);
|
||||
*ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF);
|
||||
*ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF);
|
||||
*ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1071,7 +1127,39 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
|
|||
{
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code);
|
||||
unsigned long nsectors, val1, val2, val3, val4;
|
||||
int i;
|
||||
|
||||
nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
|
||||
|
||||
for (i = 0; i < nsectors; i++) {
|
||||
|
||||
/* Read hw-computed remainder */
|
||||
val1 = readl(info->reg.gpmc_bch_result0[i]);
|
||||
val2 = readl(info->reg.gpmc_bch_result1[i]);
|
||||
val3 = readl(info->reg.gpmc_bch_result2[i]);
|
||||
val4 = readl(info->reg.gpmc_bch_result3[i]);
|
||||
|
||||
/*
|
||||
* Add constant polynomial to remainder, in order to get an ecc
|
||||
* sequence of 0xFFs for a buffer filled with 0xFFs.
|
||||
*/
|
||||
*ecc_code++ = 0xef ^ (val4 & 0xFF);
|
||||
*ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF);
|
||||
*ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF);
|
||||
*ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF);
|
||||
*ecc_code++ = 0xed ^ (val3 & 0xFF);
|
||||
*ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF);
|
||||
*ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF);
|
||||
*ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
|
||||
*ecc_code++ = 0x97 ^ (val2 & 0xFF);
|
||||
*ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF);
|
||||
*ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
|
||||
*ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF);
|
||||
*ecc_code++ = 0xb5 ^ (val1 & 0xFF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1127,7 +1215,7 @@ static void omap3_free_bch(struct mtd_info *mtd)
|
|||
*/
|
||||
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
|
||||
{
|
||||
int ret, max_errors;
|
||||
int max_errors;
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH8
|
||||
|
@ -1144,11 +1232,6 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/* initialize GPMC BCH engine */
|
||||
ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* software bch library is only used to detect and locate errors */
|
||||
info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */);
|
||||
if (!info->bch)
|
||||
|
@ -1515,7 +1598,7 @@ static int omap_nand_remove(struct platform_device *pdev)
|
|||
/* Release NAND device, its internal structures and partitions */
|
||||
nand_release(&info->mtd);
|
||||
iounmap(info->nand.IO_ADDR_R);
|
||||
release_mem_region(info->phys_base, NAND_IO_SIZE);
|
||||
release_mem_region(info->phys_base, info->mem_size);
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,12 +38,10 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <asm/mach/flash.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <linux/platform_data/mtd-onenand-omap2.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <plat-omap/dma-omap.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#define DRIVER_NAME "omap2-onenand"
|
||||
|
||||
|
@ -63,6 +61,7 @@ struct omap2_onenand {
|
|||
int freq;
|
||||
int (*setup)(void __iomem *base, int *freq_ptr);
|
||||
struct regulator *regulator;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
|
||||
|
@ -155,7 +154,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
|
|||
if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) {
|
||||
syscfg |= ONENAND_SYS_CFG1_IOBE;
|
||||
write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
|
||||
if (cpu_is_omap34xx())
|
||||
if (c->flags & ONENAND_IN_OMAP34XX)
|
||||
/* Add a delay to let GPIO settle */
|
||||
syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
|
||||
}
|
||||
|
@ -639,6 +638,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
|
|||
|
||||
init_completion(&c->irq_done);
|
||||
init_completion(&c->dma_done);
|
||||
c->flags = pdata->flags;
|
||||
c->gpmc_cs = pdata->cs;
|
||||
c->gpio_irq = pdata->gpio_irq;
|
||||
c->dma_channel = pdata->dma_channel;
|
||||
|
@ -729,7 +729,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
|
|||
this = &c->onenand;
|
||||
if (c->dma_channel >= 0) {
|
||||
this->wait = omap2_onenand_wait;
|
||||
if (cpu_is_omap34xx()) {
|
||||
if (c->flags & ONENAND_IN_OMAP34XX) {
|
||||
this->read_bufferram = omap3_onenand_read_bufferram;
|
||||
this->write_bufferram = omap3_onenand_write_bufferram;
|
||||
} else {
|
||||
|
@ -803,7 +803,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
|
|||
}
|
||||
iounmap(c->onenand.base);
|
||||
release_mem_region(c->phys_base, c->mem_size);
|
||||
gpmc_cs_free(c->gpmc_cs);
|
||||
kfree(c);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <plat/gpmc.h>
|
||||
#ifndef _MTD_NAND_OMAP2_H
|
||||
#define _MTD_NAND_OMAP2_H
|
||||
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#define GPMC_BCH_NUM_REMAINDER 8
|
||||
|
||||
enum nand_io {
|
||||
NAND_OMAP_PREFETCH_POLLED = 0, /* prefetch polled mode, default */
|
||||
NAND_OMAP_POLLED, /* polled mode, without prefetch */
|
||||
|
@ -18,10 +22,38 @@ enum nand_io {
|
|||
NAND_OMAP_PREFETCH_IRQ /* prefetch enabled irq mode */
|
||||
};
|
||||
|
||||
enum omap_ecc {
|
||||
/* 1-bit ecc: stored at end of spare area */
|
||||
OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
|
||||
OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
|
||||
/* 1-bit ecc: stored at beginning of spare area as romcode */
|
||||
OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
|
||||
OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
|
||||
OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
|
||||
};
|
||||
|
||||
struct gpmc_nand_regs {
|
||||
void __iomem *gpmc_status;
|
||||
void __iomem *gpmc_nand_command;
|
||||
void __iomem *gpmc_nand_address;
|
||||
void __iomem *gpmc_nand_data;
|
||||
void __iomem *gpmc_prefetch_config1;
|
||||
void __iomem *gpmc_prefetch_config2;
|
||||
void __iomem *gpmc_prefetch_control;
|
||||
void __iomem *gpmc_prefetch_status;
|
||||
void __iomem *gpmc_ecc_config;
|
||||
void __iomem *gpmc_ecc_control;
|
||||
void __iomem *gpmc_ecc_size_config;
|
||||
void __iomem *gpmc_ecc1_result;
|
||||
void __iomem *gpmc_bch_result0[GPMC_BCH_NUM_REMAINDER];
|
||||
void __iomem *gpmc_bch_result1[GPMC_BCH_NUM_REMAINDER];
|
||||
void __iomem *gpmc_bch_result2[GPMC_BCH_NUM_REMAINDER];
|
||||
void __iomem *gpmc_bch_result3[GPMC_BCH_NUM_REMAINDER];
|
||||
};
|
||||
|
||||
struct omap_nand_platform_data {
|
||||
int cs;
|
||||
struct mtd_partition *parts;
|
||||
struct gpmc_timings *gpmc_t;
|
||||
int nr_parts;
|
||||
bool dev_ready;
|
||||
enum nand_io xfer_type;
|
||||
|
@ -30,14 +62,4 @@ struct omap_nand_platform_data {
|
|||
struct gpmc_nand_regs reg;
|
||||
};
|
||||
|
||||
/* minimum size for IO mapping */
|
||||
#define NAND_IO_SIZE 4
|
||||
|
||||
#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
|
||||
extern int gpmc_nand_init(struct omap_nand_platform_data *d);
|
||||
#else
|
||||
static inline int gpmc_nand_init(struct omap_nand_platform_data *d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -9,17 +9,15 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_ONENAND_OMAP2_H
|
||||
#define __MTD_ONENAND_OMAP2_H
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#define ONENAND_SYNC_READ (1 << 0)
|
||||
#define ONENAND_SYNC_READWRITE (1 << 1)
|
||||
|
||||
struct onenand_freq_info {
|
||||
u16 maf_id;
|
||||
u16 dev_id;
|
||||
u16 ver_id;
|
||||
};
|
||||
#define ONENAND_IN_OMAP34XX (1 << 2)
|
||||
|
||||
struct omap_onenand_platform_data {
|
||||
int cs;
|
||||
|
@ -27,27 +25,9 @@ struct omap_onenand_platform_data {
|
|||
struct mtd_partition *parts;
|
||||
int nr_parts;
|
||||
int (*onenand_setup)(void __iomem *, int *freq_ptr);
|
||||
int (*get_freq)(const struct onenand_freq_info *freq_info,
|
||||
bool *clk_dep);
|
||||
int dma_channel;
|
||||
u8 flags;
|
||||
u8 regulator_can_sleep;
|
||||
u8 skip_initial_unlocking;
|
||||
};
|
||||
|
||||
#define ONENAND_MAX_PARTITIONS 8
|
||||
|
||||
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
|
||||
defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
|
||||
|
||||
extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
|
||||
|
||||
#else
|
||||
|
||||
#define board_onenand_data NULL
|
||||
|
||||
static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче