[dm][serial] add new serial driver for DM
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled

1. 8250 serila family (OFW, PCI, DWC, early)
2. Virtual serial (by graphic and input)
3. HVC early serial
4. ARM PL011 serial

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2025-12-13 01:59:12 +08:00
committed by R b b666
parent 6394797471
commit 9a6d515e27
23 changed files with 4123 additions and 0 deletions

View File

@@ -0,0 +1,351 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-22 GuEe-GUI first version
*/
/*
* The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#include <rtthread.h>
#include "8250.h"
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DMASA 0xa8 /* DMA Software Ack */
#define OCTEON_UART_USR 0x27 /* UART Status Register */
#define RZN1_UART_TDMACR 0x10c /* DMA Control Register Transmit Mode */
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
#define DW_UART_MCR_SIRE RT_BIT(6)
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN RT_BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
#define RZN1_UART_xDMACR_4_WORD_BURST (1 << 1)
#define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
/* Quirks */
#define DW_UART_QUIRK_OCTEON RT_BIT(0)
#define DW_UART_QUIRK_ARMADA_38X RT_BIT(1)
#define DW_UART_QUIRK_SKIP_SET_RATE RT_BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC RT_BIT(3)
struct dw8250_platform_data
{
rt_uint8_t usr_reg;
rt_uint32_t cpr_val;
rt_uint32_t quirks;
};
struct dw8250
{
struct serial8250 parent;
struct rt_spinlock spinlock;
struct rt_clk *pclk;
rt_bool_t uart_16550_compatible;
struct dw8250_platform_data *platform_data;
};
#define to_dw8250(serial8250) rt_container_of(serial8250, struct dw8250, parent)
static void dw8250_check_lcr(struct serial8250 *serial, int value)
{
void *offset = (void *)(serial->base + (UART_LCR << serial->regshift));
int tries = 1000;
/* Make sure LCR write wasn't ignored */
while (tries--)
{
rt_uint32_t lcr = serial->serial_in(serial, UART_LCR);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
{
break;
}
serial->serial_out(serial, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial->serial_in(serial, UART_RX);
if (serial->iotype == PORT_MMIO32)
{
HWREG32(offset) = value;
}
else if (serial->iotype == PORT_MMIO32BE)
{
HWREG32(offset) = rt_cpu_to_be32(value);
}
else
{
HWREG8(offset) = value;
}
}
}
static void dw8250_serial_out32(struct serial8250 *serial, int offset, int value)
{
struct dw8250 *dw8250 = to_dw8250(serial);
HWREG32(serial->base + (offset << serial->regshift)) = value;
if (offset == UART_LCR && !dw8250->uart_16550_compatible)
{
dw8250_check_lcr(serial, value);
}
}
static rt_uint32_t dw8250_serial_in32(struct serial8250 *serial, int offset)
{
return HWREG32(serial->base + (offset << serial->regshift));
}
static rt_err_t dw8250_isr(struct serial8250 *serial, int irq)
{
unsigned int iir, status;
struct dw8250 *dw8250 = to_dw8250(serial);
iir = serial8250_in(serial, UART_IIR);
/*
* If don't do this in non-DMA mode then the "RX TIMEOUT" interrupt will
* fire forever.
*/
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT)
{
rt_base_t level = rt_spin_lock_irqsave(&dw8250->spinlock);
status = serial8250_in(serial, UART_LSR);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
{
serial8250_in(serial, UART_RX);
}
rt_spin_unlock_irqrestore(&dw8250->spinlock, level);
}
if (!(iir & UART_IIR_NO_INT))
{
rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND);
}
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY)
{
/* Clear the USR */
serial8250_in(serial, dw8250->platform_data->usr_reg);
}
return RT_EOK;
}
static void dw8250_free_resource(struct dw8250 *dw8250)
{
struct serial8250 *serial = &dw8250->parent;
if (serial->base)
{
rt_iounmap(serial->base);
}
if (!rt_is_err_or_null(serial->clk))
{
rt_clk_disable_unprepare(serial->clk);
rt_clk_put(serial->clk);
}
if (!rt_is_err_or_null(dw8250->pclk))
{
rt_clk_disable_unprepare(dw8250->pclk);
rt_clk_put(dw8250->pclk);
}
rt_free(dw8250);
}
static void dw8250_serial_remove(struct serial8250 *serial)
{
struct dw8250 *dw8250 = to_dw8250(serial);
dw8250_free_resource(dw8250);
}
static rt_err_t dw8250_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
rt_uint32_t val;
struct serial8250 *serial;
struct rt_device *dev = &pdev->parent;
struct dw8250 *dw8250 = serial8250_alloc(dw8250);
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
if (!dw8250)
{
return -RT_ENOMEM;
}
serial = &dw8250->parent;
serial->base = rt_dm_dev_iomap(dev, 0);
if (!serial->base)
{
err = -RT_EIO;
goto _free_res;
}
serial->irq = rt_dm_dev_get_irq(dev, 0);
if (serial->irq < 0)
{
err = serial->irq;
goto _free_res;
}
serial->clk = rt_clk_get_by_name(dev, "baudclk");
dw8250->pclk = rt_clk_get_by_name(dev, "apb_pclk");
if (rt_is_err_or_null(serial->clk))
{
if ((err = rt_dm_dev_prop_read_u32(dev, "clock-frequency", &serial->freq)))
{
goto _free_res;
}
}
else
{
if ((err = rt_clk_prepare_enable(serial->clk)))
{
goto _free_res;
}
serial->freq = rt_clk_get_rate(serial->clk);
}
if (rt_is_err(dw8250->pclk))
{
err = rt_ptr_err(dw8250->pclk);
goto _free_res;
}
if ((err = rt_clk_prepare_enable(dw8250->pclk)))
{
goto _free_res;
}
if (!rt_dm_dev_prop_read_u32(dev, "reg-io-width", &val) && val == 4)
{
serial->iotype = PORT_MMIO32;
serial->serial_in = &dw8250_serial_in32;
serial->serial_out = &dw8250_serial_out32;
}
dw8250->uart_16550_compatible = rt_dm_dev_prop_read_bool(dev, "snps,uart-16550-compatible");
dw8250->platform_data = (struct dw8250_platform_data *)pdev->id->data;
rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent);
dev->user_data = serial;
serial->parent.ops = &serial8250_uart_ops;
serial->parent.config = config;
serial->handle_irq = &dw8250_isr;
serial->remove = &dw8250_serial_remove;
serial->data = dw8250;
rt_spin_lock_init(&dw8250->spinlock);
if ((err = serial8250_setup(serial)))
{
goto _free_res;
}
return RT_EOK;
_free_res:
dw8250_free_resource(dw8250);
return err;
}
static rt_err_t dw8250_remove(struct rt_platform_device *pdev)
{
struct rt_device *dev = &pdev->parent;
struct serial8250 *serial = dev->user_data;
rt_dm_dev_unbind_fwdata(dev, RT_NULL);
return serial8250_remove(serial);
}
static const struct dw8250_platform_data dw8250_dw_apb =
{
.usr_reg = DW_UART_USR,
};
static const struct dw8250_platform_data dw8250_octeon_3860_data =
{
.usr_reg = OCTEON_UART_USR,
.quirks = DW_UART_QUIRK_OCTEON,
};
static const struct dw8250_platform_data dw8250_armada_38x_data =
{
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_ARMADA_38X,
};
static const struct dw8250_platform_data dw8250_renesas_rzn1_data =
{
.usr_reg = DW_UART_USR,
.cpr_val = 0x00012f32,
.quirks = DW_UART_QUIRK_IS_DMA_FC,
};
static const struct dw8250_platform_data dw8250_starfive_jh7100_data =
{
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
static const struct rt_ofw_node_id dw8250_ofw_ids[] =
{
{ .type = "ttyS", .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .type = "ttyS", .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .type = "ttyS", .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .type = "ttyS", .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
{ .type = "ttyS", .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data },
{ /* sentinel */ }
};
static struct rt_platform_driver dw8250_driver =
{
.name = "dw-apb-uart",
.ids = dw8250_ofw_ids,
.probe = dw8250_probe,
.remove = dw8250_remove,
};
static int dw8250_drv_register(void)
{
rt_platform_driver_register(&dw8250_driver);
return 0;
}
INIT_PLATFORM_EXPORT(dw8250_drv_register);

View File

@@ -0,0 +1,211 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-09 GuEe-GUI first version
*/
#include <rtthread.h>
#include "8250.h"
struct ofw_platform_8250
{
struct serial8250 parent;
struct rt_reset_control *rstc;
};
#define to_ofw_platform_8250(serial8250) rt_container_of(serial8250, struct ofw_platform_8250, parent)
static void ofw_platform_8250_free_resource(struct ofw_platform_8250 *op8250)
{
struct serial8250 *serial = &op8250->parent;
if (serial->base)
{
rt_iounmap(serial->base);
}
if (!rt_is_err_or_null(serial->clk))
{
rt_clk_disable_unprepare(serial->clk);
rt_clk_put(serial->clk);
}
if (!rt_is_err_or_null(op8250->rstc))
{
rt_reset_control_put(op8250->rstc);
}
rt_free(op8250);
}
static void op8250_remove(struct serial8250 *serial)
{
struct ofw_platform_8250 *op8250 = to_ofw_platform_8250(serial);
ofw_platform_8250_free_resource(op8250);
}
static rt_err_t ofw_platform_8250_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
rt_uint32_t val;
struct serial8250 *serial;
struct ofw_platform_8250 *op8250;
struct rt_ofw_node *np = pdev->parent.ofw_node;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
if (rt_ofw_prop_read_bool(np, "used-by-rtas"))
{
return -RT_EBUSY;
}
op8250 = serial8250_alloc(op8250);
if (!op8250)
{
return -RT_ENOMEM;
}
serial = &op8250->parent;
serial->base = rt_ofw_iomap(np, 0);
if (!serial->base)
{
err = -RT_EIO;
goto _fail;
}
serial->irq = rt_ofw_get_irq(np, 0);
if (serial->irq < 0)
{
err = serial->irq;
goto _fail;
}
if (!rt_ofw_prop_read_u32(np, "clock-frequency", &val))
{
serial->freq = val;
}
else
{
serial->clk = rt_ofw_get_clk(np, 0);
if (rt_is_err(serial->clk))
{
err = rt_ptr_err(serial->clk);
goto _fail;
}
if ((err = rt_clk_prepare_enable(serial->clk)))
{
goto _fail;
}
serial->freq = rt_clk_get_rate(serial->clk);
}
if (!rt_ofw_prop_read_u32(np, "reg-shift", &val))
{
serial->regshift = val;
}
serial->iotype = PORT_MMIO;
if (!rt_ofw_prop_read_u32(np, "reg-io-width", &val))
{
switch (val)
{
case 1:
serial->iotype = PORT_MMIO;
break;
case 2:
serial->iotype = PORT_MMIO16;
break;
case 4:
serial->iotype = rt_ofw_prop_read_bool(np, "big-endian") ?
PORT_MMIO32BE : PORT_MMIO32;
break;
}
}
op8250->rstc = rt_ofw_get_reset_control_by_index(np, 0);
if (rt_is_err(op8250->rstc))
{
err = rt_ptr_err(op8250->rstc);
goto _fail;
}
if (op8250->rstc && (err = rt_reset_control_deassert(op8250->rstc)))
{
goto _fail;
}
rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent);
pdev->parent.user_data = serial;
serial->parent.ops = &serial8250_uart_ops;
serial->parent.config = config;
serial->remove = &op8250_remove;
serial->data = op8250;
if ((err = serial8250_setup(serial)))
{
goto _fail;
}
return RT_EOK;
_fail:
ofw_platform_8250_free_resource(op8250);
return err;
}
static rt_err_t ofw_platform_8250_remove(struct rt_platform_device *pdev)
{
struct rt_device *dev = &pdev->parent;
struct serial8250 *serial = dev->user_data;
rt_dm_dev_unbind_fwdata(dev, RT_NULL);
return serial8250_remove(serial);
}
static const struct rt_ofw_node_id ofw_platform_8250_ofw_ids[] =
{
{ .type = "ttyS", .compatible = "ns16550a" },
{ .type = "ttyS", .compatible = "ns16550" },
#ifndef RT_SERIAL_8250_BCM7271
{ .type = "ttyS", .compatible = "brcm,bcm7271-uart" },
#endif
{ /* sentinel */ }
};
static struct rt_platform_driver ofw_platform_8250_driver =
{
.name = "8250-ofw",
.ids = ofw_platform_8250_ofw_ids,
.probe = ofw_platform_8250_probe,
.remove = ofw_platform_8250_remove,
};
static int ofw_platform_8250_drv_register(void)
{
rt_platform_driver_register(&ofw_platform_8250_driver);
return 0;
}
INIT_PLATFORM_EXPORT(ofw_platform_8250_drv_register);

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-09 GuEe-GUI first version
*/
#include <rtthread.h>
#include "8250.h"
#define IO_PORT_BAR 0
enum
{
PCI_SERIAL = 0,
PCI_SERIAL2 = 2,
PCI_SERIAL4 = 4,
};
enum
{
SERIAL_8250 = 0,
SERIAL_16450,
SERIAL_16550,
SERIAL_16650,
SERIAL_16750,
SERIAL_16850,
SERIAL_16950,
};
struct pci_serial
{
struct serial8250 parent;
struct rt_spinlock spinlock;
struct rt_pci_device *pci_dev;
rt_uint8_t type;
rt_uint8_t compat;
};
#define to_pci_serial(raw) rt_container_of(raw, struct pci_serial, parent)
static rt_err_t pci_serial_isr(struct serial8250 *serial, int irq)
{
rt_uint32_t iir;
void *base = serial->base;
iir = HWREG8(base + UART_IIR);
if (!(iir & UART_IIR_NO_INT))
{
rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND);
}
return RT_EOK;
}
static rt_ubase_t pci_serial_clock(struct pci_serial *pci_serial)
{
rt_ubase_t clock = 1843200;
return clock;
}
static void pci_serial_free_resource(struct pci_serial *pci_serial)
{
struct serial8250 *serial = &pci_serial->parent;
if (serial->base)
{
rt_iounmap(serial->base);
}
rt_free(pci_serial);
}
static void pci_8250serial_remove(struct serial8250 *serial)
{
struct pci_serial *pci_serial = to_pci_serial(serial);
rt_pci_irq_mask(pci_serial->pci_dev);
pci_serial_free_resource(pci_serial);
}
static rt_err_t pci_serial_probe(struct rt_pci_device *pdev)
{
rt_err_t err;
struct serial8250 *serial;
struct pci_serial *pci_serial = serial8250_alloc(pci_serial);
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
if (!pci_serial)
{
return -RT_ENOMEM;
}
serial = &pci_serial->parent;
serial->size = pdev->resource[IO_PORT_BAR].size;
serial->base = rt_pci_iomap(pdev, IO_PORT_BAR);
if (!serial->base)
{
err = -RT_EIO;
goto _free_res;
}
pdev->parent.user_data = serial;
serial->irq = pdev->irq;
serial->parent.ops = &serial8250_uart_ops;
serial->parent.config = config;
serial->freq = pci_serial_clock(pci_serial);
serial->handle_irq = &pci_serial_isr;
serial->iotype = PORT_MMIO;
serial->remove = &pci_8250serial_remove;
serial->data = pci_serial;
pci_serial->pci_dev = pdev;
pci_serial->type = (rt_ubase_t)pdev->id->data;
rt_spin_lock_init(&pci_serial->spinlock);
rt_pci_read_config_u8(pdev, PCIR_PROGIF, &pci_serial->compat);
if ((err = serial8250_setup(serial)))
{
goto _free_res;
}
rt_pci_irq_unmask(pci_serial->pci_dev);
return RT_EOK;
_free_res:
pci_serial_free_resource(pci_serial);
return err;
}
static rt_err_t pci_serial_remove(struct rt_pci_device *pdev)
{
struct serial8250 *serial = pdev->parent.user_data;
return serial8250_remove(serial);
}
static const struct rt_pci_device_id pci_serial_pci_ids[] =
{
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0002), .data = (void *)PCI_SERIAL, },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0003), .data = (void *)PCI_SERIAL2, },
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0004), .data = (void *)PCI_SERIAL4, },
{ /* sentinel */ }
};
static struct rt_pci_driver pci_serial_driver =
{
.name = "serial-pci",
.ids = pci_serial_pci_ids,
.probe = pci_serial_probe,
.remove = pci_serial_remove,
};
RT_PCI_DRIVER_EXPORT(pci_serial_driver);

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-16 GuEe-GUI first version
*/
#ifndef __SERIAL_8250_H__
#define __SERIAL_8250_H__
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <drivers/serial_dm.h>
#include <ioremap.h>
#include "regs.h"
enum
{
PORT_UNKNOWN,
PORT_IO,
PORT_MMIO,
PORT_MMIO16,
PORT_MMIO32,
PORT_MMIO32BE,
};
struct serial8250
{
struct rt_serial_device parent;
struct rt_clk *clk;
int irq;
void *base;
rt_size_t size;
rt_uint32_t freq; /* frequency */
rt_uint32_t regshift; /* reg offset shift */
rt_uint8_t iotype; /* io access style */
struct rt_spinlock spinlock;
rt_err_t (*serial_ios)(struct serial8250 *, struct serial_configure *ios);
rt_uint32_t (*serial_in)(struct serial8250 *, int offset);
void (*serial_out)(struct serial8250 *, int offset, int value);
rt_err_t (*serial_dma_enable)(struct serial8250 *, rt_bool_t enabled);
rt_ssize_t (*serial_dma_tx)(struct serial8250 *, const rt_uint8_t *buf, rt_size_t size);
rt_ssize_t (*serial_dma_rx)(struct serial8250 *, rt_uint8_t *buf, rt_size_t size);
rt_err_t (*handle_irq)(struct serial8250 *, int irq);
/* Free all resource (and parent) by child */
void (*remove)(struct serial8250 *);
void *data;
};
#define serial8250_alloc(obj) rt_calloc(1, sizeof(typeof(*obj)))
#define raw_to_serial8250(raw_serial) rt_container_of(raw_serial, struct serial8250, parent)
rt_err_t serial8250_config(struct serial8250 *serial, const char *options);
rt_err_t serial8250_setup(struct serial8250 *serial);
rt_err_t serial8250_remove(struct serial8250 *serial);
rt_uint32_t serial8250_in(struct serial8250 *serial, int offset);
void serial8250_out(struct serial8250 *serial, int offset, int value);
void serial8250_dma_tx_done(struct serial8250 *serial);
void serial8250_dma_rx_done(struct serial8250 *serial, int recv_len);
rt_err_t serial8250_ios(struct serial8250 *serial, struct serial_configure *cfg);
rt_err_t serial8250_uart_configure(struct rt_serial_device *raw_serial, struct serial_configure *cfg);
rt_err_t serial8250_uart_control(struct rt_serial_device *raw_serial, int cmd, void *arg);
int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c);
int serial8250_uart_getc(struct rt_serial_device *raw_serial);
rt_ssize_t serial8250_uart_dma_transmit(struct rt_serial_device *raw_serial,
rt_uint8_t *buf, rt_size_t size, int direction);
int serial8250_early_putc(struct rt_serial_device *raw_serial, char c);
rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options);
extern struct serial8250 early_serial8250;
extern const struct rt_uart_ops serial8250_uart_ops;
#endif /* __SERIAL_8250_H__ */

