1 /* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
2 * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
4 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/miscdevice.h>
11 #include <linux/slab.h>
12 #include <linux/fcntl.h>
13 #include <linux/poll.h>
14 #include <linux/init.h>
15 #include <linux/smp_lock.h>
16 #include <linux/spinlock.h>
19 #include <asm/system.h>
20 #include <asm/uaccess.h>
21 #include <asm/pgtable.h>
27 static DEFINE_SPINLOCK(flash_lock
);
29 unsigned long read_base
; /* Physical read address */
30 unsigned long write_base
; /* Physical write address */
31 unsigned long read_size
; /* Size of read area */
32 unsigned long write_size
; /* Size of write area */
33 unsigned long busy
; /* In use? */
36 #define FLASH_MINOR 152
39 flash_mmap(struct file
*file
, struct vm_area_struct
*vma
)
44 spin_lock(&flash_lock
);
45 if (flash
.read_base
== flash
.write_base
) {
46 addr
= flash
.read_base
;
47 size
= flash
.read_size
;
49 if ((vma
->vm_flags
& VM_READ
) &&
50 (vma
->vm_flags
& VM_WRITE
)) {
51 spin_unlock(&flash_lock
);
54 if (vma
->vm_flags
& VM_READ
) {
55 addr
= flash
.read_base
;
56 size
= flash
.read_size
;
57 } else if (vma
->vm_flags
& VM_WRITE
) {
58 addr
= flash
.write_base
;
59 size
= flash
.write_size
;
61 spin_unlock(&flash_lock
);
65 spin_unlock(&flash_lock
);
67 if ((vma
->vm_pgoff
<< PAGE_SHIFT
) > size
)
69 addr
= vma
->vm_pgoff
+ (addr
>> PAGE_SHIFT
);
71 if (vma
->vm_end
- (vma
->vm_start
+ (vma
->vm_pgoff
<< PAGE_SHIFT
)) > size
)
72 size
= vma
->vm_end
- (vma
->vm_start
+ (vma
->vm_pgoff
<< PAGE_SHIFT
));
74 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
76 if (io_remap_pfn_range(vma
, vma
->vm_start
, addr
, size
, vma
->vm_page_prot
))
83 flash_llseek(struct file
*file
, long long offset
, int origin
)
91 file
->f_pos
+= offset
;
92 if (file
->f_pos
> flash
.read_size
)
93 file
->f_pos
= flash
.read_size
;
96 file
->f_pos
= flash
.read_size
;
107 flash_read(struct file
* file
, char __user
* buf
,
108 size_t count
, loff_t
*ppos
)
110 unsigned long p
= file
->f_pos
;
113 if (count
> flash
.read_size
- p
)
114 count
= flash
.read_size
- p
;
116 for (i
= 0; i
< count
; i
++) {
117 u8 data
= upa_readb(flash
.read_base
+ p
+ i
);
118 if (put_user(data
, buf
))
123 file
->f_pos
+= count
;
128 flash_open(struct inode
*inode
, struct file
*file
)
130 if (test_and_set_bit(0, (void *)&flash
.busy
) != 0)
137 flash_release(struct inode
*inode
, struct file
*file
)
139 spin_lock(&flash_lock
);
141 spin_unlock(&flash_lock
);
146 static const struct file_operations flash_fops
= {
147 /* no write to the Flash, use mmap
148 * and play flash dependent tricks.
150 .owner
= THIS_MODULE
,
151 .llseek
= flash_llseek
,
155 .release
= flash_release
,
158 static struct miscdevice flash_dev
= { FLASH_MINOR
, "flash", &flash_fops
};
160 static int __init
flash_init(void)
162 struct sbus_bus
*sbus
;
163 struct sbus_dev
*sdev
= NULL
;
165 struct linux_ebus
*ebus
;
166 struct linux_ebus_device
*edev
= NULL
;
167 struct linux_prom_registers regs
[2];
172 for_all_sbusdev(sdev
, sbus
) {
173 if (!strcmp(sdev
->prom_name
, "flashprom")) {
174 if (sdev
->reg_addrs
[0].phys_addr
== sdev
->reg_addrs
[1].phys_addr
) {
175 flash
.read_base
= ((unsigned long)sdev
->reg_addrs
[0].phys_addr
) |
176 (((unsigned long)sdev
->reg_addrs
[0].which_io
)<<32UL);
177 flash
.read_size
= sdev
->reg_addrs
[0].reg_size
;
178 flash
.write_base
= flash
.read_base
;
179 flash
.write_size
= flash
.read_size
;
181 flash
.read_base
= ((unsigned long)sdev
->reg_addrs
[0].phys_addr
) |
182 (((unsigned long)sdev
->reg_addrs
[0].which_io
)<<32UL);
183 flash
.read_size
= sdev
->reg_addrs
[0].reg_size
;
184 flash
.write_base
= ((unsigned long)sdev
->reg_addrs
[1].phys_addr
) |
185 (((unsigned long)sdev
->reg_addrs
[1].which_io
)<<32UL);
186 flash
.write_size
= sdev
->reg_addrs
[1].reg_size
;
194 const struct linux_prom_registers
*ebus_regs
;
196 for_each_ebus(ebus
) {
197 for_each_ebusdev(edev
, ebus
) {
198 if (!strcmp(edev
->prom_node
->name
, "flashprom"))
206 ebus_regs
= of_get_property(edev
->prom_node
, "reg", &len
);
207 if (!ebus_regs
|| (len
% sizeof(regs
[0])) != 0) {
208 printk("flash: Strange reg property size %d\n", len
);
212 nregs
= len
/ sizeof(ebus_regs
[0]);
214 flash
.read_base
= edev
->resource
[0].start
;
215 flash
.read_size
= ebus_regs
[0].reg_size
;
218 flash
.write_base
= edev
->resource
[0].start
;
219 flash
.write_size
= ebus_regs
[0].reg_size
;
220 } else if (nregs
== 2) {
221 flash
.write_base
= edev
->resource
[1].start
;
222 flash
.write_size
= ebus_regs
[1].reg_size
;
224 printk("flash: Strange number of regs %d\n", nregs
);
235 printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
236 flash
.read_base
, flash
.read_size
,
237 flash
.write_base
, flash
.write_size
);
239 err
= misc_register(&flash_dev
);
241 printk(KERN_ERR
"flash: unable to get misc minor\n");
248 static void __exit
flash_cleanup(void)
250 misc_deregister(&flash_dev
);
253 module_init(flash_init
);
254 module_exit(flash_cleanup
);
255 MODULE_LICENSE("GPL");