1 /* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
3 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
6 #include <linux/module.h>
7 #include <linux/types.h>
8 #include <linux/errno.h>
9 #include <linux/miscdevice.h>
10 #include <linux/slab.h>
11 #include <linux/fcntl.h>
12 #include <linux/poll.h>
13 #include <linux/init.h>
14 #include <linux/smp_lock.h>
15 #include <linux/spinlock.h>
18 #include <linux/of_device.h>
20 #include <asm/system.h>
21 #include <asm/uaccess.h>
22 #include <asm/pgtable.h>
26 static DEFINE_SPINLOCK(flash_lock
);
28 unsigned long read_base
; /* Physical read address */
29 unsigned long write_base
; /* Physical write address */
30 unsigned long read_size
; /* Size of read area */
31 unsigned long write_size
; /* Size of write area */
32 unsigned long busy
; /* In use? */
35 #define FLASH_MINOR 152
38 flash_mmap(struct file
*file
, struct vm_area_struct
*vma
)
43 spin_lock(&flash_lock
);
44 if (flash
.read_base
== flash
.write_base
) {
45 addr
= flash
.read_base
;
46 size
= flash
.read_size
;
48 if ((vma
->vm_flags
& VM_READ
) &&
49 (vma
->vm_flags
& VM_WRITE
)) {
50 spin_unlock(&flash_lock
);
53 if (vma
->vm_flags
& VM_READ
) {
54 addr
= flash
.read_base
;
55 size
= flash
.read_size
;
56 } else if (vma
->vm_flags
& VM_WRITE
) {
57 addr
= flash
.write_base
;
58 size
= flash
.write_size
;
60 spin_unlock(&flash_lock
);
64 spin_unlock(&flash_lock
);
66 if ((vma
->vm_pgoff
<< PAGE_SHIFT
) > size
)
68 addr
= vma
->vm_pgoff
+ (addr
>> PAGE_SHIFT
);
70 if (vma
->vm_end
- (vma
->vm_start
+ (vma
->vm_pgoff
<< PAGE_SHIFT
)) > size
)
71 size
= vma
->vm_end
- (vma
->vm_start
+ (vma
->vm_pgoff
<< PAGE_SHIFT
));
73 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
75 if (io_remap_pfn_range(vma
, vma
->vm_start
, addr
, size
, vma
->vm_page_prot
))
82 flash_llseek(struct file
*file
, long long offset
, int origin
)
90 file
->f_pos
+= offset
;
91 if (file
->f_pos
> flash
.read_size
)
92 file
->f_pos
= flash
.read_size
;
95 file
->f_pos
= flash
.read_size
;
106 flash_read(struct file
* file
, char __user
* buf
,
107 size_t count
, loff_t
*ppos
)
109 unsigned long p
= file
->f_pos
;
112 if (count
> flash
.read_size
- p
)
113 count
= flash
.read_size
- p
;
115 for (i
= 0; i
< count
; i
++) {
116 u8 data
= upa_readb(flash
.read_base
+ p
+ i
);
117 if (put_user(data
, buf
))
122 file
->f_pos
+= count
;
127 flash_open(struct inode
*inode
, struct file
*file
)
130 if (test_and_set_bit(0, (void *)&flash
.busy
) != 0) {
140 flash_release(struct inode
*inode
, struct file
*file
)
142 spin_lock(&flash_lock
);
144 spin_unlock(&flash_lock
);
149 static const struct file_operations flash_fops
= {
150 /* no write to the Flash, use mmap
151 * and play flash dependent tricks.
153 .owner
= THIS_MODULE
,
154 .llseek
= flash_llseek
,
158 .release
= flash_release
,
161 static struct miscdevice flash_dev
= { FLASH_MINOR
, "flash", &flash_fops
};
163 static int __devinit
flash_probe(struct of_device
*op
,
164 const struct of_device_id
*match
)
166 struct device_node
*dp
= op
->node
;
167 struct device_node
*parent
;
171 if (strcmp(parent
->name
, "sbus") &&
172 strcmp(parent
->name
, "sbi") &&
173 strcmp(parent
->name
, "ebus"))
176 flash
.read_base
= op
->resource
[0].start
;
177 flash
.read_size
= resource_size(&op
->resource
[0]);
178 if (op
->resource
[1].flags
) {
179 flash
.write_base
= op
->resource
[1].start
;
180 flash
.write_size
= resource_size(&op
->resource
[1]);
182 flash
.write_base
= op
->resource
[0].start
;
183 flash
.write_size
= resource_size(&op
->resource
[0]);
187 printk(KERN_INFO
"%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
189 flash
.read_base
, flash
.read_size
,
190 flash
.write_base
, flash
.write_size
);
192 return misc_register(&flash_dev
);
195 static int __devexit
flash_remove(struct of_device
*op
)
197 misc_deregister(&flash_dev
);
202 static const struct of_device_id flash_match
[] = {
208 MODULE_DEVICE_TABLE(of
, flash_match
);
210 static struct of_platform_driver flash_driver
= {
212 .match_table
= flash_match
,
213 .probe
= flash_probe
,
214 .remove
= __devexit_p(flash_remove
),
217 static int __init
flash_init(void)
219 return of_register_driver(&flash_driver
, &of_bus_type
);
222 static void __exit
flash_cleanup(void)
224 of_unregister_driver(&flash_driver
);
227 module_init(flash_init
);
228 module_exit(flash_cleanup
);
229 MODULE_LICENSE("GPL");