diff options
Diffstat (limited to 'src/arch/riscv/include/ipxe/riscv_io.h')
| -rw-r--r-- | src/arch/riscv/include/ipxe/riscv_io.h | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/arch/riscv/include/ipxe/riscv_io.h b/src/arch/riscv/include/ipxe/riscv_io.h new file mode 100644 index 000000000..539dbd7ed --- /dev/null +++ b/src/arch/riscv/include/ipxe/riscv_io.h @@ -0,0 +1,141 @@ +#ifndef _IPXE_RISCV_IO_H +#define _IPXE_RISCV_IO_H + +/** @file + * + * iPXE I/O API for RISC-V + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef IOAPI_RISCV +#define IOAPI_PREFIX_riscv +#else +#define IOAPI_PREFIX_riscv __riscv_ +#endif + +#include <ipxe/dummy_pio.h> + +/* + * Memory space mappings + * + */ + +/* + * Physical<->Bus address mappings + * + */ + +static inline __always_inline unsigned long +IOAPI_INLINE ( riscv, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( riscv, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; +} + +/* + * MMIO reads and writes + * + */ + +/* Single-register read */ +#define RISCV_READX( _suffix, _type, _insn_suffix ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \ + unsigned long data; \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "l" _insn_suffix " %0, %1\n\t" \ + : "=r" ( data ) : "m" ( *io_addr ) ); \ + return data; \ +} + +/* Single-register write */ +#define RISCV_WRITEX( _suffix, _type, _insn_suffix) \ +static inline __always_inline void \ +IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \ + volatile _type *io_addr ) { \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "s" _insn_suffix " %0, %1\n\t" \ + : : "r" ( data ), "m" ( *io_addr ) ); \ +} + +/* Double-register hopefully-fused read */ +#define RISCV_READX_FUSED( _suffix, _type, _insn_suffix ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \ + union { \ + unsigned long half[2]; \ + _type data; \ + } u; \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "l" _insn_suffix " %0, 0(%2)\n\t" \ + "l" _insn_suffix " %1, %3(%2)\n\t" \ + : "=&r" ( u.half[0] ), \ + "=&r" ( u.half[1] ) \ + : "r" ( io_addr ), \ + "i" ( sizeof ( u.half[0] ) ) ); \ + return u.data; \ +} + +/* Double-register hopefully-fused write */ +#define RISCV_WRITEX_FUSED( _suffix, _type, _insn_suffix ) \ +static inline __always_inline void \ +IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \ + volatile _type *io_addr ) { \ + union { \ + unsigned long half[2]; \ + _type data; \ + } u = { .data = data }; \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "s" _insn_suffix " %0, 0(%2)\n\t" \ + "s" _insn_suffix " %1, %3(%2)\n\t" : \ + : "r" ( u.half[0] ), \ + "r" ( u.half[1] ), \ + "r" ( io_addr ), \ + "i" ( sizeof ( u.half[0] ) ) ); \ +} + +RISCV_READX ( b, uint8_t, "bu" ); +RISCV_WRITEX ( b, uint8_t, "b" ); + +RISCV_READX ( w, uint16_t, "hu" ); +RISCV_WRITEX ( w, uint16_t, "h" ); + +#if __riscv_xlen > 32 + RISCV_READX ( l, uint32_t, "wu" ); + RISCV_WRITEX ( l, uint32_t, "w" ); +#else + RISCV_READX ( l, uint32_t, "w" ); + RISCV_WRITEX ( l, uint32_t, "w" ); +#endif + +#if __riscv_xlen >= 64 + #if __riscv_xlen > 64 + RISCV_READX ( q, uint64_t, "du" ); + RISCV_WRITEX ( q, uint64_t, "d" ); + #else + RISCV_READX ( q, uint64_t, "d" ); + RISCV_WRITEX ( q, uint64_t, "d" ); + #endif +#else + RISCV_READX_FUSED ( q, uint64_t, "w" ); + RISCV_WRITEX_FUSED ( q, uint64_t, "w" ); +#endif + +/* + * Memory barrier + * + */ +static inline __always_inline void +IOAPI_INLINE ( riscv, mb ) ( void ) { + __asm__ __volatile__ ( "fence" : : : "memory" ); +} + +/* Dummy PIO */ +DUMMY_PIO ( riscv ); + +#endif /* _IPXE_RISCV_IO_H */ |
