Add support for MMIO UART console (#300)

8/16/32-bit MMIO supported, with configuration options as kernel parameters.
This commit is contained in:
Sam Demeulemeester 2023-05-12 15:49:00 +02:00 committed by GitHub
parent acea409a51
commit 9e3958714b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 24 deletions

View File

@ -162,6 +162,12 @@ recognised:
* 57600
* 115200 (default if not specified or invalid)
* 230400
* console=*x*,*y*
* activate MMIO UART console, where *x* is the MMIO stride (reg. width)
* mmio = 8-bit MMIO
* mmio16 = 16-bit MMIO
* mmio32 = 32-bit MMIO
* and *y* is the MMIO address in hex. with `0x` prefix (eg: 0xFEDC9000)
## Keyboard Selection

View File

@ -104,11 +104,14 @@ bool pause_at_start = true;
power_save_t power_save = POWER_SAVE_HIGH;
bool enable_tty = false;
int tty_params_port = SERIAL_PORT_0x3F8;
int tty_params_baud = SERIAL_DEFAULT_BAUDRATE;
uintptr_t tty_address = 0x3F8; // Legacy IO or MMIO Address accepted
int tty_baud_rate = 115200;
int tty_update_period = 2; // Update TTY every 2 seconds (default)
bool err_banner_redraw = false; // Redraw banner on new errors (if previsouly removed)
uint32_t tty_mmio_ref_clk = UART_REF_CLK_MMIO; // Reference clock for MMIO (in Hz)
int tty_mmio_stride = 4; // Stride for MMIO (register width in bytes)
bool err_banner_redraw = false; // Redraw banner on new errors
//------------------------------------------------------------------------------
// Private Functions
@ -123,6 +126,28 @@ static void parse_serial_params(const char *params)
return;
}
// Check if console is MMIO and grab address and stride
uintptr_t mmio_adr = 0;
if (strncmp(params, "mmio,0x", 7) == 0) {
mmio_adr = hexstr2int(params+7);
tty_mmio_stride = 1;
} else if (strncmp(params, "mmio16,0x", 9) == 0) {
mmio_adr = hexstr2int(params+9);
tty_mmio_stride = 2;
} else if (strncmp(params, "mmio32,0x", 9) == 0) {
mmio_adr = hexstr2int(params+9);
tty_mmio_stride = 4;
}
if(strncmp(params, "mmio", 4) == 0) {
if (mmio_adr > 0xFFFF) {
tty_address = mmio_adr;
} else {
enable_tty = false;
}
return;
}
// No TTY port passed, use default ttyS0
if (strncmp(params, "ttyS", 5) == 0) {
return;
@ -130,7 +155,7 @@ static void parse_serial_params(const char *params)
// Configure TTY port or use default
if (params[4] >= '0' && params[4] <= '3') {
tty_params_port = params[4] - '0';
tty_address = serial_io_ports[params[4] - '0'];
} else {
return;
}
@ -145,27 +170,27 @@ static void parse_serial_params(const char *params)
default:
return;
case '1':
tty_params_baud = (params[7] == '9') ? 19200 : 115200;
tty_baud_rate = (params[7] == '9') ? 19200 : 115200;
tty_update_period = (params[7] == '9') ? 4 : 2;
break;
case '2':
tty_params_baud = 230400;
tty_baud_rate = 230400;
tty_update_period = 2;
break;
case '3':
tty_params_baud = 38400;
tty_baud_rate = 38400;
tty_update_period = 4;
break;
case '5':
tty_params_baud = 57600;
tty_baud_rate = 57600;
tty_update_period = 3;
break;
case '7':
tty_params_baud = 76800;
tty_baud_rate = 76800;
tty_update_period = 3;
break;
case '9':
tty_params_baud = 9600;
tty_baud_rate = 9600;
tty_update_period = 5;
break;
}

View File

@ -64,10 +64,13 @@ extern bool pause_at_start;
extern power_save_t power_save;
extern int tty_params_port;
extern int tty_params_baud;
extern uintptr_t tty_address;
extern int tty_baud_rate;
extern int tty_update_period;
extern uint32_t tty_mmio_ref_clk;
extern int tty_mmio_stride;
extern bool err_banner_redraw;
void config_init(void);

