/src/u-boot/drivers/bootcount/rtc.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH |
4 | | */ |
5 | | |
6 | | #include <bootcount.h> |
7 | | #include <dm.h> |
8 | | #include <log.h> |
9 | | #include <rtc.h> |
10 | | |
11 | | static const u8 bootcount_magic = 0xbc; |
12 | | |
13 | | struct bootcount_rtc_priv { |
14 | | struct udevice *rtc; |
15 | | u32 offset; |
16 | | }; |
17 | | |
18 | | static int bootcount_rtc_set(struct udevice *dev, const u32 a) |
19 | 0 | { |
20 | 0 | struct bootcount_rtc_priv *priv = dev_get_priv(dev); |
21 | 0 | const u16 val = bootcount_magic << 8 | (a & 0xff); |
22 | |
|
23 | 0 | if (rtc_write16(priv->rtc, priv->offset, val) < 0) { |
24 | 0 | debug("%s: rtc_write16 failed\n", __func__); |
25 | 0 | return -EIO; |
26 | 0 | } |
27 | | |
28 | 0 | return 0; |
29 | 0 | } |
30 | | |
31 | | static int bootcount_rtc_get(struct udevice *dev, u32 *a) |
32 | 0 | { |
33 | 0 | struct bootcount_rtc_priv *priv = dev_get_priv(dev); |
34 | 0 | u16 val; |
35 | |
|
36 | 0 | if (rtc_read16(priv->rtc, priv->offset, &val) < 0) { |
37 | 0 | debug("%s: rtc_write16 failed\n", __func__); |
38 | 0 | return -EIO; |
39 | 0 | } |
40 | | |
41 | 0 | if (val >> 8 == bootcount_magic) { |
42 | 0 | *a = val & 0xff; |
43 | 0 | return 0; |
44 | 0 | } |
45 | | |
46 | 0 | debug("%s: bootcount magic does not match on %04x\n", __func__, val); |
47 | 0 | return -EIO; |
48 | 0 | } |
49 | | |
50 | | static int bootcount_rtc_probe(struct udevice *dev) |
51 | 0 | { |
52 | 0 | struct ofnode_phandle_args phandle_args; |
53 | 0 | struct bootcount_rtc_priv *priv = dev_get_priv(dev); |
54 | 0 | struct udevice *rtc; |
55 | |
|
56 | 0 | if (dev_read_phandle_with_args(dev, "rtc", NULL, 0, 0, &phandle_args)) { |
57 | 0 | debug("%s: rtc backing device not specified\n", dev->name); |
58 | 0 | return -ENOENT; |
59 | 0 | } |
60 | | |
61 | 0 | if (uclass_get_device_by_ofnode(UCLASS_RTC, phandle_args.node, &rtc)) { |
62 | 0 | debug("%s: could not get backing device\n", dev->name); |
63 | 0 | return -ENODEV; |
64 | 0 | } |
65 | | |
66 | 0 | priv->rtc = rtc; |
67 | 0 | priv->offset = dev_read_u32_default(dev, "offset", 0); |
68 | |
|
69 | 0 | return 0; |
70 | 0 | } |
71 | | |
72 | | static const struct bootcount_ops bootcount_rtc_ops = { |
73 | | .get = bootcount_rtc_get, |
74 | | .set = bootcount_rtc_set, |
75 | | }; |
76 | | |
77 | | static const struct udevice_id bootcount_rtc_ids[] = { |
78 | | { .compatible = "u-boot,bootcount-rtc" }, |
79 | | { } |
80 | | }; |
81 | | |
82 | | U_BOOT_DRIVER(bootcount_rtc) = { |
83 | | .name = "bootcount-rtc", |
84 | | .id = UCLASS_BOOTCOUNT, |
85 | | .priv_auto = sizeof(struct bootcount_rtc_priv), |
86 | | .probe = bootcount_rtc_probe, |
87 | | .of_match = bootcount_rtc_ids, |
88 | | .ops = &bootcount_rtc_ops, |
89 | | }; |