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 | // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2023 * Philip Richard Oberfichtner <pro@denx.de> * * Based on previous work from Heiko Schocher (legacy bootcount_i2c.c driver) */ #include <bootcount.h> #include <dm.h> #include <i2c.h> #define BC_MAGIC 0x55 struct bootcount_i2c_priv { struct udevice *bcdev; unsigned int offset; unsigned int size; }; static int bootcount_i2c_set(struct udevice *dev, const u32 val) { int ret; struct bootcount_i2c_priv *priv = dev_get_priv(dev); if (priv->size == 4) { u32 bc = (CONFIG_SYS_BOOTCOUNT_MAGIC & BOOTCOUNT_MAGIC_MASK) | (val & BOOTCOUNT_COUNT_MASK); ret = dm_i2c_write(priv->bcdev, priv->offset, (uint8_t *)&bc, sizeof(bc)); if (ret < 0) goto err_exit; } else { ret = dm_i2c_reg_write(priv->bcdev, priv->offset, BC_MAGIC); if (ret < 0) goto err_exit; ret = dm_i2c_reg_write(priv->bcdev, priv->offset + 1, val & 0xff); if (ret < 0) goto err_exit; } return 0; err_exit: log_debug("%s: Error writing to I2C device (%d)\n", __func__, ret); return ret; } static int bootcount_i2c_get(struct udevice *dev, u32 *val) { int ret; struct bootcount_i2c_priv *priv = dev_get_priv(dev); if (priv->size == 4) { u32 bc; ret = dm_i2c_read(priv->bcdev, priv->offset, (uint8_t *)&bc, sizeof(bc)); if (ret < 0) goto err_exit; if ((bc & BOOTCOUNT_MAGIC_MASK) != (CONFIG_SYS_BOOTCOUNT_MAGIC & BOOTCOUNT_MAGIC_MASK)) { log_debug("%s: Invalid Magic, reset bootcounter.\n", __func__); *val = 0; return bootcount_i2c_set(dev, 0); } *val = (bc & BOOTCOUNT_COUNT_MASK); } else { ret = dm_i2c_reg_read(priv->bcdev, priv->offset); if (ret < 0) goto err_exit; if ((ret & 0xff) != BC_MAGIC) { log_debug("%s: Invalid Magic, reset bootcounter.\n", __func__); *val = 0; return bootcount_i2c_set(dev, 0); } ret = dm_i2c_reg_read(priv->bcdev, priv->offset + 1); if (ret < 0) goto err_exit; *val = ret; } return 0; err_exit: log_debug("%s: Error reading from I2C device (%d)\n", __func__, ret); return ret; } static int bootcount_i2c_probe(struct udevice *dev) { struct bootcount_i2c_priv *priv = dev_get_priv(dev); int ret; ret = dev_read_u32(dev, "offset", &priv->offset); if (ret) goto exit; priv->size = dev_read_u32_default(dev, "size", 2); if (priv->size != 2 && priv->size != 4) { ret = -EINVAL; goto exit; } ret = i2c_get_chip_by_phandle(dev, "i2cbcdev", &priv->bcdev); exit: if (ret) log_debug("%s failed, ret = %d\n", __func__, ret); return ret; } static const struct bootcount_ops bootcount_i2c_ops = { .get = bootcount_i2c_get, .set = bootcount_i2c_set, }; static const struct udevice_id bootcount_i2c_ids[] = { { .compatible = "u-boot,bootcount-i2c" }, { } }; U_BOOT_DRIVER(bootcount_i2c) = { .name = "bootcount-i2c", .id = UCLASS_BOOTCOUNT, .priv_auto = sizeof(struct bootcount_i2c_priv), .probe = bootcount_i2c_probe, .of_match = bootcount_i2c_ids, .ops = &bootcount_i2c_ops, }; |