1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <hwreg/internal.h>
8 #include <hwreg/mmio.h>
9 
10 #ifndef _KERNEL
11 #include <ddktl/mmio.h>
12 #endif
13 #include <limits.h>
14 #include <stdint.h>
15 #include <zircon/assert.h>
16 
17 // This file provides some helpers for accessing bitfields in registers.
18 //
19 // Example usage:
20 //
21 //   // Define bitfields for an "AuxControl" 32-bit register.
22 //   class AuxControl : public hwreg::RegisterBase<AuxControl, uint32_t> {
23 //   public:
24 //       // Define a single-bit field.
25 //       DEF_BIT(31, enabled);
26 //       // Define a 5-bit field, from bits 20-24 (inclusive).
27 //       DEF_FIELD(24, 20, message_size);
28 //
29 //       // Bits [30:25] and [19:0] are automatically preserved across RMW cycles
30 //
31 //       // Returns an object representing the register's type and address.
32 //       static auto Get() { return hwreg::RegisterAddr<AuxControl>(0x64010); }
33 //   };
34 //
35 //   void Example1(hwreg::RegisterIo* reg_io) {
36 //       // Read the register's value from MMIO.  "reg" is a snapshot of the
37 //       // register's value which also knows the register's address.
38 //       auto reg = AuxControl::Get().ReadFrom(reg_io);
39 //
40 //       // Read this register's "message_size" field.
41 //       uint32_t size = reg.message_size();
42 //
43 //       // Change this field's value.  This modifies the snapshot.
44 //       reg.set_message_size(1234);
45 //
46 //       // Write the modified register value to MMIO.
47 //       reg.WriteTo(reg_io);
48 //   }
49 //
50 //   // Fields may also be set in a fluent style
51 //   void Example2(hwreg::RegisterIo* reg_io) {
52 //       // Read the register's value from MMIO, updates the message size and
53 //       // enabled bit, then writes the value back to MMIO
54 //       AuxControl::Get().ReadFrom(reg_io).set_message_size(1234).set_enabled(1).WriteTo(reg_io);
55 //   }
56 //
57 //   // It is also possible to write a register without having to read it
58 //   // first:
59 //   void Example3(hwreg::RegisterIo* reg_io) {
60 //       // Start off with a value that is initialized to zero.
61 //       auto reg = AuxControl::Get().FromValue(0);
62 //       // Fill out fields.
63 //       reg.set_message_size(2345);
64 //       // Write the register value to MMIO.
65 //       reg.WriteTo(reg_io);
66 //   }
67 //
68 // Note that this produces efficient code with GCC and Clang, which are
69 // capable of optimizing away the intermediate objects.
70 //
71 // The arguments to DEF_FIELD() are organized to match up with Intel's
72 // documentation for their graphics hardware.  For example, if the docs
73 // specify a field as:
74 //   23:0  Data M value
75 // then that translates to:
76 //   DEF_FIELD(23, 0, data_m_value)
77 // To match up, we put the upper bit first and use an inclusive bit range.
78 
79 namespace hwreg {
80 
81 // Tag that can be passed as the third template parameter for RegisterBase to enable
82 // the pretty-printing interfaces on a register.
83 struct EnablePrinter;
84 
85 // An instance of RegisterBase represents a staging copy of a register,
86 // which can be written to the register itself.  It knows the register's
87 // address and stores a value for the register.
88 //
89 // Normal usage is to create classes that derive from RegisterBase and
90 // provide methods for accessing bitfields of the register.  RegisterBase
91 // does not provide a constructor because constructors are not inherited by
92 // derived classes by default, and we don't want the derived classes to
93 // have to declare constructors.
94 //
95 // Any bits not declared using DEF_FIELD/DEF_BIT/DEF_RSVDZ_FIELD/DEF_RSVDZ_BIT
96 // will be automatically preserved across RMW operations.
97 template <class DerivedType, class IntType, class PrinterState = void>
98 class RegisterBase {
99     static_assert(internal::IsSupportedInt<IntType>::value, "unsupported register access width");
100     static_assert(fbl::is_same<PrinterState, void>::value ||
101                   fbl::is_same<PrinterState, EnablePrinter>::value, "unsupported printer state");
102 public:
103     using SelfType = DerivedType;
104     using ValueType = IntType;
105     using PrinterEnabled = fbl::is_same<PrinterState, EnablePrinter>;
106 
reg_addr()107     uint32_t reg_addr() const { return reg_addr_; }
set_reg_addr(uint32_t addr)108     void set_reg_addr(uint32_t addr) { reg_addr_ = addr; }
109 
reg_value()110     ValueType reg_value() const { return reg_value_; }
reg_value_ptr()111     ValueType* reg_value_ptr() { return &reg_value_; }
reg_value_ptr()112     const ValueType* reg_value_ptr() const { return &reg_value_; }
set_reg_value(IntType value)113     SelfType& set_reg_value(IntType value) {
114         reg_value_ = value;
115         return *static_cast<SelfType*>(this);
116     }
117 
ReadFrom(RegisterIo * reg_io)118     SelfType& ReadFrom(RegisterIo* reg_io) {
119         reg_value_ = reg_io->Read<ValueType>(reg_addr_);
120         return *static_cast<SelfType*>(this);
121     }
122 #ifndef _KERNEL
ReadFrom(ddk::MmioBuffer * mmio)123     SelfType& ReadFrom(ddk::MmioBuffer* mmio) {
124         reg_value_ = mmio->Read<ValueType>(reg_addr_);
125         return *static_cast<SelfType*>(this);
126     }
127 #endif
128 
WriteTo(RegisterIo * reg_io)129     SelfType& WriteTo(RegisterIo* reg_io) {
130         reg_io->Write(reg_addr_, static_cast<IntType>(reg_value_ & ~rsvdz_mask_));
131         return *static_cast<SelfType*>(this);
132     }
133 #ifndef _KERNEL
WriteTo(ddk::MmioBuffer * mmio)134     SelfType& WriteTo(ddk::MmioBuffer* mmio) {
135         mmio->Write(static_cast<IntType>(reg_value_ & ~rsvdz_mask_), reg_addr_);
136         return *static_cast<SelfType*>(this);
137     }
138 #endif
139 
140     // Invokes print_fn(const char* buf) once for each field, including each
141     // RsvdZ field, and one extra time if there are any undefined bits set.
142     // The callback argument must not be accessed after the callback
143     // returns.  The callback will be called once for each field with a
144     // null-terminated string describing the name and contents of the field.
145     //
146     // Printed fields will look like: "field_name[26:8]: 0x00123 (291)"
147     // The undefined bits message will look like: "unknown set bits: 0x00301000"
148     //
149     // WARNING: This will substantially increase code size at the call site.
150     //
151     // Example use:
152     // reg.Print([](const char* arg) { printf("%s\n", arg); });
153     template <typename F>
Print(F print_fn)154     void Print(F print_fn) {
155         static_assert(PrinterEnabled::value, "Pass hwreg::EnablePrinter to RegisterBase to enable");
156         internal::PrintRegister(print_fn, printer_.fields, printer_.num_fields, reg_value_,
157                                 fields_mask_, sizeof(ValueType));
158     }
159 
160     // Equivalent to Print([](const char* arg) { printf("%s\n", arg); });
Print()161     void Print() {
162         static_assert(PrinterEnabled::value, "Pass hwreg::EnablePrinter to RegisterBase to enable");
163         internal::PrintRegisterPrintf(printer_.fields, printer_.num_fields, reg_value_,
164                                       fields_mask_, sizeof(ValueType));
165     }
166 
167 private:
168     friend internal::Field<SelfType>;
169     friend internal::RsvdZField<SelfType>;
170     ValueType rsvdz_mask_ = 0;
171     ValueType fields_mask_ = 0;
172 
173     uint32_t reg_addr_ = 0;
174     ValueType reg_value_ = 0;
175 
176     internal::FieldPrinterList<PrinterState, ValueType> printer_;
177 };
178 
179 // An instance of RegisterAddr represents a typed register address: It
180 // knows the address of the register (within the MMIO address space) and
181 // the type of its contents, RegType.  RegType represents the register's
182 // bitfields.  RegType should be a subclass of RegisterBase.
183 template <class RegType> class RegisterAddr {
184 public:
RegisterAddr(uint32_t reg_addr)185     RegisterAddr(uint32_t reg_addr) : reg_addr_(reg_addr) {}
186 
187     static_assert(fbl::is_base_of<RegisterBase<RegType,
188                                                typename RegType::ValueType>, RegType>::value ||
189                   fbl::is_base_of<RegisterBase<RegType,
190                                                typename RegType::ValueType,
191                                                EnablePrinter>, RegType>::value,
192                   "Parameter of RegisterAddr<> should derive from RegisterBase");
193 
194     // Instantiate a RegisterBase using the value of the register read from
195     // MMIO.
ReadFrom(RegisterIo * reg_io)196     RegType ReadFrom(RegisterIo* reg_io) {
197         RegType reg;
198         reg.set_reg_addr(reg_addr_);
199         reg.ReadFrom(reg_io);
200         return reg;
201     }
202 #ifndef _KERNEL
ReadFrom(ddk::MmioBuffer * mmio)203     RegType ReadFrom(ddk::MmioBuffer* mmio) {
204         RegType reg;
205         reg.set_reg_addr(reg_addr_);
206         reg.ReadFrom(mmio);
207         return reg;
208     }
209 #endif
210 
211     // Instantiate a RegisterBase using the given value for the register.
FromValue(typename RegType::ValueType value)212     RegType FromValue(typename RegType::ValueType value) {
213         RegType reg;
214         reg.set_reg_addr(reg_addr_);
215         reg.set_reg_value(value);
216         return reg;
217     }
218 
addr()219     uint32_t addr() const { return reg_addr_; }
220 
221 private:
222     const uint32_t reg_addr_;
223 };
224 
225 template <class IntType> class BitfieldRef {
226 public:
BitfieldRef(IntType * value_ptr,uint32_t bit_high_incl,uint32_t bit_low)227     BitfieldRef(IntType* value_ptr, uint32_t bit_high_incl, uint32_t bit_low)
228         : value_ptr_(value_ptr), shift_(bit_low),
229           mask_(internal::ComputeMask<IntType>(bit_high_incl - bit_low + 1)) {
230     }
231 
get()232     IntType get() const { return static_cast<IntType>((*value_ptr_ >> shift_) & mask_); }
233 
set(IntType field_val)234     void set(IntType field_val) {
235         static_assert(!fbl::is_const<IntType>::value, "");
236         ZX_DEBUG_ASSERT((field_val & ~mask_) == 0);
237         *value_ptr_ = static_cast<IntType>(*value_ptr_ & ~(mask_ << shift_));
238         *value_ptr_ = static_cast<IntType>(*value_ptr_ | (field_val << shift_));
239     }
240 
241 private:
242     IntType* const value_ptr_;
243     const uint32_t shift_;
244     const IntType mask_;
245 };
246 
247 // Declares multi-bit fields in a derived class of RegisterBase<D, T>.  This
248 // produces functions "T NAME() const" and "D& set_NAME(T)".  Both bit indices
249 // are inclusive.
250 #define DEF_FIELD(BIT_HIGH, BIT_LOW, NAME)                                                        \
251     static_assert((BIT_HIGH) >= (BIT_LOW), "Upper bit goes before lower bit");                    \
252     static_assert((BIT_HIGH) < sizeof(ValueType) * CHAR_BIT, "Upper bit is out of range");        \
253     hwreg::internal::Field<SelfType> Field ## BIT_HIGH ## _ ## BIT_LOW =                          \
254         hwreg::internal::Field<SelfType>(this, #NAME, (BIT_HIGH), (BIT_LOW));                     \
255     ValueType NAME() const {                                                                      \
256         return hwreg::BitfieldRef<const ValueType>(reg_value_ptr(), (BIT_HIGH), (BIT_LOW)).get(); \
257     }                                                                                             \
258     SelfType& set_ ## NAME(ValueType val) {                                                       \
259         hwreg::BitfieldRef<ValueType>(reg_value_ptr(), (BIT_HIGH), (BIT_LOW)).set(val);           \
260         return *this;                                                                             \
261     }
262 
263 // Declares single-bit fields in a derived class of RegisterBase<D, T>.  This
264 // produces functions "T NAME() const" and "void set_NAME(T)".
265 #define DEF_BIT(BIT, NAME) DEF_FIELD(BIT, BIT, NAME)
266 
267 // Declares multi-bit reserved-zero fields in a derived class of RegisterBase<D, T>.
268 // This will ensure that on RegisterBase<T>::WriteTo(), reserved-zero bits are
269 // automatically zeroed.  Both bit indices are inclusive.
270 #define DEF_RSVDZ_FIELD(BIT_HIGH, BIT_LOW)                                                        \
271     static_assert((BIT_HIGH) >= (BIT_LOW), "Upper bit goes before lower bit");                    \
272     static_assert((BIT_HIGH) < sizeof(ValueType) * CHAR_BIT, "Upper bit is out of range");        \
273     hwreg::internal::Field<SelfType> Field ## BIT_HIGH ## _ ## BIT_LOW =                          \
274         hwreg::internal::Field<SelfType>(this, "RsvdZ", (BIT_HIGH), (BIT_LOW));                   \
275     hwreg::internal::RsvdZField<SelfType> RsvdZ ## BIT_HIGH ## _ ## BIT_LOW =                     \
276         hwreg::internal::RsvdZField<SelfType>(this, (BIT_HIGH), (BIT_LOW));
277 
278 // Declares single-bit reserved-zero fields in a derived class of RegisterBase<D, T>.
279 // This will ensure that on RegisterBase<T>::WriteTo(), reserved-zero bits are
280 // automatically zeroed.
281 #define DEF_RSVDZ_BIT(BIT) DEF_RSVDZ_FIELD(BIT, BIT)
282 
283 // Declares "decltype(FIELD) NAME() const" and "void set_NAME(decltype(FIELD))" that
284 // reads/modifies the declared bitrange.  Both bit indices are inclusive.
285 #define DEF_SUBFIELD(FIELD, BIT_HIGH, BIT_LOW, NAME)                                              \
286     static_assert(hwreg::internal::IsSupportedInt<                                                \
287                       typename fbl::remove_reference<decltype(FIELD)>::type>::value,              \
288                   #FIELD " has unsupported type");                                                \
289     static_assert((BIT_HIGH) >= (BIT_LOW), "Upper bit goes before lower bit");                    \
290     static_assert((BIT_HIGH) < sizeof(decltype(FIELD)) * CHAR_BIT, "Upper bit is out of range");  \
291     typename fbl::remove_reference<decltype(FIELD)>::type NAME() const {                          \
292         return hwreg::BitfieldRef<const typename fbl::remove_reference<decltype(FIELD)>::type>(   \
293             &FIELD, (BIT_HIGH), (BIT_LOW)).get();                                                 \
294     }                                                                                             \
295     void set_ ## NAME(typename fbl::remove_reference<decltype(FIELD)>::type val) {                \
296         hwreg::BitfieldRef<typename fbl::remove_reference<decltype(FIELD)>::type>(                \
297                 &FIELD, (BIT_HIGH), (BIT_LOW)).set(val);                                          \
298     }
299 
300 // Declares "decltype(FIELD) NAME() const" and "void set_NAME(decltype(FIELD))" that
301 // reads/modifies the declared bit.
302 #define DEF_SUBBIT(FIELD, BIT, NAME) DEF_SUBFIELD(FIELD, BIT, BIT, NAME)
303 
304 } // namespace hwreg
305