View File

@@ -0,0 +1,14 @@
menuconfig RT_SERIAL_8250
bool "8250 Serial Family"
default n
config RT_SERIAL_8250_DW
bool "Synopsys DesignWare 8250"
depends on RT_SERIAL_8250
default n
config RT_SERIAL_8250_PCI
bool "8250 PCI/2x/4x"
depends on RT_SERIAL_8250
depends on RT_USING_PCI
default n

View File

@@ -0,0 +1,23 @@
from building import *
group = []
if not GetDepend(['RT_SERIAL_8250']):
Return('group')
cwd = GetCurrentDir()
CPPPATH = [cwd + '/../../include']
src = ['core.c', 'early.c']
if GetDepend(['RT_SERIAL_8250_DW']):
src += ['8250-dw.c']
if GetDepend(['RT_USING_OFW', 'RT_USING_RESET']):
src += ['8250-ofw.c']
if GetDepend(['RT_SERIAL_8250_PCI']):
src += ['8250-pci.c']
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-16 GuEe-GUI first version
*/
#include "8250.h"
struct serial8250 early_serial8250 = { 0 };
static rt_uint32_t serial8250_early_in(struct serial8250 *serial, int offset)
{
return serial8250_in(serial, offset);
}
static void serial8250_early_out(struct serial8250 *serial, int offset, int value)
{
serial8250_out(serial, offset, value);
}
int serial8250_early_putc(struct rt_serial_device *raw_serial, char c)
{
if (raw_serial)
{
/* FIFO and shifting register empty */
const int uart_lsr_both_empty = (UART_LSR_TEMT | UART_LSR_THRE);
struct serial8250 *serial = rt_container_of(raw_serial, struct serial8250, parent);
serial8250_early_out(serial, UART_TX, c);
while ((serial8250_early_in(serial, UART_LSR) & uart_lsr_both_empty) != uart_lsr_both_empty)
{
rt_hw_cpu_relax();
}
}
return 1;
}
static void init_serial(struct serial8250 *serial)
{
unsigned char c;
rt_uint32_t ier, divisor;
serial8250_early_out(serial, UART_LCR, 0x3); /* 8n1 */
ier = serial8250_early_in(serial, UART_IER);
serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE); /* No interrupt */
serial8250_early_out(serial, UART_FCR, 0); /* No fifo */
serial8250_early_out(serial, UART_MCR, 0x3); /* DTR + RTS */
if (serial->freq)
{
divisor = RT_DIV_ROUND_CLOSEST(serial->freq, 16 * serial->parent.config.baud_rate);
c = serial8250_early_in(serial, UART_LCR);
serial8250_early_out(serial, UART_LCR, c | UART_LCR_DLAB);
serial8250_early_out(serial, UART_DLL, divisor & 0xff);
serial8250_early_out(serial, UART_DLM, (divisor >> 8) & 0xff);
serial8250_early_out(serial, UART_LCR, c & ~UART_LCR_DLAB);
}
}
static void serial8250_early_kick(struct rt_fdt_earlycon *con, int why)
{
struct serial8250 *serial = raw_to_serial8250(con->data);
switch (why)
{
case FDT_EARLYCON_KICK_UPDATE:
serial->base = rt_ioremap((void *)con->mmio, con->size);
break;
case FDT_EARLYCON_KICK_COMPLETED:
rt_iounmap(serial->base);
break;
default:
break;
}
}
rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options)
{
rt_err_t ret = RT_EOK;
if (!serial->base && con)
{
serial8250_config(serial, options);
con->mmio = (rt_ubase_t)serial->base;
con->size = serial->size;
}
if (serial->base && con)
{
serial->base = rt_ioremap_early((void *)serial->base, serial->size);
}
if (serial->base && con)
{
con->console_putc = (typeof(con->console_putc))&serial8250_early_putc;
con->console_kick = serial8250_early_kick;
con->data = &serial->parent;
if (!serial->parent.config.baud_rate)
{
/* Assume the device was initialized, only mask interrupts */
rt_uint32_t ier = serial8250_early_in(serial, UART_IER);
serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE);
}
else
{
init_serial(serial);
}
}
else
{
ret = -RT_ERROR;
}
return ret;
}
static void common_init(struct serial8250 *serial, struct rt_fdt_earlycon *con)
{
serial->base = (void *)con->mmio;
serial->size = con->size;
serial->iotype = PORT_MMIO32;
}
static rt_err_t common_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
struct serial8250 *serial = &early_serial8250;
common_init(serial, con);
serial->regshift = 2;
fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL);
return serial8250_early_fdt_setup(serial, con, options);
}
RT_FDT_EARLYCON_EXPORT(bcm2835aux, "uart8250", "brcm,bcm2835-aux-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(tegra20, "uart8250", "nvidia,tegra20-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(dw8250, "uart8250", "snps,dw-apb-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(ns16550a, "uart8250", "ns16550a", common_early_setup);
RT_FDT_EARLYCON_EXPORT(ns16550, "uart8250", "ns16550", common_early_setup);
#ifdef RT_USING_8250_OMAP
static rt_err_t omap8250_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
struct serial8250 *serial = &early_serial8250;
common_init(serial, con);
serial->regshift = 2;
return serial8250_early_fdt_setup(serial, con, options);
}
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap2-uart", omap8250_early_setup);
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap3-uart", omap8250_early_setup);
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap4-uart", omap8250_early_setup);
#endif /* RT_USING_8250_OMAP */

View File

@@ -0,0 +1,365 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SERIAL_8250_REGS_H__
#define __SERIAL_8250_REGS_H__
/*
* DLAB=0
*/
#define UART_RX 0 /* In: Receive buffer */
#define UART_TX 0 /* Out: Transmit buffer */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
/*
* Sleep mode for ST16650 and TI16750. For the ST16650, EFR[4]=1
*/
#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x0e /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */
#define UART_IIR_RX_TIMEOUT 0x0c /* OMAP RX Timeout interrupt */
#define UART_IIR_XOFF 0x10 /* OMAP XOFF/Special Character */
#define UART_IIR_CTS_RTS_DSR 0x20 /* OMAP CTS/RTS/DSR Change */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
/*
* Note: The FIFO trigger levels are chip specific:
* RX:76 = 00 01 10 11 TX:54 = 00 01 10 11
* PC16550D: 1 4 8 14 xx xx xx xx
* TI16C550A: 1 4 8 14 xx xx xx xx
* TI16C550C: 1 4 8 14 xx xx xx xx
* ST16C550: 1 4 8 14 xx xx xx xx
* ST16C650: 8 16 24 28 16 8 24 30 PORT_16650V2
* NS16C552: 1 4 8 14 xx xx xx xx
* ST16C654: 8 16 56 60 8 16 32 56 PORT_16654
* TI16C750: 1 16 32 56 xx xx xx xx PORT_16750
* TI16C752: 8 16 56 60 8 16 32 56
* OX16C950: 16 32 112 120 16 32 64 112 PORT_16C950
* Tegra: 1 4 8 14 16 8 4 1 PORT_TEGRA
*/
#define UART_FCR_R_TRIG_00 0x00
#define UART_FCR_R_TRIG_01 0x40
#define UART_FCR_R_TRIG_10 0x80
#define UART_FCR_R_TRIG_11 0xc0
#define UART_FCR_T_TRIG_00 0x00
#define UART_FCR_T_TRIG_01 0x10
#define UART_FCR_T_TRIG_10 0x20
#define UART_FCR_T_TRIG_11 0x30
#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
/* 16650 definitions */
#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode (TI16C750 and some Freescale UARTs) */
#define UART_FCR_R_TRIG_SHIFT 6
#define UART_FCR_R_TRIG_BITS(x) (((x) & UART_FCR_TRIGGER_MASK) >> UART_FCR_R_TRIG_SHIFT)
#define UART_FCR_R_TRIG_MAX_STATE 4
#define UART_LCR 3 /* Out: Line Control Register */
/*
* Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
* UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
/*
* Access to some registers depends on register access / configuration mode.
*/
#define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configutation mode A */
#define UART_LCR_CONF_MODE_B 0xBF /* Configutation mode B */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_MCR_CLKSEL 0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) */
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */
#define UART_MCR_XONANY 0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */
#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C550C/TI16C750) */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
#define UART_LSR 5 /* In: Line Status Register */
#define UART_LSR_FIFOE 0x80 /* Fifo error */
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
#define UART_LSR_FE 0x08 /* Frame error indicator */
#define UART_LSR_PE 0x04 /* Parity error indicator */
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_LSR_BRK_ERROR_BITS (UART_LSR_BI|UART_LSR_FE|UART_LSR_PE|UART_LSR_OE)
#define UART_MSR 6 /* In: Modem Status Register */
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
#define UART_MSR_RI 0x40 /* Ring Indicator */
#define UART_MSR_DSR 0x20 /* Data Set Ready */
#define UART_MSR_CTS 0x10 /* Clear to Send */
#define UART_MSR_DDCD 0x08 /* Delta DCD */
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
#define UART_MSR_DDSR 0x02 /* Delta DSR */
#define UART_MSR_DCTS 0x01 /* Delta CTS */
#define UART_MSR_ANY_DELTA (UART_MSR_DDCD|UART_MSR_TERI|UART_MSR_DDSR|UART_MSR_DCTS)
#define UART_SCR 7 /* I/O: Scratch Register */
/*
* DLAB=1
*/
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_DIV_MAX 0xFFFF /* Max divisor value */
/*
* LCR=0xBF (or DLAB=1 for 16C660)
*/
#define UART_EFR 2 /* I/O: Extended Features Register */
#define UART_XR_EFR 9 /* I/O: Extended Features Register (XR17D15x) */
#define UART_EFR_CTS 0x80 /* CTS flow control */
#define UART_EFR_RTS 0x40 /* RTS flow control */
#define UART_EFR_SCD 0x20 /* Special character detect */
#define UART_EFR_ECB 0x10 /* Enhanced control bit */
/*
* the low four bits control software flow control
*/
/*
* LCR=0xBF, TI16C752, ST16650, ST16650A, ST16654
*/
#define UART_XON1 4 /* I/O: Xon character 1 */
#define UART_XON2 5 /* I/O: Xon character 2 */
#define UART_XOFF1 6 /* I/O: Xoff character 1 */
#define UART_XOFF2 7 /* I/O: Xoff character 2 */
/*
* EFR[4]=1 MCR[6]=1, TI16C752
*/
#define UART_TI752_TCR 6 /* I/O: transmission control register */
#define UART_TI752_TLR 7 /* I/O: trigger level register */
/*
* LCR=0xBF, XR16C85x
*/
#define UART_TRG 0 /* FCTR bit 7 selects Rx or Tx In: Fifo count Out: Fifo custom trigger levels */
/*
* These are the definitions for the Programmable Trigger Register
*/
#define UART_TRG_1 0x01
#define UART_TRG_4 0x04
#define UART_TRG_8 0x08
#define UART_TRG_16 0x10
#define UART_TRG_32 0x20
#define UART_TRG_64 0x40
#define UART_TRG_96 0x60
#define UART_TRG_120 0x78
#define UART_TRG_128 0x80
#define UART_FCTR 1 /* Feature Control Register */
#define UART_FCTR_RTS_NODELAY 0x00 /* RTS flow control delay */
#define UART_FCTR_RTS_4DELAY 0x01
#define UART_FCTR_RTS_6DELAY 0x02
#define UART_FCTR_RTS_8DELAY 0x03
#define UART_FCTR_IRDA 0x04 /* IrDa data encode select */
#define UART_FCTR_TX_INT 0x08 /* Tx interrupt type select */
#define UART_FCTR_TRGA 0x00 /* Tx/Rx 550 trigger table select */
#define UART_FCTR_TRGB 0x10 /* Tx/Rx 650 trigger table select */
#define UART_FCTR_TRGC 0x20 /* Tx/Rx 654 trigger table select */
#define UART_FCTR_TRGD 0x30 /* Tx/Rx 850 programmable trigger select */
#define UART_FCTR_SCR_SWAP 0x40 /* Scratch pad register swap */
#define UART_FCTR_RX 0x00 /* Programmable trigger mode select */
#define UART_FCTR_TX 0x80 /* Programmable trigger mode select */
/*
* LCR=0xBF, FCTR[6]=1
*/
#define UART_EMSR 7 /* Extended Mode Select Register */
#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
#define UART_EMSR_ALT_COUNT 0x02 /* Alternating count select */
/*
* The Intel XScale on-chip UARTs define these bits
*/
#define UART_IER_DMAE 0x80 /* DMA Requests Enable */
#define UART_IER_UUE 0x40 /* UART Unit Enable */
#define UART_IER_NRZE 0x20 /* NRZ coding Enable */
#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */
#define UART_IIR_TOD 0x08 /* Character Timeout Indication Detected */
#define UART_FCR_PXAR1 0x00 /* receive FIFO threshold = 1 */
#define UART_FCR_PXAR8 0x40 /* receive FIFO threshold = 8 */
#define UART_FCR_PXAR16 0x80 /* receive FIFO threshold = 16 */
#define UART_FCR_PXAR32 0xc0 /* receive FIFO threshold = 32 */
/*
* These register definitions are for the 16C950
*/
#define UART_ASR 0x01 /* Additional Status Register */
#define UART_RFL 0x03 /* Receiver FIFO level */
#define UART_TFL 0x04 /* Transmitter FIFO level */
#define UART_ICR 0x05 /* Index Control Register */
/* The 16950 ICR registers */
#define UART_ACR 0x00 /* Additional Control Register */
#define UART_CPR 0x01 /* Clock Prescalar Register */
#define UART_TCR 0x02 /* Times Clock Register */
#define UART_CKS 0x03 /* Clock Select Register */
#define UART_TTL 0x04 /* Transmitter Interrupt Trigger Level */
#define UART_RTL 0x05 /* Receiver Interrupt Trigger Level */
#define UART_FCL 0x06 /* Flow Control Level Lower */
#define UART_FCH 0x07 /* Flow Control Level Higher */
#define UART_ID1 0x08 /* ID #1 */
#define UART_ID2 0x09 /* ID #2 */
#define UART_ID3 0x0A /* ID #3 */
#define UART_REV 0x0B /* Revision */
#define UART_CSR 0x0C /* Channel Software Reset */
#define UART_NMR 0x0D /* Nine-bit Mode Register */
#define UART_CTR 0xFF
/*
* The 16C950 Additional Control Register
*/
#define UART_ACR_RXDIS 0x01 /* Receiver disable */
#define UART_ACR_TXDIS 0x02 /* Transmitter disable */
#define UART_ACR_DSRFC 0x04 /* DSR Flow Control */
#define UART_ACR_TLENB 0x20 /* 950 trigger levels enable */
#define UART_ACR_ICRRD 0x40 /* ICR Read enable */
#define UART_ACR_ASREN 0x80 /* Additional status enable */
/*
* These definitions are for the RSA-DV II/S card, from
*
* Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
*/
#define UART_RSA_BASE (-8)
#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
/*
* The RSA DSV/II board has two fixed clock frequencies. One is the
* standard rate, and the other is 8 times faster.
*/
#define SERIAL_RSA_BAUD_BASE (921600)
#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
/* Extra registers for TI DA8xx/66AK2x */
#define UART_DA830_PWREMU_MGMT 12
/* PWREMU_MGMT register bits */
#define UART_DA830_PWREMU_MGMT_FREE (1 << 0) /* Free-running mode */
#define UART_DA830_PWREMU_MGMT_URRST (1 << 13) /* Receiver reset/enable */
#define UART_DA830_PWREMU_MGMT_UTRST (1 << 14) /* Transmitter reset/enable */
/*
* Extra serial register definitions for the internal UARTs
* in TI OMAP processors.
*/
#define OMAP1_UART1_BASE 0xfffb0000
#define OMAP1_UART2_BASE 0xfffb0800
#define OMAP1_UART3_BASE 0xfffb9800
#define UART_OMAP_MDR1 0x08 /* Mode definition register */
#define UART_OMAP_MDR2 0x09 /* Mode definition register 2 */
#define UART_OMAP_SCR 0x10 /* Supplementary control register */
#define UART_OMAP_SSR 0x11 /* Supplementary status register */
#define UART_OMAP_EBLR 0x12 /* BOF length register */
#define UART_OMAP_OSC_12M_SEL 0x13 /* OMAP1510 12MHz osc select */
#define UART_OMAP_MVER 0x14 /* Module version register */
#define UART_OMAP_SYSC 0x15 /* System configuration register */
#define UART_OMAP_SYSS 0x16 /* System status register */
#define UART_OMAP_WER 0x17 /* Wake-up enable register */
#define UART_OMAP_TX_LVL 0x1a /* TX FIFO level register */
/*
* These are the definitions for the MDR1 register
*/
#define UART_OMAP_MDR1_16X_MODE 0x00 /* UART 16x mode */
#define UART_OMAP_MDR1_SIR_MODE 0x01 /* SIR mode */
#define UART_OMAP_MDR1_16X_ABAUD_MODE 0x02 /* UART 16x auto-baud */
#define UART_OMAP_MDR1_13X_MODE 0x03 /* UART 13x mode */
#define UART_OMAP_MDR1_MIR_MODE 0x04 /* MIR mode */
#define UART_OMAP_MDR1_FIR_MODE 0x05 /* FIR mode */
#define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */
#define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */
/*
* These are definitions for the Altera ALTR_16550_F32/F64/F128
* Normalized from 0x100 to 0x40 because of shift by 2 (32 bit regs).
*/
#define UART_ALTR_AFR 0x40 /* Additional Features Register */
#define UART_ALTR_EN_TXFIFO_LW 0x01 /* Enable the TX FIFO Low Watermark */
#define UART_ALTR_TX_LOW 0x41 /* Tx FIFO Low Watermark */
#endif /* __SERIAL_8250_REGS_H__ */

View File

@@ -1 +1,12 @@
config RT_SERIAL_EARLY_HVC
bool "Early HVC"
default n
config RT_SERIAL_PL011
bool "ARM PL011"
default n
rsource "8250/Kconfig"
rsource "virtual/Kconfig"
osource "$(SOC_DM_SERIAL_DIR)/Kconfig"

View File

@@ -8,6 +8,12 @@ CPPPATH = [cwd + '/../../include']
src = []
if GetDepend(['RT_SERIAL_EARLY_HVC']):
src += ['serial-early-hvc.c']
if GetDepend(['RT_SERIAL_PL011']):
src += ['serial-pl011.c']
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
for d in list:

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-01-30 GuEe-GUI first version
*/
#include <rtdevice.h>
#include <hypercall.h>
static void hvc_early_console_putchar(void *data, char c)
{
rt_hv_console(c);
}
static rt_err_t hvc_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
rt_err_t err;
rt_uint32_t version;
if ((err = rt_hv_version(&version)))
{
return err;
}
con->console_putc = hvc_early_console_putchar;
return err;
}
RT_FDT_EARLYCON_EXPORT(hvc, "hvc", "vmrt-thread,hvc-console", hvc_early_setup);

