mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-27 08:50:17 +00:00
hv_vuart: Implement RX & enough to support Linux
This works to get to a serial shell on Linux, and to use m1n1-as-LV1 proxyclient with M1N1DEVICE=/dev/m1n1-sec Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
4b4ae3ab90
commit
017f050fff
8 changed files with 101 additions and 10 deletions
|
@ -983,7 +983,8 @@ class HV(Reloadable):
|
|||
|
||||
def map_vuart(self):
|
||||
zone = irange(0x2_35200000, 0x4000)
|
||||
self.p.hv_map_vuart(0x2_35200000, getattr(IODEV, self.iodev.name + "_SEC"))
|
||||
irq = 605
|
||||
self.p.hv_map_vuart(0x2_35200000, irq, getattr(IODEV, self.iodev.name + "_SEC"))
|
||||
self.add_tracer(zone, "VUART", TraceMode.RESERVED)
|
||||
|
||||
def map_essential(self):
|
||||
|
|
|
@ -951,8 +951,8 @@ class M1N1Proxy(Reloadable):
|
|||
return self.request(self.P_HV_TRANSLATE, addr, s1, w)
|
||||
def hv_pt_walk(self, addr):
|
||||
return self.request(self.P_HV_PT_WALK, addr)
|
||||
def hv_map_vuart(self, base, iodev):
|
||||
return self.request(self.P_HV_MAP_VUART, base, iodev)
|
||||
def hv_map_vuart(self, base, irq, iodev):
|
||||
return self.request(self.P_HV_MAP_VUART, base, irq, iodev)
|
||||
def hv_trace_irq(self, evt_type, num, count, flags):
|
||||
return self.request(self.P_HV_TRACE_IRQ, evt_type, num, count, flags)
|
||||
|
||||
|
|
1
src/hv.c
1
src/hv.c
|
@ -147,4 +147,5 @@ void hv_tick(u64 *regs)
|
|||
iodev_handle_events(uartproxy_iodev);
|
||||
if (iodev_can_read(uartproxy_iodev))
|
||||
hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL);
|
||||
hv_vuart_poll();
|
||||
}
|
||||
|
|
3
src/hv.h
3
src/hv.h
|
@ -59,7 +59,8 @@ bool hv_pa_rw(u64 addr, u64 *val, bool write, int width);
|
|||
bool hv_trace_irq(u32 type, u32 num, u32 count, u32 flags);
|
||||
|
||||
/* Virtual peripherals */
|
||||
void hv_map_vuart(u64 base, iodev_id_t iodev);
|
||||
void hv_vuart_poll(void);
|
||||
void hv_map_vuart(u64 base, int irq, iodev_id_t iodev);
|
||||
|
||||
/* Exceptions */
|
||||
void hv_exc_proxy(u64 *regs, uartproxy_boot_reason_t reason, uartproxy_exc_code_t type,
|
||||
|
|
|
@ -1,42 +1,123 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "hv.h"
|
||||
#include "aic.h"
|
||||
#include "uart.h"
|
||||
#include "uart_regs.h"
|
||||
|
||||
static iodev_id_t vuart_iodev;
|
||||
|
||||
bool handle_vuart(u64 addr, u64 *val, bool write, int width)
|
||||
bool active = false;
|
||||
|
||||
u32 ucon = 0;
|
||||
u32 utrstat = 0;
|
||||
u32 ufstat = 0;
|
||||
|
||||
int vuart_irq = 0;
|
||||
|
||||
static void update_irq(void)
|
||||
{
|
||||
ssize_t rx_queued;
|
||||
|
||||
iodev_handle_events(vuart_iodev);
|
||||
|
||||
utrstat |= UTRSTAT_TXBE | UTRSTAT_TXE;
|
||||
utrstat &= ~UTRSTAT_RXD;
|
||||
|
||||
if ((rx_queued = iodev_can_read(vuart_iodev))) {
|
||||
utrstat |= UTRSTAT_RXD;
|
||||
if (rx_queued > 15)
|
||||
ufstat = FIELD_PREP(UFSTAT_RXCNT, 15) | UFSTAT_RXFULL;
|
||||
else
|
||||
ufstat = FIELD_PREP(UFSTAT_RXCNT, rx_queued);
|
||||
|
||||
if (FIELD_GET(UCON_RXMODE, ucon) == UCON_MODE_IRQ && ucon & UCON_RXTO_ENA) {
|
||||
utrstat |= UTRSTAT_RXTO;
|
||||
}
|
||||
}
|
||||
|
||||
if (FIELD_GET(UCON_TXMODE, ucon) == UCON_MODE_IRQ && ucon & UCON_TXTHRESH_ENA) {
|
||||
utrstat |= UTRSTAT_TXTHRESH;
|
||||
}
|
||||
|
||||
if (vuart_irq) {
|
||||
uart_clear_irqs();
|
||||
if (utrstat & (UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO)) {
|
||||
aic_set_sw(vuart_irq, true);
|
||||
} else {
|
||||
aic_set_sw(vuart_irq, false);
|
||||
}
|
||||
}
|
||||
|
||||
// printf("HV: vuart UTRSTAT=0x%x UFSTAT=0x%x UCON=0x%x\n", utrstat, ufstat, ucon);
|
||||
}
|
||||
|
||||
static bool handle_vuart(u64 addr, u64 *val, bool write, int width)
|
||||
{
|
||||
UNUSED(width);
|
||||
|
||||
addr &= 0xfff;
|
||||
|
||||
update_irq();
|
||||
|
||||
if (write) {
|
||||
// printf("HV: vuart W 0x%lx <- 0x%lx (%d)\n", addr, *val, width);
|
||||
switch (addr) {
|
||||
case UCON:
|
||||
ucon = *val;
|
||||
break;
|
||||
case UTXH: {
|
||||
uint8_t b = *val;
|
||||
if (iodev_can_write(vuart_iodev))
|
||||
iodev_write(vuart_iodev, &b, 1);
|
||||
break;
|
||||
}
|
||||
case UTRSTAT:
|
||||
utrstat &= ~(*val & (UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (addr) {
|
||||
case UCON:
|
||||
*val = ucon;
|
||||
break;
|
||||
case URXH:
|
||||
if (iodev_can_read(vuart_iodev)) {
|
||||
uint8_t c;
|
||||
iodev_read(vuart_iodev, &c, 1);
|
||||
*val = c;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
break;
|
||||
case UTRSTAT:
|
||||
*val = 0x06;
|
||||
*val = utrstat;
|
||||
break;
|
||||
case UFSTAT:
|
||||
*val = ufstat;
|
||||
break;
|
||||
default:
|
||||
*val = 0;
|
||||
break;
|
||||
}
|
||||
// printf("HV: vuart R 0x%lx -> 0x%lx (%d)\n", addr, *val, width);
|
||||
}
|
||||
|
||||
// printf("HV: vuart(0x%lx, 0x%lx, %d, %d)\n", addr, *val, write, width);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hv_map_vuart(u64 base, iodev_id_t iodev)
|
||||
void hv_vuart_poll(void)
|
||||
{
|
||||
if (!active)
|
||||
return;
|
||||
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void hv_map_vuart(u64 base, int irq, iodev_id_t iodev)
|
||||
{
|
||||
hv_map_hook(base, handle_vuart, 0x1000);
|
||||
vuart_iodev = iodev;
|
||||
vuart_irq = irq;
|
||||
active = true;
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
|||
reply->retval = hv_pt_walk(request->args[0]);
|
||||
break;
|
||||
case P_HV_MAP_VUART:
|
||||
hv_map_vuart(request->args[0], request->args[1]);
|
||||
hv_map_vuart(request->args[0], request->args[1], request->args[2]);
|
||||
break;
|
||||
case P_HV_TRACE_IRQ:
|
||||
reply->retval = hv_trace_irq(request->args[0], request->args[1], request->args[2],
|
||||
|
|
|
@ -90,6 +90,11 @@ void uart_flush(void)
|
|||
;
|
||||
}
|
||||
|
||||
void uart_clear_irqs(void)
|
||||
{
|
||||
write32(UART_BASE + UTRSTAT, UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO);
|
||||
}
|
||||
|
||||
int uart_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
|
|
@ -22,6 +22,8 @@ void uart_setbaud(int baudrate);
|
|||
|
||||
void uart_flush(void);
|
||||
|
||||
void uart_clear_irqs(void);
|
||||
|
||||
int uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue