Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef FWH_LOCK_H
0003 #define FWH_LOCK_H
0004 
0005 
0006 enum fwh_lock_state {
0007         FWH_UNLOCKED   = 0,
0008     FWH_DENY_WRITE = 1,
0009     FWH_IMMUTABLE  = 2,
0010     FWH_DENY_READ  = 4,
0011 };
0012 
0013 struct fwh_xxlock_thunk {
0014     enum fwh_lock_state val;
0015     flstate_t state;
0016 };
0017 
0018 
0019 #define FWH_XXLOCK_ONEBLOCK_LOCK   ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING})
0020 #define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED,   FL_UNLOCKING})
0021 
0022 /*
0023  * This locking/unlock is specific to firmware hub parts.  Only one
0024  * is known that supports the Intel command set.    Firmware
0025  * hub parts cannot be interleaved as they are on the LPC bus
0026  * so this code has not been tested with interleaved chips,
0027  * and will likely fail in that context.
0028  */
0029 static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
0030     unsigned long adr, int len, void *thunk)
0031 {
0032     struct cfi_private *cfi = map->fldrv_priv;
0033     struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk;
0034     int ret;
0035 
0036     /* Refuse the operation if the we cannot look behind the chip */
0037     if (chip->start < 0x400000) {
0038         pr_debug( "MTD %s(): chip->start: %lx wanted >= 0x400000\n",
0039             __func__, chip->start );
0040         return -EIO;
0041     }
0042     /*
0043      * lock block registers:
0044      * - on 64k boundariesand
0045      * - bit 1 set high
0046      * - block lock registers are 4MiB lower - overflow subtract (danger)
0047      *
0048      * The address manipulation is first done on the logical address
0049      * which is 0 at the start of the chip, and then the offset of
0050      * the individual chip is addted to it.  Any other order a weird
0051      * map offset could cause problems.
0052      */
0053     adr = (adr & ~0xffffUL) | 0x2;
0054     adr += chip->start - 0x400000;
0055 
0056     /*
0057      * This is easy because these are writes to registers and not writes
0058      * to flash memory - that means that we don't have to check status
0059      * and timeout.
0060      */
0061     mutex_lock(&chip->mutex);
0062     ret = get_chip(map, chip, adr, FL_LOCKING);
0063     if (ret) {
0064         mutex_unlock(&chip->mutex);
0065         return ret;
0066     }
0067 
0068     chip->oldstate = chip->state;
0069     chip->state = xxlt->state;
0070     map_write(map, CMD(xxlt->val), adr);
0071 
0072     /* Done and happy. */
0073     chip->state = chip->oldstate;
0074     put_chip(map, chip, adr);
0075     mutex_unlock(&chip->mutex);
0076     return 0;
0077 }
0078 
0079 
0080 static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0081 {
0082     int ret;
0083 
0084     ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
0085         (void *)&FWH_XXLOCK_ONEBLOCK_LOCK);
0086 
0087     return ret;
0088 }
0089 
0090 
0091 static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0092 {
0093     int ret;
0094 
0095     ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
0096         (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
0097 
0098     return ret;
0099 }
0100 
0101 static void fixup_use_fwh_lock(struct mtd_info *mtd)
0102 {
0103     printk(KERN_NOTICE "using fwh lock/unlock method\n");
0104     /* Setup for the chips with the fwh lock method */
0105     mtd->_lock   = fwh_lock_varsize;
0106     mtd->_unlock = fwh_unlock_varsize;
0107 }
0108 #endif /* FWH_LOCK_H */