1 /* SPDX-License-Identifier: GPL-2.0 */
2
3 /* *Copyright (C) 2022-2023 Linaro Ltd. */
4
5 #ifndef _REG_H_
6 #define _REG_H_
7
8 #include <linux/types.h>
9 #include <linux/bits.h>
10
11 /**
12 * struct reg - A register descriptor
13 * @offset: Register offset relative to base of register memory
14 * @stride: Distance between two instances, if parameterized
15 * @fcount: Number of entries in the @fmask array
16 * @fmask: Array of mask values defining position and width of fields
17 * @name: Upper-case name of the register
18 */
19 struct reg {
20 u32 offset;
21 u32 stride;
22 u32 fcount;
23 const u32 *fmask; /* BIT(nr) or GENMASK(h, l) */
24 const char *name;
25 };
26
27 /* Helper macro for defining "simple" (non-parameterized) registers */
28 #define REG(__NAME, __reg_id, __offset) \
29 REG_STRIDE(__NAME, __reg_id, __offset, 0)
30
31 /* Helper macro for defining parameterized registers, specifying stride */
32 #define REG_STRIDE(__NAME, __reg_id, __offset, __stride) \
33 static const struct reg reg_ ## __reg_id = { \
34 .name = #__NAME, \
35 .offset = __offset, \
36 .stride = __stride, \
37 }
38
39 #define REG_FIELDS(__NAME, __name, __offset) \
40 REG_STRIDE_FIELDS(__NAME, __name, __offset, 0)
41
42 #define REG_STRIDE_FIELDS(__NAME, __name, __offset, __stride) \
43 static const struct reg reg_ ## __name = { \
44 .name = #__NAME, \
45 .offset = __offset, \
46 .stride = __stride, \
47 .fcount = ARRAY_SIZE(reg_ ## __name ## _fmask), \
48 .fmask = reg_ ## __name ## _fmask, \
49 }
50
51 /**
52 * struct regs - Description of registers supported by hardware
53 * @reg_count: Number of registers in the @reg[] array
54 * @reg: Array of register descriptors
55 */
56 struct regs {
57 u32 reg_count;
58 const struct reg **reg;
59 };
60
reg(const struct regs * regs,u32 reg_id)61 static inline const struct reg *reg(const struct regs *regs, u32 reg_id)
62 {
63 if (WARN(reg_id >= regs->reg_count,
64 "reg out of range (%u > %u)\n", reg_id, regs->reg_count - 1))
65 return NULL;
66
67 return regs->reg[reg_id];
68 }
69
70 /* Return the field mask for a field in a register, or 0 on error */
reg_fmask(const struct reg * reg,u32 field_id)71 static inline u32 reg_fmask(const struct reg *reg, u32 field_id)
72 {
73 if (!reg || WARN_ON(field_id >= reg->fcount))
74 return 0;
75
76 return reg->fmask[field_id];
77 }
78
79 /* Return the mask for a single-bit field in a register, or 0 on error */
reg_bit(const struct reg * reg,u32 field_id)80 static inline u32 reg_bit(const struct reg *reg, u32 field_id)
81 {
82 u32 fmask = reg_fmask(reg, field_id);
83
84 if (WARN_ON(!is_power_of_2(fmask)))
85 return 0;
86
87 return fmask;
88 }
89
90 /* Return the maximum value representable by the given field; always 2^n - 1 */
reg_field_max(const struct reg * reg,u32 field_id)91 static inline u32 reg_field_max(const struct reg *reg, u32 field_id)
92 {
93 u32 fmask = reg_fmask(reg, field_id);
94
95 return fmask ? fmask >> __ffs(fmask) : 0;
96 }
97
98 /* Encode a value into the given field of a register */
reg_encode(const struct reg * reg,u32 field_id,u32 val)99 static inline u32 reg_encode(const struct reg *reg, u32 field_id, u32 val)
100 {
101 u32 fmask = reg_fmask(reg, field_id);
102
103 if (!fmask)
104 return 0;
105
106 val <<= __ffs(fmask);
107 if (WARN_ON(val & ~fmask))
108 return 0;
109
110 return val;
111 }
112
113 /* Given a register value, decode (extract) the value in the given field */
reg_decode(const struct reg * reg,u32 field_id,u32 val)114 static inline u32 reg_decode(const struct reg *reg, u32 field_id, u32 val)
115 {
116 u32 fmask = reg_fmask(reg, field_id);
117
118 return fmask ? (val & fmask) >> __ffs(fmask) : 0;
119 }
120
121 /* Returns 0 for NULL reg; warning should have already been issued */
reg_offset(const struct reg * reg)122 static inline u32 reg_offset(const struct reg *reg)
123 {
124 return reg ? reg->offset : 0;
125 }
126
127 /* Returns 0 for NULL reg; warning should have already been issued */
reg_n_offset(const struct reg * reg,u32 n)128 static inline u32 reg_n_offset(const struct reg *reg, u32 n)
129 {
130 return reg ? reg->offset + n * reg->stride : 0;
131 }
132
133 #endif /* _REG_H_ */
134