Add register access utility functions for device models, like checking aligned access and reading and writing to a register backstore.
Signed-off-by: Octavian Purdila <ta...@google.com> --- include/hw/regs.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 include/hw/regs.h diff --git a/include/hw/regs.h b/include/hw/regs.h new file mode 100644 index 0000000000..8d0da0629d --- /dev/null +++ b/include/hw/regs.h @@ -0,0 +1,89 @@ +/* + * Useful macros/functions for register handling. + * + * Copyright (c) 2021 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_REGS_H +#define HW_REGS_H + +#include "exec/hwaddr.h" +#include "exec/memattrs.h" + +#define BITS(hi, lo) (BIT(hi + 1) - BIT(lo)) +#define BIT_IS_SET(v, b) (((v) & BIT(b)) != 0) + +/* + * reg32_aligned_access + * @addr: address to check + * @size: size of access + * + * Check if access to a hardware address is 32bit aligned. + * + * Returns: true if access is 32bit aligned, false otherwise + */ +static inline bool reg32_aligned_access(hwaddr addr, unsigned size) +{ + if (size != 4 || addr % 4 != 0) { + return false; + } + return true; +} + +/* + * reg32_write + * @base: base address + * @addr: register offset in bytes + * @val: value to write + * @wr_bits_array: RW bitmask array + * + * Update the RW/WO bits of a 32bit register backstore with a given value + * (discarding updats to the RO bits). The RW/WO bits are encoded in the + * @wr_bits_array with bits set being RW and bits unset being RO. + * + * Usage example: + * + * wr_bits_array[] = { + * [REG1_ADDR/4] = 0xFF000000, // MSB byte writable + * [REG2_ADDR/4] = 0xFF, // LSB byte writable + * // all other registers are read-only + * }; + * + * // backstore is updated to 0x12000000 + * reg32_write(&backstore, REG1_ADDR, 0x12345678, wr_bits_array); + * // backstore is updated to 0x78 + * reg32_write(&backstore, REG2_ADDR, 0x12345678, wr_bits_array); + */ +static inline uint32_t reg32_write(void *base, uint32_t off, uint32_t val, + const uint32_t *rw_bits_array) +{ + uint32_t *ptr = base + addr; + uint32_t old_value = *ptr; + uint32_t mask = rw_bits_array ? rw_bits_array[addr / 4] : 0xFFFFFFFF; + + /* set WO/RW bits */ + *ptr |= val & mask; + /* clear RO bits */ + *ptr &= val | ~mask; + + return old_value; +} + +/* + * reg32_read + * @base: base address + * @addr: register offset in bytes + * + * Returns: 32bit value from register backstore + */ +static inline uint32_t reg32_read(void *base, uint32_t addr) +{ + return *(uint32_t *)(base + addr); +} + +#endif /* HW_REGS_H */ -- 2.46.0.rc2.264.g509ed76dc8-goog