blob: 4293a44043ed1071121c1220548013e546bd6ccc [file] [log] [blame]
// Copyright 2018 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.
#pragma once
#include <string.h>
#include <ddk/debug.h>
#include <ddk/mmio-buffer.h>
#include <fbl/macros.h>
#include <fbl/type_support.h>
#include <fbl/unique_ptr.h>
#include <hw/arch_ops.h>
#include <lib/zx/bti.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
#include <zircon/process.h>
namespace ddk {
class MmioPinnedBuffer;
// MmioBuffer is wrapper around mmio_block_t.
class MmioBuffer {
public:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(MmioBuffer);
MmioBuffer(mmio_buffer_t& mmio)
: mmio_(mmio), ptr_(reinterpret_cast<uintptr_t>(mmio.vaddr)) {
ZX_ASSERT(mmio_.vaddr != nullptr);
}
~MmioBuffer() {
mmio_buffer_release(&mmio_);
}
MmioBuffer(MmioBuffer&& other) {
transfer(fbl::move(other));
}
MmioBuffer& operator=(MmioBuffer&& other) {
transfer(fbl::move(other));
return *this;
}
static zx_status_t Create(zx_off_t offset, size_t size, zx::vmo vmo, uint32_t cache_policy,
fbl::unique_ptr<MmioBuffer>* mmio_buffer) {
mmio_buffer_t mmio;
zx_status_t status = mmio_buffer_init(&mmio, offset, size, vmo.release(), cache_policy);
if (status == ZX_OK) {
*mmio_buffer = fbl::make_unique<MmioBuffer>(mmio);
}
return status;
}
void reset() {
memset(&mmio_, 0, sizeof(mmio_));
}
void Info() const {
zxlogf(INFO, "vaddr = %p\n", mmio_.vaddr);
zxlogf(INFO, "size = %lu\n", mmio_.size);
}
void* get() const {
return mmio_.vaddr;
}
zx_status_t Pin(const zx::bti& bti, fbl::unique_ptr<MmioPinnedBuffer>* pinned_buffer) {
mmio_pinned_buffer_t pinned;
zx_status_t status = mmio_buffer_pin(&mmio_, bti.get(), &pinned);
if (status == ZX_OK) {
*pinned_buffer = fbl::make_unique<MmioPinnedBuffer>(pinned);
}
return status;
}
// TODO: Consider removing the following in favor of hwreg::RegisterIo.
uint32_t Read32(zx_off_t offs) const {
return Read<uint32_t>(offs);
}
uint32_t ReadMasked32(uint32_t mask, zx_off_t offs) const {
return ReadMasked<uint32_t>(mask, offs);
}
void Write32(uint32_t val, zx_off_t offs) const {
Write<uint32_t>(val, offs);
}
void SetBits32(uint32_t mask, zx_off_t offs) const {
SetBits<uint32_t>(mask, offs);
}
void ClearBits32(uint32_t mask, zx_off_t offs) const {
ClearBits<uint32_t>(mask, offs);
}
private:
void transfer(MmioBuffer&& other) {
mmio_ = other.mmio_;
ptr_ = other.ptr_;
other.reset();
}
template <typename T>
T Read(zx_off_t offs) const {
ZX_DEBUG_ASSERT(offs + sizeof(T) < mmio_.size);
ZX_DEBUG_ASSERT(ptr_);
return *reinterpret_cast<volatile T*>(ptr_ + offs);
}
template <typename T>
T ReadMasked(T mask, zx_off_t offs) const {
return (Read<T>(offs) & mask);
}
template <typename T>
void Write(T val, zx_off_t offs) const {
ZX_DEBUG_ASSERT(offs + sizeof(T) < mmio_.size);
ZX_DEBUG_ASSERT(ptr_);
*reinterpret_cast<volatile T*>(ptr_ + offs) = val;
hw_mb();
}
template <typename T>
void SetBits(T mask, zx_off_t offs) const {
T val = Read<T>(offs);
Write<T>(val | mask, offs);
}
template <typename T>
void ClearBits(T mask, zx_off_t offs) const {
T val = Read<T>(offs);
Write<T>(val & ~mask, offs);
}
mmio_buffer_t mmio_;
uintptr_t ptr_;
};
// MmioPinnedBuffer is wrapper around mmio_pinned_buffer_t.
class MmioPinnedBuffer {
public:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(MmioPinnedBuffer);
MmioPinnedBuffer(mmio_pinned_buffer_t pinned)
: pinned_(pinned) {
ZX_ASSERT(pinned_.paddr != 0);
}
~MmioPinnedBuffer() {
mmio_buffer_unpin(&pinned_);
}
MmioPinnedBuffer(MmioPinnedBuffer&& other) {
transfer(fbl::move(other));
}
MmioPinnedBuffer& operator=(MmioPinnedBuffer&& other) {
transfer(fbl::move(other));
return *this;
}
void reset() {
memset(&pinned_, 0, sizeof(pinned_));
}
zx_paddr_t get_paddr() const {
return pinned_.paddr;
}
private:
void transfer(MmioPinnedBuffer&& other) {
pinned_ = other.pinned_;
other.reset();
}
mmio_pinned_buffer_t pinned_;
};
} //namespace ddk