📄 omap-nor-flash.c
字号:
module_name, offset); return -EPERM; } if ((status & (3 << 4)) == (3 << 4)) { printk(KERN_ERR "%s ERROR: erasing at address 0x%.8x: command sequence error\n", module_name, offset); return -EPERM; } if (status & (1 << 5)) { printk(KERN_ERR "%s ERROR: erasing at address 0x%.8x: block erase error\n", module_name, offset); return -ETIMEDOUT; } if (status & (1 << 1)) { printk(KERN_ERR "%s ERROR: erasing at address 0x%.8x: block locked error\n", module_name, offset); return -EPERM; } return 0;}/* Pick the proper sector addresses for erasing */static intomap_flash_erase(struct mtd_info *mtd, struct erase_info *instr){ __u32 addr, len; int i, first; /* sanity checks */ if (instr->addr + instr->len > mtd->size) return (-EINVAL); /* * check that both start and end of the requested erase are * aligned with the erasesize at the appropriate addresses. * * skip all erase regions which are ended before the start of * the requested erase. Actually, to save on the calculations, * we skip to the first erase region which starts after the * start of the requested erase, and then go back one. */ for (i = 0; (i < mtd->numeraseregions) && (instr->addr >= mtd->eraseregions[i].offset); i++) ; i--; /* * ok, now i is pointing at the erase region in which this * erase request starts. Check the start of the requested * erase range is aligned with the erase size which is in * effect here. */ if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); /* Remember the erase region we start on */ first = i; /* * next, check that the end of the requested erase is aligned * with the erase region at that address. * * as before, drop back one to point at the region in which * the address actually falls */ for (; (i < mtd->numeraseregions) && ((instr->addr + instr->len) >= mtd->eraseregions[i].offset); i++) ; i--; /* is the end aligned on a block boundary? */ if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); addr = instr->addr; len = instr->len; i = first; /* now erase those blocks */ while (len) { if (omap_flash_sector_erase(addr)) { instr->state = MTD_ERASE_FAILED; return (-EIO); } addr += mtd->eraseregions[i].erasesize; len -= mtd->eraseregions[i].erasesize; if (addr == (mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks))) i++; } instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); return (0);}/* Read a block of data from flash */static intomap_flash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){ /* Sanity checks. */ if (!len) return (0); if (from + len > mtd->size) return (-EINVAL); /* We always read len bytes. */ *retlen = len; down(&omap_flash_lock); memcpy(buf, (void *) (omap_nor_flash_base + (__u32) from), len); up(&omap_flash_lock); return (0);}/* Write a flash word. The offset must be on a word boudary */static intomap_flash_write_word(__u32 offset, __u16 x){ __u16 status; down(&omap_flash_lock); /* Check if Flash is (sufficiently) erased */ if ((omap_flash_inw(offset) & x) != x) { printk(KERN_ERR "%s ERROR: cannot write, flash not erased at address 0x%.8x.\n", module_name, offset); up(&omap_flash_lock); return -EIO; /*flash not erased */ } omap_flash_outw(offset, 0x0050); /* clear status register */ omap_flash_outw(offset, 0x0040); /* write setup */ omap_flash_outw(offset, x); /* wait for program complete while polling the status register */ while (((status = omap_flash_inw(offset)) & 0x0080) != 0x0080) schedule_timeout(1); omap_flash_outw(offset, 0x0050); /* clear status register */ omap_flash_outw(offset, 0x00FF); /* restore read mode */ up(&omap_flash_lock); /* process status register */ if (status & (1 << 3)) { printk(KERN_ERR "%s ERROR: writing at address 0x%.8x: Vpp range error \n", module_name, offset); return -EPERM; } if (status & (1 << 4)) { printk(KERN_ERR "%s ERROR: writing at address 0x%.8x: program error \n", module_name, offset); return -ETIMEDOUT; } if (status & (1 << 1)) { printk(KERN_ERR "%s ERROR: writing at address 0x%.8x: device protect error\n", module_name, offset); return -EPERM; } return 0;}/* Write a block of data to flash. Takes care of the word boundaries */static intomap_flash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){ __u8 tmp[BUSWIDTH]; int i, n; *retlen = 0; /* Sanity checks */ if (!len) return (0); if (to + len > mtd->size) return (-EINVAL); /* First, we write a byte padded with original data until we reach a * word boundary. */ if (to & (BUSWIDTH - 1)) { __u32 aligned = to & ~(BUSWIDTH - 1); i = to - aligned; n = 0; down(&omap_flash_lock); *((__u16 *) tmp) = omap_flash_inw(aligned); up(&omap_flash_lock); while (len && i < BUSWIDTH) tmp[i++] = buf[n++], len--; if (omap_flash_write_word(aligned, *((__u16 *) tmp))) return (-EIO); to += n; buf += n; *retlen += n; } /* Now we write words until we reach a non-word boundary. */ while (len >= BUSWIDTH) { if (omap_flash_write_word(to, *((__u16 *) buf))) return (-EIO); to += BUSWIDTH; buf += BUSWIDTH; *retlen += BUSWIDTH; len -= BUSWIDTH; } /* Top up the last unaligned bytes, padded with original data.... */ if (len & (BUSWIDTH - 1)) { i = n = 0; down(&omap_flash_lock); *((__u16 *) tmp) = omap_flash_inw(to); up(&omap_flash_lock); while (len--) tmp[i++] = buf[n++]; if (omap_flash_write_word(to, *((__u16 *) tmp))) return (-EIO); *retlen += n; } return 0;}int __initomap_flash_init(void){ int result; printk("%s: MTD Self-Contained Driver ver. 1.0 size=0x%ulx\n", module_name, OMAP_NOR_FLASH_SIZE); omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START1, OMAP_NOR_FLASH_SIZE); result = omap_flash_probe(); if (result < 0) { iounmap((void *) omap_nor_flash_base); omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START2, OMAP_NOR_FLASH_SIZE); result = omap_flash_probe(); if (result < 0) { iounmap((void *) omap_nor_flash_base); return (-ENXIO); } }#ifndef CONFIG_MTD_PARTITIONS result = add_mtd_device(&mtd);#else result = add_mtd_partitions(&mtd, omap_partitions, NB_OF(omap_partitions));#endif /* check result */ if (result) iounmap((void *) omap_nor_flash_base); return (result);}void __exitomap_flash_exit(void){#ifndef CONFIG_MTD_PARTITIONS del_mtd_device(&mtd);#else del_mtd_partitions(&mtd);#endif iounmap((void *) omap_nor_flash_base);}module_init(omap_flash_init);module_exit(omap_flash_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("MontaVista Software Inc.");MODULE_DESCRIPTION("Self-Contained MTD driver for NOR Flash on OMAP board");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -