mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
serial: serial_octeon_bootcmd.c: Add PCI remote console support
This patch adds the PCI bootcmd feature for MIPS Octeon, which will be used by the upcoming Octeon III NIC23 board support. It enables the use of the "oct-remote-load" and "oct-remote-bootcmd" on host PC's to communicate with the PCIe target and load images into the onboard memory and issue commands. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Aaron Williams <awilliams@marvell.com> Cc: Chandrakala Chavva <cchavva@marvell.com> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
This commit is contained in:
parent
4dead10d02
commit
f1054661e5
3 changed files with 194 additions and 0 deletions
|
@ -788,6 +788,17 @@ config MSM_SERIAL
|
||||||
for example APQ8016 and MSM8916.
|
for example APQ8016 and MSM8916.
|
||||||
Single baudrate is supported in current implementation (115200).
|
Single baudrate is supported in current implementation (115200).
|
||||||
|
|
||||||
|
config OCTEON_SERIAL_BOOTCMD
|
||||||
|
bool "MIPS Octeon PCI remote bootcmd input"
|
||||||
|
depends on ARCH_OCTEON
|
||||||
|
depends on DM_SERIAL
|
||||||
|
select SYS_IS_IN_ENV
|
||||||
|
select CONSOLE_MUX
|
||||||
|
help
|
||||||
|
This driver supports remote input over the PCIe bus from a host
|
||||||
|
to U-Boot for entering commands. It is utilized by the host
|
||||||
|
commands 'oct-remote-load' and 'oct-remote-bootcmd'.
|
||||||
|
|
||||||
config OCTEON_SERIAL_PCIE_CONSOLE
|
config OCTEON_SERIAL_PCIE_CONSOLE
|
||||||
bool "MIPS Octeon PCIe remote console"
|
bool "MIPS Octeon PCIe remote console"
|
||||||
depends on ARCH_OCTEON
|
depends on ARCH_OCTEON
|
||||||
|
|
|
@ -66,6 +66,7 @@ obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
|
||||||
obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o
|
obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o
|
||||||
obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o
|
obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o
|
||||||
obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
|
obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
|
||||||
|
obj-$(CONFIG_OCTEON_SERIAL_BOOTCMD) += serial_octeon_bootcmd.o
|
||||||
obj-$(CONFIG_OCTEON_SERIAL_PCIE_CONSOLE) += serial_octeon_pcie_console.o
|
obj-$(CONFIG_OCTEON_SERIAL_PCIE_CONSOLE) += serial_octeon_pcie_console.o
|
||||||
obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
|
obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
|
||||||
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
|
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
|
||||||
|
|
182
drivers/serial/serial_octeon_bootcmd.c
Normal file
182
drivers/serial/serial_octeon_bootcmd.c
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Marvell International Ltd.
|
||||||
|
* Copyright (C) 2021 Stefan Roese <sr@denx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dm/uclass.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <input.h>
|
||||||
|
#include <iomux.h>
|
||||||
|
#include <log.h>
|
||||||
|
#include <serial.h>
|
||||||
|
#include <stdio_dev.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <watchdog.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <asm/addrspace.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <mach/cvmx-regs.h>
|
||||||
|
#include <mach/cvmx-bootmem.h>
|
||||||
|
|
||||||
|
#define DRIVER_NAME "pci-bootcmd"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Important:
|
||||||
|
* This address cannot be changed as the PCI console tool relies on exactly
|
||||||
|
* this value!
|
||||||
|
*/
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_BASE 0x6c000
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_SIZE 256
|
||||||
|
#define BOOTLOADER_PCI_WRITE_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_STR_LEN \
|
||||||
|
(BOOTLOADER_PCI_READ_BUFFER_SIZE - 8)
|
||||||
|
#define BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN \
|
||||||
|
(BOOTLOADER_PCI_WRITE_BUFFER_SIZE - 8)
|
||||||
|
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR \
|
||||||
|
(BOOTLOADER_PCI_READ_BUFFER_BASE + 0)
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR \
|
||||||
|
(BOOTLOADER_PCI_READ_BUFFER_BASE + 4)
|
||||||
|
#define BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR \
|
||||||
|
(BOOTLOADER_PCI_READ_BUFFER_BASE + 8)
|
||||||
|
|
||||||
|
enum octeon_pci_io_buf_owner {
|
||||||
|
/* Must be zero, set when memory cleared */
|
||||||
|
OCTEON_PCI_IO_BUF_OWNER_INVALID = 0,
|
||||||
|
OCTEON_PCI_IO_BUF_OWNER_OCTEON = 1,
|
||||||
|
OCTEON_PCI_IO_BUF_OWNER_HOST = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure for bootloader PCI IO buffers */
|
||||||
|
struct octeon_pci_io_buf {
|
||||||
|
u32 owner;
|
||||||
|
u32 len;
|
||||||
|
char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct octeon_bootcmd_priv {
|
||||||
|
bool started;
|
||||||
|
int copy_offset;
|
||||||
|
bool eol;
|
||||||
|
bool unlocked;
|
||||||
|
struct octeon_pci_io_buf *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int octeon_bootcmd_pending(struct udevice *dev, bool input)
|
||||||
|
{
|
||||||
|
struct octeon_bootcmd_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
if (!input)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (priv->eol)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
CVMX_SYNC;
|
||||||
|
if (priv->buf->owner != OCTEON_PCI_IO_BUF_OWNER_OCTEON)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (priv->buf->len > priv->copy_offset &&
|
||||||
|
(priv->buf->data[priv->copy_offset] != '\0'))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int octeon_bootcmd_getc(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct octeon_bootcmd_priv *priv = dev_get_priv(dev);
|
||||||
|
char c;
|
||||||
|
|
||||||
|
/* There's no EOL for boot commands so we fake it. */
|
||||||
|
if (priv->eol) {
|
||||||
|
priv->eol = false;
|
||||||
|
return '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!octeon_bootcmd_pending(dev, true)) {
|
||||||
|
WATCHDOG_RESET();
|
||||||
|
/*
|
||||||
|
* ToDo:
|
||||||
|
* The original code calls octeon_board_poll() here. We may
|
||||||
|
* need to implement something similar here.
|
||||||
|
*/
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = priv->buf->data[priv->copy_offset];
|
||||||
|
priv->buf->data[priv->copy_offset++] = '\0';
|
||||||
|
|
||||||
|
if (priv->copy_offset >= min_t(int, CONFIG_SYS_CBSIZE - 1,
|
||||||
|
BOOTLOADER_PCI_READ_BUFFER_STR_LEN - 1) ||
|
||||||
|
(priv->buf->data[priv->copy_offset] == '\0')) {
|
||||||
|
priv->copy_offset = 0;
|
||||||
|
priv->buf->len = 0;
|
||||||
|
priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST;
|
||||||
|
priv->eol = true;
|
||||||
|
CVMX_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dm_serial_ops octeon_bootcmd_ops = {
|
||||||
|
.getc = octeon_bootcmd_getc,
|
||||||
|
.pending = octeon_bootcmd_pending,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int octeon_bootcmd_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct octeon_bootcmd_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
priv->buf = (void *)CKSEG0ADDR(BOOTLOADER_PCI_READ_BUFFER_BASE);
|
||||||
|
memset(priv->buf, 0, BOOTLOADER_PCI_READ_BUFFER_SIZE);
|
||||||
|
priv->eol = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the bootcmd console is first started it is started as locked to
|
||||||
|
* block any calls sending a command until U-Boot is ready to accept
|
||||||
|
* commands. Just before the main loop starts to accept commands the
|
||||||
|
* bootcmd console is unlocked.
|
||||||
|
*/
|
||||||
|
if (priv->unlocked)
|
||||||
|
priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST;
|
||||||
|
else
|
||||||
|
priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_OCTEON;
|
||||||
|
|
||||||
|
debug("%s called, buffer ptr: 0x%p, owner: %s\n", __func__,
|
||||||
|
priv->buf,
|
||||||
|
priv->buf->owner == OCTEON_PCI_IO_BUF_OWNER_HOST ?
|
||||||
|
"host" : "octeon");
|
||||||
|
debug("&priv->copy_offset: 0x%p\n", &priv->copy_offset);
|
||||||
|
CVMX_SYNC;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perhaps reinvestige this: In the original code, "unlocked" etc
|
||||||
|
* is set in the octeon_pci_bootcmd_unlock() function called very
|
||||||
|
* late.
|
||||||
|
*/
|
||||||
|
priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST;
|
||||||
|
priv->unlocked = true;
|
||||||
|
priv->started = true;
|
||||||
|
CVMX_SYNC;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id octeon_bootcmd_serial_id[] = {
|
||||||
|
{ .compatible = "marvell,pci-bootcmd", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(octeon_bootcmd) = {
|
||||||
|
.name = DRIVER_NAME,
|
||||||
|
.id = UCLASS_SERIAL,
|
||||||
|
.ops = &octeon_bootcmd_ops,
|
||||||
|
.of_match = of_match_ptr(octeon_bootcmd_serial_id),
|
||||||
|
.probe = octeon_bootcmd_probe,
|
||||||
|
.priv_auto = sizeof(struct octeon_bootcmd_priv),
|
||||||
|
};
|
Loading…
Reference in a new issue