term/ns8250: Support more MMIO access sizes

It is common for PCI based UARTs to use larger than one byte access
sizes. This adds support for this and uses the information present
in SPCR accordingly.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Benjamin Herrenschmidt authored and Daniel Kiper committed 2023-01-19 17:39:04 +01:00
1 parent 7b192ec4cd
commit f5e1d23a18
3 files changed
+60 -6

No files matched your search

+50 -3
View File
@@ -42,7 +42,31 @@ ns8250_reg_read (struct grub_serial_port *port, grub_addr_t reg)
{
asm volatile("" : : : "memory");
if (port->mmio == true)
return *((volatile grub_uint8_t *) (port->mmio_base + reg));
{
/*
* Note: we assume MMIO UARTs are little endian. This is not true of all
* embedded platforms but will do for now.
*/
switch(port->access_size)
{
default:
/* ACPI tables occasionally uses "0" (legacy) as equivalent to "1" (byte). */
case 1:
return *((volatile grub_uint8_t *) (port->mmio_base + reg));
case 2:
return grub_le_to_cpu16 (*((volatile grub_uint16_t *) (port->mmio_base + (reg << 1))));
case 3:
return grub_le_to_cpu32 (*((volatile grub_uint32_t *) (port->mmio_base + (reg << 2))));
case 4:
/*
* This will only work properly on 64-bit systems since 64-bit
* accessors aren't atomic on 32-bit hardware. Thankfully the
* case of a UART with a 64-bit register spacing on 32-bit
* also probably doesn't exist.
*/
return grub_le_to_cpu64 (*((volatile grub_uint64_t *) (port->mmio_base + (reg << 3))));
}
}
return grub_inb (port->port + reg);
}
@@ -51,7 +75,26 @@ ns8250_reg_write (struct grub_serial_port *port, grub_uint8_t value, grub_addr_t
{
asm volatile("" : : : "memory");
if (port->mmio == true)
*((volatile grub_uint8_t *) (port->mmio_base + reg)) = value;
{
switch(port->access_size)
{
default:
/* ACPI tables occasionally uses "0" (legacy) as equivalent to "1" (byte). */
case 1:
*((volatile grub_uint8_t *) (port->mmio_base + reg)) = value;
break;
case 2:
*((volatile grub_uint16_t *) (port->mmio_base + (reg << 1))) = grub_cpu_to_le16 (value);
break;
case 3:
*((volatile grub_uint32_t *) (port->mmio_base + (reg << 2))) = grub_cpu_to_le32 (value);
break;
case 4:
/* See commment in ns8250_reg_read(). */
*((volatile grub_uint64_t *) (port->mmio_base + (reg << 3))) = grub_cpu_to_le64 (value);
break;
}
}
else
grub_outb (value, port->port + reg);
}
@@ -286,6 +329,7 @@ grub_ns8250_init (void)
grub_print_error ();
grub_serial_register (&com_ports[i]);
com_ports[i].access_size = 1;
}
}
@@ -340,6 +384,7 @@ grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config
p->driver = &grub_ns8250_driver;
p->mmio = false;
p->port = port;
p->access_size = 1;
if (config != NULL)
grub_serial_port_configure (p, config);
else
@@ -350,7 +395,8 @@ grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config
}
char *
grub_serial_ns8250_add_mmio (grub_addr_t addr, struct grub_serial_config *config)
grub_serial_ns8250_add_mmio (grub_addr_t addr, unsigned int acc_size,
struct grub_serial_config *config)
{
struct grub_serial_port *p;
unsigned i;
@@ -375,6 +421,7 @@ grub_serial_ns8250_add_mmio (grub_addr_t addr, struct grub_serial_config *config
p->driver = &grub_ns8250_driver;
p->mmio = true;
p->mmio_base = addr;
p->access_size = acc_size;
if (config != NULL)
grub_serial_port_configure (p, config);
else