1*069089acSMichael Walle // SPDX-License-Identifier: GPL-2.0 2*069089acSMichael Walle /* 3*069089acSMichael Walle * OTP support for SPI NOR flashes 4*069089acSMichael Walle * 5*069089acSMichael Walle * Copyright (C) 2021 Michael Walle <michael@walle.cc> 6*069089acSMichael Walle */ 7*069089acSMichael Walle 8*069089acSMichael Walle #include <linux/log2.h> 9*069089acSMichael Walle #include <linux/mtd/mtd.h> 10*069089acSMichael Walle #include <linux/mtd/spi-nor.h> 11*069089acSMichael Walle 12*069089acSMichael Walle #include "core.h" 13*069089acSMichael Walle 14*069089acSMichael Walle #define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len) 15*069089acSMichael Walle #define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions) 16*069089acSMichael Walle 17*069089acSMichael Walle static loff_t spi_nor_otp_region_start(const struct spi_nor *nor, unsigned int region) 18*069089acSMichael Walle { 19*069089acSMichael Walle const struct spi_nor_otp_organization *org = nor->params->otp.org; 20*069089acSMichael Walle 21*069089acSMichael Walle return org->base + region * org->offset; 22*069089acSMichael Walle } 23*069089acSMichael Walle 24*069089acSMichael Walle static size_t spi_nor_otp_size(struct spi_nor *nor) 25*069089acSMichael Walle { 26*069089acSMichael Walle return spi_nor_otp_n_regions(nor) * spi_nor_otp_region_len(nor); 27*069089acSMichael Walle } 28*069089acSMichael Walle 29*069089acSMichael Walle /* Translate the file offsets from and to OTP regions. */ 30*069089acSMichael Walle static loff_t spi_nor_otp_region_to_offset(struct spi_nor *nor, unsigned int region) 31*069089acSMichael Walle { 32*069089acSMichael Walle return region * spi_nor_otp_region_len(nor); 33*069089acSMichael Walle } 34*069089acSMichael Walle 35*069089acSMichael Walle static unsigned int spi_nor_otp_offset_to_region(struct spi_nor *nor, loff_t ofs) 36*069089acSMichael Walle { 37*069089acSMichael Walle return div64_u64(ofs, spi_nor_otp_region_len(nor)); 38*069089acSMichael Walle } 39*069089acSMichael Walle 40*069089acSMichael Walle static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len, 41*069089acSMichael Walle size_t *retlen, struct otp_info *buf) 42*069089acSMichael Walle { 43*069089acSMichael Walle struct spi_nor *nor = mtd_to_spi_nor(mtd); 44*069089acSMichael Walle const struct spi_nor_otp_ops *ops = nor->params->otp.ops; 45*069089acSMichael Walle unsigned int n_regions = spi_nor_otp_n_regions(nor); 46*069089acSMichael Walle unsigned int i; 47*069089acSMichael Walle int ret, locked; 48*069089acSMichael Walle 49*069089acSMichael Walle if (len < n_regions * sizeof(*buf)) 50*069089acSMichael Walle return -ENOSPC; 51*069089acSMichael Walle 52*069089acSMichael Walle ret = spi_nor_lock_and_prep(nor); 53*069089acSMichael Walle if (ret) 54*069089acSMichael Walle return ret; 55*069089acSMichael Walle 56*069089acSMichael Walle for (i = 0; i < n_regions; i++) { 57*069089acSMichael Walle buf->start = spi_nor_otp_region_to_offset(nor, i); 58*069089acSMichael Walle buf->length = spi_nor_otp_region_len(nor); 59*069089acSMichael Walle 60*069089acSMichael Walle locked = ops->is_locked(nor, i); 61*069089acSMichael Walle if (locked < 0) { 62*069089acSMichael Walle ret = locked; 63*069089acSMichael Walle goto out; 64*069089acSMichael Walle } 65*069089acSMichael Walle 66*069089acSMichael Walle buf->locked = !!locked; 67*069089acSMichael Walle buf++; 68*069089acSMichael Walle } 69*069089acSMichael Walle 70*069089acSMichael Walle *retlen = n_regions * sizeof(*buf); 71*069089acSMichael Walle 72*069089acSMichael Walle out: 73*069089acSMichael Walle spi_nor_unlock_and_unprep(nor); 74*069089acSMichael Walle 75*069089acSMichael Walle return ret; 76*069089acSMichael Walle } 77*069089acSMichael Walle 78*069089acSMichael Walle static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs, 79*069089acSMichael Walle size_t total_len, size_t *retlen, 80*069089acSMichael Walle u8 *buf, bool is_write) 81*069089acSMichael Walle { 82*069089acSMichael Walle struct spi_nor *nor = mtd_to_spi_nor(mtd); 83*069089acSMichael Walle const struct spi_nor_otp_ops *ops = nor->params->otp.ops; 84*069089acSMichael Walle const size_t rlen = spi_nor_otp_region_len(nor); 85*069089acSMichael Walle loff_t rstart, rofs; 86*069089acSMichael Walle unsigned int region; 87*069089acSMichael Walle size_t len; 88*069089acSMichael Walle int ret; 89*069089acSMichael Walle 90*069089acSMichael Walle if (ofs < 0 || ofs >= spi_nor_otp_size(nor)) 91*069089acSMichael Walle return 0; 92*069089acSMichael Walle 93*069089acSMichael Walle ret = spi_nor_lock_and_prep(nor); 94*069089acSMichael Walle if (ret) 95*069089acSMichael Walle return ret; 96*069089acSMichael Walle 97*069089acSMichael Walle /* don't access beyond the end */ 98*069089acSMichael Walle total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs); 99*069089acSMichael Walle 100*069089acSMichael Walle *retlen = 0; 101*069089acSMichael Walle while (total_len) { 102*069089acSMichael Walle /* 103*069089acSMichael Walle * The OTP regions are mapped into a contiguous area starting 104*069089acSMichael Walle * at 0 as expected by the MTD layer. This will map the MTD 105*069089acSMichael Walle * file offsets to the address of an OTP region as used in the 106*069089acSMichael Walle * actual SPI commands. 107*069089acSMichael Walle */ 108*069089acSMichael Walle region = spi_nor_otp_offset_to_region(nor, ofs); 109*069089acSMichael Walle rstart = spi_nor_otp_region_start(nor, region); 110*069089acSMichael Walle 111*069089acSMichael Walle /* 112*069089acSMichael Walle * The size of a OTP region is expected to be a power of two, 113*069089acSMichael Walle * thus we can just mask the lower bits and get the offset into 114*069089acSMichael Walle * a region. 115*069089acSMichael Walle */ 116*069089acSMichael Walle rofs = ofs & (rlen - 1); 117*069089acSMichael Walle 118*069089acSMichael Walle /* don't access beyond one OTP region */ 119*069089acSMichael Walle len = min_t(size_t, total_len, rlen - rofs); 120*069089acSMichael Walle 121*069089acSMichael Walle if (is_write) 122*069089acSMichael Walle ret = ops->write(nor, rstart + rofs, len, buf); 123*069089acSMichael Walle else 124*069089acSMichael Walle ret = ops->read(nor, rstart + rofs, len, buf); 125*069089acSMichael Walle if (ret == 0) 126*069089acSMichael Walle ret = -EIO; 127*069089acSMichael Walle if (ret < 0) 128*069089acSMichael Walle goto out; 129*069089acSMichael Walle 130*069089acSMichael Walle *retlen += ret; 131*069089acSMichael Walle ofs += ret; 132*069089acSMichael Walle buf += ret; 133*069089acSMichael Walle total_len -= ret; 134*069089acSMichael Walle } 135*069089acSMichael Walle ret = 0; 136*069089acSMichael Walle 137*069089acSMichael Walle out: 138*069089acSMichael Walle spi_nor_unlock_and_unprep(nor); 139*069089acSMichael Walle return ret; 140*069089acSMichael Walle } 141*069089acSMichael Walle 142*069089acSMichael Walle static int spi_nor_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len, 143*069089acSMichael Walle size_t *retlen, u8 *buf) 144*069089acSMichael Walle { 145*069089acSMichael Walle return spi_nor_mtd_otp_read_write(mtd, from, len, retlen, buf, false); 146*069089acSMichael Walle } 147*069089acSMichael Walle 148*069089acSMichael Walle static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len, 149*069089acSMichael Walle size_t *retlen, u8 *buf) 150*069089acSMichael Walle { 151*069089acSMichael Walle return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true); 152*069089acSMichael Walle } 153*069089acSMichael Walle 154*069089acSMichael Walle static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len) 155*069089acSMichael Walle { 156*069089acSMichael Walle struct spi_nor *nor = mtd_to_spi_nor(mtd); 157*069089acSMichael Walle const struct spi_nor_otp_ops *ops = nor->params->otp.ops; 158*069089acSMichael Walle const size_t rlen = spi_nor_otp_region_len(nor); 159*069089acSMichael Walle unsigned int region; 160*069089acSMichael Walle int ret; 161*069089acSMichael Walle 162*069089acSMichael Walle if (from < 0 || (from + len) > spi_nor_otp_size(nor)) 163*069089acSMichael Walle return -EINVAL; 164*069089acSMichael Walle 165*069089acSMichael Walle /* the user has to explicitly ask for whole regions */ 166*069089acSMichael Walle if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) 167*069089acSMichael Walle return -EINVAL; 168*069089acSMichael Walle 169*069089acSMichael Walle ret = spi_nor_lock_and_prep(nor); 170*069089acSMichael Walle if (ret) 171*069089acSMichael Walle return ret; 172*069089acSMichael Walle 173*069089acSMichael Walle while (len) { 174*069089acSMichael Walle region = spi_nor_otp_offset_to_region(nor, from); 175*069089acSMichael Walle ret = ops->lock(nor, region); 176*069089acSMichael Walle if (ret) 177*069089acSMichael Walle goto out; 178*069089acSMichael Walle 179*069089acSMichael Walle len -= rlen; 180*069089acSMichael Walle from += rlen; 181*069089acSMichael Walle } 182*069089acSMichael Walle 183*069089acSMichael Walle out: 184*069089acSMichael Walle spi_nor_unlock_and_unprep(nor); 185*069089acSMichael Walle 186*069089acSMichael Walle return ret; 187*069089acSMichael Walle } 188*069089acSMichael Walle 189*069089acSMichael Walle void spi_nor_otp_init(struct spi_nor *nor) 190*069089acSMichael Walle { 191*069089acSMichael Walle struct mtd_info *mtd = &nor->mtd; 192*069089acSMichael Walle 193*069089acSMichael Walle if (!nor->params->otp.ops) 194*069089acSMichael Walle return; 195*069089acSMichael Walle 196*069089acSMichael Walle if (WARN_ON(!is_power_of_2(spi_nor_otp_region_len(nor)))) 197*069089acSMichael Walle return; 198*069089acSMichael Walle 199*069089acSMichael Walle /* 200*069089acSMichael Walle * We only support user_prot callbacks (yet). 201*069089acSMichael Walle * 202*069089acSMichael Walle * Some SPI NOR flashes like Macronix ones can be ordered in two 203*069089acSMichael Walle * different variants. One with a factory locked OTP area and one where 204*069089acSMichael Walle * it is left to the user to write to it. The factory locked OTP is 205*069089acSMichael Walle * usually preprogrammed with an "electrical serial number". We don't 206*069089acSMichael Walle * support these for now. 207*069089acSMichael Walle */ 208*069089acSMichael Walle mtd->_get_user_prot_info = spi_nor_mtd_otp_info; 209*069089acSMichael Walle mtd->_read_user_prot_reg = spi_nor_mtd_otp_read; 210*069089acSMichael Walle mtd->_write_user_prot_reg = spi_nor_mtd_otp_write; 211*069089acSMichael Walle mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock; 212*069089acSMichael Walle } 213