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