blob: 30090c4b07f413da084b8ea5c75f72ebe6d90201 [file] [log] [blame] [edit]
#include <asm/alternative-macros.h>
#include <asm/barrier.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_pkvm_module.h>
#include <asm/io.h>
static unsigned long uart_addr;
static inline unsigned int __hyp_readw(void *ioaddr)
{
unsigned int val;
asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (ioaddr));
return val;
}
static inline void __hyp_writew(unsigned int val, void *ioaddr)
{
asm volatile("str %w0, [%1]" : : "r" (val), "r" (ioaddr));
}
static void pl011_hyp_putc(char c)
{
void *base = (void *)uart_addr;
unsigned int val;
do {
val = __hyp_readw(base + CONFIG_SERIAL_PKVM_PL011_UARTFR);
} while (val & (1U <<CONFIG_SERIAL_PKVM_PL011_FULL));
dmb(sy);
__hyp_writew(c, base + CONFIG_SERIAL_PKVM_PL011_UARTTX);
do {
val = __hyp_readw(base + CONFIG_SERIAL_PKVM_PL011_UARTFR);
} while (val & (1U << CONFIG_SERIAL_PKVM_PL011_BUSY));
dmb(sy);
}
int pl011_hyp_init(const struct pkvm_module_ops *ops)
{
int ret;
ret = ops->create_private_mapping(CONFIG_SERIAL_PKVM_PL011_BASE_PHYS, PAGE_SIZE,
PAGE_HYP_DEVICE, &uart_addr);
if (ret)
return ret;
ret = ops->register_serial_driver(pl011_hyp_putc);
if (ret)
return ret;
ops->puts("pKVM pl011 UART driver loaded");
return 0;
}