Skip to content

Commit

Permalink
mtd: nand/fsmc: Access the NAND device word by word whenever possible
Browse files Browse the repository at this point in the history
The default way of accessing nand device is using the nand width. This means
that 8bit devices are using u8 * and 16bit devices are accessed using u16 *.

This results in a non-optimal performance since the FSMC is designed to
translate the normal word accesses into device width based accesses. This patch
implements read_buf and write_buf callbacks using word by word accesses.

Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
Reviewed-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
Vipin Kumar authored and David Woodhouse committed Mar 27, 2012
1 parent 712c4ad commit 604e754
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
55 changes: 55 additions & 0 deletions drivers/mtd/nand/fsmc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,52 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits)
return written_bits;
}

/*
* fsmc_write_buf - write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
* @len: number of bytes to write
*/
static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
struct nand_chip *chip = mtd->priv;

if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
writel(p[i], chip->IO_ADDR_W);
} else {
for (i = 0; i < len; i++)
writeb(buf[i], chip->IO_ADDR_W);
}
}

/*
* fsmc_read_buf - read chip data into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
* @len: number of bytes to read
*/
static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
struct nand_chip *chip = mtd->priv;

if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
p[i] = readl(chip->IO_ADDR_R);
} else {
for (i = 0; i < len; i++)
buf[i] = readb(chip->IO_ADDR_R);
}
}

/*
* fsmc_read_page_hwecc
* @mtd: mtd info structure
Expand Down Expand Up @@ -825,6 +871,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (pdata->width == FSMC_NAND_BW16)
nand->options |= NAND_BUSWIDTH_16;

/*
* use customized (word by word) version of read_buf, write_buf if
* access_with_dev_width is reset supported
*/
if (pdata->mode == USE_WORD_ACCESS) {
nand->read_buf = fsmc_read_buf;
nand->write_buf = fsmc_write_buf;
}

fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16,
host->dev_timings);

Expand Down
6 changes: 6 additions & 0 deletions include/linux/mtd/fsmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ struct fsmc_nand_timings {
uint8_t tset;
};

enum access_mode {
USE_DMA_ACCESS = 1,
USE_WORD_ACCESS,
};

/**
* fsmc_nand_platform_data - platform specific NAND controller config
* @partitions: partition table for the platform, use a default fallback
Expand All @@ -164,6 +169,7 @@ struct fsmc_nand_platform_data {
/* CLE, ALE offsets */
unsigned long cle_off;
unsigned long ale_off;
enum access_mode mode;

void (*select_bank)(uint32_t bank, uint32_t busw);
};
Expand Down

0 comments on commit 604e754

Please sign in to comment.