mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Device tree related changes for omaps.
Note that this branch is based on omap-cleanup-sparseirq-for-v3.7 to avoid merge conflicts with the sparseirq changes for gpio-twl4030 driver. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQVlRgAAoJEBvUPslcq6VzbSwP/RNdw33WTv7slY8v2x9C+jfe fzpJltqtWf1xLQ5ixAMwzBxc4/I+m/fz3ZhxG15amqD1sQuwDNNVwI6D5F4pIH4K ZfyaeA8jteH487f7PxMlurtVYgPRqLrMXBahxKgcM6WwJ0tFspGuXQeKMhjhRnYJ 4+0GQ/R60UmexyAF4Ish4YfVfe0Iy8deVuGjOO7xIdsKrC1uymXbT7HB0o7Tz4tj btsEUXs4UMCh2VoYzqVxaP1uMumOnuVOFOuWjcNOni3TMdjmllPpoApsXE27rNKC 0D/MzCyutFEO7q7/8TSUs3TOy+my18Z6Fz9hEkw7fUOOXQ3iUDqI79FbvMv9mWe+ nW2BFZZCeuTqErGNakgluGtasLOfvqOqzSO7U68XGgHp86G42N2EDs4raTDAeKTN YXzLSiPYvV5QOUFbP5uagiKFcFUbcfNYZytTPwZ8hBk4hXtDmwqhSEgzxhAKGtgx y0ljt3iQNxk3EVhIv7oi0FxCFX2ioikYPTOlHkpvNwkXa7ruvvU1CudIGSdZ/Nn3 SoEkRDwx6CpA37aAusfWioYKWhrctfDBl9Nt0IXwZy1b0MO1QIUaL0RY3Y5FsES+ 25MP+5Ns6nkmzzTs72Gu+W9bL6E3eHAkAoaDb9JPH2Jix8vXRMgIISyu9Fzze504 ypeFe5TtLc/uYkviZhi6 =fzT6 -----END PGP SIGNATURE----- Merge tag 'omap-devel-dt-merged-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/dt Device tree related changes for omaps. Note that this branch is based on omap-cleanup-sparseirq-for-v3.7 to avoid merge conflicts with the sparseirq changes for gpio-twl4030 driver. * tag 'omap-devel-dt-merged-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: arm/dts: Mux uart pins for omap4-sdp ARM: OMAP2+: select PINCTRL in Kconfig arm/dts: Add pinctrl driver entries for omap2/3/4 arm/dts: Add omap36xx.dtsi file and rename omap3-beagle to omap3-beagle-xm ARM: dts: omap3-overo: Add support for the blue LED Documentation: dt: Update the OMAP documentation with Overo/Toby ARM: dts: OMAP3: Add support for Gumstix Overo with Tobi expansion board ARM: dts: OMAP4: Add reg and interrupts for every nodes ARM: dts: AM33XX: Specify reg and interrupt property for all nodes ARM: dts: AM33XX: Convert all hex numbers to lower-case ARM: dts: omap3-beagle: Enable audio support ARM: dts: omap5: Add McPDM and DMIC section to the dtsi file ARM: dts: omap5: Add McBSP entries ARM: dts: omap4: Add reg-names for McPDM and DMIC ARM: dts: omap4: Add McBSP entries ARM: dts: omap3: Add McBSP entries ARM: dts: omap2420-h4: Include omap2420.dtsi file instead the common omap2 ARM: dts: omap2: Add McBSP entries for OMAP2420 and OMAP2430 SoC ARM: dts: omap3-beagle: Add heartbeat and mmc LEDs support ARM: dts: omap3: Add gpio-twl4030 properties for BeagleBoard and omap3-EVM ...
This commit is contained in:
commit
2843c7d2c0
554 changed files with 10469 additions and 11431 deletions
|
|
@ -23,12 +23,16 @@
|
|||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/sizes.h>
|
||||
|
||||
#include <plat/board-ams-delta.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
/*
|
||||
* MTD structure for E3 (Delta)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@
|
|||
#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0)
|
||||
#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1)
|
||||
|
||||
#define PREFETCH_CONFIG1_CS_SHIFT 24
|
||||
#define ECC_CONFIG_CS_SHIFT 1
|
||||
#define CS_MASK 0x7
|
||||
#define ENABLE_PREFETCH (0x1 << 7)
|
||||
#define DMA_MPU_MODE_SHIFT 2
|
||||
#define ECCSIZE1_SHIFT 22
|
||||
#define ECC1RESULTSIZE 0x1
|
||||
#define ECCCLEAR 0x100
|
||||
#define ECC1 0x1
|
||||
|
||||
/* oob info generated runtime depending on ecc algorithm and layout selected */
|
||||
static struct nand_ecclayout omap_oobinfo;
|
||||
/* Define some generic bad / good block scan pattern which are used
|
||||
|
|
@ -124,15 +134,18 @@ struct omap_nand_info {
|
|||
|
||||
int gpmc_cs;
|
||||
unsigned long phys_base;
|
||||
unsigned long mem_size;
|
||||
struct completion comp;
|
||||
struct dma_chan *dma;
|
||||
int gpmc_irq;
|
||||
int gpmc_irq_fifo;
|
||||
int gpmc_irq_count;
|
||||
enum {
|
||||
OMAP_NAND_IO_READ = 0, /* read */
|
||||
OMAP_NAND_IO_WRITE, /* write */
|
||||
} iomode;
|
||||
u_char *buf;
|
||||
int buf_len;
|
||||
struct gpmc_nand_regs reg;
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
struct bch_control *bch;
|
||||
|
|
@ -140,6 +153,63 @@ struct omap_nand_info {
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* omap_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
|
||||
*/
|
||||
static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
|
||||
unsigned int u32_count, int is_write, struct omap_nand_info *info)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
|
||||
return -1;
|
||||
|
||||
if (readl(info->reg.gpmc_prefetch_control))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set the amount of bytes to be prefetched */
|
||||
writel(u32_count, info->reg.gpmc_prefetch_config2);
|
||||
|
||||
/* Set dma/mpu mode, the prefetch read / post write and
|
||||
* enable the engine. Set which cs is has requested for.
|
||||
*/
|
||||
val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
|
||||
PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
|
||||
(dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write));
|
||||
writel(val, info->reg.gpmc_prefetch_config1);
|
||||
|
||||
/* Start the prefetch engine */
|
||||
writel(0x1, info->reg.gpmc_prefetch_control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_prefetch_reset - disables and stops the prefetch engine
|
||||
*/
|
||||
static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
|
||||
{
|
||||
u32 config1;
|
||||
|
||||
/* check if the same module/cs is trying to reset */
|
||||
config1 = readl(info->reg.gpmc_prefetch_config1);
|
||||
if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
|
||||
return -EINVAL;
|
||||
|
||||
/* Stop the PFPW engine */
|
||||
writel(0x0, info->reg.gpmc_prefetch_control);
|
||||
|
||||
/* Reset/disable the PFPW engine */
|
||||
writel(0x0, info->reg.gpmc_prefetch_config1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_hwcontrol - hardware specific access to control-lines
|
||||
* @mtd: MTD device structure
|
||||
|
|
@ -158,13 +228,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
if (ctrl & NAND_CLE)
|
||||
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd);
|
||||
writeb(cmd, info->reg.gpmc_nand_command);
|
||||
|
||||
else if (ctrl & NAND_ALE)
|
||||
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd);
|
||||
writeb(cmd, info->reg.gpmc_nand_address);
|
||||
|
||||
else /* NAND_NCE */
|
||||
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd);
|
||||
writeb(cmd, info->reg.gpmc_nand_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +268,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
iowrite8(*p++, info->nand.IO_ADDR_W);
|
||||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = gpmc_read_status(GPMC_STATUS_BUFFER);
|
||||
status = readl(info->reg.gpmc_status) &
|
||||
GPMC_STATUS_BUFF_EMPTY;
|
||||
} while (!status);
|
||||
}
|
||||
}
|
||||
|
|
@ -235,7 +306,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
|
|||
iowrite16(*p++, info->nand.IO_ADDR_W);
|
||||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = gpmc_read_status(GPMC_STATUS_BUFFER);
|
||||
status = readl(info->reg.gpmc_status) &
|
||||
GPMC_STATUS_BUFF_EMPTY;
|
||||
} while (!status);
|
||||
}
|
||||
}
|
||||
|
|
@ -265,8 +337,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
}
|
||||
|
||||
/* configure and start prefetch transfer */
|
||||
ret = gpmc_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
|
||||
ret = omap_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
|
||||
if (ret) {
|
||||
/* PFPW engine is busy, use cpu copy method */
|
||||
if (info->nand.options & NAND_BUSWIDTH_16)
|
||||
|
|
@ -275,14 +347,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
omap_read_buf8(mtd, (u_char *)p, len);
|
||||
} else {
|
||||
do {
|
||||
r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
|
||||
r_count = readl(info->reg.gpmc_prefetch_status);
|
||||
r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
|
||||
r_count = r_count >> 2;
|
||||
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
|
||||
p += r_count;
|
||||
len -= r_count << 2;
|
||||
} while (len);
|
||||
/* disable and stop the PFPW engine */
|
||||
gpmc_prefetch_reset(info->gpmc_cs);
|
||||
omap_prefetch_reset(info->gpmc_cs, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -301,6 +374,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
int i = 0, ret = 0;
|
||||
u16 *p = (u16 *)buf;
|
||||
unsigned long tim, limit;
|
||||
u32 val;
|
||||
|
||||
/* take care of subpage writes */
|
||||
if (len % 2 != 0) {
|
||||
|
|
@ -310,8 +384,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
}
|
||||
|
||||
/* configure and start prefetch transfer */
|
||||
ret = gpmc_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
|
||||
ret = omap_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
|
||||
if (ret) {
|
||||
/* PFPW engine is busy, use cpu copy method */
|
||||
if (info->nand.options & NAND_BUSWIDTH_16)
|
||||
|
|
@ -320,7 +394,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
omap_write_buf8(mtd, (u_char *)p, len);
|
||||
} else {
|
||||
while (len) {
|
||||
w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
|
||||
w_count = readl(info->reg.gpmc_prefetch_status);
|
||||
w_count = GPMC_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);
|
||||
|
|
@ -329,11 +404,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
tim = 0;
|
||||
limit = (loops_per_jiffy *
|
||||
msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
|
||||
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
|
||||
do {
|
||||
cpu_relax();
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
gpmc_prefetch_reset(info->gpmc_cs);
|
||||
omap_prefetch_reset(info->gpmc_cs, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,6 +443,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
|
|||
unsigned long tim, limit;
|
||||
unsigned n;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (addr >= high_memory) {
|
||||
struct page *p1;
|
||||
|
|
@ -396,9 +475,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
|
|||
tx->callback_param = &info->comp;
|
||||
dmaengine_submit(tx);
|
||||
|
||||
/* configure and start prefetch transfer */
|
||||
ret = gpmc_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write);
|
||||
/* configure and start prefetch transfer */
|
||||
ret = omap_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
|
||||
if (ret)
|
||||
/* PFPW engine is busy, use cpu copy method */
|
||||
goto out_copy_unmap;
|
||||
|
|
@ -410,11 +489,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
|
|||
wait_for_completion(&info->comp);
|
||||
tim = 0;
|
||||
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
|
||||
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
|
||||
|
||||
do {
|
||||
cpu_relax();
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
gpmc_prefetch_reset(info->gpmc_cs);
|
||||
omap_prefetch_reset(info->gpmc_cs, info);
|
||||
|
||||
dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
|
||||
return 0;
|
||||
|
|
@ -471,13 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
|
|||
{
|
||||
struct omap_nand_info *info = (struct omap_nand_info *) dev;
|
||||
u32 bytes;
|
||||
u32 irq_stat;
|
||||
|
||||
irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS);
|
||||
bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
|
||||
bytes = readl(info->reg.gpmc_prefetch_status);
|
||||
bytes = GPMC_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 (irq_stat & 0x2)
|
||||
if (this_irq == info->gpmc_irq_count)
|
||||
goto done;
|
||||
|
||||
if (info->buf_len && (info->buf_len < bytes))
|
||||
|
|
@ -494,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
|
|||
(u32 *)info->buf, bytes >> 2);
|
||||
info->buf = info->buf + bytes;
|
||||
|
||||
if (irq_stat & 0x2)
|
||||
if (this_irq == info->gpmc_irq_count)
|
||||
goto done;
|
||||
}
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
done:
|
||||
complete(&info->comp);
|
||||
/* disable irq */
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0);
|
||||
|
||||
/* clear status */
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
|
||||
disable_irq_nosync(info->gpmc_irq_fifo);
|
||||
disable_irq_nosync(info->gpmc_irq_count);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -534,22 +613,22 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
init_completion(&info->comp);
|
||||
|
||||
/* configure and start prefetch transfer */
|
||||
ret = gpmc_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0);
|
||||
ret = omap_prefetch_enable(info->gpmc_cs,
|
||||
PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
|
||||
if (ret)
|
||||
/* PFPW engine is busy, use cpu copy method */
|
||||
goto out_copy;
|
||||
|
||||
info->buf_len = len;
|
||||
/* enable irq */
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
|
||||
(GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
|
||||
|
||||
enable_irq(info->gpmc_irq_count);
|
||||
enable_irq(info->gpmc_irq_fifo);
|
||||
|
||||
/* waiting for read to complete */
|
||||
wait_for_completion(&info->comp);
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
gpmc_prefetch_reset(info->gpmc_cs);
|
||||
omap_prefetch_reset(info->gpmc_cs, info);
|
||||
return;
|
||||
|
||||
out_copy:
|
||||
|
|
@ -572,6 +651,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
|
|||
struct omap_nand_info, mtd);
|
||||
int ret = 0;
|
||||
unsigned long tim, limit;
|
||||
u32 val;
|
||||
|
||||
if (len <= mtd->oobsize) {
|
||||
omap_write_buf_pref(mtd, buf, len);
|
||||
|
|
@ -583,27 +663,31 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
|
|||
init_completion(&info->comp);
|
||||
|
||||
/* configure and start prefetch transfer : size=24 */
|
||||
ret = gpmc_prefetch_enable(info->gpmc_cs,
|
||||
(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1);
|
||||
ret = omap_prefetch_enable(info->gpmc_cs,
|
||||
(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
|
||||
if (ret)
|
||||
/* PFPW engine is busy, use cpu copy method */
|
||||
goto out_copy;
|
||||
|
||||
info->buf_len = len;
|
||||
/* enable irq */
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
|
||||
(GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
|
||||
|
||||
enable_irq(info->gpmc_irq_count);
|
||||
enable_irq(info->gpmc_irq_fifo);
|
||||
|
||||
/* waiting for write to complete */
|
||||
wait_for_completion(&info->comp);
|
||||
|
||||
/* wait for data to flushed-out before reset the prefetch */
|
||||
tim = 0;
|
||||
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
|
||||
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
|
||||
do {
|
||||
val = readl(info->reg.gpmc_prefetch_status);
|
||||
val = GPMC_PREFETCH_STATUS_COUNT(val);
|
||||
cpu_relax();
|
||||
} while (val && (tim++ < limit));
|
||||
|
||||
/* disable and stop the PFPW engine */
|
||||
gpmc_prefetch_reset(info->gpmc_cs);
|
||||
omap_prefetch_reset(info->gpmc_cs, info);
|
||||
return;
|
||||
|
||||
out_copy:
|
||||
|
|
@ -843,7 +927,20 @@ static int omap_calculate_ecc(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(info->gpmc_cs, dat, ecc_code);
|
||||
u32 val;
|
||||
|
||||
val = readl(info->reg.gpmc_ecc_config);
|
||||
if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs)
|
||||
return -EINVAL;
|
||||
|
||||
/* read ecc result */
|
||||
val = readl(info->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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -857,8 +954,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
mtd);
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
|
||||
u32 val;
|
||||
|
||||
gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size);
|
||||
/* clear ecc and enable bits */
|
||||
val = ECCCLEAR | ECC1;
|
||||
writel(val, info->reg.gpmc_ecc_control);
|
||||
|
||||
/* program ecc and result sizes */
|
||||
val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
|
||||
ECC1RESULTSIZE);
|
||||
writel(val, info->reg.gpmc_ecc_size_config);
|
||||
|
||||
switch (mode) {
|
||||
case NAND_ECC_READ:
|
||||
case NAND_ECC_WRITE:
|
||||
writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
|
||||
break;
|
||||
case NAND_ECC_READSYN:
|
||||
writel(ECCCLEAR, info->reg.gpmc_ecc_control);
|
||||
break;
|
||||
default:
|
||||
dev_info(&info->pdev->dev,
|
||||
"error: unrecognized Mode[%d]!\n", mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
|
||||
val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
|
||||
writel(val, info->reg.gpmc_ecc_config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -886,10 +1009,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
else
|
||||
timeo += (HZ * 20) / 1000;
|
||||
|
||||
gpmc_nand_write(info->gpmc_cs,
|
||||
GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF));
|
||||
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
|
||||
while (time_before(jiffies, timeo)) {
|
||||
status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
|
||||
status = readb(info->reg.gpmc_nand_data);
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
cond_resched();
|
||||
|
|
@ -909,22 +1031,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
|
|||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
|
||||
val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
|
||||
if ((val & 0x100) == 0x100) {
|
||||
/* Clear IRQ Interrupt */
|
||||
val |= 0x100;
|
||||
val &= ~(0x0);
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val);
|
||||
} else {
|
||||
unsigned int cnt = 0;
|
||||
while (cnt++ < 0x1FF) {
|
||||
if ((val & 0x100) == 0x100)
|
||||
return 0;
|
||||
val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
|
||||
}
|
||||
}
|
||||
val = readl(info->reg.gpmc_status);
|
||||
|
||||
return 1;
|
||||
if ((val & 0x100) == 0x100) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
|
|
@ -1155,6 +1268,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||
int i, offset;
|
||||
dma_cap_mask_t mask;
|
||||
unsigned sig;
|
||||
struct resource *res;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
|
|
@ -1174,7 +1288,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||
info->pdev = pdev;
|
||||
|
||||
info->gpmc_cs = pdata->cs;
|
||||
info->phys_base = pdata->phys_base;
|
||||
info->reg = pdata->reg;
|
||||
|
||||
info->mtd.priv = &info->nand;
|
||||
info->mtd.name = dev_name(&pdev->dev);
|
||||
|
|
@ -1183,16 +1297,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||
info->nand.options = pdata->devsize;
|
||||
info->nand.options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
/* NAND write protect off */
|
||||
gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "error getting memory resource\n");
|
||||
goto out_free_info;
|
||||
}
|
||||
|
||||
if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
|
||||
info->phys_base = res->start;
|
||||
info->mem_size = resource_size(res);
|
||||
|
||||
if (!request_mem_region(info->phys_base, info->mem_size,
|
||||
pdev->dev.driver->name)) {
|
||||
err = -EBUSY;
|
||||
goto out_free_info;
|
||||
}
|
||||
|
||||
info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
|
||||
info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size);
|
||||
if (!info->nand.IO_ADDR_R) {
|
||||
err = -ENOMEM;
|
||||
goto out_release_mem_region;
|
||||
|
|
@ -1265,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_IRQ:
|
||||
err = request_irq(pdata->gpmc_irq,
|
||||
omap_nand_irq, IRQF_SHARED, "gpmc-nand", info);
|
||||
info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
|
||||
if (info->gpmc_irq_fifo <= 0) {
|
||||
dev_err(&pdev->dev, "error getting fifo irq\n");
|
||||
err = -ENODEV;
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
err = request_irq(info->gpmc_irq_fifo, omap_nand_irq,
|
||||
IRQF_SHARED, "gpmc-nand-fifo", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
pdata->gpmc_irq, err);
|
||||
info->gpmc_irq_fifo, err);
|
||||
info->gpmc_irq_fifo = 0;
|
||||
goto out_release_mem_region;
|
||||
} else {
|
||||
info->gpmc_irq = pdata->gpmc_irq;
|
||||
info->nand.read_buf = omap_read_buf_irq_pref;
|
||||
info->nand.write_buf = omap_write_buf_irq_pref;
|
||||
}
|
||||
|
||||
info->gpmc_irq_count = platform_get_irq(pdev, 1);
|
||||
if (info->gpmc_irq_count <= 0) {
|
||||
dev_err(&pdev->dev, "error getting count irq\n");
|
||||
err = -ENODEV;
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
err = request_irq(info->gpmc_irq_count, omap_nand_irq,
|
||||
IRQF_SHARED, "gpmc-nand-count", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
info->gpmc_irq_count, err);
|
||||
info->gpmc_irq_count = 0;
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
|
||||
info->nand.read_buf = omap_read_buf_irq_pref;
|
||||
info->nand.write_buf = omap_write_buf_irq_pref;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1363,7 +1506,11 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||
out_release_mem_region:
|
||||
if (info->dma)
|
||||
dma_release_channel(info->dma);
|
||||
release_mem_region(info->phys_base, NAND_IO_SIZE);
|
||||
if (info->gpmc_irq_count > 0)
|
||||
free_irq(info->gpmc_irq_count, info);
|
||||
if (info->gpmc_irq_fifo > 0)
|
||||
free_irq(info->gpmc_irq_fifo, info);
|
||||
release_mem_region(info->phys_base, info->mem_size);
|
||||
out_free_info:
|
||||
kfree(info);
|
||||
|
||||
|
|
@ -1381,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev)
|
|||
if (info->dma)
|
||||
dma_release_channel(info->dma);
|
||||
|
||||
if (info->gpmc_irq)
|
||||
free_irq(info->gpmc_irq, info);
|
||||
if (info->gpmc_irq_count > 0)
|
||||
free_irq(info->gpmc_irq_count, info);
|
||||
if (info->gpmc_irq_fifo > 0)
|
||||
free_irq(info->gpmc_irq_fifo, info);
|
||||
|
||||
/* Release NAND device, its internal structures and partitions */
|
||||
nand_release(&info->mtd);
|
||||
|
|
|
|||
|
|
@ -43,18 +43,17 @@
|
|||
#include <asm/gpio.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
|
||||
#include <plat/board.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#define DRIVER_NAME "omap2-onenand"
|
||||
|
||||
#define ONENAND_IO_SIZE SZ_128K
|
||||
#define ONENAND_BUFRAM_SIZE (1024 * 5)
|
||||
|
||||
struct omap2_onenand {
|
||||
struct platform_device *pdev;
|
||||
int gpmc_cs;
|
||||
unsigned long phys_base;
|
||||
unsigned int mem_size;
|
||||
int gpio_irq;
|
||||
struct mtd_info mtd;
|
||||
struct onenand_chip onenand;
|
||||
|
|
@ -626,6 +625,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
|
|||
struct omap2_onenand *c;
|
||||
struct onenand_chip *this;
|
||||
int r;
|
||||
struct resource *res;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
|
|
@ -647,20 +647,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
|
|||
c->gpio_irq = 0;
|
||||
}
|
||||
|
||||
r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
|
||||
if (r < 0) {
|
||||
dev_err(&pdev->dev, "Cannot request GPMC CS\n");
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
r = -EINVAL;
|
||||
dev_err(&pdev->dev, "error getting memory resource\n");
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
|
||||
c->phys_base = res->start;
|
||||
c->mem_size = resource_size(res);
|
||||
|
||||
if (request_mem_region(c->phys_base, c->mem_size,
|
||||
pdev->dev.driver->name) == NULL) {
|
||||
dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
|
||||
"size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
|
||||
dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
|
||||
c->phys_base, c->mem_size);
|
||||
r = -EBUSY;
|
||||
goto err_free_cs;
|
||||
goto err_kfree;
|
||||
}
|
||||
c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
|
||||
c->onenand.base = ioremap(c->phys_base, c->mem_size);
|
||||
if (c->onenand.base == NULL) {
|
||||
r = -ENOMEM;
|
||||
goto err_release_mem_region;
|
||||
|
|
@ -776,9 +780,7 @@ err_release_gpio:
|
|||
err_iounmap:
|
||||
iounmap(c->onenand.base);
|
||||
err_release_mem_region:
|
||||
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
|
||||
err_free_cs:
|
||||
gpmc_cs_free(c->gpmc_cs);
|
||||
release_mem_region(c->phys_base, c->mem_size);
|
||||
err_kfree:
|
||||
kfree(c);
|
||||
|
||||
|
|
@ -800,7 +802,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
|
|||
gpio_free(c->gpio_irq);
|
||||
}
|
||||
iounmap(c->onenand.base);
|
||||
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
|
||||
release_mem_region(c->phys_base, c->mem_size);
|
||||
gpmc_cs_free(c->gpmc_cs);
|
||||
kfree(c);
|
||||
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ retry:
|
|||
* of this LEB as it will be deleted and freed in 'ubi_add_to_av()'.
|
||||
*/
|
||||
err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0);
|
||||
kfree(new_aeb);
|
||||
kmem_cache_free(ai->aeb_slab_cache, new_aeb);
|
||||
ubi_free_vid_hdr(ubi, vid_hdr);
|
||||
return err;
|
||||
|
||||
|
|
@ -353,7 +353,7 @@ write_error:
|
|||
list_add(&new_aeb->u.list, &ai->erase);
|
||||
goto retry;
|
||||
}
|
||||
kfree(new_aeb);
|
||||
kmem_cache_free(ai->aeb_slab_cache, new_aeb);
|
||||
out_free:
|
||||
ubi_free_vid_hdr(ubi, vid_hdr);
|
||||
return err;
|
||||
|
|
|
|||
Loading…
Reference in a new issue