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 ®_value_; } reg_value_ptr()112 const ValueType* reg_value_ptr() const { return ®_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