Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com> * * This driver supports the Security Fuse Processor device found on some * Layerscape processors. At the moment, we only support a few processors. * This driver was written with reference to the Layerscape SDK User * Guide [1] and the ATF SFP driver [2]. * * [1] https://docs.nxp.com/bundle/GUID-487B2E69-BB19-42CB-AC38-7EF18C0FE3AE/page/GUID-27FC40AD-3321-4A82-B29E-7BB49EE94F23.html * [2] https://source.codeaurora.org/external/qoriq/qoriq-components/atf/tree/drivers/nxp/sfp?h=github.com/master */ #define LOG_CATEGORY UCLASS_MISC #include <clk.h> #include <fuse.h> #include <misc.h> #include <asm/io.h> #include <dm/device_compat.h> #include <dm/read.h> #include <linux/bitfield.h> #include <power/regulator.h> DECLARE_GLOBAL_DATA_PTR; #define SFP_INGR 0x20 #define SFP_SVHESR 0x24 #define SFP_SFPCR 0x28 #define SFP_START 0x200 #define SFP_END 0x284 #define SFP_SIZE (SFP_END - SFP_START + 4) #define SFP_INGR_ERR BIT(8) #define SFP_INGR_INST GENMASK(7, 0) #define SFP_INGR_READFB 0x01 #define SFP_INGR_PROGFB 0x02 #define SFP_SFPCR_PPW GENMASK(15, 0) enum ls2_sfp_ioctl { LS2_SFP_IOCTL_READ, LS2_SFP_IOCTL_PROG, }; /** * struct ls2_sfp_priv - private data for LS2 SFP * @base: Base address of SFP * @supply: The (optional) supply for TA_PROG_SFP * @programmed: Whether we've already programmed the fuses since the last * reset. The SFP has a *very* limited amount of programming * cycles (two to six, depending on the model), so we try and * prevent accidentally performing additional programming * cycles. * @dirty: Whether the mirror registers have been written to (overridden) * since we've last read the fuses (either as part of the reset * process or using a READFB instruction). There is a much larger, * but still finite, limit on the number of SFP read cycles (around * 300,000), so we try and minimize reads as well. */ struct ls2_sfp_priv { void __iomem *base; struct udevice *supply; bool programmed, dirty; }; static u32 ls2_sfp_readl(struct ls2_sfp_priv *priv, ulong off) { u32 val = be32_to_cpu(readl(priv->base + off)); log_debug("%08x = readl(%p)\n", val, priv->base + off); return val; } static void ls2_sfp_writel(struct ls2_sfp_priv *priv, ulong val, ulong off) { log_debug("writel(%08lx, %p)\n", val, priv->base + off); writel(cpu_to_be32(val), priv->base + off); } static bool ls2_sfp_validate(struct udevice *dev, int offset, int size) { if (offset < 0 || size < 0) { dev_notice(dev, "size and offset must be positive\n"); return false; } if (offset & 3 || size & 3) { dev_notice(dev, "size and offset must be multiples of 4\n"); return false; } if (offset + size > SFP_SIZE) { dev_notice(dev, "size + offset must be <= %#x\n", SFP_SIZE); return false; } return true; } static int ls2_sfp_read(struct udevice *dev, int offset, void *buf_bytes, int size) { int i; struct ls2_sfp_priv *priv = dev_get_priv(dev); u32 *buf = buf_bytes; if (!ls2_sfp_validate(dev, offset, size)) return -EINVAL; for (i = 0; i < size; i += 4) buf[i >> 2] = ls2_sfp_readl(priv, SFP_START + offset + i); return size; } static int ls2_sfp_write(struct udevice *dev, int offset, const void *buf_bytes, int size) { int i; struct ls2_sfp_priv *priv = dev_get_priv(dev); const u32 *buf = buf_bytes; if (!ls2_sfp_validate(dev, offset, size)) return -EINVAL; for (i = 0; i < size; i += 4) ls2_sfp_writel(priv, buf[i >> 2], SFP_START + offset + i); priv->dirty = true; return size; } static int ls2_sfp_check_secret(struct udevice *dev) { struct ls2_sfp_priv *priv = dev_get_priv(dev); u32 svhesr = ls2_sfp_readl(priv, SFP_SVHESR); if (svhesr) { dev_warn(dev, "secret value hamming error not zero: %08x\n", svhesr); return -EIO; } return 0; } static int ls2_sfp_transaction(struct ls2_sfp_priv *priv, ulong inst) { u32 ingr; ls2_sfp_writel(priv, inst, SFP_INGR); do { ingr = ls2_sfp_readl(priv, SFP_INGR); } while (FIELD_GET(SFP_INGR_INST, ingr)); return FIELD_GET(SFP_INGR_ERR, ingr) ? -EIO : 0; } static int ls2_sfp_ioctl(struct udevice *dev, unsigned long request, void *buf) { int ret; struct ls2_sfp_priv *priv = dev_get_priv(dev); switch (request) { case LS2_SFP_IOCTL_READ: if (!priv->dirty) { dev_dbg(dev, "ignoring read request, since fuses are not dirty\n"); return 0; } ret = ls2_sfp_transaction(priv, SFP_INGR_READFB); if (ret) { dev_err(dev, "error reading fuses\n"); return ret; } ls2_sfp_check_secret(dev); priv->dirty = false; return 0; case LS2_SFP_IOCTL_PROG: if (priv->programmed) { dev_warn(dev, "fuses already programmed\n"); return -EPERM; } ret = ls2_sfp_check_secret(dev); if (ret) return ret; if (priv->supply) { ret = regulator_set_enable(priv->supply, true); if (ret) return ret; } ret = ls2_sfp_transaction(priv, SFP_INGR_PROGFB); priv->programmed = true; if (priv->supply) regulator_set_enable(priv->supply, false); if (ret) dev_err(dev, "error programming fuses\n"); return ret; default: dev_dbg(dev, "unknown ioctl %lu\n", request); return -EINVAL; } } static const struct misc_ops ls2_sfp_ops = { .read = ls2_sfp_read, .write = ls2_sfp_write, .ioctl = ls2_sfp_ioctl, }; static int ls2_sfp_probe(struct udevice *dev) { int ret; struct clk clk; struct ls2_sfp_priv *priv = dev_get_priv(dev); ulong rate; priv->base = dev_read_addr_ptr(dev); if (!priv->base) { dev_dbg(dev, "could not read register base\n"); return -EINVAL; } ret = device_get_supply_regulator(dev, "ta-sfp-prog-supply", &priv->supply); if (ret && ret != -ENODEV && ret != -ENOSYS) { dev_dbg(dev, "problem getting supply (err %d)\n", ret); return ret; } ret = clk_get_by_name(dev, "sfp", &clk); if (ret == -ENOSYS) { rate = gd->bus_clk / 4; } else if (ret) { dev_dbg(dev, "could not get clock (err %d)\n", ret); return ret; } else { ret = clk_enable(&clk); if (ret) { dev_dbg(dev, "could not enable clock (err %d)\n", ret); return ret; } rate = clk_get_rate(&clk); if (!rate || IS_ERR_VALUE(rate)) { ret = rate ? rate : -ENOENT; dev_dbg(dev, "could not get clock rate (err %d)\n", ret); return ret; } } /* sfp clock in MHz * 12 */ ls2_sfp_writel(priv, FIELD_PREP(SFP_SFPCR_PPW, rate * 12 / 1000000), SFP_SFPCR); ls2_sfp_check_secret(dev); return 0; } static const struct udevice_id ls2_sfp_ids[] = { { .compatible = "fsl,ls1021a-sfp" }, { } }; U_BOOT_DRIVER(ls2_sfp) = { .name = "ls2_sfp", .id = UCLASS_MISC, .of_match = ls2_sfp_ids, .probe = ls2_sfp_probe, .ops = &ls2_sfp_ops, .priv_auto = sizeof(struct ls2_sfp_priv), }; static int ls2_sfp_device(struct udevice **dev) { int ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(ls2_sfp), dev); if (ret) log_debug("device not found (err %d)\n", ret); return ret; } int fuse_read(u32 bank, u32 word, u32 *val) { int ret; struct udevice *dev; ret = ls2_sfp_device(&dev); if (ret) return ret; ret = misc_ioctl(dev, LS2_SFP_IOCTL_READ, NULL); if (ret) return ret; ret = misc_read(dev, word << 2, val, sizeof(*val)); return ret < 0 ? ret : 0; } int fuse_sense(u32 bank, u32 word, u32 *val) { int ret; struct udevice *dev; ret = ls2_sfp_device(&dev); if (ret) return ret; ret = misc_read(dev, word << 2, val, sizeof(*val)); return ret < 0 ? ret : 0; } int fuse_prog(u32 bank, u32 word, u32 val) { int ret; struct udevice *dev; ret = ls2_sfp_device(&dev); if (ret) return ret; ret = misc_write(dev, word << 2, &val, sizeof(val)); if (ret < 0) return ret; return misc_ioctl(dev, LS2_SFP_IOCTL_PROG, NULL); } int fuse_override(u32 bank, u32 word, u32 val) { int ret; struct udevice *dev; ret = ls2_sfp_device(&dev); if (ret) return ret; ret = misc_write(dev, word << 2, &val, sizeof(val)); return ret < 0 ? ret : 0; } |