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