1/* SPDX-License-Identifier: GPL-2.0+ */ 2/* 3 * (C) Copyright 2012 4 * Stefan Roese, DENX Software Engineering, sr@denx.de. 5 */ 6#ifndef _BOOTCOUNT_H__ 7#define _BOOTCOUNT_H__ 8 9#include <asm/global_data.h> 10#include <asm/io.h> 11#include <asm/byteorder.h> 12#include <env.h> 13 14#ifdef CONFIG_DM_BOOTCOUNT 15 16struct bootcount_ops { 17 /** 18 * get() - get the current bootcount value 19 * 20 * Returns the current counter value of the bootcount backing 21 * store. 22 * 23 * @dev: Device to read from 24 * @bootcount: Address to put the current bootcount value 25 */ 26 int (*get)(struct udevice *dev, u32 *bootcount); 27 28 /** 29 * set() - set a bootcount value (e.g. to reset or increment) 30 * 31 * Sets the value in the bootcount backing store. 32 * 33 * @dev: Device to read from 34 * @bootcount: New bootcount value to store 35 */ 36 int (*set)(struct udevice *dev, const u32 bootcount); 37}; 38 39/* Access the operations for a bootcount device */ 40#define bootcount_get_ops(dev) ((struct bootcount_ops *)(dev)->driver->ops) 41 42/** 43 * dm_bootcount_get() - Read the current value from a bootcount storage 44 * 45 * @dev: Device to read from 46 * @bootcount: Place to put the current bootcount 47 * Return: 0 if OK, -ve on error 48 */ 49int dm_bootcount_get(struct udevice *dev, u32 *bootcount); 50 51/** 52 * dm_bootcount_set() - Write a value to a bootcount storage 53 * 54 * @dev: Device to read from 55 * @bootcount: Value to be written to the backing storage 56 * Return: 0 if OK, -ve on error 57 */ 58int dm_bootcount_set(struct udevice *dev, u32 bootcount); 59 60#endif 61 62/** bootcount_store() - store the current bootcount */ 63void bootcount_store(ulong); 64 65/** 66 * bootcount_load() - load the current bootcount 67 * 68 * Return: bootcount, read from the appropriate location 69 */ 70ulong bootcount_load(void); 71 72#if defined(CONFIG_SPL_BOOTCOUNT_LIMIT) || defined(CONFIG_TPL_BOOTCOUNT_LIMIT) || defined(CONFIG_BOOTCOUNT_LIMIT) 73 74#ifdef CONFIG_SYS_BOOTCOUNT_LE 75static inline void raw_bootcount_store(volatile u32 *addr, u32 data) 76{ 77 out_le32(addr, data); 78} 79 80static inline u32 raw_bootcount_load(volatile u32 *addr) 81{ 82 return in_le32(addr); 83} 84#else 85static inline void raw_bootcount_store(volatile u32 *addr, u32 data) 86{ 87 out_be32(addr, data); 88} 89 90static inline u32 raw_bootcount_load(volatile u32 *addr) 91{ 92 return in_be32(addr); 93} 94#endif 95 96DECLARE_GLOBAL_DATA_PTR; 97static inline int bootcount_error(void) 98{ 99 unsigned long bootcount = bootcount_load(); 100 unsigned long bootlimit = env_get_ulong("bootlimit", 10, 0); 101 102 if (bootlimit && bootcount > bootlimit) { 103 printf("Warning: Bootlimit (%lu) exceeded.", bootlimit); 104 if (!(gd->flags & GD_FLG_SPL_INIT)) 105 printf(" Using altbootcmd."); 106 printf("\n"); 107 108 return 1; 109 } 110 111 return 0; 112} 113 114static inline void bootcount_inc(void) 115{ 116 unsigned long bootcount = bootcount_load(); 117 118 if (gd->flags & GD_FLG_SPL_INIT) { 119 bootcount_store(++bootcount); 120 return; 121 } 122 123#ifndef CONFIG_SPL_BUILD 124 /* Only increment bootcount when no bootcount support in SPL */ 125#if !defined(CONFIG_SPL_BOOTCOUNT_LIMIT) && !defined(CONFIG_TPL_BOOTCOUNT_LIMIT) 126 bootcount_store(++bootcount); 127#endif 128 env_set_ulong("bootcount", bootcount); 129#endif /* !CONFIG_SPL_BUILD */ 130} 131 132#else 133static inline int bootcount_error(void) { return 0; } 134static inline void bootcount_inc(void) {} 135#endif /* CONFIG_SPL_BOOTCOUNT_LIMIT || CONFIG_TPL_BOOTCOUNT_LIMIT || CONFIG_BOOTCOUNT_LIMIT */ 136#endif /* _BOOTCOUNT_H__ */ 137