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