summaryrefslogtreecommitdiffstats
path: root/src/arch/riscv/include/ipxe/riscv_io.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/riscv/include/ipxe/riscv_io.h')
-rw-r--r--src/arch/riscv/include/ipxe/riscv_io.h141
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 */