+
+#ifdef DEBUG_LOCK_BITS
+
+static int do_printlockstatus_oneblock(struct map_info *map,
+ struct flchip *chip,
+ unsigned long adr,
+ void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ofs_factor = cfi->interleave * cfi->device_type;
+
+ cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+ adr, cfi_read_query(map, adr+(2*ofs_factor)));
+ cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+
+ return 0;
+}
+
+
+#define debug_dump_locks(mtd, frob, ofs, len, thunk) \
+ cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk))
+
+#else
+
+#define debug_dump_locks(...)
+
+#endif /* DEBUG_LOCK_BITS */
+
+
+struct xxlock_thunk {
+ uint8_t val;
+ flstate_t state;
+};
+
+
+#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING})
+#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING})
+
+
+/*
+ * FIXME - this is *very* specific to a particular chip. It likely won't
+ * work for all chips that require unlock. It also hasn't been tested
+ * with interleaved chips.
+ */
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk;
+ int ret;
+
+ /*
+ * This is easy because these are writes to registers and not writes
+ * to flash memory - that means that we don't have to check status
+ * and timeout.
+ */
+
+ adr += chip->start;
+ /*
+ * lock block registers:
+ * - on 64k boundariesand
+ * - bit 1 set high
+ * - block lock registers are 4MiB lower - overflow subtract (danger)
+ */
+ adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff;
+
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_LOCKING);
+ if (ret) {
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ chip->state = xxlt->state;
+ map_write(map, CMD(xxlt->val), adr);
+
+ /* Done and happy. */
+ chip->state = FL_READY;
+ put_chip(map, chip, adr);
+ cfi_spin_unlock(chip->mutex);
+ return 0;
+}
+
+
+static int cfi_amdstd_lock_varsize(struct mtd_info *mtd,
+ loff_t ofs,
+ size_t len)
+{
+ int ret;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status before, ofs=0x%08llx, len=0x%08zX\n",
+ __func__, ofs, len);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+ (void *)&DO_XXLOCK_ONEBLOCK_LOCK);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status after, ret=%d\n",
+ __func__, ret);
+
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ return ret;
+}
+
+
+static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd,
+ loff_t ofs,
+ size_t len)
+{
+ int ret;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status before, ofs=0x%08llx, len=0x%08zX\n",
+ __func__, ofs, len);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+ (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status after, ret=%d\n",
+ __func__, ret);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ return ret;
+}
+
+