1 /* flash.c: Allow mmap access to the OBP Flash, for OBP updates. 2 * 3 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 4 */ 5 6 #include <linux/module.h> 7 #include <linux/types.h> 8 #include <linux/errno.h> 9 #include <linux/miscdevice.h> 10 #include <linux/fcntl.h> 11 #include <linux/poll.h> 12 #include <linux/init.h> 13 #include <linux/mutex.h> 14 #include <linux/spinlock.h> 15 #include <linux/mm.h> 16 #include <linux/of.h> 17 #include <linux/of_device.h> 18 19 #include <asm/system.h> 20 #include <asm/uaccess.h> 21 #include <asm/pgtable.h> 22 #include <asm/io.h> 23 #include <asm/upa.h> 24 25 static DEFINE_MUTEX(flash_mutex); 26 static DEFINE_SPINLOCK(flash_lock); 27 static struct { 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? */ 33 } flash; 34 35 #define FLASH_MINOR 152 36 37 static int 38 flash_mmap(struct file *file, struct vm_area_struct *vma) 39 { 40 unsigned long addr; 41 unsigned long size; 42 43 spin_lock(&flash_lock); 44 if (flash.read_base == flash.write_base) { 45 addr = flash.read_base; 46 size = flash.read_size; 47 } else { 48 if ((vma->vm_flags & VM_READ) && 49 (vma->vm_flags & VM_WRITE)) { 50 spin_unlock(&flash_lock); 51 return -EINVAL; 52 } 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; 59 } else { 60 spin_unlock(&flash_lock); 61 return -ENXIO; 62 } 63 } 64 spin_unlock(&flash_lock); 65 66 if ((vma->vm_pgoff << PAGE_SHIFT) > size) 67 return -ENXIO; 68 addr = vma->vm_pgoff + (addr >> PAGE_SHIFT); 69 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)); 72 73 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 74 75 if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot)) 76 return -EAGAIN; 77 78 return 0; 79 } 80 81 static long long 82 flash_llseek(struct file *file, long long offset, int origin) 83 { 84 mutex_lock(&flash_mutex); 85 switch (origin) { 86 case 0: 87 file->f_pos = offset; 88 break; 89 case 1: 90 file->f_pos += offset; 91 if (file->f_pos > flash.read_size) 92 file->f_pos = flash.read_size; 93 break; 94 case 2: 95 file->f_pos = flash.read_size; 96 break; 97 default: 98 mutex_unlock(&flash_mutex); 99 return -EINVAL; 100 } 101 mutex_unlock(&flash_mutex); 102 return file->f_pos; 103 } 104 105 static ssize_t 106 flash_read(struct file * file, char __user * buf, 107 size_t count, loff_t *ppos) 108 { 109 loff_t p = *ppos; 110 int i; 111 112 if (count > flash.read_size - p) 113 count = flash.read_size - p; 114 115 for (i = 0; i < count; i++) { 116 u8 data = upa_readb(flash.read_base + p + i); 117 if (put_user(data, buf)) 118 return -EFAULT; 119 buf++; 120 } 121 122 *ppos += count; 123 return count; 124 } 125 126 static int 127 flash_open(struct inode *inode, struct file *file) 128 { 129 mutex_lock(&flash_mutex); 130 if (test_and_set_bit(0, (void *)&flash.busy) != 0) { 131 mutex_unlock(&flash_mutex); 132 return -EBUSY; 133 } 134 135 mutex_unlock(&flash_mutex); 136 return 0; 137 } 138 139 static int 140 flash_release(struct inode *inode, struct file *file) 141 { 142 spin_lock(&flash_lock); 143 flash.busy = 0; 144 spin_unlock(&flash_lock); 145 146 return 0; 147 } 148 149 static const struct file_operations flash_fops = { 150 /* no write to the Flash, use mmap 151 * and play flash dependent tricks. 152 */ 153 .owner = THIS_MODULE, 154 .llseek = flash_llseek, 155 .read = flash_read, 156 .mmap = flash_mmap, 157 .open = flash_open, 158 .release = flash_release, 159 }; 160 161 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; 162 163 static int __devinit flash_probe(struct platform_device *op, 164 const struct of_device_id *match) 165 { 166 struct device_node *dp = op->dev.of_node; 167 struct device_node *parent; 168 169 parent = dp->parent; 170 171 if (strcmp(parent->name, "sbus") && 172 strcmp(parent->name, "sbi") && 173 strcmp(parent->name, "ebus")) 174 return -ENODEV; 175 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]); 181 } else { 182 flash.write_base = op->resource[0].start; 183 flash.write_size = resource_size(&op->resource[0]); 184 } 185 flash.busy = 0; 186 187 printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", 188 op->dev.of_node->full_name, 189 flash.read_base, flash.read_size, 190 flash.write_base, flash.write_size); 191 192 return misc_register(&flash_dev); 193 } 194 195 static int __devexit flash_remove(struct platform_device *op) 196 { 197 misc_deregister(&flash_dev); 198 199 return 0; 200 } 201 202 static const struct of_device_id flash_match[] = { 203 { 204 .name = "flashprom", 205 }, 206 {}, 207 }; 208 MODULE_DEVICE_TABLE(of, flash_match); 209 210 static struct of_platform_driver flash_driver = { 211 .driver = { 212 .name = "flash", 213 .owner = THIS_MODULE, 214 .of_match_table = flash_match, 215 }, 216 .probe = flash_probe, 217 .remove = __devexit_p(flash_remove), 218 }; 219 220 static int __init flash_init(void) 221 { 222 return of_register_platform_driver(&flash_driver); 223 } 224 225 static void __exit flash_cleanup(void) 226 { 227 of_unregister_platform_driver(&flash_driver); 228 } 229 230 module_init(flash_init); 231 module_exit(flash_cleanup); 232 MODULE_LICENSE("GPL"); 233