blob: 9a146a2fbfe10eb8f06267744996748f152e4e79 [file] [log] [blame]
/*
* Copyright 2019 The Hafnium Authors.
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/BSD-3-Clause.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "hf/arch/barriers.h"
#include "hf/check.h"
/* Opaque types for different sized fields of memory mapped IO. */
typedef struct {
volatile uint8_t *ptr;
} io8_t;
typedef struct {
volatile uint16_t *ptr;
} io16_t;
typedef struct {
volatile uint32_t *ptr;
} io32_t;
typedef struct {
volatile uint64_t *ptr;
} io64_t;
typedef struct {
volatile uint8_t *base;
size_t count;
} io8_array_t;
typedef struct {
volatile uint16_t *base;
size_t count;
} io16_array_t;
typedef struct {
volatile uint32_t *base;
size_t count;
} io32_array_t;
typedef struct {
volatile uint64_t *base;
size_t count;
} io64_array_t;
/* Contructors for literals. */
#define IO8_C(addr) ((io8_t){.ptr = (volatile uint8_t *)(addr)})
#define IO16_C(addr) ((io16_t){.ptr = (volatile uint16_t *)(addr)})
#define IO32_C(addr) ((io32_t){.ptr = (volatile uint32_t *)(addr)})
#define IO64_C(addr) ((io64_t){.ptr = (volatile uint64_t *)(addr)})
#define IO8_ARRAY_C(addr, cnt) \
((io8_array_t){.base = (volatile uint8_t *)(addr), .count = (cnt)})
#define IO16_ARRAY_C(addr, cnt) \
((io16_array_t){.base = (volatile uint16_t *)(addr), .count = (cnt)})
#define IO32_ARRAY_C(addr, cnt) \
((io32_array_t){.base = (volatile uint32_t *)(addr), .count = (cnt)})
#define IO64_ARRAY_C(addr, cnt) \
((io64_array_t){.base = (volatile uint64_t *)(addr), .count = (cnt)})
/** Read from memory-mapped IO. */
static inline uint8_t io_read8(io8_t io)
{
return *io.ptr;
}
static inline uint16_t io_read16(io16_t io)
{
return *io.ptr;
}
static inline uint32_t io_read32(io32_t io)
{
return *io.ptr;
}
static inline uint64_t io_read64(io64_t io)
{
return *io.ptr;
}
static inline uint8_t io_read8_array(io8_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint16_t io_read16_array(io16_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint32_t io_read32_array(io32_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
static inline uint64_t io_read64_array(io64_array_t io, size_t n)
{
CHECK(n < io.count);
return io.base[n];
}
/**
* Read from memory-mapped IO with memory barrier.
*
* The read is ordered before subsequent memory accesses.
*/
static inline uint8_t io_read8_mb(io8_t io)
{
uint8_t v = io_read8(io);
data_sync_barrier();
return v;
}
static inline uint16_t io_read16_mb(io16_t io)
{
uint16_t v = io_read16(io);
data_sync_barrier();
return v;
}
static inline uint32_t io_read32_mb(io32_t io)
{
uint32_t v = io_read32(io);
data_sync_barrier();
return v;
}
static inline uint64_t io_read64_mb(io64_t io)
{
uint64_t v = io_read64(io);
data_sync_barrier();
return v;
}
static inline uint8_t io_read8_array_mb(io8_array_t io, size_t n)
{
uint8_t v = io_read8_array(io, n);
data_sync_barrier();
return v;
}
static inline uint16_t io_read16_array_mb(io16_array_t io, size_t n)
{
uint16_t v = io_read16_array(io, n);
data_sync_barrier();
return v;
}
static inline uint32_t io_read32_array_mb(io32_array_t io, size_t n)
{
uint32_t v = io_read32_array(io, n);
data_sync_barrier();
return v;
}
static inline uint64_t io_read64_array_mb(io64_array_t io, size_t n)
{
uint64_t v = io_read64_array(io, n);
data_sync_barrier();
return v;
}
/* Write to memory-mapped IO. */
static inline void io_write8(io8_t io, uint8_t v)
{
*io.ptr = v;
}
static inline void io_write16(io16_t io, uint16_t v)
{
*io.ptr = v;
}
static inline void io_write32(io32_t io, uint32_t v)
{
*io.ptr = v;
}
static inline void io_write64(io64_t io, uint64_t v)
{
*io.ptr = v;
}
static inline void io_clrbits32(io32_t io, uint32_t clear)
{
io_write32(io, io_read32(io) & ~clear);
}
static inline void io_setbits32(io32_t io, uint32_t set)
{
io_write32(io, io_read32(io) | set);
}
static inline void io_clrsetbits32(io32_t io, uint32_t clear, uint32_t set)
{
io_write32(io, (io_read32(io) & ~clear) | set);
}
static inline void io_write8_array(io8_array_t io, size_t n, uint8_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write16_array(io16_array_t io, size_t n, uint16_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write32_array(io32_array_t io, size_t n, uint32_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
static inline void io_write64_array(io64_array_t io, size_t n, uint64_t v)
{
CHECK(n < io.count);
io.base[n] = v;
}
/*
* Write to memory-mapped IO with memory barrier.
*
* The write is ordered after previous memory accesses.
*/
static inline void io_write8_mb(io8_t io, uint8_t v)
{
data_sync_barrier();
io_write8(io, v);
}
static inline void io_write16_mb(io16_t io, uint16_t v)
{
data_sync_barrier();
io_write16(io, v);
}
static inline void io_write32_mb(io32_t io, uint32_t v)
{
data_sync_barrier();
io_write32(io, v);
}
static inline void io_write64_mb(io64_t io, uint64_t v)
{
data_sync_barrier();
io_write64(io, v);
}
static inline void io_write8_array_mb(io8_array_t io, size_t n, uint8_t v)
{
data_sync_barrier();
io_write8_array(io, n, v);
}
static inline void io_write16_array_mb(io16_array_t io, size_t n, uint16_t v)
{
data_sync_barrier();
io_write16_array(io, n, v);
}
static inline void io_write32_array_mb(io32_array_t io, size_t n, uint32_t v)
{
data_sync_barrier();
io_write32_array(io, n, v);
}
static inline void io_write64_array_mb(io64_array_t io, size_t n, uint64_t v)
{
data_sync_barrier();
io_write64_array(io, n, v);
}