View File

@@ -0,0 +1,417 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-05 Bernard The first version
* 2022-08-24 GuEe-GUI add OFW support
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <drivers/serial_dm.h>
#include <cpuport.h>
#include <ioremap.h>
#define PL011_OEIM RT_BIT(10) /* overrun error interrupt mask */
#define PL011_BEIM RT_BIT(9) /* break error interrupt mask */
#define PL011_PEIM RT_BIT(8) /* parity error interrupt mask */
#define PL011_FEIM RT_BIT(7) /* framing error interrupt mask */
#define PL011_RTIM RT_BIT(6) /* receive timeout interrupt mask */
#define PL011_TXIM RT_BIT(5) /* transmit interrupt mask */
#define PL011_RXIM RT_BIT(4) /* receive interrupt mask */
#define PL011_DSRMIM RT_BIT(3) /* DSR interrupt mask */
#define PL011_DCDMIM RT_BIT(2) /* DCD interrupt mask */
#define PL011_CTSMIM RT_BIT(1) /* CTS interrupt mask */
#define PL011_RIMIM RT_BIT(0) /* RI interrupt mask */
#define PL011_DR 0x000
#define PL011_FR 0x018
#define PL011_IBRD 0x024
#define PL011_FBRD 0x028
#define PL011_LCR 0x02c
#define PL011_CR 0x030
#define PL011_IMSC 0x038
#define PL011_RIS 0x03c
#define PL011_DMACR 0x048
#define PL011_LCRH_SPS (1 << 7)
#define PL011_LCRH_WLEN_8 (3 << 5)
#define PL011_LCRH_WLEN_7 (2 << 5)
#define PL011_LCRH_WLEN_6 (1 << 5)
#define PL011_LCRH_WLEN_5 (0 << 5)
#define PL011_LCRH_FEN (1 << 4)
#define PL011_LCRH_STP2 (1 << 3)
#define PL011_LCRH_EPS (1 << 2)
#define PL011_LCRH_PEN (1 << 1)
#define PL011_LCRH_BRK (1 << 0)
#define PL011_LCRH_WLEN(n) ((n - 5) << 5)
#define PL011_CR_CTSEN RT_BIT(15)
#define PL011_CR_RTSEN RT_BIT(14)
#define PL011_CR_RTS RT_BIT(11)
#define PL011_CR_DTR RT_BIT(10)
#define PL011_CR_RXE RT_BIT(9)
#define PL011_CR_TXE RT_BIT(8)
#define PL011_CR_LBE RT_BIT(7)
#define PL011_CR_SIRLP RT_BIT(2)
#define PL011_CR_SIREN RT_BIT(1)
#define PL011_CR_UARTEN RT_BIT(0)
struct pl011
{
struct rt_serial_device parent;
int irq;
void *base;
rt_ubase_t freq;
struct rt_clk *clk;
struct rt_clk *pclk;
struct rt_spinlock spinlock;
};
#define raw_to_pl011(raw) rt_container_of(raw, struct pl011, parent)
rt_inline rt_uint32_t pl011_read(struct pl011 *pl011, int offset)
{
return HWREG32(pl011->base + offset);
}
rt_inline void pl011_write(struct pl011 *pl011, int offset, rt_uint32_t value)
{
HWREG32(pl011->base + offset) = value;
}
static void pl011_isr(int irqno, void *param)
{
struct pl011 *pl011 = param;
/* Check irq */
if (pl011_read(pl011, PL011_RIS) & PL011_RXIM)
{
rt_base_t level = rt_spin_lock_irqsave(&pl011->spinlock);
rt_hw_serial_isr(&pl011->parent, RT_SERIAL_EVENT_RX_IND);
rt_spin_unlock_irqrestore(&pl011->spinlock, level);
}
}
static rt_err_t pl011_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
rt_ubase_t quot;
struct pl011 *pl011 = raw_to_pl011(serial);
/* Clear UART setting */
pl011_write(pl011, PL011_CR, 0);
/* Disable FIFO */
pl011_write(pl011, PL011_LCR, 0);
if (cfg->baud_rate > pl011->freq / 16)
{
quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 8, cfg->baud_rate);
}
else
{
quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 4, cfg->baud_rate);
}
pl011_write(pl011, PL011_IBRD, quot >> 6);
pl011_write(pl011, PL011_FBRD, quot & 0x3f);
/* FIFO */
pl011_write(pl011, PL011_LCR, PL011_LCRH_WLEN(cfg->data_bits));
/* Art enable, TX/RX enable */
pl011_write(pl011, PL011_CR, PL011_CR_UARTEN | PL011_CR_TXE | PL011_CR_RXE);
return RT_EOK;
}
static rt_err_t pl011_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct pl011 *pl011 = raw_to_pl011(serial);
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
/* Disable rx irq */
pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) & ~PL011_RXIM);
rt_hw_interrupt_mask(pl011->irq);
break;
case RT_DEVICE_CTRL_SET_INT:
/* Enable rx irq */
pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) | PL011_RXIM);
rt_hw_interrupt_umask(pl011->irq);
break;
}
return RT_EOK;
}
static int pl011_uart_putc(struct rt_serial_device *serial, char c)
{
struct pl011 *pl011 = raw_to_pl011(serial);
while (pl011_read(pl011, PL011_FR) & PL011_TXIM)
{
rt_hw_cpu_relax();
}
pl011_write(pl011, PL011_DR, c);
return 1;
}
static int pl011_uart_getc(struct rt_serial_device *serial)
{
int ch = -1;
struct pl011 *pl011 = raw_to_pl011(serial);
if (!(pl011_read(pl011, PL011_FR) & PL011_RXIM))
{
ch = pl011_read(pl011, PL011_DR);
}
return ch;
}
static const struct rt_uart_ops pl011_uart_ops =
{
.configure = pl011_uart_configure,
.control = pl011_uart_control,
.putc = pl011_uart_putc,
.getc = pl011_uart_getc,
};
static void pl011_early_kick(struct rt_fdt_earlycon *con, int why)
{
struct pl011 *pl011 = raw_to_pl011(con->data);
switch (why)
{
case FDT_EARLYCON_KICK_UPDATE:
pl011->base = rt_ioremap((void *)con->mmio, con->size);
break;
case FDT_EARLYCON_KICK_COMPLETED:
rt_iounmap(pl011->base);
break;
default:
break;
}
}
static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
rt_err_t err = RT_EOK;
static struct pl011 pl011 = { };
if (options && !con->mmio)
{
char *arg;
con->mmio = RT_NULL;
/*
* The pl011 serial port must already be setup and configured in early.
* Options are not yet supported.
* pl011,<addr>
* pl011,mmio32,<addr>
*/
serial_for_each_args(arg, options)
{
if (!rt_strcmp(arg, "pl011") || !rt_strcmp(arg, "mmio32"))
{
continue;
}
if (!con->mmio)
{
con->mmio = (rt_ubase_t)serial_base_from_args(arg);
break;
}
}
}
if (!con->size)
{
con->size = 0x1000;
}
if (con->mmio)
{
pl011.base = rt_ioremap_early((void *)con->mmio, con->size);
}
if (pl011.base)
{
con->console_putc = (typeof(con->console_putc))&pl011_uart_putc;
con->console_kick = pl011_early_kick;
con->data = &pl011.parent;
pl011.parent.config = (typeof(pl011.parent.config))RT_SERIAL_CONFIG_DEFAULT;
}
else
{
err = -RT_ERROR;
}
return err;
}
RT_FDT_EARLYCON_EXPORT(pl011, "pl011", "arm,pl011", pl011_early_setup);
static void pl011_free(struct pl011 *pl011)
{
if (pl011->base)
{
rt_iounmap(pl011->base);
}
if (!rt_is_err_or_null(pl011->clk))
{
rt_clk_disable(pl011->clk);
rt_clk_put(pl011->clk);
}
if (!rt_is_err_or_null(pl011->pclk))
{
rt_clk_disable_unprepare(pl011->pclk);
rt_clk_put(pl011->pclk);
}
rt_free(pl011);
}
static rt_err_t pl011_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
const char *name;
char isr_name[RT_NAME_MAX];
struct rt_device *dev = &pdev->parent;
struct pl011 *pl011 = rt_calloc(1, sizeof(*pl011));
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
if (!pl011)
{
return -RT_ENOMEM;
}
pl011->base = rt_dm_dev_iomap(dev, 0);
if (!pl011->base)
{
err = -RT_EIO;
goto _fail;
}
pl011->irq = rt_dm_dev_get_irq(dev, 0);
if (pl011->irq < 0)
{
err = pl011->irq;
goto _fail;
}
pl011->clk = rt_clk_get_by_index(dev, 0);
if (rt_is_err(pl011->clk))
{
err = rt_ptr_err(pl011->clk);
goto _fail;
}
pl011->pclk = rt_clk_get_by_name(dev, "apb_pclk");
if (rt_is_err(pl011->pclk))
{
err = rt_ptr_err(pl011->pclk);
goto _fail;
}
if ((err = rt_clk_prepare_enable(pl011->pclk)))
{
goto _fail;
}
rt_dm_dev_bind_fwdata(&pl011->parent.parent, dev->ofw_node, &pl011->parent);
rt_clk_enable(pl011->clk);
pl011->freq = rt_clk_get_rate(pl011->clk);
dev->user_data = pl011;
pl011->parent.ops = &pl011_uart_ops;
pl011->parent.config = config;
rt_spin_lock_init(&pl011->spinlock);
serial_dev_set_name(&pl011->parent);
name = rt_dm_dev_get_name(&pl011->parent.parent);
rt_hw_serial_register(&pl011->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, pl011);
rt_snprintf(isr_name, RT_NAME_MAX, "%s-pl011", name);
rt_hw_interrupt_install(pl011->irq, pl011_isr, pl011, isr_name);
return RT_EOK;
_fail:
pl011_free(pl011);
return err;
}
static rt_err_t pl011_remove(struct rt_platform_device *pdev)
{
struct rt_device *dev = &pdev->parent;
struct pl011 *pl011 = dev->user_data;
rt_dm_dev_unbind_fwdata(dev, RT_NULL);
rt_hw_interrupt_mask(pl011->irq);
rt_pic_detach_irq(pl011->irq, pl011);
rt_device_unregister(&pl011->parent.parent);
pl011_free(pl011);
return RT_EOK;
}
static const struct rt_ofw_node_id pl011_ofw_ids[] =
{
{ .type = "ttyAMA", .compatible = "arm,pl011" },
{ .type = "ttyAMA", .compatible = "arm,pl011-axi" },
{ /* sentinel */ }
};
static struct rt_platform_driver pl011_driver =
{
.name = "serial-pl011",
.ids = pl011_ofw_ids,
.probe = pl011_probe,
.remove = pl011_remove,
};
static int pl011_drv_register(void)
{
rt_platform_driver_register(&pl011_driver);
return 0;
}
INIT_PLATFORM_EXPORT(pl011_drv_register);

