summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/maps/tegra_nor.c43
1 files changed, 26 insertions, 17 deletions
diff --git a/drivers/mtd/maps/tegra_nor.c b/drivers/mtd/maps/tegra_nor.c
index 2059ce066cbb..b455fd5e1c00 100644
--- a/drivers/mtd/maps/tegra_nor.c
+++ b/drivers/mtd/maps/tegra_nor.c
@@ -118,6 +118,8 @@ struct tegra_nor_info {
struct map_info map;
struct completion dma_complete;
void __iomem *base;
+ void *dma_virt_buffer;
+ dma_addr_t dma_phys_buffer;
u32 init_config;
u32 timing0_default, timing1_default;
u32 timing0_read, timing1_read;
@@ -154,7 +156,8 @@ static void tegra_flash_dma(struct map_info *map,
{
u32 snor_config, dma_config = 0;
int dma_transfer_count = 0, word32_count = 0;
- u32 nor_address, ahb_address, current_transfer;
+ u32 nor_address, current_transfer = 0;
+ u32 copy_to = (u32)to;
struct tegra_nor_info *c =
container_of(map, struct tegra_nor_info, map);
unsigned int bytes_remaining = len;
@@ -164,16 +167,6 @@ static void tegra_flash_dma(struct map_info *map,
snor_tegra_writel(c, c->timing1_read, TEGRA_SNOR_TIMING1_REG);
if (len > 32) {
-
- if (to >= high_memory)
- goto out_copy;
-
- ahb_address = dma_map_single(c->dev, to, len, DMA_FROM_DEVICE);
- if (dma_mapping_error(c->dev, ahb_address)) {
- dev_err(c->dev,
- "Couldn't DMA map a %d byte buffer\n", len);
- goto out_copy;
- }
word32_count = len >> 2;
bytes_remaining = len & 0x00000003;
/*
@@ -196,7 +189,7 @@ static void tegra_flash_dma(struct map_info *map,
word32_count -= current_transfer,
dma_transfer_count += current_transfer,
nor_address += (current_transfer * 4),
- ahb_address += (current_transfer * 4)) {
+ copy_to += (current_transfer * 4)) {
current_transfer =
(word32_count > TEGRA_SNOR_DMA_LIMIT_WORDS)
@@ -210,7 +203,7 @@ static void tegra_flash_dma(struct map_info *map,
/* Num of AHB (32-bit) words to transferred minus 1 */
dma_config |=
TEGRA_SNOR_DMA_CFG_WRD_CNT(current_transfer - 1);
- snor_tegra_writel(c, ahb_address,
+ snor_tegra_writel(c, c->dma_phys_buffer,
TEGRA_SNOR_AHB_ADDR_PTR_REG);
snor_tegra_writel(c, nor_address,
TEGRA_SNOR_NOR_ADDR_PTR_REG);
@@ -224,15 +217,17 @@ static void tegra_flash_dma(struct map_info *map,
bytes_remaining += (word32_count << 2);
break;
}
+ memcpy((char *)(copy_to), (char *)(c->dma_virt_buffer),
+ (current_transfer << 2));
+
}
- dma_unmap_single(c->dev, ahb_address, len, DMA_FROM_DEVICE);
}
/* Put the controller back into slave mode. */
snor_config = snor_tegra_readl(c, TEGRA_SNOR_CONFIG_REG);
snor_config &= ~TEGRA_SNOR_CONFIG_MST_ENB;
snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0);
snor_tegra_writel(c, snor_config, TEGRA_SNOR_CONFIG_REG);
-out_copy:
+
memcpy_fromio(((char *)to + (dma_transfer_count << 2)),
((char *)(map->virt + from) + (dma_transfer_count << 2)),
bytes_remaining);
@@ -313,7 +308,7 @@ static int tegra_nor_probe(struct platform_device *pdev)
goto fail;
}
- /* Get NOR flash aperture & map the same */
+ /* Get NOR controller & map the same */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "no mem resource?\n");
@@ -401,11 +396,20 @@ static int tegra_nor_probe(struct platform_device *pdev)
dev_err(dev, "Failed to request irq %i\n", irq);
goto out_clk_disable;
}
+ info->dma_virt_buffer = dma_alloc_coherent(dev,
+ TEGRA_SNOR_DMA_LIMIT,
+ &info->dma_phys_buffer,
+ GFP_KERNEL);
+ if (info->dma_virt_buffer == NULL) {
+ dev_err(&pdev->dev, "Could not allocate buffer for DMA");
+ err = -ENOMEM;
+ goto out_clk_disable;
+ }
info->mtd = do_map_probe(plat->flash.map_name, &info->map);
if (!info->mtd) {
err = -EIO;
- goto out_clk_disable;
+ goto out_dma_free_coherent;
}
info->mtd->owner = THIS_MODULE;
info->parts = NULL;
@@ -423,6 +427,9 @@ static int tegra_nor_probe(struct platform_device *pdev)
return 0;
+out_dma_free_coherent:
+ dma_free_coherent(dev, TEGRA_SNOR_DMA_LIMIT,
+ info->dma_virt_buffer, info->dma_phys_buffer);
out_clk_disable:
clk_disable(info->clk);
out_clk_put:
@@ -439,6 +446,8 @@ static int tegra_nor_remove(struct platform_device *pdev)
mtd_device_unregister(info->mtd);
if (info->parts)
kfree(info->parts);
+ dma_free_coherent(&pdev->dev, TEGRA_SNOR_DMA_LIMIT,
+ info->dma_virt_buffer, info->dma_phys_buffer);
map_destroy(info->mtd);
clk_disable(info->clk);
clk_put(info->clk);