1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2001 Maciej W. Rozycki
6 #include <linux/init.h>
7 #include <linux/ioport.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/mtd/mtd.h>
11 #include <linux/slab.h>
12 #include <linux/types.h>
14 #include <asm/addrspace.h>
15 #include <asm/bootinfo.h>
16 #include <asm/dec/ioasic_addrs.h>
17 #include <asm/dec/kn02.h>
18 #include <asm/dec/kn03.h>
20 #include <asm/paccess.h>
25 static char version
[] __initdata
=
26 "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
28 MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
29 MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
30 MODULE_LICENSE("GPL");
34 * Addresses we probe for an MS02-NV at. Modules may be located
35 * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
36 * boundary within a 0MiB up to 448MiB range. We don't support a module
39 static ulong ms02nv_addrs
[] __initdata
= {
40 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
41 0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000,
42 0x02000000, 0x01800000, 0x01000000, 0x00800000
45 static const char ms02nv_name
[] = "DEC MS02-NV NVRAM";
46 static const char ms02nv_res_diag_ram
[] = "Diagnostic RAM";
47 static const char ms02nv_res_user_ram
[] = "General-purpose RAM";
48 static const char ms02nv_res_csr
[] = "Control and status register";
50 static struct mtd_info
*root_ms02nv_mtd
;
53 static int ms02nv_read(struct mtd_info
*mtd
, loff_t from
,
54 size_t len
, size_t *retlen
, u_char
*buf
)
56 struct ms02nv_private
*mp
= mtd
->priv
;
58 memcpy(buf
, mp
->uaddr
+ from
, len
);
63 static int ms02nv_write(struct mtd_info
*mtd
, loff_t to
,
64 size_t len
, size_t *retlen
, const u_char
*buf
)
66 struct ms02nv_private
*mp
= mtd
->priv
;
68 memcpy(mp
->uaddr
+ to
, buf
, len
);
74 static inline uint
ms02nv_probe_one(ulong addr
)
76 ms02nv_uint
*ms02nv_diagp
;
77 ms02nv_uint
*ms02nv_magicp
;
85 * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
86 * a diagnostic status at MS02NV_DIAG.
88 ms02nv_diagp
= (ms02nv_uint
*)(CKSEG1ADDR(addr
+ MS02NV_DIAG
));
89 ms02nv_magicp
= (ms02nv_uint
*)(CKSEG1ADDR(addr
+ MS02NV_MAGIC
));
90 err
= get_dbe(ms02nv_magic
, ms02nv_magicp
);
93 if (ms02nv_magic
!= MS02NV_ID
)
96 ms02nv_diag
= *ms02nv_diagp
;
97 size
= (ms02nv_diag
& MS02NV_DIAG_SIZE_MASK
) << MS02NV_DIAG_SIZE_SHIFT
;
98 if (size
> MS02NV_CSR
)
104 static int __init
ms02nv_init_one(ulong addr
)
106 struct mtd_info
*mtd
;
107 struct ms02nv_private
*mp
;
108 struct resource
*mod_res
;
109 struct resource
*diag_res
;
110 struct resource
*user_res
;
111 struct resource
*csr_res
;
113 size_t size
, fixsize
;
115 static int version_printed
;
119 /* The module decodes 8MiB of address space. */
120 mod_res
= kzalloc(sizeof(*mod_res
), GFP_KERNEL
);
124 mod_res
->name
= ms02nv_name
;
125 mod_res
->start
= addr
;
126 mod_res
->end
= addr
+ MS02NV_SLOT_SIZE
- 1;
127 mod_res
->flags
= IORESOURCE_MEM
| IORESOURCE_BUSY
;
128 if (request_resource(&iomem_resource
, mod_res
) < 0)
129 goto err_out_mod_res
;
131 size
= ms02nv_probe_one(addr
);
133 goto err_out_mod_res_rel
;
135 if (!version_printed
) {
136 printk(KERN_INFO
"%s", version
);
141 mtd
= kzalloc(sizeof(*mtd
), GFP_KERNEL
);
143 goto err_out_mod_res_rel
;
144 mp
= kzalloc(sizeof(*mp
), GFP_KERNEL
);
149 mp
->resource
.module
= mod_res
;
151 /* Firmware's diagnostic NVRAM area. */
152 diag_res
= kzalloc(sizeof(*diag_res
), GFP_KERNEL
);
156 diag_res
->name
= ms02nv_res_diag_ram
;
157 diag_res
->start
= addr
;
158 diag_res
->end
= addr
+ MS02NV_RAM
- 1;
159 diag_res
->flags
= IORESOURCE_BUSY
;
160 request_resource(mod_res
, diag_res
);
162 mp
->resource
.diag_ram
= diag_res
;
164 /* User-available general-purpose NVRAM area. */
165 user_res
= kzalloc(sizeof(*user_res
), GFP_KERNEL
);
167 goto err_out_diag_res
;
169 user_res
->name
= ms02nv_res_user_ram
;
170 user_res
->start
= addr
+ MS02NV_RAM
;
171 user_res
->end
= addr
+ size
- 1;
172 user_res
->flags
= IORESOURCE_BUSY
;
173 request_resource(mod_res
, user_res
);
175 mp
->resource
.user_ram
= user_res
;
177 /* Control and status register. */
178 csr_res
= kzalloc(sizeof(*csr_res
), GFP_KERNEL
);
180 goto err_out_user_res
;
182 csr_res
->name
= ms02nv_res_csr
;
183 csr_res
->start
= addr
+ MS02NV_CSR
;
184 csr_res
->end
= addr
+ MS02NV_CSR
+ 3;
185 csr_res
->flags
= IORESOURCE_BUSY
;
186 request_resource(mod_res
, csr_res
);
188 mp
->resource
.csr
= csr_res
;
190 mp
->addr
= phys_to_virt(addr
);
194 * Hide the firmware's diagnostic area. It may get destroyed
195 * upon a reboot. Take paging into account for mapping support.
197 fixaddr
= (addr
+ MS02NV_RAM
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1);
198 fixsize
= (size
- (fixaddr
- addr
)) & ~(PAGE_SIZE
- 1);
199 mp
->uaddr
= phys_to_virt(fixaddr
);
202 mtd
->flags
= MTD_CAP_RAM
;
204 mtd
->name
= ms02nv_name
;
205 mtd
->owner
= THIS_MODULE
;
206 mtd
->_read
= ms02nv_read
;
207 mtd
->_write
= ms02nv_write
;
211 if (mtd_device_register(mtd
, NULL
, 0)) {
213 "ms02-nv: Unable to register MTD device, aborting!\n");
214 goto err_out_csr_res
;
217 printk(KERN_INFO
"mtd%d: %s at 0x%08lx, size %zuMiB.\n",
218 mtd
->index
, ms02nv_name
, addr
, size
>> 20);
220 mp
->next
= root_ms02nv_mtd
;
221 root_ms02nv_mtd
= mtd
;
227 release_resource(csr_res
);
230 release_resource(user_res
);
233 release_resource(diag_res
);
240 release_resource(mod_res
);
246 static void __exit
ms02nv_remove_one(void)
248 struct mtd_info
*mtd
= root_ms02nv_mtd
;
249 struct ms02nv_private
*mp
= mtd
->priv
;
251 root_ms02nv_mtd
= mp
->next
;
253 mtd_device_unregister(mtd
);
255 release_resource(mp
->resource
.csr
);
256 kfree(mp
->resource
.csr
);
257 release_resource(mp
->resource
.user_ram
);
258 kfree(mp
->resource
.user_ram
);
259 release_resource(mp
->resource
.diag_ram
);
260 kfree(mp
->resource
.diag_ram
);
261 release_resource(mp
->resource
.module
);
262 kfree(mp
->resource
.module
);
268 static int __init
ms02nv_init(void)
275 switch (mips_machtype
) {
276 case MACH_DS5000_200
:
277 csr
= (volatile u32
*)CKSEG1ADDR(KN02_SLOT_BASE
+ KN02_CSR
);
278 if (*csr
& KN02_CSR_BNK32M
)
281 case MACH_DS5000_2X0
:
283 csr
= (volatile u32
*)CKSEG1ADDR(KN03_SLOT_BASE
+ IOASIC_MCR
);
284 if (*csr
& KN03_MCR_BNK32M
)
292 for (i
= 0; i
< ARRAY_SIZE(ms02nv_addrs
); i
++)
293 if (!ms02nv_init_one(ms02nv_addrs
[i
] << stride
))
296 return (count
> 0) ? 0 : -ENODEV
;
299 static void __exit
ms02nv_cleanup(void)
301 while (root_ms02nv_mtd
)
306 module_init(ms02nv_init
);
307 module_exit(ms02nv_cleanup
);