Commit 0c6c8878 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://github.com/openrisc/linux

Pull OpenRISC updates from Stafford Horne:

 - New drivers and OpenRISC support for the LiteX platform

 - A bug fix to support userspace gdb debugging

 - Fixes one compile issue with blk-iocost

* tag 'for-linus' of git://github.com/openrisc/linux:
  openrisc: add local64.h to fix blk-iocost build
  openrisc: fix trap for debugger breakpoint signalling
  openrisc: add support for LiteX
  drivers/tty/serial: add LiteUART driver
  dt-bindings: serial: document LiteUART bindings
  drivers/soc/litex: add LiteX SoC Controller driver
  dt-bindings: soc: document LiteX SoC Controller bindings
  dt-bindings: vendor: add vendor prefix for LiteX
parents 8a5be36b d8398bf8
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/serial/litex,liteuart.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LiteUART serial controller
maintainers:
- Karol Gugala <kgugala@antmicro.com>
- Mateusz Holenko <mholenko@antmicro.com>
description: |
LiteUART serial controller is a part of the LiteX FPGA SoC builder. It supports
multiple CPU architectures, currently including e.g. OpenRISC and RISC-V.
properties:
compatible:
const: litex,liteuart
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
examples:
- |
uart0: serial@e0001800 {
compatible = "litex,liteuart";
reg = <0xe0001800 0x100>;
interrupts = <2>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
# Copyright 2020 Antmicro <www.antmicro.com>
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/litex/litex,soc-controller.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: LiteX SoC Controller driver
description: |
This is the SoC Controller driver for the LiteX SoC Builder.
Its purpose is to verify LiteX CSR (Control&Status Register) access
operations and provide functions for other drivers to read/write CSRs
and to check if those accessors are ready to be used.
maintainers:
- Karol Gugala <kgugala@antmicro.com>
- Mateusz Holenko <mholenko@antmicro.com>
properties:
compatible:
const: litex,soc-controller
reg:
maxItems: 1
required:
- compatible
- reg
examples:
- |
soc_ctrl0: soc-controller@f0000000 {
compatible = "litex,soc-controller";
reg = <0xf0000000 0xc>;
status = "okay";
};
...
...@@ -621,6 +621,8 @@ patternProperties: ...@@ -621,6 +621,8 @@ patternProperties:
description: Linux-specific binding description: Linux-specific binding
"^linx,.*": "^linx,.*":
description: Linx Technologies description: Linx Technologies
"^litex,.*":
description: LiteX SoC builder
"^lltc,.*": "^lltc,.*":
description: Linear Technology Corporation description: Linear Technology Corporation
"^logicpd,.*": "^logicpd,.*":
......
...@@ -10264,6 +10264,16 @@ L: kunit-dev@googlegroups.com ...@@ -10264,6 +10264,16 @@ L: kunit-dev@googlegroups.com
S: Maintained S: Maintained
F: lib/list-test.c F: lib/list-test.c
LITEX PLATFORM
M: Karol Gugala <kgugala@antmicro.com>
M: Mateusz Holenko <mholenko@antmicro.com>
S: Maintained
F: Documentation/devicetree/bindings/*/litex,*.yaml
F: arch/openrisc/boot/dts/or1klitex.dts
F: drivers/soc/litex/litex_soc_ctrl.c
F: drivers/tty/serial/liteuart.c
F: include/linux/litex.h
LIVE PATCHING LIVE PATCHING
M: Josh Poimboeuf <jpoimboe@redhat.com> M: Josh Poimboeuf <jpoimboe@redhat.com>
M: Jiri Kosina <jikos@kernel.org> M: Jiri Kosina <jikos@kernel.org>
......
// SPDX-License-Identifier: GPL-2.0
/*
* LiteX-based System on Chip
*
* Copyright (C) 2019 Antmicro <www.antmicro.com>
*/
/dts-v1/;
/ {
compatible = "opencores,or1ksim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&pic>;
aliases {
serial0 = &serial0;
};
chosen {
bootargs = "console=liteuart";
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "opencores,or1200-rtlsvn481";
reg = <0>;
clock-frequency = <100000000>;
};
};
pic: pic {
compatible = "opencores,or1k-pic";
#interrupt-cells = <1>;
interrupt-controller;
};
serial0: serial@e0002000 {
device_type = "serial";
compatible = "litex,liteuart";
reg = <0xe0002000 0x100>;
};
soc_ctrl0: soc_controller@e0000000 {
compatible = "litex,soc-controller";
reg = <0xe0000000 0xc>;
status = "okay";
};
};
CONFIG_BLK_DEV_INITRD=y
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_EMBEDDED=y
CONFIG_HZ_100=y
CONFIG_INITRAMFS_SOURCE="openrisc-rootfs.cpio.gz"
CONFIG_OF_OVERLAY=y
CONFIG_OPENRISC_BUILTIN_DTB="or1klitex"
CONFIG_PANIC_ON_OOPS=y
CONFIG_PRINTK_TIME=y
CONFIG_LITEX_SOC_CONTROLLER=y
CONFIG_SERIAL_LITEUART=y
CONFIG_SERIAL_LITEUART_CONSOLE=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_TTY_PRINTK=y
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
generic-y += extable.h generic-y += extable.h
generic-y += kvm_para.h generic-y += kvm_para.h
generic-y += local64.h
generic-y += mcs_spinlock.h generic-y += mcs_spinlock.h
generic-y += qspinlock_types.h generic-y += qspinlock_types.h
generic-y += qspinlock.h generic-y += qspinlock.h
......
...@@ -238,9 +238,7 @@ void __init trap_init(void) ...@@ -238,9 +238,7 @@ void __init trap_init(void)
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
{ {
force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)address); force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);
regs->pc += 4;
} }
asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
......
...@@ -9,6 +9,7 @@ source "drivers/soc/bcm/Kconfig" ...@@ -9,6 +9,7 @@ source "drivers/soc/bcm/Kconfig"
source "drivers/soc/fsl/Kconfig" source "drivers/soc/fsl/Kconfig"
source "drivers/soc/imx/Kconfig" source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig" source "drivers/soc/ixp4xx/Kconfig"
source "drivers/soc/litex/Kconfig"
source "drivers/soc/mediatek/Kconfig" source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig" source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig" source "drivers/soc/renesas/Kconfig"
......
...@@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/ ...@@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/
obj-y += imx/ obj-y += imx/
obj-$(CONFIG_ARCH_IXP4XX) += ixp4xx/ obj-$(CONFIG_ARCH_IXP4XX) += ixp4xx/
obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-$(CONFIG_SOC_XWAY) += lantiq/
obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
obj-y += mediatek/ obj-y += mediatek/
obj-y += amlogic/ obj-y += amlogic/
obj-y += qcom/ obj-y += qcom/
......
# SPDX-License_Identifier: GPL-2.0
menu "Enable LiteX SoC Builder specific drivers"
config LITEX
bool
config LITEX_SOC_CONTROLLER
tristate "Enable LiteX SoC Controller driver"
depends on OF || COMPILE_TEST
select LITEX
help
This option enables the SoC Controller Driver which verifies
LiteX CSR access and provides common litex_get_reg/litex_set_reg
accessors.
All drivers that use functions from litex.h must depend on
LITEX.
endmenu
# SPDX-License_Identifier: GPL-2.0
obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex_soc_ctrl.o
// SPDX-License-Identifier: GPL-2.0
/*
* LiteX SoC Controller Driver
*
* Copyright (C) 2020 Antmicro <www.antmicro.com>
*
*/
#include <linux/litex.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/io.h>
/*
* LiteX SoC Generator, depending on the configuration, can split a single
* logical CSR (Control&Status Register) into a series of consecutive physical
* registers.
*
* For example, in the configuration with 8-bit CSR Bus, 32-bit aligned (the
* default one for 32-bit CPUs) a 32-bit logical CSR will be generated as four
* 32-bit physical registers, each one containing one byte of meaningful data.
*
* For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
*
* The purpose of `litex_set_reg`/`litex_get_reg` is to implement the logic
* of writing to/reading from the LiteX CSR in a single place that can be
* then reused by all LiteX drivers.
*/
/**
* litex_set_reg() - Writes the value to the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
* @val: Value to be written to the CSR
*
* In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
* a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
* each one containing one byte of meaningful data.
*
* This function splits a single possibly multi-byte write into a series of
* single-byte writes with a proper offset.
*/
void litex_set_reg(void __iomem *reg, unsigned long reg_size,
unsigned long val)
{
unsigned long shifted_data, shift, i;
for (i = 0; i < reg_size; ++i) {
shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
shifted_data = val >> shift;
WRITE_LITEX_SUBREGISTER(shifted_data, reg, i);
}
}
EXPORT_SYMBOL_GPL(litex_set_reg);
/**
* litex_get_reg() - Reads the value of the LiteX CSR (Control&Status Register)
* @reg: Address of the CSR
* @reg_size: The width of the CSR expressed in the number of bytes
*
* Return: Value read from the CSR
*
* In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
* a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
* each one containing one byte of meaningful data.
*
* This function generates a series of single-byte reads with a proper offset
* and joins their results into a single multi-byte value.
*/
unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size)
{
unsigned long shifted_data, shift, i;
unsigned long result = 0;
for (i = 0; i < reg_size; ++i) {
shifted_data = READ_LITEX_SUBREGISTER(reg, i);
shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
result |= (shifted_data << shift);
}
return result;
}
EXPORT_SYMBOL_GPL(litex_get_reg);
#define SCRATCH_REG_OFF 0x04
#define SCRATCH_REG_VALUE 0x12345678
#define SCRATCH_TEST_VALUE 0xdeadbeef
/*
* Check LiteX CSR read/write access
*
* This function reads and writes a scratch register in order to verify if CSR
* access works.
*
* In case any problems are detected, the driver should panic.
*
* Access to the LiteX CSR is, by design, done in CPU native endianness.
* The driver should not dynamically configure access functions when
* the endianness mismatch is detected. Such situation indicates problems in
* the soft SoC design and should be solved at the LiteX generator level,
* not in the software.
*/
static int litex_check_csr_access(void __iomem *reg_addr)
{
unsigned long reg;
reg = litex_read32(reg_addr + SCRATCH_REG_OFF);
if (reg != SCRATCH_REG_VALUE) {
panic("Scratch register read error - the system is probably broken! Expected: 0x%x but got: 0x%lx",
SCRATCH_REG_VALUE, reg);
return -EINVAL;
}
litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_TEST_VALUE);
reg = litex_read32(reg_addr + SCRATCH_REG_OFF);
if (reg != SCRATCH_TEST_VALUE) {
panic("Scratch register write error - the system is probably broken! Expected: 0x%x but got: 0x%lx",
SCRATCH_TEST_VALUE, reg);
return -EINVAL;
}
/* restore original value of the SCRATCH register */
litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE);
pr_info("LiteX SoC Controller driver initialized");
return 0;
}
struct litex_soc_ctrl_device {
void __iomem *base;
};
static const struct of_device_id litex_soc_ctrl_of_match[] = {
{.compatible = "litex,soc-controller"},
{},
};
MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
static int litex_soc_ctrl_probe(struct platform_device *pdev)
{
struct litex_soc_ctrl_device *soc_ctrl_dev;
soc_ctrl_dev = devm_kzalloc(&pdev->dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
if (!soc_ctrl_dev)
return -ENOMEM;
soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(soc_ctrl_dev->base))
return PTR_ERR(soc_ctrl_dev->base);
return litex_check_csr_access(soc_ctrl_dev->base);
}
static struct platform_driver litex_soc_ctrl_driver = {
.driver = {
.name = "litex-soc-controller",
.of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
},
.probe = litex_soc_ctrl_probe,
};
module_platform_driver(litex_soc_ctrl_driver);
MODULE_DESCRIPTION("LiteX SoC Controller driver");
MODULE_AUTHOR("Antmicro <www.antmicro.com>");
MODULE_LICENSE("GPL v2");
...@@ -1567,6 +1567,38 @@ config SERIAL_MILBEAUT_USIO_CONSOLE ...@@ -1567,6 +1567,38 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
receives all kernel messages and warnings and which allows logins in receives all kernel messages and warnings and which allows logins in
single user mode). single user mode).
config SERIAL_LITEUART
tristate "LiteUART serial port support"
depends on HAS_IOMEM
depends on OF || COMPILE_TEST
depends on LITEX
select SERIAL_CORE
help
This driver is for the FPGA-based LiteUART serial controller from LiteX
SoC builder.
Say 'Y' or 'M' here if you wish to use the LiteUART serial controller.
Otherwise, say 'N'.
config SERIAL_LITEUART_MAX_PORTS
int "Maximum number of LiteUART ports"
depends on SERIAL_LITEUART
default "1"
help
Set this to the maximum number of serial ports you want the driver
to support.
config SERIAL_LITEUART_CONSOLE
bool "LiteUART serial port console support"
depends on SERIAL_LITEUART=y
select SERIAL_CORE_CONSOLE
help
Say 'Y' or 'M' here if you wish to use the FPGA-based LiteUART serial
controller from LiteX SoC builder as the system console
(the system console is the device which receives all kernel messages
and warnings and which allows logins in single user mode).
Otherwise, say 'N'.
endmenu endmenu
config SERIAL_MCTRL_GPIO config SERIAL_MCTRL_GPIO
......
...@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_OWL) += owl-uart.o ...@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_OWL) += owl-uart.o
obj-$(CONFIG_SERIAL_RDA) += rda-uart.o obj-$(CONFIG_SERIAL_RDA) += rda-uart.o
obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o
# GPIOLIB helpers for modem control lines # GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* LiteUART serial controller (LiteX) Driver
*
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
*/
#include <linux/console.h>
#include <linux/litex.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/tty_flip.h>
#include <linux/xarray.h>
/*
* CSRs definitions (base address offsets + width)
*
* The definitions below are true for LiteX SoC configured for 8-bit CSR Bus,
* 32-bit aligned.
*
* Supporting other configurations might require new definitions or a more
* generic way of indexing the LiteX CSRs.
*
* For more details on how CSRs are defined and handled in LiteX, see comments
* in the LiteX SoC Driver: drivers/soc/litex/litex_soc_ctrl.c
*/
#define OFF_RXTX 0x00
#define OFF_TXFULL 0x04
#define OFF_RXEMPTY 0x08
#define OFF_EV_STATUS 0x0c
#define OFF_EV_PENDING 0x10
#define OFF_EV_ENABLE 0x14
/* events */
#define EV_TX 0x1
#define EV_RX 0x2
struct liteuart_port {
struct uart_port port;
struct timer_list timer;
u32 id;
};
#define to_liteuart_port(port) container_of(port, struct liteuart_port, port)
static DEFINE_XARRAY_FLAGS(liteuart_array, XA_FLAGS_ALLOC);
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
static struct console liteuart_console;
#endif
static struct uart_driver liteuart_driver = {
.owner = THIS_MODULE,
.driver_name = "liteuart",
.dev_name = "ttyLXU",
.major = 0,
.minor = 0,
.nr = CONFIG_SERIAL_LITEUART_MAX_PORTS,
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
.cons = &liteuart_console,
#endif
};
static void liteuart_timer(struct timer_list *t)
{
struct liteuart_port *uart = from_timer(uart, t, timer);
struct uart_port *port = &uart->port;
unsigned char __iomem *membase = port->membase;
unsigned int flg = TTY_NORMAL;
int ch;
unsigned long status;
while ((status = !litex_read8(membase + OFF_RXEMPTY)) == 1) {
ch = litex_read8(membase + OFF_RXTX);
port->icount.rx++;
/* necessary for RXEMPTY to refresh its value */
litex_write8(membase + OFF_EV_PENDING, EV_TX | EV_RX);
/* no overflow bits in status */
if (!(uart_handle_sysrq_char(port, ch)))
uart_insert_char(port, status, 0, ch, flg);
tty_flip_buffer_push(&port->state->port);
}
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
}
static void liteuart_putchar(struct uart_port *port, int ch)
{
while (litex_read8(port->membase + OFF_TXFULL))
cpu_relax();
litex_write8(port->membase + OFF_RXTX, ch);
}
static unsigned int liteuart_tx_empty(struct uart_port *port)
{
/* not really tx empty, just checking if tx is not full */
if (!litex_read8(port->membase + OFF_TXFULL))
return TIOCSER_TEMT;
return 0;
}
static void liteuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* modem control register is not present in LiteUART */
}
static unsigned int liteuart_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void liteuart_stop_tx(struct uart_port *port)
{
}
static void liteuart_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned char ch;
if (unlikely(port->x_char)) {
litex_write8(port->membase + OFF_RXTX, port->x_char);
port->icount.tx++;
port->x_char = 0;
} else if (!uart_circ_empty(xmit)) {
while (xmit->head != xmit->tail) {
ch = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
liteuart_putchar(port, ch);
}
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
static void liteuart_stop_rx(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
del_timer(&uart->timer);
}
static void liteuart_break_ctl(struct uart_port *port, int break_state)
{
/* LiteUART doesn't support sending break signal */
}
static int liteuart_startup(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
/* disable events */
litex_write8(port->membase + OFF_EV_ENABLE, 0);
/* prepare timer for polling */
timer_setup(&uart->timer, liteuart_timer, 0);
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
return 0;
}
static void liteuart_shutdown(struct uart_port *port)
{
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
struct ktermios *old)
{
unsigned int baud;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* update baudrate */
baud = uart_get_baud_rate(port, new, old, 0, 460800);
uart_update_timeout(port, new->c_cflag, baud);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *liteuart_type(struct uart_port *port)
{
return "liteuart";
}
static void liteuart_release_port(struct uart_port *port)
{
}
static int liteuart_request_port(struct uart_port *port)
{
return 0;
}
static void liteuart_config_port(struct uart_port *port, int flags)
{
/*
* Driver core for serial ports forces a non-zero value for port type.
* Write an arbitrary value here to accommodate the serial core driver,
* as ID part of UAPI is redundant.
*/
port->type = 1;
}
static int liteuart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (port->type != PORT_UNKNOWN && ser->type != 1)
return -EINVAL;
return 0;
}
static const struct uart_ops liteuart_ops = {
.tx_empty = liteuart_tx_empty,
.set_mctrl = liteuart_set_mctrl,
.get_mctrl = liteuart_get_mctrl,
.stop_tx = liteuart_stop_tx,
.start_tx = liteuart_start_tx,
.stop_rx = liteuart_stop_rx,
.break_ctl = liteuart_break_ctl,
.startup = liteuart_startup,
.shutdown = liteuart_shutdown,
.set_termios = liteuart_set_termios,
.type = liteuart_type,
.release_port = liteuart_release_port,
.request_port = liteuart_request_port,
.config_port = liteuart_config_port,
.verify_port = liteuart_verify_port,
};
static int liteuart_probe(struct platform_device *pdev)
{
struct liteuart_port *uart;
struct uart_port *port;
struct xa_limit limit;
int dev_id, ret;
/* look for aliases; auto-enumerate for free index if not found */
dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
if (dev_id < 0)
limit = XA_LIMIT(0, CONFIG_SERIAL_LITEUART_MAX_PORTS);
else
limit = XA_LIMIT(dev_id, dev_id);
uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
if (!uart)
return -ENOMEM;
ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
if (ret)
return ret;
uart->id = dev_id;
port = &uart->port;
/* get membase */
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (!port->membase)
return -ENXIO;
/* values not from device tree */
port->dev = &pdev->dev;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &liteuart_ops;
port->regshift = 2;
port->fifosize = 16;
port->iobase = 1;
port->type = PORT_UNKNOWN;
port->line = dev_id;
spin_lock_init(&port->lock);
return uart_add_one_port(&liteuart_driver, &uart->port);
}
static int liteuart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct liteuart_port *uart = to_liteuart_port(port);
xa_erase(&liteuart_array, uart->id);
return 0;
}
static const struct of_device_id liteuart_of_match[] = {
{ .compatible = "litex,liteuart" },
{}
};
MODULE_DEVICE_TABLE(of, liteuart_of_match);
static struct platform_driver liteuart_platform_driver = {
.probe = liteuart_probe,
.remove = liteuart_remove,
.driver = {
.name = "liteuart",
.of_match_table = liteuart_of_match,
},
};
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
static void liteuart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct liteuart_port *uart;
struct uart_port *port;
unsigned long flags;
uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
port = &uart->port;
spin_lock_irqsave(&port->lock, flags);
uart_console_write(port, s, count, liteuart_putchar);
spin_unlock_irqrestore(&port->lock, flags);
}
static int liteuart_console_setup(struct console *co, char *options)
{
struct liteuart_port *uart;
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
if (!uart)
return -ENODEV;
port = &uart->port;
if (!port->membase)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct console liteuart_console = {
.name = "liteuart",
.write = liteuart_console_write,
.device = uart_console_device,
.setup = liteuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &liteuart_driver,
};
static int __init liteuart_console_init(void)
{
register_console(&liteuart_console);
return 0;
}
console_initcall(liteuart_console_init);
#endif /* CONFIG_SERIAL_LITEUART_CONSOLE */
static int __init liteuart_init(void)
{
int res;
res = uart_register_driver(&liteuart_driver);
if (res)
return res;
res = platform_driver_register(&liteuart_platform_driver);
if (res) {
uart_unregister_driver(&liteuart_driver);
return res;
}
return 0;
}
static void __exit liteuart_exit(void)
{
platform_driver_unregister(&liteuart_platform_driver);
uart_unregister_driver(&liteuart_driver);
}
module_init(liteuart_init);
module_exit(liteuart_exit);
MODULE_AUTHOR("Antmicro <www.antmicro.com>");
MODULE_DESCRIPTION("LiteUART serial driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform: liteuart");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Common LiteX header providing
* helper functions for accessing CSRs.
*
* Implementation of the functions is provided by
* the LiteX SoC Controller driver.
*
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
*/
#ifndef _LINUX_LITEX_H
#define _LINUX_LITEX_H
#include <linux/io.h>
#include <linux/types.h>
#include <linux/compiler_types.h>
/*
* The parameters below are true for LiteX SoCs configured for 8-bit CSR Bus,
* 32-bit aligned.
*
* Supporting other configurations will require extending the logic in this
* header and in the LiteX SoC controller driver.
*/
#define LITEX_REG_SIZE 0x4
#define LITEX_SUBREG_SIZE 0x1
#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8)
#define WRITE_LITEX_SUBREGISTER(val, base_offset, subreg_id) \
writel((u32 __force)cpu_to_le32(val), base_offset + (LITEX_REG_SIZE * subreg_id))
#define READ_LITEX_SUBREGISTER(base_offset, subreg_id) \
le32_to_cpu((__le32 __force)readl(base_offset + (LITEX_REG_SIZE * subreg_id)))
void litex_set_reg(void __iomem *reg, unsigned long reg_sz, unsigned long val);
unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_sz);
static inline void litex_write8(void __iomem *reg, u8 val)
{
WRITE_LITEX_SUBREGISTER(val, reg, 0);
}
static inline void litex_write16(void __iomem *reg, u16 val)
{
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 0);
WRITE_LITEX_SUBREGISTER(val, reg, 1);
}
static inline void litex_write32(void __iomem *reg, u32 val)
{
WRITE_LITEX_SUBREGISTER(val >> 24, reg, 0);
WRITE_LITEX_SUBREGISTER(val >> 16, reg, 1);
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 2);
WRITE_LITEX_SUBREGISTER(val, reg, 3);
}
static inline void litex_write64(void __iomem *reg, u64 val)
{
WRITE_LITEX_SUBREGISTER(val >> 56, reg, 0);
WRITE_LITEX_SUBREGISTER(val >> 48, reg, 1);
WRITE_LITEX_SUBREGISTER(val >> 40, reg, 2);
WRITE_LITEX_SUBREGISTER(val >> 32, reg, 3);
WRITE_LITEX_SUBREGISTER(val >> 24, reg, 4);
WRITE_LITEX_SUBREGISTER(val >> 16, reg, 5);
WRITE_LITEX_SUBREGISTER(val >> 8, reg, 6);
WRITE_LITEX_SUBREGISTER(val, reg, 7);
}
static inline u8 litex_read8(void __iomem *reg)
{
return READ_LITEX_SUBREGISTER(reg, 0);
}
static inline u16 litex_read16(void __iomem *reg)
{
return (READ_LITEX_SUBREGISTER(reg, 0) << 8)
| (READ_LITEX_SUBREGISTER(reg, 1));
}
static inline u32 litex_read32(void __iomem *reg)
{
return (READ_LITEX_SUBREGISTER(reg, 0) << 24)
| (READ_LITEX_SUBREGISTER(reg, 1) << 16)
| (READ_LITEX_SUBREGISTER(reg, 2) << 8)
| (READ_LITEX_SUBREGISTER(reg, 3));
}
static inline u64 litex_read64(void __iomem *reg)
{
return ((u64)READ_LITEX_SUBREGISTER(reg, 0) << 56)
| ((u64)READ_LITEX_SUBREGISTER(reg, 1) << 48)
| ((u64)READ_LITEX_SUBREGISTER(reg, 2) << 40)
| ((u64)READ_LITEX_SUBREGISTER(reg, 3) << 32)
| ((u64)READ_LITEX_SUBREGISTER(reg, 4) << 24)
| ((u64)READ_LITEX_SUBREGISTER(reg, 5) << 16)
| ((u64)READ_LITEX_SUBREGISTER(reg, 6) << 8)
| ((u64)READ_LITEX_SUBREGISTER(reg, 7));
}
#endif /* _LINUX_LITEX_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment