"Das U-Boot" Source Tree
at master 144 lines 3.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2010-2012 4 * Stefan Roese, DENX Software Engineering, sr@denx.de. 5 */ 6 7#include <bootcount.h> 8#include <cpu_func.h> 9#include <asm/cache.h> 10#include <linux/compiler.h> 11 12#if !defined(CONFIG_DM_BOOTCOUNT) 13/* Now implement the generic default functions */ 14__weak void bootcount_store(ulong a) 15{ 16 void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR; 17 uintptr_t flush_start = rounddown(CONFIG_SYS_BOOTCOUNT_ADDR, 18 CONFIG_SYS_CACHELINE_SIZE); 19 uintptr_t flush_end; 20 21#if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) 22 raw_bootcount_store(reg, (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000) | a); 23 24 flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 4, 25 CONFIG_SYS_CACHELINE_SIZE); 26#else 27 raw_bootcount_store(reg, a); 28 raw_bootcount_store(reg + 4, CONFIG_SYS_BOOTCOUNT_MAGIC); 29 30 flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 8, 31 CONFIG_SYS_CACHELINE_SIZE); 32#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD */ 33 flush_dcache_range(flush_start, flush_end); 34} 35 36__weak ulong bootcount_load(void) 37{ 38 void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR; 39 40#if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) 41 u32 tmp = raw_bootcount_load(reg); 42 43 if ((tmp & 0xffff0000) != (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000)) 44 return 0; 45 else 46 return (tmp & 0x0000ffff); 47#else 48 if (raw_bootcount_load(reg + 4) != CONFIG_SYS_BOOTCOUNT_MAGIC) 49 return 0; 50 else 51 return raw_bootcount_load(reg); 52#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */ 53} 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 */ 63struct bootcount_mem_priv { 64 phys_addr_t base; 65 bool singleword; 66}; 67 68static 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 91static 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 115static const struct bootcount_ops bootcount_mem_ops = { 116 .get = bootcount_mem_get, 117 .set = bootcount_mem_set, 118}; 119 120static 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 131static const struct udevice_id bootcount_mem_ids[] = { 132 { .compatible = "u-boot,bootcount" }, 133 { } 134}; 135 136U_BOOT_DRIVER(bootcount_mem) = { 137 .name = "bootcount-mem", 138 .id = UCLASS_BOOTCOUNT, 139 .priv_auto = sizeof(struct bootcount_mem_priv), 140 .probe = bootcount_mem_probe, 141 .of_match = bootcount_mem_ids, 142 .ops = &bootcount_mem_ops, 143}; 144#endif