]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e4a95d11 | 2 | /* |
0044c42e | 3 | * (C) Copyright 2010-2012 |
e4a95d11 | 4 | * Stefan Roese, DENX Software Engineering, [email protected]. |
e4a95d11 SR |
5 | */ |
6 | ||
0044c42e | 7 | #include <bootcount.h> |
1eb69ae4 | 8 | #include <cpu_func.h> |
90526e9f | 9 | #include <asm/cache.h> |
0044c42e | 10 | #include <linux/compiler.h> |
e4a95d11 | 11 | |
80e8b8ad | 12 | #if !defined(CONFIG_DM_BOOTCOUNT) |
0044c42e | 13 | /* Now implement the generic default functions */ |
0044c42e | 14 | __weak void bootcount_store(ulong a) |
e4a95d11 SR |
15 | { |
16 | void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR; | |
fe9805fc AK |
17 | uintptr_t flush_start = rounddown(CONFIG_SYS_BOOTCOUNT_ADDR, |
18 | CONFIG_SYS_CACHELINE_SIZE); | |
19 | uintptr_t flush_end; | |
e4a95d11 SR |
20 | |
21 | #if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) | |
758694ff | 22 | raw_bootcount_store(reg, (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000) | a); |
fe9805fc AK |
23 | |
24 | flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 4, | |
25 | CONFIG_SYS_CACHELINE_SIZE); | |
e4a95d11 | 26 | #else |
0044c42e | 27 | raw_bootcount_store(reg, a); |
758694ff | 28 | raw_bootcount_store(reg + 4, CONFIG_SYS_BOOTCOUNT_MAGIC); |
fe9805fc AK |
29 | |
30 | flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 8, | |
31 | CONFIG_SYS_CACHELINE_SIZE); | |
76765375 | 32 | #endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD */ |
fe9805fc | 33 | flush_dcache_range(flush_start, flush_end); |
e4a95d11 SR |
34 | } |
35 | ||
0044c42e | 36 | __weak ulong bootcount_load(void) |
e4a95d11 SR |
37 | { |
38 | void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR; | |
39 | ||
40 | #if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) | |
0044c42e | 41 | u32 tmp = raw_bootcount_load(reg); |
59dde44a | 42 | |
758694ff | 43 | if ((tmp & 0xffff0000) != (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000)) |
e4a95d11 SR |
44 | return 0; |
45 | else | |
59dde44a | 46 | return (tmp & 0x0000ffff); |
e4a95d11 | 47 | #else |
758694ff | 48 | if (raw_bootcount_load(reg + 4) != CONFIG_SYS_BOOTCOUNT_MAGIC) |
e4a95d11 SR |
49 | return 0; |
50 | else | |
0044c42e | 51 | return raw_bootcount_load(reg); |
76765375 | 52 | #endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */ |
e4a95d11 | 53 | } |
80e8b8ad HS |
54 | #else |
55 | #include <dm.h> | |
56 | ||
57 | /* | |
58 | * struct bootcount_mem_priv - private bootcount mem driver data | |
59 | * | |
60 | * @base: base address used for bootcounter | |
61 | * @singleword: if true use only one 32 bit word for bootcounter | |
62 | */ | |
63 | struct bootcount_mem_priv { | |
64 | phys_addr_t base; | |
65 | bool singleword; | |
66 | }; | |
67 | ||
68 | static int bootcount_mem_get(struct udevice *dev, u32 *a) | |
69 | { | |
70 | struct bootcount_mem_priv *priv = dev_get_priv(dev); | |
71 | void *reg = (void *)priv->base; | |
72 | u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC; | |
73 | ||
74 | if (priv->singleword) { | |
75 | u32 tmp = raw_bootcount_load(reg); | |
76 | ||
77 | if ((tmp & 0xffff0000) != (magic & 0xffff0000)) | |
78 | return -ENODEV; | |
79 | ||
80 | *a = (tmp & 0x0000ffff); | |
81 | } else { | |
82 | if (raw_bootcount_load(reg + 4) != magic) | |
83 | return -ENODEV; | |
84 | ||
85 | *a = raw_bootcount_load(reg); | |
86 | } | |
87 | ||
88 | return 0; | |
89 | }; | |
90 | ||
91 | static int bootcount_mem_set(struct udevice *dev, const u32 a) | |
92 | { | |
93 | struct bootcount_mem_priv *priv = dev_get_priv(dev); | |
94 | void *reg = (void *)priv->base; | |
95 | u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC; | |
96 | uintptr_t flush_start = rounddown(priv->base, | |
97 | CONFIG_SYS_CACHELINE_SIZE); | |
98 | uintptr_t flush_end; | |
99 | ||
100 | if (priv->singleword) { | |
101 | raw_bootcount_store(reg, (magic & 0xffff0000) | a); | |
102 | flush_end = roundup(priv->base + 4, | |
103 | CONFIG_SYS_CACHELINE_SIZE); | |
104 | } else { | |
105 | raw_bootcount_store(reg, a); | |
106 | raw_bootcount_store(reg + 4, magic); | |
107 | flush_end = roundup(priv->base + 8, | |
108 | CONFIG_SYS_CACHELINE_SIZE); | |
109 | } | |
110 | flush_dcache_range(flush_start, flush_end); | |
111 | ||
112 | return 0; | |
113 | }; | |
114 | ||
115 | static const struct bootcount_ops bootcount_mem_ops = { | |
116 | .get = bootcount_mem_get, | |
117 | .set = bootcount_mem_set, | |
118 | }; | |
119 | ||
120 | static int bootcount_mem_probe(struct udevice *dev) | |
121 | { | |
122 | struct bootcount_mem_priv *priv = dev_get_priv(dev); | |
123 | ||
124 | priv->base = (phys_addr_t)dev_read_addr(dev); | |
125 | if (dev_read_bool(dev, "single-word")) | |
126 | priv->singleword = true; | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static const struct udevice_id bootcount_mem_ids[] = { | |
132 | { .compatible = "u-boot,bootcount" }, | |
133 | { } | |
134 | }; | |
135 | ||
136 | U_BOOT_DRIVER(bootcount_mem) = { | |
137 | .name = "bootcount-mem", | |
138 | .id = UCLASS_BOOTCOUNT, | |
41575d8e | 139 | .priv_auto = sizeof(struct bootcount_mem_priv), |
80e8b8ad HS |
140 | .probe = bootcount_mem_probe, |
141 | .of_match = bootcount_mem_ids, | |
142 | .ops = &bootcount_mem_ops, | |
143 | }; | |
144 | #endif |