blob: c79de29b278b595fb645fb4c91914b081322be52 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HWREG_MMIO_H_
#define HWREG_MMIO_H_
#include <lib/mmio-ptr/mmio-ptr.h>
#include <cstdint>
#include <type_traits>
#include "internal.h"
namespace hwreg {
// This can be passed to ReadFrom and WriteTo methods. The RegisterAddr object holds an offset from
// an MMIO base address stored in this object.
//
// The template parameter defines a type meant to be used for MMIO operations (read/write).
// This implies that values are casted to and from |ForcedAccessType|. This affects register
// offsets as well, since offsets will be scaled with by |sizeof(ForcedAccessType)|.
//
// |ForcedAccessType = void| is a special case where unscaled and unconstrained MMIO operations are
// performed; that is no casting is performed between types and no scaling is applied to the
// offsets.
template <typename ForcedAccessType = void>
class RegisterMmioScaled {
public:
RegisterMmioScaled(volatile void* mmio) : mmio_(InitPtr(mmio)) {}
// Write |val| to the |sizeof(IntType)| byte field located |offset| bytes from
// |base()|.
template <typename IntType>
void Write(IntType val, uint32_t offset) {
static_assert(sizeof(IntType) <= sizeof(IoType<IntType>));
MmioWrite(static_cast<IoType<IntType>>(val), MmioPtr<IoType<IntType>>(offset));
}
// Read the value of the |sizeof(IntType)| byte field located |offset| bytes from
// |base()|.
template <typename IntType>
IntType Read(uint32_t offset) {
static_assert(sizeof(IntType) <= sizeof(IoType<IntType>));
return static_cast<IntType>(MmioRead(MmioPtr<const IoType<IntType>>(offset)));
}
uintptr_t base() const { return reinterpret_cast<uintptr_t>(mmio_); }
private:
static_assert(std::is_void_v<ForcedAccessType> ||
hwreg::internal::IsSupportedInt<ForcedAccessType>::value,
"Unsupported type.");
template <typename IntType>
using IoType = std::conditional_t<std::is_void_v<ForcedAccessType>, IntType, ForcedAccessType>;
static constexpr uint32_t kScale =
sizeof(std::conditional_t<std::is_void_v<ForcedAccessType>, char, ForcedAccessType>);
MMIO_PTR volatile std::byte* InitPtr(volatile void* ptr) {
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
return reinterpret_cast<MMIO_PTR volatile std::byte*>(addr);
}
template <typename U>
MMIO_PTR volatile U* MmioPtr(uint32_t offset) {
using PtrType = MMIO_PTR volatile U*;
using IntType = std::remove_const_t<U>;
static_assert(internal::IsSupportedInt<IntType>::value, "unsupported register access width");
MMIO_PTR volatile std::byte* addr = mmio_ + (offset * kScale);
return reinterpret_cast<PtrType>(addr);
}
MMIO_PTR volatile std::byte* mmio_ = nullptr;
};
using RegisterMmio = RegisterMmioScaled<>;
static_assert(std::is_copy_constructible_v<RegisterMmio>);
} // namespace hwreg
#endif // HWREG_MMIO_H_