View File

@ -9,6 +9,7 @@
// By Chris Brady
#include <stddef.h>
#include <stdint.h>
#include "string.h"
@ -92,3 +93,18 @@ char *itoa(int num, char *str)
return str;
}
uint32_t hexstr2int(const char *hexstr) {
uint32_t ival = 0;
while (*hexstr) {
uint8_t b = *hexstr++;
if (b >= '0' && b <= '9') b = b - '0';
else if (b >= 'a' && b <='f') b = b - 'a' + 10;
else if (b >= 'A' && b <='F') b = b - 'A' + 10;
else return 0;
ival = (ival << 4) | (b & 0xF);
}
return ival;
}

View File

@ -96,4 +96,11 @@ char *strstr(const char *haystack, const char *needle);
char *itoa(int num, char *str);
/**
* Convert a hex string to the corresponding 32-bit uint value.
* returns 0 if a non-hex char is found (not 0-9/a-f/A-F).
*/
uint32_t hexstr2int(const char *hexstr);
#endif // STRING_H

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2004-2022 Sam Demeulemeester
// Copyright (C) 2004-2023 Sam Demeulemeester
#include <stdbool.h>
#include <stddef.h>
@ -101,13 +101,21 @@ void tty_init(void)
unsigned char lcr;
console_serial.enable = true;
console_serial.is_mmio = false;
console_serial.base_addr = tty_address;
console_serial.baudrate = tty_baud_rate;
console_serial.parity = SERIAL_DEFAULT_PARITY;
console_serial.bits = SERIAL_DEFAULT_BITS;
console_serial.baudrate = tty_params_baud;
// UART MMIO Address is usually above TOLUD and never < 1MB
if (console_serial.base_addr > 0xFFFF) {
console_serial.is_mmio = true;
console_serial.reg_width = tty_mmio_stride;
console_serial.refclk = tty_mmio_ref_clk;
} else {
console_serial.is_mmio = false;
console_serial.reg_width = 1;
console_serial.refclk = UART_REF_CLK;
console_serial.base_addr = serial_base_ports[tty_params_port];
console_serial.refclk = UART_REF_CLK_IO;
}
/* read the Divisor Latch */
uart_status = serial_read_reg(&console_serial, UART_LCR);
@ -130,6 +138,12 @@ void tty_init(void)
uart_status = serial_read_reg(&console_serial, UART_RX); /* COM? RBR */
serial_write_reg(&console_serial, UART_IER, 0x00); /* Disable all interrupts */
/* In case of MMIO UART, set up FIFO Reg */
if (console_serial.is_mmio) {
serial_write_reg(&console_serial, UART_FCR, 0x00);
serial_write_reg(&console_serial, UART_FCR, (0xFF) & (UART_FCR_ENA | UART_FCR_THR));
}
tty_clear_screen();
tty_disable_cursor();
}

View File

@ -7,10 +7,9 @@
* display via Serial/UART.
*
*//*
* Copyright (C) 2004-2022 Sam Demeulemeester.
* Copyright (C) 2004-2023 Sam Demeulemeester.
*/
#define SERIAL_DEFAULT_BAUDRATE 115200
#define SERIAL_DEFAULT_BITS 8
#define SERIAL_DEFAULT_PARITY 0
@ -19,7 +18,7 @@
#define SERIAL_PORT_0x3E8 2
#define SERIAL_PORT_0x2E8 3
static const uint16_t serial_base_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static const uint16_t serial_io_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
struct serial_port {
bool enable;
@ -49,7 +48,8 @@ struct serial_port {
* Definitions for the Base UART Registers
*/
#define UART_REF_CLK 1843200
#define UART_REF_CLK_IO 1843200
#define UART_REF_CLK_MMIO 48000000
#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
@ -103,6 +103,12 @@ struct serial_port {
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
/*
* Definitions for the FIFO Control Register
*/
#define UART_FCR_ENA 0x01 /* FIFO Enable */
#define UART_FCR_THR 0x20 /* FIFO Threshold */
/*
* Definitions for the Interrupt Enable Register
*/