Skip to content
Permalink
Browse files
early_tcu
  • Loading branch information
Thierry Reding committed Mar 19, 2021
1 parent b740f32 commit f3d8000cf65d974c4b59bdb20f72a7b2af0260de
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
@@ -309,6 +309,18 @@ config SERIAL_TEGRA_TCU_CONSOLE

If unsure, say Y.

config SERIAL_TEGRA_TCU_EARLYCON
bool "Earlycon on NVIDIA Tegra Combined UART"
depends on ARCH_TEGRA || COMPILE_TEST
select SERIAL_EARLYCON
select SERIAL_CORE_CONSOLE
default y if SERIAL_TEGRA_TCU_CONSOLE
help
If you say Y here, TCU output will be supported during the earlycon
phase of the boot.

If unsure, say Y.

config SERIAL_MAX3100
tristate "MAX3100 support"
depends on SPI
@@ -70,6 +70,7 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
obj-$(CONFIG_SERIAL_TEGRA_TCU_EARLYCON) += tegra-tcu-earlycon.o
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved.
*/

#include <linux/console.h>
#include <linux/io.h>
#include <linux/serial_core.h>

#define NUM_BYTES_FIELD_BIT 24
#define FLUSH_BIT 26
#define INTR_TRIGGER_BIT 31

static u32 update_and_send_mbox(u8 __iomem *addr, u32 mbox_val, char c)
{
int bytes = bytes = (mbox_val >> NUM_BYTES_FIELD_BIT) & 0x3;

mbox_val |= BIT(INTR_TRIGGER_BIT);
mbox_val |= c << (bytes * 8);
bytes++;
mbox_val = (mbox_val & ~(3 << NUM_BYTES_FIELD_BIT)) |
(bytes << NUM_BYTES_FIELD_BIT);

if (bytes == 3) {
/* Send current packet to SPE */
while (readl(addr) & BIT(INTR_TRIGGER_BIT))
cpu_relax();
writel(mbox_val, addr);
mbox_val = BIT(INTR_TRIGGER_BIT);
}

return mbox_val;
}

/*
* This function splits the string to be printed (const char *s) into multiple
* packets. Each packet contains a max of 3 characters. Packets are sent to the
* SPE-based combined UART server for printing. Communication with SPE is done
* through mailbox registers which can generate interrupts for SPE.
*/
static void early_tcu_write(struct console *console, const char *s, unsigned int count)
{
struct earlycon_device *device = console->data;
u8 __iomem *addr = device->port.membase;
u32 mbox_val = BIT(INTR_TRIGGER_BIT);
unsigned int i;

/* Loop for processing each 3 char packet */
for (i = 0; i < count; i++) {
if (s[i] == '\n')
mbox_val = update_and_send_mbox(addr, mbox_val, '\r');
mbox_val = update_and_send_mbox(addr, mbox_val, s[i]);
}

if ((mbox_val >> NUM_BYTES_FIELD_BIT) & 0x3) {
while (readl(addr) & BIT(INTR_TRIGGER_BIT))
cpu_relax();
writel(mbox_val, addr);
}
}

int __init early_tegra_combined_uart_setup(struct earlycon_device *device, const char *options)
{
if (!(device->port.membase))
return -ENODEV;

device->con->write = early_tcu_write;

return 0;
}

EARLYCON_DECLARE(tegra_comb_uart, early_tegra_combined_uart_setup);

0 comments on commit f3d8000

Please sign in to comment.