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 
12 static const u8 bootcount_magic = 0xbc;
13 
14 struct bootcount_spi_flash_priv {
15 	struct udevice *spi_flash;
16 	u32 offset;
17 };
18 
bootcount_spi_flash_update(struct udevice * dev,u32 offset,u32 len,const void * buf)19 static 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 
49 out:
50 	free(buffer);
51 	return err;
52 }
53 
bootcount_spi_flash_set(struct udevice * dev,const u32 a)54 static 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 
bootcount_spi_flash_get(struct udevice * dev,u32 * a)67 static 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 
bootcount_spi_flash_probe(struct udevice * dev)86 static 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 
108 static const struct bootcount_ops bootcount_spi_flash_ops = {
109 	.get = bootcount_spi_flash_get,
110 	.set = bootcount_spi_flash_set,
111 };
112 
113 static const struct udevice_id bootcount_spi_flash_ids[] = {
114 	{ .compatible = "u-boot,bootcount-spi-flash" },
115 	{ }
116 };
117 
118 U_BOOT_DRIVER(bootcount_spi_flash) = {
119 	.name	= "bootcount-spi-flash",
120 	.id	= UCLASS_BOOTCOUNT,
121 	.priv_auto	= 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