^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2001 Maciej W. Rozycki
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/addrspace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/dec/ioasic_addrs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/dec/kn02.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/dec/kn03.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/paccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "ms02-nv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static char version[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Addresses we probe for an MS02-NV at. Modules may be located
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * boundary within a 0MiB up to 448MiB range. We don't support a module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * at 0MiB, though.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static ulong ms02nv_addrs[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) 0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) 0x02000000, 0x01800000, 0x01000000, 0x00800000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static const char ms02nv_name[] = "DEC MS02-NV NVRAM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static const char ms02nv_res_diag_ram[] = "Diagnostic RAM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static const char ms02nv_res_user_ram[] = "General-purpose RAM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const char ms02nv_res_csr[] = "Control and status register";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static struct mtd_info *root_ms02nv_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int ms02nv_read(struct mtd_info *mtd, loff_t from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) size_t len, size_t *retlen, u_char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct ms02nv_private *mp = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) memcpy(buf, mp->uaddr + from, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *retlen = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static int ms02nv_write(struct mtd_info *mtd, loff_t to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) size_t len, size_t *retlen, const u_char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct ms02nv_private *mp = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) memcpy(mp->uaddr + to, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *retlen = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static inline uint ms02nv_probe_one(ulong addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ms02nv_uint *ms02nv_diagp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ms02nv_uint *ms02nv_magicp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) uint ms02nv_diag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) uint ms02nv_magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * a diagnostic status at MS02NV_DIAG.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) err = get_dbe(ms02nv_magic, ms02nv_magicp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (ms02nv_magic != MS02NV_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ms02nv_diag = *ms02nv_diagp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (size > MS02NV_CSR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) size = MS02NV_CSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static int __init ms02nv_init_one(ulong addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct ms02nv_private *mp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct resource *mod_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct resource *diag_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct resource *user_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct resource *csr_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ulong fixaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) size_t size, fixsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int version_printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* The module decodes 8MiB of address space. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) mod_res = kzalloc(sizeof(*mod_res), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!mod_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mod_res->name = ms02nv_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) mod_res->start = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (request_resource(&iomem_resource, mod_res) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) goto err_out_mod_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) size = ms02nv_probe_one(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) goto err_out_mod_res_rel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!version_printed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) printk(KERN_INFO "%s", version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) version_printed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) goto err_out_mod_res_rel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) mp = kzalloc(sizeof(*mp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!mp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) goto err_out_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) mtd->priv = mp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) mp->resource.module = mod_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Firmware's diagnostic NVRAM area. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) diag_res = kzalloc(sizeof(*diag_res), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (!diag_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) goto err_out_mp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) diag_res->name = ms02nv_res_diag_ram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) diag_res->start = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) diag_res->end = addr + MS02NV_RAM - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) diag_res->flags = IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) request_resource(mod_res, diag_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) mp->resource.diag_ram = diag_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* User-available general-purpose NVRAM area. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) user_res = kzalloc(sizeof(*user_res), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (!user_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) goto err_out_diag_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) user_res->name = ms02nv_res_user_ram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) user_res->start = addr + MS02NV_RAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) user_res->end = addr + size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) user_res->flags = IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) request_resource(mod_res, user_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) mp->resource.user_ram = user_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /* Control and status register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) csr_res = kzalloc(sizeof(*csr_res), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (!csr_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) goto err_out_user_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) csr_res->name = ms02nv_res_csr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) csr_res->start = addr + MS02NV_CSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) csr_res->end = addr + MS02NV_CSR + 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) csr_res->flags = IORESOURCE_BUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) request_resource(mod_res, csr_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) mp->resource.csr = csr_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) mp->addr = phys_to_virt(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) mp->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * Hide the firmware's diagnostic area. It may get destroyed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * upon a reboot. Take paging into account for mapping support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) mp->uaddr = phys_to_virt(fixaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) mtd->type = MTD_RAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) mtd->flags = MTD_CAP_RAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) mtd->size = fixsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) mtd->name = ms02nv_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) mtd->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) mtd->_read = ms02nv_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) mtd->_write = ms02nv_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) mtd->writesize = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (mtd_device_register(mtd, NULL, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) printk(KERN_ERR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) "ms02-nv: Unable to register MTD device, aborting!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto err_out_csr_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) mtd->index, ms02nv_name, addr, size >> 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) mp->next = root_ms02nv_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) root_ms02nv_mtd = mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) err_out_csr_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) release_resource(csr_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) kfree(csr_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) err_out_user_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) release_resource(user_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) kfree(user_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) err_out_diag_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) release_resource(diag_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) kfree(diag_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) err_out_mp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) kfree(mp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) err_out_mtd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) err_out_mod_res_rel:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) release_resource(mod_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) err_out_mod_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) kfree(mod_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static void __exit ms02nv_remove_one(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct mtd_info *mtd = root_ms02nv_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct ms02nv_private *mp = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) root_ms02nv_mtd = mp->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) mtd_device_unregister(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) release_resource(mp->resource.csr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) kfree(mp->resource.csr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) release_resource(mp->resource.user_ram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) kfree(mp->resource.user_ram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) release_resource(mp->resource.diag_ram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) kfree(mp->resource.diag_ram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) release_resource(mp->resource.module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) kfree(mp->resource.module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) kfree(mp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static int __init ms02nv_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) volatile u32 *csr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) uint stride = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) switch (mips_machtype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case MACH_DS5000_200:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (*csr & KN02_CSR_BNK32M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) stride = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) case MACH_DS5000_2X0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case MACH_DS5900:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) csr = (volatile u32 *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_MCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (*csr & KN03_MCR_BNK32M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) stride = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (!ms02nv_init_one(ms02nv_addrs[i] << stride))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return (count > 0) ? 0 : -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void __exit ms02nv_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) while (root_ms02nv_mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) ms02nv_remove_one();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) module_init(ms02nv_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) module_exit(ms02nv_cleanup);