1 /* Copyright 2019 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
4 #include <metal/machine/platform.h>
6 #ifdef METAL_SIFIVE_TRACE
8 #include <metal/drivers/sifive_trace.h>
9 #include <metal/machine.h>
11 #define TRACE_REG(offset) (((unsigned long)base + (offset)))
12 #define TRACE_REG8(offset) \
13 (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset)))
14 #define TRACE_REG16(offset) \
15 (__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset)))
16 #define TRACE_REG32(offset) \
17 (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset)))
19 static void write_itc_uint32(struct metal_uart *trace, uint32_t data) {
20 long base = __metal_driver_sifive_trace_base(trace);
22 TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data;
25 static void write_itc_uint16(struct metal_uart *trace, uint16_t data) {
26 long base = __metal_driver_sifive_trace_base(trace);
28 TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data;
31 static void write_itc_uint8(struct metal_uart *trace, uint8_t data) {
32 long base = __metal_driver_sifive_trace_base(trace);
34 TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data;
37 int __metal_driver_sifive_trace_putc(struct metal_uart *trace,
39 static uint32_t buffer = 0;
40 static int bytes_in_buffer = 0;
42 buffer |= (((uint32_t)c) << (bytes_in_buffer * 8));
46 if (bytes_in_buffer >= 4) {
47 write_itc_uint32(trace, buffer);
51 } else if ((c == '\n') || (c == '\r')) { // partial write
52 switch (bytes_in_buffer) {
53 case 3: // do a full word write
54 write_itc_uint16(trace, (uint16_t)(buffer));
55 write_itc_uint8(trace, (uint8_t)(buffer >> 16));
57 case 2: // do a 16 bit write
58 write_itc_uint16(trace, (uint16_t)buffer);
60 case 1: // do a 1 byte write
61 write_itc_uint8(trace, (uint8_t)buffer);
72 void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) {
73 // The only init we do here is to make sure ITC 0 is enabled. It is up to
74 // Freedom Studio or other mechanisms to make sure tracing is enabled. If we
75 // try to enable tracing here, it will likely conflict with Freedom Studio,
76 // and they will just fight with each other.
78 long base = __metal_driver_sifive_trace_base(trace);
80 TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001;
83 __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = {
84 .uart.init = __metal_driver_sifive_trace_init,
85 .uart.putc = __metal_driver_sifive_trace_putc,
88 .uart.get_baud_rate = NULL,
89 .uart.set_baud_rate = NULL,
91 .uart.controller_interrupt = NULL,
92 .uart.get_interrupt_id = NULL,
95 #endif /* METAL_SIFIVE_TRACE */