mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
3.4 KiB
157 lines
3.4 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* sun_uflash.c - Driver for user-programmable flash on |
|
* Sun Microsystems SME boardsets. |
|
* |
|
* This driver does NOT provide access to the OBP-flash for |
|
* safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. |
|
* |
|
* Copyright (c) 2001 Eric Brower ([email protected]) |
|
*/ |
|
|
|
#include <linux/kernel.h> |
|
#include <linux/module.h> |
|
#include <linux/fs.h> |
|
#include <linux/errno.h> |
|
#include <linux/ioport.h> |
|
#include <linux/of.h> |
|
#include <linux/of_device.h> |
|
#include <linux/slab.h> |
|
#include <asm/prom.h> |
|
#include <linux/uaccess.h> |
|
#include <asm/io.h> |
|
|
|
#include <linux/mtd/mtd.h> |
|
#include <linux/mtd/map.h> |
|
|
|
#define UFLASH_OBPNAME "flashprom" |
|
#define DRIVER_NAME "sun_uflash" |
|
#define PFX DRIVER_NAME ": " |
|
|
|
#define UFLASH_WINDOW_SIZE 0x200000 |
|
#define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ |
|
|
|
MODULE_AUTHOR("Eric Brower <[email protected]>"); |
|
MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); |
|
MODULE_LICENSE("GPL"); |
|
MODULE_VERSION("2.1"); |
|
|
|
struct uflash_dev { |
|
const char *name; /* device name */ |
|
struct map_info map; /* mtd map info */ |
|
struct mtd_info *mtd; /* mtd info */ |
|
}; |
|
|
|
struct map_info uflash_map_templ = { |
|
.name = "SUNW,???-????", |
|
.size = UFLASH_WINDOW_SIZE, |
|
.bankwidth = UFLASH_BUSWIDTH, |
|
}; |
|
|
|
int uflash_devinit(struct platform_device *op, struct device_node *dp) |
|
{ |
|
struct uflash_dev *up; |
|
|
|
if (op->resource[1].flags) { |
|
/* Non-CFI userflash device-- once I find one we |
|
* can work on supporting it. |
|
*/ |
|
printk(KERN_ERR PFX "Unsupported device at %pOF, 0x%llx\n", |
|
dp, (unsigned long long)op->resource[0].start); |
|
|
|
return -ENODEV; |
|
} |
|
|
|
up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); |
|
if (!up) |
|
return -ENOMEM; |
|
|
|
/* copy defaults and tweak parameters */ |
|
memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); |
|
|
|
up->map.size = resource_size(&op->resource[0]); |
|
|
|
up->name = of_get_property(dp, "model", NULL); |
|
if (up->name && 0 < strlen(up->name)) |
|
up->map.name = up->name; |
|
|
|
up->map.phys = op->resource[0].start; |
|
|
|
up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size, |
|
DRIVER_NAME); |
|
if (!up->map.virt) { |
|
printk(KERN_ERR PFX "Failed to map device.\n"); |
|
kfree(up); |
|
|
|
return -EINVAL; |
|
} |
|
|
|
simple_map_init(&up->map); |
|
|
|
/* MTD registration */ |
|
up->mtd = do_map_probe("cfi_probe", &up->map); |
|
if (!up->mtd) { |
|
of_iounmap(&op->resource[0], up->map.virt, up->map.size); |
|
kfree(up); |
|
|
|
return -ENXIO; |
|
} |
|
|
|
up->mtd->owner = THIS_MODULE; |
|
|
|
mtd_device_register(up->mtd, NULL, 0); |
|
|
|
dev_set_drvdata(&op->dev, up); |
|
|
|
return 0; |
|
} |
|
|
|
static int uflash_probe(struct platform_device *op) |
|
{ |
|
struct device_node *dp = op->dev.of_node; |
|
|
|
/* Flashprom must have the "user" property in order to |
|
* be used by this driver. |
|
*/ |
|
if (!of_find_property(dp, "user", NULL)) |
|
return -ENODEV; |
|
|
|
return uflash_devinit(op, dp); |
|
} |
|
|
|
static int uflash_remove(struct platform_device *op) |
|
{ |
|
struct uflash_dev *up = dev_get_drvdata(&op->dev); |
|
|
|
if (up->mtd) { |
|
mtd_device_unregister(up->mtd); |
|
map_destroy(up->mtd); |
|
} |
|
if (up->map.virt) { |
|
of_iounmap(&op->resource[0], up->map.virt, up->map.size); |
|
up->map.virt = NULL; |
|
} |
|
|
|
kfree(up); |
|
|
|
return 0; |
|
} |
|
|
|
static const struct of_device_id uflash_match[] = { |
|
{ |
|
.name = UFLASH_OBPNAME, |
|
}, |
|
{}, |
|
}; |
|
|
|
MODULE_DEVICE_TABLE(of, uflash_match); |
|
|
|
static struct platform_driver uflash_driver = { |
|
.driver = { |
|
.name = DRIVER_NAME, |
|
.of_match_table = uflash_match, |
|
}, |
|
.probe = uflash_probe, |
|
.remove = uflash_remove, |
|
}; |
|
|
|
module_platform_driver(uflash_driver);
|
|
|