uboot/drivers/bootcount/spi-flash.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2019 Collabora
   4 * (C) Copyright 2019 GE
   5 */
   6
   7#include <common.h>
   8#include <bootcount.h>
   9#include <dm.h>
  10#include <spi_flash.h>
  11
  12static const u8 bootcount_magic = 0xbc;
  13
  14struct bootcount_spi_flash_priv {
  15        struct udevice *spi_flash;
  16        u32 offset;
  17};
  18
  19static int bootcount_spi_flash_update(struct udevice *dev, u32 offset, u32 len, const void *buf)
  20{
  21        struct spi_flash *flash = dev_get_uclass_priv(dev);
  22        u32 sector_size = flash->sector_size;
  23        u32 sector_offset = offset % sector_size;
  24        u32 sector = offset - sector_offset;
  25        int err = 0;
  26
  27        /* code only supports updating a single sector */
  28        if (sector_offset + len > sector_size)
  29                return -ENOSYS;
  30
  31        u8 *buffer = malloc(sector_size);
  32        if (!buffer)
  33                return -ENOMEM;
  34
  35        err = spi_flash_read_dm(dev, sector, sector_size, buffer);
  36        if (err < 0)
  37                goto out;
  38
  39        memcpy(buffer + sector_offset, buf, len);
  40
  41        err = spi_flash_erase_dm(dev, sector, sector_size);
  42        if (err < 0)
  43                goto out;
  44
  45        err = spi_flash_write_dm(dev, sector, sector_size, buffer);
  46        if (err < 0)
  47                goto out;
  48
  49out:
  50        free(buffer);
  51        return err;
  52}
  53
  54static int bootcount_spi_flash_set(struct udevice *dev, const u32 a)
  55{
  56        struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
  57        const u16 val = bootcount_magic << 8 | (a & 0xff);
  58
  59        if (bootcount_spi_flash_update(priv->spi_flash, priv->offset, 2, &val) < 0) {
  60                debug("%s: write failed\n", __func__);
  61                return -EIO;
  62        }
  63
  64        return 0;
  65}
  66
  67static int bootcount_spi_flash_get(struct udevice *dev, u32 *a)
  68{
  69        struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
  70        u16 val;
  71
  72        if (spi_flash_read_dm(priv->spi_flash, priv->offset, 2, &val) < 0) {
  73                debug("%s: read failed\n", __func__);
  74                return -EIO;
  75        }
  76
  77        if (val >> 8 == bootcount_magic) {
  78                *a = val & 0xff;
  79                return 0;
  80        }
  81
  82        debug("%s: bootcount magic does not match on %04x\n", __func__, val);
  83        return -EIO;
  84}
  85
  86static int bootcount_spi_flash_probe(struct udevice *dev)
  87{
  88        struct ofnode_phandle_args phandle_args;
  89        struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
  90        struct udevice *spi_flash;
  91
  92        if (dev_read_phandle_with_args(dev, "spi-flash", NULL, 0, 0, &phandle_args)) {
  93                debug("%s: spi-flash backing device not specified\n", dev->name);
  94                return -ENOENT;
  95        }
  96
  97        if (uclass_get_device_by_ofnode(UCLASS_SPI_FLASH, phandle_args.node, &spi_flash)) {
  98                debug("%s: could not get backing device\n", dev->name);
  99                return -ENODEV;
 100        }
 101
 102        priv->spi_flash = spi_flash;
 103        priv->offset = dev_read_u32_default(dev, "offset", 0);
 104
 105        return 0;
 106}
 107
 108static const struct bootcount_ops bootcount_spi_flash_ops = {
 109        .get = bootcount_spi_flash_get,
 110        .set = bootcount_spi_flash_set,
 111};
 112
 113static const struct udevice_id bootcount_spi_flash_ids[] = {
 114        { .compatible = "u-boot,bootcount-spi-flash" },
 115        { }
 116};
 117
 118U_BOOT_DRIVER(bootcount_spi_flash) = {
 119        .name   = "bootcount-spi-flash",
 120        .id     = UCLASS_BOOTCOUNT,
 121        .priv_auto_alloc_size = sizeof(struct bootcount_spi_flash_priv),
 122        .probe  = bootcount_spi_flash_probe,
 123        .of_match = bootcount_spi_flash_ids,
 124        .ops    = &bootcount_spi_flash_ops,
 125};
 126