summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/Kconfig7
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c3
-rw-r--r--drivers/mtd/devices/ps3vram.c768
-rw-r--r--drivers/mtd/maps/Kconfig12
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/physmap.c19
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c37
-rw-r--r--drivers/mtd/maps/vmu-flash.c832
-rw-r--r--drivers/mtd/nand/excite_nandflash.c25
-rw-r--r--drivers/mtd/nand/ndfc.c2
-rw-r--r--drivers/mtd/onenand/generic.c26
12 files changed, 903 insertions, 830 deletions
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index bc33200..6fde0a2 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -120,13 +120,6 @@ config MTD_PHRAM
doesn't have access to, memory beyond the mem=xxx limit, nvram,
memory on the video card, etc...
-config MTD_PS3VRAM
- tristate "PS3 video RAM"
- depends on FB_PS3
- help
- This driver allows you to use excess PS3 video RAM as volatile
- storage or system swap.
-
config MTD_LART
tristate "28F160xx flash driver for LART"
depends on SA1100_LART
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index e51521d..0993d5c 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,4 +16,3 @@ obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
-obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index d44f741..6d9f810 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -821,7 +821,8 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
if (!(info->flags & IS_POW2PS))
return info;
}
- }
+ } else
+ return info;
}
}
diff --git a/drivers/mtd/devices/ps3vram.c b/drivers/mtd/devices/ps3vram.c
deleted file mode 100644
index d21e9be..0000000
--- a/drivers/mtd/devices/ps3vram.c
+++ /dev/null
@@ -1,768 +0,0 @@
-/**
- * ps3vram - Use extra PS3 video ram as MTD block device.
- *
- * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
- * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
- */
-
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/gfp.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-
-#include <asm/lv1call.h>
-#include <asm/ps3.h>
-
-#define DEVICE_NAME "ps3vram"
-
-#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */
-#define XDR_IOIF 0x0c000000
-
-#define FIFO_BASE XDR_IOIF
-#define FIFO_SIZE (64 * 1024)
-
-#define DMA_PAGE_SIZE (4 * 1024)
-
-#define CACHE_PAGE_SIZE (256 * 1024)
-#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
-
-#define CACHE_OFFSET CACHE_PAGE_SIZE
-#define FIFO_OFFSET 0
-
-#define CTRL_PUT 0x10
-#define CTRL_GET 0x11
-#define CTRL_TOP 0x15
-
-#define UPLOAD_SUBCH 1
-#define DOWNLOAD_SUBCH 2
-
-#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
-#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
-
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
-
-struct mtd_info ps3vram_mtd;
-
-#define CACHE_PAGE_PRESENT 1
-#define CACHE_PAGE_DIRTY 2
-
-struct ps3vram_tag {
- unsigned int address;
- unsigned int flags;
-};
-
-struct ps3vram_cache {
- unsigned int page_count;
- unsigned int page_size;
- struct ps3vram_tag *tags;
-};
-
-struct ps3vram_priv {
- u64 memory_handle;
- u64 context_handle;
- u32 *ctrl;
- u32 *reports;
- u8 __iomem *ddr_base;
- u8 *xdr_buf;
-
- u32 *fifo_base;
- u32 *fifo_ptr;
-
- struct device *dev;
- struct ps3vram_cache cache;
-
- /* Used to serialize cache/DMA operations */
- struct mutex lock;
-};
-
-#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
-#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
-#define DMA_NOTIFIER_SIZE 0x40
-#define NOTIFIER 7 /* notifier used for completion report */
-
-/* A trailing '-' means to subtract off ps3fb_videomemory.size */
-char *size = "256M-";
-module_param(size, charp, 0);
-MODULE_PARM_DESC(size, "memory size");
-
-static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
-{
- return (void *) reports +
- DMA_NOTIFIER_OFFSET_BASE +
- DMA_NOTIFIER_SIZE * notifier;
-}
-
-static void ps3vram_notifier_reset(struct mtd_info *mtd)
-{
- int i;
-
- struct ps3vram_priv *priv = mtd->priv;
- u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
- for (i = 0; i < 4; i++)
- notify[i] = 0xffffffff;
-}
-
-static int ps3vram_notifier_wait(struct mtd_info *mtd, unsigned int timeout_ms)
-{
- struct ps3vram_priv *priv = mtd->priv;
- u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
- unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-
- do {
- if (!notify[3])
- return 0;
- msleep(1);
- } while (time_before(jiffies, timeout));
-
- return -ETIMEDOUT;
-}
-
-static void ps3vram_init_ring(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
- priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
-}
-
-static int ps3vram_wait_ring(struct mtd_info *mtd, unsigned int timeout_ms)
-{
- struct ps3vram_priv *priv = mtd->priv;
- unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-
- do {
- if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
- return 0;
- msleep(1);
- } while (time_before(jiffies, timeout));
-
- dev_dbg(priv->dev, "%s:%d: FIFO timeout (%08x/%08x/%08x)\n", __func__,
- __LINE__, priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
- priv->ctrl[CTRL_TOP]);
-
- return -ETIMEDOUT;
-}
-
-static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data)
-{
- *(priv->fifo_ptr)++ = data;
-}
-
-static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan,
- u32 tag, u32 size)
-{
- ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
-}
-
-static void ps3vram_rewind_ring(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
- u64 status;
-
- ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
-
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
-
- /* asking the HV for a blit will kick the fifo */
- status = lv1_gpu_context_attribute(priv->context_handle,
- L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
- 0, 0, 0, 0);
- if (status)
- dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
- __func__, __LINE__);
-
- priv->fifo_ptr = priv->fifo_base;
-}
-
-static void ps3vram_fire_ring(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
- u64 status;
-
- mutex_lock(&ps3_gpu_mutex);
-
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
- (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
-
- /* asking the HV for a blit will kick the fifo */
- status = lv1_gpu_context_attribute(priv->context_handle,
- L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
- 0, 0, 0, 0);
- if (status)
- dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
- __func__, __LINE__);
-
- if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
- FIFO_SIZE - 1024) {
- dev_dbg(priv->dev, "%s:%d: fifo full, rewinding\n", __func__,
- __LINE__);
- ps3vram_wait_ring(mtd, 200);
- ps3vram_rewind_ring(mtd);
- }
-
- mutex_unlock(&ps3_gpu_mutex);
-}
-
-static void ps3vram_bind(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
- ps3vram_out_ring(priv, 0x31337303);
- ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
- ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
- ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
- ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
-
- ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
- ps3vram_out_ring(priv, 0x3137c0de);
- ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
- ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
- ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
- ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
-
- ps3vram_fire_ring(mtd);
-}
-
-static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset,
- unsigned int dst_offset, int len, int count)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- ps3vram_begin_ring(priv, UPLOAD_SUBCH,
- NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
- ps3vram_out_ring(priv, XDR_IOIF + src_offset);
- ps3vram_out_ring(priv, dst_offset);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, count);
- ps3vram_out_ring(priv, (1 << 8) | 1);
- ps3vram_out_ring(priv, 0);
-
- ps3vram_notifier_reset(mtd);
- ps3vram_begin_ring(priv, UPLOAD_SUBCH,
- NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
- ps3vram_out_ring(priv, 0);
- ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
- ps3vram_out_ring(priv, 0);
- ps3vram_fire_ring(mtd);
- if (ps3vram_notifier_wait(mtd, 200) < 0) {
- dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
- __LINE__);
- return -1;
- }
-
- return 0;
-}
-
-static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset,
- unsigned int dst_offset, int len, int count)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
- NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
- ps3vram_out_ring(priv, src_offset);
- ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, len);
- ps3vram_out_ring(priv, count);
- ps3vram_out_ring(priv, (1 << 8) | 1);
- ps3vram_out_ring(priv, 0);
-
- ps3vram_notifier_reset(mtd);
- ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
- NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
- ps3vram_out_ring(priv, 0);
- ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
- ps3vram_out_ring(priv, 0);
- ps3vram_fire_ring(mtd);
- if (ps3vram_notifier_wait(mtd, 200) < 0) {
- dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
- __LINE__);
- return -1;
- }
-
- return 0;
-}
-
-static void ps3vram_cache_evict(struct mtd_info *mtd, int entry)
-{
- struct ps3vram_priv *priv = mtd->priv;
- struct ps3vram_cache *cache = &priv->cache;
-
- if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) {
- dev_dbg(priv->dev, "%s:%d: flushing %d : 0x%08x\n", __func__,
- __LINE__, entry, cache->tags[entry].address);
- if (ps3vram_upload(mtd,
- CACHE_OFFSET + entry * cache->page_size,
- cache->tags[entry].address,
- DMA_PAGE_SIZE,
- cache->page_size / DMA_PAGE_SIZE) < 0) {
- dev_dbg(priv->dev, "%s:%d: failed to upload from "
- "0x%x to 0x%x size 0x%x\n", __func__, __LINE__,
- entry * cache->page_size,
- cache->tags[entry].address, cache->page_size);
- }
- cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
- }
-}
-
-static void ps3vram_cache_load(struct mtd_info *mtd, int entry,
- unsigned int address)
-{
- struct ps3vram_priv *priv = mtd->priv;
- struct ps3vram_cache *cache = &priv->cache;
-
- dev_dbg(priv->dev, "%s:%d: fetching %d : 0x%08x\n", __func__, __LINE__,
- entry, address);
- if (ps3vram_download(mtd,
- address,
- CACHE_OFFSET + entry * cache->page_size,
- DMA_PAGE_SIZE,
- cache->page_size / DMA_PAGE_SIZE) < 0) {
- dev_err(priv->dev, "%s:%d: failed to download from "
- "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, address,
- entry * cache->page_size, cache->page_size);
- }
-
- cache->tags[entry].address = address;
- cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
-}
-
-
-static void ps3vram_cache_flush(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
- struct ps3vram_cache *cache = &priv->cache;
- int i;
-
- dev_dbg(priv->dev, "%s:%d: FLUSH\n", __func__, __LINE__);
- for (i = 0; i < cache->page_count; i++) {
- ps3vram_cache_evict(mtd, i);
- cache->tags[i].flags = 0;
- }
-}
-
-static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address)
-{
- struct ps3vram_priv *priv = mtd->priv;
- struct ps3vram_cache *cache = &priv->cache;
- unsigned int base;
- unsigned int offset;
- int i;
- static int counter;
-
- offset = (unsigned int) (address & (cache->page_size - 1));
- base = (unsigned int) (address - offset);
-
- /* fully associative check */
- for (i = 0; i < cache->page_count; i++) {
- if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
- cache->tags[i].address == base) {
- dev_dbg(priv->dev, "%s:%d: found entry %d : 0x%08x\n",
- __func__, __LINE__, i, cache->tags[i].address);
- return i;
- }
- }
-
- /* choose a random entry */
- i = (jiffies + (counter++)) % cache->page_count;
- dev_dbg(priv->dev, "%s:%d: using entry %d\n", __func__, __LINE__, i);
-
- ps3vram_cache_evict(mtd, i);
- ps3vram_cache_load(mtd, i, base);
-
- return i;
-}
-
-static int ps3vram_cache_init(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- priv->cache.page_count = CACHE_PAGE_COUNT;
- priv->cache.page_size = CACHE_PAGE_SIZE;
- priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
- CACHE_PAGE_COUNT, GFP_KERNEL);
- if (priv->cache.tags == NULL) {
- dev_err(priv->dev, "%s:%d: could not allocate cache tags\n",
- __func__, __LINE__);
- return -ENOMEM;
- }
-
- dev_info(priv->dev, "created ram cache: %d entries, %d KiB each\n",
- CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024);
-
- return 0;
-}
-
-static void ps3vram_cache_cleanup(struct mtd_info *mtd)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- ps3vram_cache_flush(mtd);
- kfree(priv->cache.tags);
-}
-
-static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- struct ps3vram_priv *priv = mtd->priv;
-
- if (instr->addr + instr->len > mtd->size)
- return -EINVAL;
-
- mutex_lock(&priv->lock);
-
- ps3vram_cache_flush(mtd);
-
- /* Set bytes to 0xFF */
- memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len);
-
- mutex_unlock(&priv->lock);
-
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
-
- return 0;
-}
-
-static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct ps3vram_priv *priv = mtd->priv;
- unsigned int cached, count;
-
- dev_dbg(priv->dev, "%s:%d: from=0x%08x len=0x%zx\n", __func__, __LINE__,
- (unsigned int)from, len);
-
- if (from >= mtd->size)
- return -EINVAL;
-
- if (len > mtd->size - from)
- len = mtd->size - from;
-
- /* Copy from vram to buf */
- count = len;
- while (count) {
- unsigned int offset, avail;
- unsigned int entry;
-
- offset = (unsigned int) (from & (priv->cache.page_size - 1));
- avail = priv->cache.page_size - offset;
-
- mutex_lock(&priv->lock);
-
- entry = ps3vram_cache_match(mtd, from);
- cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
-
- dev_dbg(priv->dev, "%s:%d: from=%08x cached=%08x offset=%08x "
- "avail=%08x count=%08x\n", __func__, __LINE__,
- (unsigned int)from, cached, offset, avail, count);
-
- if (avail > count)
- avail = count;
- memcpy(buf, priv->xdr_buf + cached, avail);
-
- mutex_unlock(&priv->lock);
-
- buf += avail;
- count -= avail;
- from += avail;
- }
-
- *retlen = len;
- return 0;
-}
-
-static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct ps3vram_priv *priv = mtd->priv;
- unsigned int cached, count;
-
- if (to >= mtd->size)
- return -EINVAL;
-
- if (len > mtd->size - to)
- len = mtd->size - to;
-
- /* Copy from buf to vram */
- count = len;
- while (count) {
- unsigned int offset, avail;
- unsigned int entry;
-
- offset = (unsigned int) (to & (priv->cache.page_size - 1));
- avail = priv->cache.page_size - offset;
-
- mutex_lock(&priv->lock);
-
- entry = ps3vram_cache_match(mtd, to);
- cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
-
- dev_dbg(priv->dev, "%s:%d: to=%08x cached=%08x offset=%08x "
- "avail=%08x count=%08x\n", __func__, __LINE__,
- (unsigned int)to, cached, offset, avail, count);
-
- if (avail > count)
- avail = count;
- memcpy(priv->xdr_buf + cached, buf, avail);
-
- priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
-
- mutex_unlock(&priv->lock);
-
- buf += avail;
- count -= avail;
- to += avail;
- }
-
- *retlen = len;
- return 0;
-}
-
-static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
-{
- struct ps3vram_priv *priv;
- int status;
- u64 ddr_lpar;
- u64 ctrl_lpar;
- u64 info_lpar;
- u64 reports_lpar;
- u64 ddr_size;
- u64 reports_size;
- int ret = -ENOMEM;
- char *rest;
-
- ret = -EIO;
- ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL);
- if (!ps3vram_mtd.priv)
- goto out;
- priv = ps3vram_mtd.priv;
-
- mutex_init(&priv->lock);
- priv->dev = &dev->core;
-
- /* Allocate XDR buffer (1MiB aligned) */
- priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
- get_order(XDR_BUF_SIZE));
- if (priv->xdr_buf == NULL) {
- dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n",
- __func__, __LINE__);
- ret = -ENOMEM;
- goto out_free_priv;
- }
-
- /* Put FIFO at begginning of XDR buffer */
- priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
- priv->fifo_ptr = priv->fifo_base;
-
- /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
- if (ps3_open_hv_device(dev)) {
- dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
- __func__, __LINE__);
- ret = -EAGAIN;
- goto out_close_gpu;
- }
-
- /* Request memory */
- status = -1;
- ddr_size = memparse(size, &rest);
- if (*rest == '-')
- ddr_size -= ps3fb_videomemory.size;
- ddr_size = ALIGN(ddr_size, 1024*1024);
- if (ddr_size <= 0) {
- dev_err(&dev->core, "%s:%d: specified size is too small\n",
- __func__, __LINE__);
- ret = -EINVAL;
- goto out_close_gpu;
- }
-
- while (ddr_size > 0) {
- status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
- &priv->memory_handle,
- &ddr_lpar);
- if (!status)
- break;
- ddr_size -= 1024*1024;
- }
- if (status || ddr_size <= 0) {
- dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n",
- __func__, __LINE__);
- ret = -ENOMEM;
- goto out_free_xdr_buf;
- }
-
- /* Request context */
- status = lv1_gpu_context_allocate(priv->memory_handle,
- 0,
- &priv->context_handle,
- &ctrl_lpar,
- &info_lpar,
- &reports_lpar,
- &reports_size);
- if (status) {
- dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n",
- __func__, __LINE__);
- ret = -ENOMEM;
- goto out_free_memory;
- }
-
- /* Map XDR buffer to RSX */
- status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
- ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
- XDR_BUF_SIZE, 0);
- if (status) {
- dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n",
- __func__, __LINE__);
- ret = -ENOMEM;
- goto out_free_context;
- }
-
- priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
-
- if (!priv->ddr_base) {
- dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
- __LINE__);
- ret = -ENOMEM;
- goto out_free_context;
- }
-
- priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
- if (!priv->ctrl) {
- dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
- __LINE__);
- ret = -ENOMEM;
- goto out_unmap_vram;
- }
-
- priv->reports = ioremap(reports_lpar, reports_size);
- if (!priv->reports) {
- dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
- __LINE__);
- ret = -ENOMEM;
- goto out_unmap_ctrl;
- }
-
- mutex_lock(&ps3_gpu_mutex);
- ps3vram_init_ring(&ps3vram_mtd);
- mutex_unlock(&ps3_gpu_mutex);
-
- ps3vram_mtd.name = "ps3vram";
- ps3vram_mtd.size = ddr_size;
- ps3vram_mtd.flags = MTD_CAP_RAM;
- ps3vram_mtd.erase = ps3vram_erase;
- ps3vram_mtd.point = NULL;
- ps3vram_mtd.unpoint = NULL;
- ps3vram_mtd.read = ps3vram_read;
- ps3vram_mtd.write = ps3vram_write;
- ps3vram_mtd.owner = THIS_MODULE;
- ps3vram_mtd.type = MTD_RAM;
- ps3vram_mtd.erasesize = CACHE_PAGE_SIZE;
- ps3vram_mtd.writesize = 1;
-
- ps3vram_bind(&ps3vram_mtd);
-
- mutex_lock(&ps3_gpu_mutex);
- ret = ps3vram_wait_ring(&ps3vram_mtd, 100);
- mutex_unlock(&ps3_gpu_mutex);
- if (ret < 0) {
- dev_err(&dev->core, "%s:%d: failed to initialize channels\n",
- __func__, __LINE__);
- ret = -ETIMEDOUT;
- goto out_unmap_reports;
- }
-
- ps3vram_cache_init(&ps3vram_mtd);
-
- if (add_mtd_device(&ps3vram_mtd)) {
- dev_err(&dev->core, "%s:%d: add_mtd_device failed\n",
- __func__, __LINE__);
- ret = -EAGAIN;
- goto out_cache_cleanup;
- }
-
- dev_info(&dev->core, "reserved %u MiB of gpu memory\n",
- (unsigned int)(ddr_size / 1024 / 1024));
-
- return 0;
-
-out_cache_cleanup:
- ps3vram_cache_cleanup(&ps3vram_mtd);
-out_unmap_reports:
- iounmap(priv->reports);
-out_unmap_ctrl:
- iounmap(priv->ctrl);
-out_unmap_vram:
- iounmap(priv->ddr_base);
-out_free_context:
- lv1_gpu_context_free(priv->context_handle);
-out_free_memory:
- lv1_gpu_memory_free(priv->memory_handle);
-out_close_gpu:
- ps3_close_hv_device(dev);
-out_free_xdr_buf:
- free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
-out_free_priv:
- kfree(ps3vram_mtd.priv);
- ps3vram_mtd.priv = NULL;
-out:
- return ret;
-}
-
-static int ps3vram_shutdown(struct ps3_system_bus_device *dev)
-{
- struct ps3vram_priv *priv;
-
- priv = ps3vram_mtd.priv;
-
- del_mtd_device(&ps3vram_mtd);
- ps3vram_cache_cleanup(&ps3vram_mtd);
- iounmap(priv->reports);
- iounmap(priv->ctrl);
- iounmap(priv->ddr_base);
- lv1_gpu_context_free(priv->context_handle);
- lv1_gpu_memory_free(priv->memory_handle);
- ps3_close_hv_device(dev);
- free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
- kfree(priv);
- return 0;
-}
-
-static struct ps3_system_bus_driver ps3vram_driver = {
- .match_id = PS3_MATCH_ID_GPU,
- .match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK,
- .core.name = DEVICE_NAME,
- .core.owner = THIS_MODULE,
- .probe = ps3vram_probe,
- .remove = ps3vram_shutdown,
- .shutdown = ps3vram_shutdown,
-};
-
-static int __init ps3vram_init(void)
-{
- return ps3_system_bus_driver_register(&ps3vram_driver);
-}
-
-static void __exit ps3vram_exit(void)
-{
- ps3_system_bus_driver_unregister(&ps3vram_driver);
-}
-
-module_init(ps3vram_init);
-module_exit(ps3vram_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jim Paris <jim@jtan.com>");
-MODULE_DESCRIPTION("MTD driver for PS3 video RAM");
-MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 043d50f..729f899 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -551,5 +551,15 @@ config MTD_PLATRAM
This selection automatically selects the map_ram driver.
-endmenu
+config MTD_VMU
+ tristate "Map driver for Dreamcast VMU"
+ depends on MAPLE
+ help
+ This driver enables access to the Dreamcast Visual Memory Unit (VMU).
+
+ Most Dreamcast users will want to say Y here.
+ To build this as a module select M here, the module will be called
+ vmu-flash.
+
+endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 6d9ba35..26b28a7 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o
+obj-$(CONFIG_MTD_VMU) += vmu-flash.o
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 4b122e7..2297182 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -46,16 +46,19 @@ static int physmap_flash_remove(struct platform_device *dev)
physmap_data = dev->dev.platform_data;
+ if (info->cmtd) {
#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts) {
- del_mtd_partitions(info->cmtd);
- kfree(info->parts);
- } else if (physmap_data->nr_parts)
- del_mtd_partitions(info->cmtd);
- else
- del_mtd_device(info->cmtd);
+ if (info->nr_parts || physmap_data->nr_parts)
+ del_mtd_partitions(info->cmtd);
+ else
+ del_mtd_device(info->cmtd);
#else
- del_mtd_device(info->cmtd);
+ del_mtd_device(info->cmtd);
+#endif
+ }
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->nr_parts)
+ kfree(info->parts);
#endif
#ifdef CONFIG_MTD_CONCAT
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index 771139c..e9026cb 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -41,9 +41,8 @@ struct pxa2xx_flash_info {
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-static int __init pxa2xx_flash_probe(struct device *dev)
+static int __init pxa2xx_flash_probe(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
struct flash_platform_data *flash = pdev->dev.platform_data;
struct pxa2xx_flash_info *info;
struct mtd_partition *parts;
@@ -114,15 +113,15 @@ static int __init pxa2xx_flash_probe(struct device *dev)
add_mtd_device(info->mtd);
}
- dev_set_drvdata(dev, info);
+ platform_set_drvdata(pdev, info);
return 0;
}
-static int __exit pxa2xx_flash_remove(struct device *dev)
+static int __exit pxa2xx_flash_remove(struct platform_device *dev)
{
- struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
- dev_set_drvdata(dev, NULL);
+ platform_set_drvdata(dev, NULL);
#ifdef CONFIG_MTD_PARTITIONS
if (info->nr_parts)
@@ -141,9 +140,9 @@ static int __exit pxa2xx_flash_remove(struct device *dev)
}
#ifdef CONFIG_PM
-static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
+static int pxa2xx_flash_suspend(struct platform_device *dev, pm_message_t state)
{
- struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
int ret = 0;
if (info->mtd && info->mtd->suspend)
@@ -151,17 +150,17 @@ static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
return ret;
}
-static int pxa2xx_flash_resume(struct device *dev)
+static int pxa2xx_flash_resume(struct platform_device *dev)
{
- struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
if (info->mtd && info->mtd->resume)
info->mtd->resume(info->mtd);
return 0;
}
-static void pxa2xx_flash_shutdown(struct device *dev)
+static void pxa2xx_flash_shutdown(struct platform_device *dev)
{
- struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
if (info && info->mtd->suspend(info->mtd) == 0)
info->mtd->resume(info->mtd);
@@ -172,11 +171,13 @@ static void pxa2xx_flash_shutdown(struct device *dev)
#define pxa2xx_flash_shutdown NULL
#endif
-static struct device_driver pxa2xx_flash_driver = {
- .name = "pxa2xx-flash",
- .bus = &platform_bus_type,
+static struct platform_driver pxa2xx_flash_driver = {
+ .driver = {
+ .name = "pxa2xx-flash",
+ .owner = THIS_MODULE,
+ },
.probe = pxa2xx_flash_probe,
- .remove = __exit_p(pxa2xx_flash_remove),
+ .remove = __devexit_p(pxa2xx_flash_remove),
.suspend = pxa2xx_flash_suspend,
.resume = pxa2xx_flash_resume,
.shutdown = pxa2xx_flash_shutdown,
@@ -184,12 +185,12 @@ static struct device_driver pxa2xx_flash_driver = {
static int __init init_pxa2xx_flash(void)
{
- return driver_register(&pxa2xx_flash_driver);
+ return platform_driver_register(&pxa2xx_flash_driver);
}
static void __exit cleanup_pxa2xx_flash(void)
{
- driver_unregister(&pxa2xx_flash_driver);
+ platform_driver_unregister(&pxa2xx_flash_driver);
}
module_init(init_pxa2xx_flash);
diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c
new file mode 100644
index 0000000..1f73297
--- /dev/null
+++ b/drivers/mtd/maps/vmu-flash.c
@@ -0,0 +1,832 @@
+/* vmu-flash.c
+ * Driver for SEGA Dreamcast Visual Memory Unit
+ *
+ * Copyright (c) Adrian McMenamin 2002 - 2009
+ * Copyright (c) Paul Mundt 2001
+ *
+ * Licensed under version 2 of the
+ * GNU General Public Licence
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/maple.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+struct vmu_cache {
+ unsigned char *buffer; /* Cache */
+ unsigned int block; /* Which block was cached */
+ unsigned long jiffies_atc; /* When was it cached? */
+ int valid;
+};
+
+struct mdev_part {
+ struct maple_device *mdev;
+ int partition;
+};
+
+struct vmupart {
+ u16 user_blocks;
+ u16 root_block;
+ u16 numblocks;
+ char *name;
+ struct vmu_cache *pcache;
+};
+
+struct memcard {
+ u16 tempA;
+ u16 tempB;
+ u32 partitions;
+ u32 blocklen;
+ u32 writecnt;
+ u32 readcnt;
+ u32 removeable;
+ int partition;
+ int read;
+ unsigned char *blockread;
+ struct vmupart *parts;
+ struct mtd_info *mtd;
+};
+
+struct vmu_block {
+ unsigned int num; /* block number */
+ unsigned int ofs; /* block offset */
+};
+
+static struct vmu_block *ofs_to_block(unsigned long src_ofs,
+ struct mtd_info *mtd, int partition)
+{
+ struct vmu_block *vblock;
+ struct maple_device *mdev;
+ struct memcard *card;
+ struct mdev_part *mpart;
+ int num;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ card = maple_get_drvdata(mdev);
+
+ if (src_ofs >= card->parts[partition].numblocks * card->blocklen)
+ goto failed;
+
+ num = src_ofs / card->blocklen;
+ if (num > card->parts[partition].numblocks)
+ goto failed;
+
+ vblock = kmalloc(sizeof(struct vmu_block), GFP_KERNEL);
+ if (!vblock)
+ goto failed;
+
+ vblock->num = num;
+ vblock->ofs = src_ofs % card->blocklen;
+ return vblock;
+
+failed:
+ return NULL;
+}
+
+/* Maple bus callback function for reads */
+static void vmu_blockread(struct mapleq *mq)
+{
+ struct maple_device *mdev;
+ struct memcard *card;
+
+ mdev = mq->dev;
+ card = maple_get_drvdata(mdev);
+ /* copy the read in data */
+
+ if (unlikely(!card->blockread))
+ return;
+
+ memcpy(card->blockread, mq->recvbuf->buf + 12,
+ card->blocklen/card->readcnt);
+
+}
+
+/* Interface with maple bus to read blocks
+ * caching the results so that other parts
+ * of the driver can access block reads */
+static int maple_vmu_read_block(unsigned int num, unsigned char *buf,
+ struct mtd_info *mtd)
+{
+ struct memcard *card;
+ struct mdev_part *mpart;
+ struct maple_device *mdev;
+ int partition, error = 0, x, wait;
+ unsigned char *blockread = NULL;
+ struct vmu_cache *pcache;
+ __be32 sendbuf;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ partition = mpart->partition;
+ card = maple_get_drvdata(mdev);
+ pcache = card->parts[partition].pcache;
+ pcache->valid = 0;
+
+ /* prepare the cache for this block */
+ if (!pcache->buffer) {
+ pcache->buffer = kmalloc(card->blocklen, GFP_KERNEL);
+ if (!pcache->buffer) {
+ dev_err(&mdev->dev, "VMU at (%d, %d) - read fails due"
+ " to lack of memory\n", mdev->port,
+ mdev->unit);
+ error = -ENOMEM;
+ goto outB;
+ }
+ }
+
+ /*
+ * Reads may be phased - again the hardware spec
+ * supports this - though may not be any devices in
+ * the wild that implement it, but we will here
+ */
+ for (x = 0; x < card->readcnt; x++) {
+ sendbuf = cpu_to_be32(partition << 24 | x << 16 | num);
+
+ if (atomic_read(&mdev->busy) == 1) {
+ wait_event_interruptible_timeout(mdev->maple_wait,
+ atomic_read(&mdev->busy) == 0, HZ);
+ if (atomic_read(&mdev->busy) == 1) {
+ dev_notice(&mdev->dev, "VMU at (%d, %d)"
+ " is busy\n", mdev->port, mdev->unit);
+ error = -EAGAIN;
+ goto outB;
+ }
+ }
+
+ atomic_set(&mdev->busy, 1);
+ blockread = kmalloc(card->blocklen/card->readcnt, GFP_KERNEL);
+ if (!blockread) {
+ error = -ENOMEM;
+ atomic_set(&mdev->busy, 0);
+ goto outB;
+ }
+ card->blockread = blockread;
+
+ maple_getcond_callback(mdev, vmu_blockread, 0,
+ MAPLE_FUNC_MEMCARD);
+ error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+ MAPLE_COMMAND_BREAD, 2, &sendbuf);
+ /* Very long timeouts seem to be needed when box is stressed */
+ wait = wait_event_interruptible_timeout(mdev->maple_wait,
+ (atomic_read(&mdev->busy) == 0 ||
+ atomic_read(&mdev->busy) == 2), HZ * 3);
+ /*
+ * MTD layer does not handle hotplugging well
+ * so have to return errors when VMU is unplugged
+ * in the middle of a read (busy == 2)
+ */
+ if (error || atomic_read(&mdev->busy) == 2) {
+ if (atomic_read(&mdev->busy) == 2)
+ error = -ENXIO;
+ atomic_set(&mdev->busy, 0);
+ card->blockread = NULL;
+ goto outA;
+ }
+ if (wait == 0 || wait == -ERESTARTSYS) {
+ card->blockread = NULL;
+ atomic_set(&mdev->busy, 0);
+ error = -EIO;
+ list_del_init(&(mdev->mq->list));
+ kfree(mdev->mq->sendbuf);
+ mdev->mq->sendbuf = NULL;
+ if (wait == -ERESTARTSYS) {
+ dev_warn(&mdev->dev, "VMU read on (%d, %d)"
+ " interrupted on block 0x%X\n",
+ mdev->port, mdev->unit, num);
+ } else
+ dev_notice(&mdev->dev, "VMU read on (%d, %d)"
+ " timed out on block 0x%X\n",
+ mdev->port, mdev->unit, num);
+ goto outA;
+ }
+
+ memcpy(buf + (card->blocklen/card->readcnt) * x, blockread,
+ card->blocklen/card->readcnt);
+
+ memcpy(pcache->buffer + (card->blocklen/card->readcnt) * x,
+ card->blockread, card->blocklen/card->readcnt);
+ card->blockread = NULL;
+ pcache->block = num;
+ pcache->jiffies_atc = jiffies;
+ pcache->valid = 1;
+ kfree(blockread);
+ }
+
+ return error;
+
+outA:
+ kfree(blockread);
+outB:
+ return error;
+}
+
+/* communicate with maple bus for phased writing */
+static int maple_vmu_write_block(unsigned int num, const unsigned char *buf,
+ struct mtd_info *mtd)
+{
+ struct memcard *card;
+ struct mdev_part *mpart;
+ struct maple_device *mdev;
+ int partition, error, locking, x, phaselen, wait;
+ __be32 *sendbuf;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ partition = mpart->partition;
+ card = maple_get_drvdata(mdev);
+
+ phaselen = card->blocklen/card->writecnt;
+
+ sendbuf = kmalloc(phaselen + 4, GFP_KERNEL);
+ if (!sendbuf) {
+ error = -ENOMEM;
+ goto fail_nosendbuf;
+ }
+ for (x = 0; x < card->writecnt; x++) {
+ sendbuf[0] = cpu_to_be32(partition << 24 | x << 16 | num);
+ memcpy(&sendbuf[1], buf + phaselen * x, phaselen);
+ /* wait until the device is not busy doing something else
+ * or 1 second - which ever is longer */
+ if (atomic_read(&mdev->busy) == 1) {
+ wait_event_interruptible_timeout(mdev->maple_wait,
+ atomic_read(&mdev->busy) == 0, HZ);
+ if (atomic_read(&mdev->busy) == 1) {
+ error = -EBUSY;
+ dev_notice(&mdev->dev, "VMU write at (%d, %d)"
+ "failed - device is busy\n",
+ mdev->port, mdev->unit);
+ goto fail_nolock;
+ }
+ }
+ atomic_set(&mdev->busy, 1);
+
+ locking = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+ MAPLE_COMMAND_BWRITE, phaselen / 4 + 2, sendbuf);
+ wait = wait_event_interruptible_timeout(mdev->maple_wait,
+ atomic_read(&mdev->busy) == 0, HZ/10);
+ if (locking) {
+ error = -EIO;
+ atomic_set(&mdev->busy, 0);
+ goto fail_nolock;
+ }
+ if (atomic_read(&mdev->busy) == 2) {
+ atomic_set(&mdev->busy, 0);
+ } else if (wait == 0 || wait == -ERESTARTSYS) {
+ error = -EIO;
+ dev_warn(&mdev->dev, "Write at (%d, %d) of block"
+ " 0x%X at phase %d failed: could not"
+ " communicate with VMU", mdev->port,
+ mdev->unit, num, x);
+ atomic_set(&mdev->busy, 0);
+ kfree(mdev->mq->sendbuf);
+ mdev->mq->sendbuf = NULL;
+ list_del_init(&(mdev->mq->list));
+ goto fail_nolock;
+ }
+ }
+ kfree(sendbuf);
+
+ return card->blocklen;
+
+fail_nolock:
+ kfree(sendbuf);
+fail_nosendbuf:
+ dev_err(&mdev->dev, "VMU (%d, %d): write failed\n", mdev->port,
+ mdev->unit);
+ return error;
+}
+
+/* mtd function to simulate reading byte by byte */
+static unsigned char vmu_flash_read_char(unsigned long ofs, int *retval,
+ struct mtd_info *mtd)
+{
+ struct vmu_block *vblock;
+ struct memcard *card;
+ struct mdev_part *mpart;
+ struct maple_device *mdev;
+ unsigned char *buf, ret;
+ int partition, error;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ partition = mpart->partition;
+ card = maple_get_drvdata(mdev);
+ *retval = 0;
+
+ buf = kmalloc(card->blocklen, GFP_KERNEL);
+ if (!buf) {
+ *retval = 1;
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ vblock = ofs_to_block(ofs, mtd, partition);
+ if (!vblock) {
+ *retval = 3;
+ ret = -ENOMEM;
+ goto out_buf;
+ }
+
+ error = maple_vmu_read_block(vblock->num, buf, mtd);
+ if (error) {
+ ret = error;
+ *retval = 2;
+ goto out_vblock;
+ }
+
+ ret = buf[vblock->ofs];
+
+out_vblock:
+ kfree(vblock);
+out_buf:
+ kfree(buf);
+finish:
+ return ret;
+}
+
+/* mtd higher order function to read flash */
+static int vmu_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct maple_device *mdev;
+ struct memcard *card;
+ struct mdev_part *mpart;
+ struct vmu_cache *pcache;
+ struct vmu_block *vblock;
+ int index = 0, retval, partition, leftover, numblocks;
+ unsigned char cx;
+
+ if (len < 1)
+ return -EIO;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ partition = mpart->partition;
+ card = maple_get_drvdata(mdev);
+
+ numblocks = card->parts[partition].numblocks;
+ if (from + len > numblocks * card->blocklen)
+ len = numblocks * card->blocklen - from;
+ if (len == 0)
+ return -EIO;
+ /* Have we cached this bit already? */
+ pcache = card->parts[partition].pcache;
+ do {
+ vblock = ofs_to_block(from + index, mtd, partition);
+ if (!vblock)
+ return -ENOMEM;
+ /* Have we cached this and is the cache valid and timely? */
+ if (pcache->valid &&
+ time_before(jiffies, pcache->jiffies_atc + HZ) &&
+ (pcache->block == vblock->num)) {
+ /* we have cached it, so do necessary copying */
+ leftover = card->blocklen - vblock->ofs;
+ if (vblock->ofs + len - index < card->blocklen) {
+ /* only a bit of this block to copy */
+ memcpy(buf + index,
+ pcache->buffer + vblock->ofs,
+ len - index);
+ index = len;
+ } else {
+ /* otherwise copy remainder of whole block */
+ memcpy(buf + index, pcache->buffer +
+ vblock->ofs, leftover);
+ index += leftover;
+ }
+ } else {
+ /*
+ * Not cached so read one byte -
+ * but cache the rest of the block
+ */
+ cx = vmu_flash_read_char(from + index, &retval, mtd);
+ if (retval) {
+ *retlen = index;
+ kfree(vblock);
+ return cx;
+ }
+ memset(buf + index, cx, 1);
+ index++;
+ }
+ kfree(vblock);
+ } while (len > index);
+ *retlen = index;
+
+ return 0;
+}
+
+static int vmu_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct maple_device *mdev;
+ struct memcard *card;
+ struct mdev_part *mpart;
+ int index = 0, partition, error = 0, numblocks;
+ struct vmu_cache *pcache;
+ struct vmu_block *vblock;
+ unsigned char *buffer;
+
+ mpart = mtd->priv;
+ mdev = mpart->mdev;
+ partition = mpart->partition;
+ card = maple_get_drvdata(mdev);
+
+ /* simple sanity checks */
+ if (len < 1) {
+ error = -EIO;
+ goto failed;
+ }
+ numblocks = card->parts[partition].numblocks;
+ if (to + len > numblocks * card->blocklen)
+ len = numblocks * card->blocklen - to;
+ if (len == 0) {
+ error = -EIO;
+ goto failed;
+ }
+
+ vblock = ofs_to_block(to, mtd, partition);
+ if (!vblock) {
+ error = -ENOMEM;
+ goto failed;
+ }
+
+ buffer = kmalloc(card->blocklen, GFP_KERNEL);
+ if (!buffer) {
+ error = -ENOMEM;
+ goto fail_buffer;
+ }
+
+ do {
+ /* Read in the block we are to write to */
+ error = maple_vmu_read_block(vblock->num, buffer, mtd);
+ if (error)
+ goto fail_io;
+
+ do {
+ buffer[vblock->ofs] = buf[index];
+ vblock->ofs++;
+ index++;
+ if (index >= len)
+ break;
+ } while (vblock->ofs < card->blocklen);
+
+ /* write out new buffer */
+ error = maple_vmu_write_block(vblock->num, buffer, mtd);
+ /* invalidate the cache */
+ pcache = card->parts[partition].pcache;
+ pcache->valid = 0;
+
+ if (error != card->blocklen)
+ goto fail_io;
+
+ vblock->num++;
+ vblock->ofs = 0;
+ } while (len > index);
+
+ kfree(buffer);
+ *retlen = index;
+ kfree(vblock);
+ return 0;
+
+fail_io:
+ kfree(buffer);
+fail_buffer:
+ kfree(vblock);
+failed:
+ dev_err(&mdev->dev, "VMU write failing with error %d\n", error);
+ return error;
+}
+
+static void vmu_flash_sync(struct mtd_info *mtd)
+{
+ /* Do nothing here */
+}
+
+/* Maple bus callback function to recursively query hardware details */
+static void vmu_queryblocks(struct mapleq *mq)
+{
+ struct maple_device *mdev;
+ unsigned short *res;
+ struct memcard *card;
+ __be32 partnum;
+ struct vmu_cache *pcache;
+ struct mdev_part *mpart;
+ struct mtd_info *mtd_cur;
+ struct vmupart *part_cur;
+ int error;
+
+ mdev = mq->dev;
+ card = maple_get_drvdata(mdev);
+ res = (unsigned short *) (mq->recvbuf->buf);
+ card->tempA = res[12];
+ card->tempB = res[6];
+
+ dev_info(&mdev->dev, "VMU device at partition %d has %d user "
+ "blocks with a root block at %d\n", card->partition,
+ card->tempA, card->tempB);
+
+ part_cur = &card->parts[card->partition];
+ part_cur->user_blocks = card->tempA;
+ part_cur->root_block = card->tempB;
+ part_cur->numblocks = card->tempB + 1;
+ part_cur->name = kmalloc(12, GFP_KERNEL);
+ if (!part_cur->name)
+ goto fail_name;
+
+ sprintf(part_cur->name, "vmu%d.%d.%d",
+ mdev->port, mdev->unit, card->partition);
+ mtd_cur = &card->mtd[card->partition];
+ mtd_cur->name = part_cur->name;
+ mtd_cur->type = 8;
+ mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
+ mtd_cur->size = part_cur->numblocks * card->blocklen;
+ mtd_cur->erasesize = card->blocklen;
+ mtd_cur->write = vmu_flash_write;
+ mtd_cur->read = vmu_flash_read;
+ mtd_cur->sync = vmu_flash_sync;
+ mtd_cur->writesize = card->blocklen;
+
+ mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
+ if (!mpart)
+ goto fail_mpart;
+
+ mpart->mdev = mdev;
+ mpart->partition = card->partition;
+ mtd_cur->priv = mpart;
+ mtd_cur->owner = THIS_MODULE;
+
+ pcache = kzalloc(sizeof(struct vmu_cache), GFP_KERNEL);
+ if (!pcache)
+ goto fail_cache_create;
+ part_cur->pcache = pcache;
+
+ error = add_mtd_device(mtd_cur);
+ if (error)
+ goto fail_mtd_register;
+
+ maple_getcond_callback(mdev, NULL, 0,
+ MAPLE_FUNC_MEMCARD);
+
+ /*
+ * Set up a recursive call to the (probably theoretical)
+ * second or more partition
+ */
+ if (++card->partition < card->partitions) {
+ partnum = cpu_to_be32(card->partition << 24);
+ maple_getcond_callback(mdev, vmu_queryblocks, 0,
+ MAPLE_FUNC_MEMCARD);
+ maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+ MAPLE_COMMAND_GETMINFO, 2, &partnum);
+ }
+ return;
+
+fail_mtd_register:
+ dev_err(&mdev->dev, "Could not register maple device at (%d, %d)"
+ "error is 0x%X\n", mdev->port, mdev->unit, error);
+ for (error = 0; error <= card->partition; error++) {
+ kfree(((card->parts)[error]).pcache);
+ ((card->parts)[error]).pcache = NULL;
+ }
+fail_cache_create:
+fail_mpart:
+ for (error = 0; error <= card->partition; error++) {
+ kfree(((card->mtd)[error]).priv);
+ ((card->mtd)[error]).priv = NULL;
+ }
+ maple_getcond_callback(mdev, NULL, 0,
+ MAPLE_FUNC_MEMCARD);
+ kfree(part_cur->name);
+fail_name:
+ return;
+}
+
+/* Handles very basic info about the flash, queries for details */
+static int __devinit vmu_connect(struct maple_device *mdev)
+{
+ unsigned long test_flash_data, basic_flash_data;
+ int c, error;
+ struct memcard *card;
+ u32 partnum = 0;
+
+ test_flash_data = be32_to_cpu(mdev->devinfo.function);
+ /* Need to count how many bits are set - to find out which
+ * function_data element has details of the memory card:
+ * using Brian Kernighan's/Peter Wegner's method */
+ for (c = 0; test_flash_data; c++)
+ test_flash_data &= test_flash_data - 1;
+
+ basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]);
+
+ card = kmalloc(sizeof(struct memcard), GFP_KERNEL);
+ if (!card) {
+ error = ENOMEM;
+ goto fail_nomem;
+ }
+
+ card->partitions = (basic_flash_data >> 24 & 0xFF) + 1;
+ card->blocklen = ((basic_flash_data >> 16 & 0xFF) + 1) << 5;
+ card->writecnt = basic_flash_data >> 12 & 0xF;
+ card->readcnt = basic_flash_data >> 8 & 0xF;
+ card->removeable = basic_flash_data >> 7 & 1;
+
+ card->partition = 0;
+
+ /*
+ * Not sure there are actually any multi-partition devices in the
+ * real world, but the hardware supports them, so, so will we
+ */
+ card->parts = kmalloc(sizeof(struct vmupart) * card->partitions,
+ GFP_KERNEL);
+ if (!card->parts) {
+ error = -ENOMEM;
+ goto fail_partitions;
+ }
+
+ card->mtd = kmalloc(sizeof(struct mtd_info) * card->partitions,
+ GFP_KERNEL);
+ if (!card->mtd) {
+ error = -ENOMEM;
+ goto fail_mtd_info;
+ }
+
+ maple_set_drvdata(mdev, card);
+
+ /*
+ * We want to trap meminfo not get cond
+ * so set interval to zero, but rely on maple bus
+ * driver to pass back the results of the meminfo
+ */
+ maple_getcond_callback(mdev, vmu_queryblocks, 0,
+ MAPLE_FUNC_MEMCARD);
+
+ /* Make sure we are clear to go */
+ if (atomic_read(&mdev->busy) == 1) {
+ wait_event_interruptible_timeout(mdev->maple_wait,
+ atomic_read(&mdev->busy) == 0, HZ);
+ if (atomic_read(&mdev->busy) == 1) {
+ dev_notice(&mdev->dev, "VMU at (%d, %d) is busy\n",
+ mdev->port, mdev->unit);
+ error = -EAGAIN;
+ goto fail_device_busy;
+ }
+ }
+
+ atomic_set(&mdev->busy, 1);
+
+ /*
+ * Set up the minfo call: vmu_queryblocks will handle
+ * the information passed back
+ */
+ error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
+ MAPLE_COMMAND_GETMINFO, 2, &partnum);
+ if (error) {
+ dev_err(&mdev->dev, "Could not lock VMU at (%d, %d)"
+ " error is 0x%X\n", mdev->port, mdev->unit, error);
+ goto fail_mtd_info;
+ }
+ return 0;
+
+fail_device_busy:
+ kfree(card->mtd);
+fail_mtd_info:
+ kfree(card->parts);
+fail_partitions:
+ kfree(card);
+fail_nomem:
+ return error;
+}
+
+static void __devexit vmu_disconnect(struct maple_device *mdev)
+{
+ struct memcard *card;
+ struct mdev_part *mpart;
+ int x;
+
+ mdev->callback = NULL;
+ card = maple_get_drvdata(mdev);
+ for (x = 0; x < card->partitions; x++) {
+ mpart = ((card->mtd)[x]).priv;
+ mpart->mdev = NULL;
+ del_mtd_device(&((card->mtd)[x]));
+ kfree(((card->parts)[x]).name);
+ }
+ kfree(card->parts);
+ kfree(card->mtd);
+ kfree(card);
+}
+
+/* Callback to handle eccentricities of both mtd subsystem
+ * and general flakyness of Dreamcast VMUs
+ */
+static int vmu_can_unload(struct maple_device *mdev)
+{
+ struct memcard *card;
+ int x;
+ struct mtd_info *mtd;
+
+ card = maple_get_drvdata(mdev);
+ for (x = 0; x < card->partitions; x++) {
+ mtd = &((card->mtd)[x]);
+ if (mtd->usecount > 0)
+ return 0;
+ }
+ return 1;
+}
+
+#define ERRSTR "VMU at (%d, %d) file error -"
+
+static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
+{
+ enum maple_file_errors error = ((int *)recvbuf)[1];
+
+ switch (error) {
+
+ case MAPLE_FILEERR_INVALID_PARTITION:
+ dev_notice(&mdev->dev, ERRSTR " invalid partition number\n",
+ mdev->port, mdev->unit);
+ break;
+
+ case MAPLE_FILEERR_PHASE_ERROR:
+ dev_notice(&mdev->dev, ERRSTR " phase error\n",
+ mdev->port, mdev->unit);
+ break;
+
+ case MAPLE_FILEERR_INVALID_BLOCK:
+ dev_notice(&mdev->dev, ERRSTR " invalid block number\n",
+ mdev->port, mdev->unit);
+ break;
+
+ case MAPLE_FILEERR_WRITE_ERROR:
+ dev_notice(&mdev->dev, ERRSTR " write error\n",
+ mdev->port, mdev->unit);
+ break;
+
+ case MAPLE_FILEERR_INVALID_WRITE_LENGTH:
+ dev_notice(&mdev->dev, ERRSTR " invalid write length\n",
+ mdev->port, mdev->unit);
+ break;
+
+ case MAPLE_FILEERR_BAD_CRC:
+ dev_notice(&mdev->dev, ERRSTR " bad CRC\n",
+ mdev->port, mdev->unit);
+ break;
+
+ default:
+ dev_notice(&mdev->dev, ERRSTR " 0x%X\n",
+ mdev->port, mdev->unit, error);
+ }
+}
+
+
+static int __devinit probe_maple_vmu(struct device *dev)
+{
+ int error;
+ struct maple_device *mdev = to_maple_dev(dev);
+ struct maple_driver *mdrv = to_maple_driver(dev->driver);
+
+ mdev->can_unload = vmu_can_unload;
+ mdev->fileerr_handler = vmu_file_error;
+ mdev->driver = mdrv;
+
+ error = vmu_connect(mdev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int __devexit remove_maple_vmu(struct device *dev)
+{
+ struct maple_device *mdev = to_maple_dev(dev);
+
+ vmu_disconnect(mdev);
+ return 0;
+}
+
+static struct maple_driver vmu_flash_driver = {
+ .function = MAPLE_FUNC_MEMCARD,
+ .drv = {
+ .name = "Dreamcast_visual_memory",
+ .probe = probe_maple_vmu,
+ .remove = __devexit_p(remove_maple_vmu),
+ },
+};
+
+static int __init vmu_flash_map_init(void)
+{
+ return maple_driver_register(&vmu_flash_driver);
+}
+
+static void __exit vmu_flash_map_exit(void)
+{
+ maple_driver_unregister(&vmu_flash_driver);
+}
+
+module_init(vmu_flash_map_init);
+module_exit(vmu_flash_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Adrian McMenamin");
+MODULE_DESCRIPTION("Flash mapping for Sega Dreamcast visual memory");
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
index ced14b5..72446fb 100644
--- a/drivers/mtd/nand/excite_nandflash.c
+++ b/drivers/mtd/nand/excite_nandflash.c
@@ -128,11 +128,11 @@ static int excite_nand_devready(struct mtd_info *mtd)
* The binding to the mtd and all allocated
* resources are released.
*/
-static int __exit excite_nand_remove(struct device *dev)
+static int __exit excite_nand_remove(struct platform_device *dev)
{
- struct excite_nand_drvdata * const this = dev_get_drvdata(dev);
+ struct excite_nand_drvdata * const this = platform_get_drvdata(dev);
- dev_set_drvdata(dev, NULL);
+ platform_set_drvdata(dev, NULL);
if (unlikely(!this)) {
printk(KERN_ERR "%s: called %s without private data!!",
@@ -159,9 +159,8 @@ static int __exit excite_nand_remove(struct device *dev)
* it can allocate all necessary resources then calls the
* nand layer to look for devices.
*/
-static int __init excite_nand_probe(struct device *dev)
+static int __init excite_nand_probe(struct platform_device *pdev)
{
- struct platform_device * const pdev = to_platform_device(dev);
struct excite_nand_drvdata *drvdata; /* private driver data */
struct nand_chip *board_chip; /* private flash chip data */
struct mtd_info *board_mtd; /* mtd info for this board */
@@ -175,7 +174,7 @@ static int __init excite_nand_probe(struct device *dev)
}
/* bind private data into driver */
- dev_set_drvdata(dev, drvdata);
+ platform_set_drvdata(pdev, drvdata);
/* allocate and map the resource */
drvdata->regs =
@@ -219,23 +218,25 @@ static int __init excite_nand_probe(struct device *dev)
return 0;
}
-static struct device_driver excite_nand_driver = {
- .name = "excite_nand",
- .bus = &platform_bus_type,
+static struct platform_driver excite_nand_driver = {
+ .driver = {
+ .name = "excite_nand",
+ .owner = THIS_MODULE,
+ },
.probe = excite_nand_probe,
- .remove = __exit_p(excite_nand_remove)
+ .remove = __devexit_p(excite_nand_remove)
};
static int __init excite_nand_init(void)
{
pr_info("Basler eXcite nand flash driver Version "
EXCITE_NANDFLASH_VERSION "\n");
- return driver_register(&excite_nand_driver);
+ return platform_driver_register(&excite_nand_driver);
}
static void __exit excite_nand_exit(void)
{
- driver_unregister(&excite_nand_driver);
+ platform_driver_unregister(&excite_nand_driver);
}
module_init(excite_nand_init);
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 582cf80..89bf85a 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -187,7 +187,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
return -ENODEV;
ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",
- ndfc->ofdev->dev.bus_id, flash_np->name);
+ dev_name(&ndfc->ofdev->dev), flash_np->name);
if (!ndfc->mtd.name) {
ret = -ENOMEM;
goto err;
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
index 5b69e77..3a496c3 100644
--- a/drivers/mtd/onenand/generic.c
+++ b/drivers/mtd/onenand/generic.c
@@ -36,10 +36,9 @@ struct onenand_info {
struct onenand_chip onenand;
};
-static int __devinit generic_onenand_probe(struct device *dev)
+static int __devinit generic_onenand_probe(struct platform_device *pdev)
{
struct onenand_info *info;
- struct platform_device *pdev = to_platform_device(dev);
struct flash_platform_data *pdata = pdev->dev.platform_data;
struct resource *res = pdev->resource;
unsigned long size = res->end - res->start + 1;
@@ -49,7 +48,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
if (!info)
return -ENOMEM;
- if (!request_mem_region(res->start, size, dev->driver->name)) {
+ if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
err = -EBUSY;
goto out_free_info;
}
@@ -82,7 +81,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
#endif
err = add_mtd_device(&info->mtd);
- dev_set_drvdata(&pdev->dev, info);
+ platform_set_drvdata(pdev, info);
return 0;
@@ -96,14 +95,13 @@ out_free_info:
return err;
}
-static int __devexit generic_onenand_remove(struct device *dev)
+static int __devexit generic_onenand_remove(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct onenand_info *info = dev_get_drvdata(&pdev->dev);
+ struct onenand_info *info = platform_get_drvdata(pdev);
struct resource *res = pdev->resource;
unsigned long size = res->end - res->start + 1;
- dev_set_drvdata(&pdev->dev, NULL);
+ platform_set_drvdata(pdev, NULL);
if (info) {
if (info->parts)
@@ -120,9 +118,11 @@ static int __devexit generic_onenand_remove(struct device *dev)
return 0;
}
-static struct device_driver generic_onenand_driver = {
- .name = DRIVER_NAME,
- .bus = &platform_bus_type,
+static struct platform_driver generic_onenand_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
.probe = generic_onenand_probe,
.remove = __devexit_p(generic_onenand_remove),
};
@@ -131,12 +131,12 @@ MODULE_ALIAS(DRIVER_NAME);
static int __init generic_onenand_init(void)
{
- return driver_register(&generic_onenand_driver);
+ return platform_driver_register(&generic_onenand_driver);
}
static void __exit generic_onenand_exit(void)
{
- driver_unregister(&generic_onenand_driver);
+ platform_driver_unregister(&generic_onenand_driver);
}
module_init(generic_onenand_init);