Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 2001 Maciej W. Rozycki
0004  */
0005 
0006 #include <linux/init.h>
0007 #include <linux/ioport.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/mtd/mtd.h>
0011 #include <linux/slab.h>
0012 #include <linux/types.h>
0013 
0014 #include <asm/addrspace.h>
0015 #include <asm/bootinfo.h>
0016 #include <asm/dec/ioasic_addrs.h>
0017 #include <asm/dec/kn02.h>
0018 #include <asm/dec/kn03.h>
0019 #include <asm/io.h>
0020 #include <asm/paccess.h>
0021 
0022 #include "ms02-nv.h"
0023 
0024 
0025 static char version[] __initdata =
0026     "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
0027 
0028 MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
0029 MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
0030 MODULE_LICENSE("GPL");
0031 
0032 
0033 /*
0034  * Addresses we probe for an MS02-NV at.  Modules may be located
0035  * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
0036  * boundary within a 0MiB up to 448MiB range.  We don't support a module
0037  * at 0MiB, though.
0038  */
0039 static ulong ms02nv_addrs[] __initdata = {
0040     0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
0041     0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000,
0042     0x02000000, 0x01800000, 0x01000000, 0x00800000
0043 };
0044 
0045 static const char ms02nv_name[] = "DEC MS02-NV NVRAM";
0046 static const char ms02nv_res_diag_ram[] = "Diagnostic RAM";
0047 static const char ms02nv_res_user_ram[] = "General-purpose RAM";
0048 static const char ms02nv_res_csr[] = "Control and status register";
0049 
0050 static struct mtd_info *root_ms02nv_mtd;
0051 
0052 
0053 static int ms02nv_read(struct mtd_info *mtd, loff_t from,
0054             size_t len, size_t *retlen, u_char *buf)
0055 {
0056     struct ms02nv_private *mp = mtd->priv;
0057 
0058     memcpy(buf, mp->uaddr + from, len);
0059     *retlen = len;
0060     return 0;
0061 }
0062 
0063 static int ms02nv_write(struct mtd_info *mtd, loff_t to,
0064             size_t len, size_t *retlen, const u_char *buf)
0065 {
0066     struct ms02nv_private *mp = mtd->priv;
0067 
0068     memcpy(mp->uaddr + to, buf, len);
0069     *retlen = len;
0070     return 0;
0071 }
0072 
0073 
0074 static inline uint ms02nv_probe_one(ulong addr)
0075 {
0076     ms02nv_uint *ms02nv_diagp;
0077     ms02nv_uint *ms02nv_magicp;
0078     uint ms02nv_diag;
0079     uint ms02nv_magic;
0080     size_t size;
0081 
0082     int err;
0083 
0084     /*
0085      * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
0086      * a diagnostic status at MS02NV_DIAG.
0087      */
0088     ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG));
0089     ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC));
0090     err = get_dbe(ms02nv_magic, ms02nv_magicp);
0091     if (err)
0092         return 0;
0093     if (ms02nv_magic != MS02NV_ID)
0094         return 0;
0095 
0096     ms02nv_diag = *ms02nv_diagp;
0097     size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT;
0098     if (size > MS02NV_CSR)
0099         size = MS02NV_CSR;
0100 
0101     return size;
0102 }
0103 
0104 static int __init ms02nv_init_one(ulong addr)
0105 {
0106     struct mtd_info *mtd;
0107     struct ms02nv_private *mp;
0108     struct resource *mod_res;
0109     struct resource *diag_res;
0110     struct resource *user_res;
0111     struct resource *csr_res;
0112     ulong fixaddr;
0113     size_t size, fixsize;
0114 
0115     static int version_printed;
0116 
0117     int ret = -ENODEV;
0118 
0119     /* The module decodes 8MiB of address space. */
0120     mod_res = kzalloc(sizeof(*mod_res), GFP_KERNEL);
0121     if (!mod_res)
0122         return -ENOMEM;
0123 
0124     mod_res->name = ms02nv_name;
0125     mod_res->start = addr;
0126     mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
0127     mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0128     if (request_resource(&iomem_resource, mod_res) < 0)
0129         goto err_out_mod_res;
0130 
0131     size = ms02nv_probe_one(addr);
0132     if (!size)
0133         goto err_out_mod_res_rel;
0134 
0135     if (!version_printed) {
0136         printk(KERN_INFO "%s", version);
0137         version_printed = 1;
0138     }
0139 
0140     ret = -ENOMEM;
0141     mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
0142     if (!mtd)
0143         goto err_out_mod_res_rel;
0144     mp = kzalloc(sizeof(*mp), GFP_KERNEL);
0145     if (!mp)
0146         goto err_out_mtd;
0147 
0148     mtd->priv = mp;
0149     mp->resource.module = mod_res;
0150 
0151     /* Firmware's diagnostic NVRAM area. */
0152     diag_res = kzalloc(sizeof(*diag_res), GFP_KERNEL);
0153     if (!diag_res)
0154         goto err_out_mp;
0155 
0156     diag_res->name = ms02nv_res_diag_ram;
0157     diag_res->start = addr;
0158     diag_res->end = addr + MS02NV_RAM - 1;
0159     diag_res->flags = IORESOURCE_BUSY;
0160     request_resource(mod_res, diag_res);
0161 
0162     mp->resource.diag_ram = diag_res;
0163 
0164     /* User-available general-purpose NVRAM area. */
0165     user_res = kzalloc(sizeof(*user_res), GFP_KERNEL);
0166     if (!user_res)
0167         goto err_out_diag_res;
0168 
0169     user_res->name = ms02nv_res_user_ram;
0170     user_res->start = addr + MS02NV_RAM;
0171     user_res->end = addr + size - 1;
0172     user_res->flags = IORESOURCE_BUSY;
0173     request_resource(mod_res, user_res);
0174 
0175     mp->resource.user_ram = user_res;
0176 
0177     /* Control and status register. */
0178     csr_res = kzalloc(sizeof(*csr_res), GFP_KERNEL);
0179     if (!csr_res)
0180         goto err_out_user_res;
0181 
0182     csr_res->name = ms02nv_res_csr;
0183     csr_res->start = addr + MS02NV_CSR;
0184     csr_res->end = addr + MS02NV_CSR + 3;
0185     csr_res->flags = IORESOURCE_BUSY;
0186     request_resource(mod_res, csr_res);
0187 
0188     mp->resource.csr = csr_res;
0189 
0190     mp->addr = phys_to_virt(addr);
0191     mp->size = size;
0192 
0193     /*
0194      * Hide the firmware's diagnostic area.  It may get destroyed
0195      * upon a reboot.  Take paging into account for mapping support.
0196      */
0197     fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
0198     fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1);
0199     mp->uaddr = phys_to_virt(fixaddr);
0200 
0201     mtd->type = MTD_RAM;
0202     mtd->flags = MTD_CAP_RAM;
0203     mtd->size = fixsize;
0204     mtd->name = ms02nv_name;
0205     mtd->owner = THIS_MODULE;
0206     mtd->_read = ms02nv_read;
0207     mtd->_write = ms02nv_write;
0208     mtd->writesize = 1;
0209 
0210     ret = -EIO;
0211     if (mtd_device_register(mtd, NULL, 0)) {
0212         printk(KERN_ERR
0213             "ms02-nv: Unable to register MTD device, aborting!\n");
0214         goto err_out_csr_res;
0215     }
0216 
0217     printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n",
0218         mtd->index, ms02nv_name, addr, size >> 20);
0219 
0220     mp->next = root_ms02nv_mtd;
0221     root_ms02nv_mtd = mtd;
0222 
0223     return 0;
0224 
0225 
0226 err_out_csr_res:
0227     release_resource(csr_res);
0228     kfree(csr_res);
0229 err_out_user_res:
0230     release_resource(user_res);
0231     kfree(user_res);
0232 err_out_diag_res:
0233     release_resource(diag_res);
0234     kfree(diag_res);
0235 err_out_mp:
0236     kfree(mp);
0237 err_out_mtd:
0238     kfree(mtd);
0239 err_out_mod_res_rel:
0240     release_resource(mod_res);
0241 err_out_mod_res:
0242     kfree(mod_res);
0243     return ret;
0244 }
0245 
0246 static void __exit ms02nv_remove_one(void)
0247 {
0248     struct mtd_info *mtd = root_ms02nv_mtd;
0249     struct ms02nv_private *mp = mtd->priv;
0250 
0251     root_ms02nv_mtd = mp->next;
0252 
0253     mtd_device_unregister(mtd);
0254 
0255     release_resource(mp->resource.csr);
0256     kfree(mp->resource.csr);
0257     release_resource(mp->resource.user_ram);
0258     kfree(mp->resource.user_ram);
0259     release_resource(mp->resource.diag_ram);
0260     kfree(mp->resource.diag_ram);
0261     release_resource(mp->resource.module);
0262     kfree(mp->resource.module);
0263     kfree(mp);
0264     kfree(mtd);
0265 }
0266 
0267 
0268 static int __init ms02nv_init(void)
0269 {
0270     volatile u32 *csr;
0271     uint stride = 0;
0272     int count = 0;
0273     int i;
0274 
0275     switch (mips_machtype) {
0276     case MACH_DS5000_200:
0277         csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR);
0278         if (*csr & KN02_CSR_BNK32M)
0279             stride = 2;
0280         break;
0281     case MACH_DS5000_2X0:
0282     case MACH_DS5900:
0283         csr = (volatile u32 *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_MCR);
0284         if (*csr & KN03_MCR_BNK32M)
0285             stride = 2;
0286         break;
0287     default:
0288         return -ENODEV;
0289     }
0290 
0291     for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++)
0292         if (!ms02nv_init_one(ms02nv_addrs[i] << stride))
0293             count++;
0294 
0295     return (count > 0) ? 0 : -ENODEV;
0296 }
0297 
0298 static void __exit ms02nv_cleanup(void)
0299 {
0300     while (root_ms02nv_mtd)
0301         ms02nv_remove_one();
0302 }
0303 
0304 
0305 module_init(ms02nv_init);
0306 module_exit(ms02nv_cleanup);