View File

@@ -0,0 +1 @@
psf.inc

View File

@@ -0,0 +1,17 @@
menuconfig RT_SERIAL_VIRTUAL
bool "Virtual Serial in video"
depends on RT_GRAPHIC_FB
depends on RT_INPUT_KEYBOARD
default n
choice
prompt "Rendering font(psf)"
default RT_SERIAL_VIRTUAL_FONT_UNI2_FIXED16
depends on RT_SERIAL_VIRTUAL
config RT_SERIAL_VIRTUAL_FONT_UNI2_FIXED16
bool "uni2 fixed16"
config RT_SERIAL_VIRTUAL_FONT_UNI2_VGA16
bool "uni2 vga16"
endchoice

View File

@@ -0,0 +1,39 @@
from building import *
group = []
if not GetDepend(['RT_SERIAL_VIRTUAL']):
Return('group')
cwd = GetCurrentDir()
CPPPATH = [cwd + '/../../include']
CPPDEFINES = []
src = []
font_path = None
if GetDepend(['RT_SERIAL_VIRTUAL_FONT_UNI2_FIXED16']):
font_path = cwd + '/font-uni2-fixed16.psf'
if GetDepend(['RT_SERIAL_VIRTUAL_FONT_UNI2_VGA16']):
font_path = cwd + '/font-uni2-vga16.psf'
if font_path != None:
with open(font_path, 'rb') as psf:
psf_data = psf.read()
first_byte = True
with open(cwd + '/psf.inc', 'w') as font:
for byte in psf_data:
if not first_byte:
font.write(", ")
font.write("0x{:02x}".format(byte))
first_byte = False
src += ['psf.c', 'render.c', 'virtual.c']
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
Return('group')

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#include "psf.h"
static void psf_read_header(struct psf_font *psf)
{
if (psf->header1->magic[0] == PSF1_MAGIC0 &&
psf->header1->magic[1] == PSF1_MAGIC1)
{
psf->font_map = (void *)&psf->header1[1];
psf->type = PSF_TYPE_1;
if (psf->header1->mode & PSF1_MODE512)
{
psf->count = 512;
}
else
{
psf->count = 256;
}
psf->size = psf->header1->charsize;
psf->height = psf->header1->charsize;
psf->width = 8;
}
else if (psf->header2->magic[0] == PSF2_MAGIC0 &&
psf->header2->magic[1] == PSF2_MAGIC1 &&
psf->header2->magic[2] == PSF2_MAGIC2 &&
psf->header2->magic[3] == PSF2_MAGIC3)
{
psf->font_map = (void *)&psf->header2[1];
psf->type = PSF_TYPE_2;
psf->count = psf->header2->length;
psf->size = psf->header2->charsize;
psf->height = psf->header2->height;
psf->width = psf->header2->width;
}
else
{
psf->type = PSF_TYPE_UNKNOW;
}
psf->glyph = psf->height * psf->width;
}
rt_err_t psf_initialize(const void *psf_data, struct psf_font *out_psf)
{
struct psf_font *psf = out_psf;
psf->raw_data = psf_data;
psf_read_header(psf);
if (psf->type == PSF_TYPE_UNKNOW)
{
return -RT_ENOSYS;
}
return RT_EOK;
}
rt_err_t psf_parse(struct psf_font *psf, const rt_uint8_t *font_data,
rt_uint8_t *tmpglyph, rt_uint32_t color_size,
rt_uint32_t foreground, rt_uint32_t background)
{
rt_uint8_t *font = (void *)font_data, *map = (void *)psf->font_map;
psf->font_data = font_data;
for (int n = 0; n < psf->count; ++n, map += psf->size)
{
rt_memcpy(tmpglyph, map, psf->size);
for (int i = 0; i < psf->size; ++i)
{
for (int j = 0; j < 8; ++j)
{
if (i % (psf->size / psf->height) * 8 + j < psf->width)
{
if (tmpglyph[i] & 0x80)
{
rt_memcpy(font, &foreground, color_size);
}
else
{
rt_memcpy(font, &background, color_size);
}
font += color_size;
}
tmpglyph[i] = tmpglyph[i] << 1;
}
}
}
return RT_EOK;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#ifndef __PSF_H__
#define __PSF_H__
#include <rtthread.h>
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
#define PSF1_MODE512 0x01
#define PSF1_MODEHASTAB 0x02
#define PSF1_MODEHASSEQ 0x04
#define PSF1_MAXMODE 0x05
#define PSF1_SEPARATOR 0xffff
#define PSF1_STARTSEQ 0xfffe
struct psf1_header
{
rt_uint8_t magic[2]; /* Magic number */
rt_uint8_t mode; /* PSF font mode */
rt_uint8_t charsize; /* Character size */
};
#define PSF2_MAGIC0 0x72
#define PSF2_MAGIC1 0xb5
#define PSF2_MAGIC2 0x4a
#define PSF2_MAGIC3 0x86
/* bits used in flags */
#define PSF2_HAS_UNICODE_TABLE 0x01
/* max version recognized so far */
#define PSF2_MAXVERSION 0
/* UTF8 separators */
#define PSF2_SEPARATOR 0xff
#define PSF2_STARTSEQ 0xfe
struct psf2_header
{
rt_uint8_t magic[4];
rt_uint32_t version;
rt_uint32_t headersize; /* offset of bitmaps in file */
rt_uint32_t flags;
rt_uint32_t length; /* number of glyphs */
rt_uint32_t charsize; /* number of bytes for each character, charsize = height * ((width + 7) / 8) */
rt_uint32_t height, width; /* max dimensions of glyphs */
};
enum psf_type
{
PSF_TYPE_1,
PSF_TYPE_2,
PSF_TYPE_UNKNOW,
};
struct psf_font
{
union
{
const rt_uint8_t *raw_data;
struct psf1_header *header1;
struct psf2_header *header2;
};
const rt_uint8_t *font_map;
const rt_uint8_t *font_data;
enum psf_type type;
rt_uint32_t count; /* fonts count */
rt_uint32_t size;
rt_uint32_t height;
rt_uint32_t width;
rt_uint32_t glyph; /* height * width */
};
rt_err_t psf_initialize(const void *psf_data, struct psf_font *out_psf);
rt_err_t psf_parse(struct psf_font *psf, const rt_uint8_t *font_data,
rt_uint8_t *tmpglyph, rt_uint32_t color_size,
rt_uint32_t foreground, rt_uint32_t background);
#endif /* __PSF_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#ifndef __VIRTUAL_RENDER_H__
#define __VIRTUAL_RENDER_H__
#include <rtdef.h>
struct render_color
{
rt_uint32_t red;
rt_uint32_t green;
rt_uint32_t blue;
rt_uint32_t alpha;
};
struct render_point
{
rt_uint32_t row;
rt_uint32_t col;
};
enum cursor
{
CURSOR_HLINE,
CURSOR_VLINE,
CURSOR_BLOCK,
};
rt_err_t render_load_fbdev(struct rt_device *fbdev);
rt_err_t render_load_font(const char *psf_data, rt_size_t size,
struct render_color *foreground, struct render_color *background,
struct render_point *out_start_point, struct render_point *out_end_point);
void render_clear_display(void);
void render_set_foreground(struct render_color *foreground);
void render_set_background(struct render_color *background);
rt_inline void render_set_color(struct render_color *foreground, struct render_color *background)
{
render_set_foreground(foreground);
render_set_background(background);
}
void render_select_cursor(enum cursor shape);
void render_move_cursor(struct render_point *position);
void render_reset_cursor(struct render_point *out_position);
void render_return_cursor(struct render_point *out_position);
void render_current_cursor(struct render_point *out_position);
void render_put_char(char ch);
#endif /* __VIRTUAL_RENDER_H__ */

File diff suppressed because it is too large Load Diff