From d54c88d19380488afecbf0257fea7f5adb60ed7f Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:08 +0800 Subject: [PATCH 01/99] dt-bindings: serial: add bindings doc for Bouffalolab uart driver Add bindings doc for Bouffalolab UART Driver Signed-off-by: Jisheng Zhang --- .../bindings/serial/bouffalolab,uart.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml diff --git a/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml new file mode 100644 index 00000000000000..6cef956d33d25e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022 Jisheng Zhang +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/serial/bouffalolab,uart.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Bouffalolab UART Controller + +maintainers: + - Jisheng Zhang + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: bouffalolab,uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + aliases { + serial0 = &uart0; + }; + + uart0: serial@30002000 { + compatible = "bouffalolab,uart"; + reg = <0x30002000 0x1000>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + }; +... From 350729c7e8e9a0764bc8d943b07f651e2c3f4183 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:09 +0800 Subject: [PATCH 02/99] serial: bflb_uart: add Bouffalolab UART Driver Add the driver for Bouffalolab UART IP which is found in Bouffalolab SoCs such as bl808. UART driver probe will create path named "/dev/ttySx". Signed-off-by: Jisheng Zhang --- drivers/tty/serial/Kconfig | 18 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/bflb_uart.c | 659 +++++++++++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 + 4 files changed, 681 insertions(+) create mode 100644 drivers/tty/serial/bflb_uart.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index c55b947f3cdbb7..4b1eb61436ae76 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -179,6 +179,24 @@ config SERIAL_ATMEL_TTYAT Say Y if you have an external 8250/16C550 UART. If unsure, say N. +config SERIAL_BFLB + tristate "Bouffalolab serial port support" + select SERIAL_CORE + depends on COMMON_CLK + help + This enables the driver for the Bouffalolab's serial. + +config SERIAL_BFLB_CONSOLE + bool "Support for console on Bouffalolab serial port" + depends on SERIAL_BFLB + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Say Y here if you wish to use a Bouffalolab UART 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) as /dev/ttySn. + config SERIAL_KGDB_NMI bool "Serial console over KGDB NMI debugger port" depends on KGDB_SERIAL_CONSOLE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 238a9557b4872e..8509cdc11d874c 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250/ obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o +obj-$(CONFIG_SERIAL_BFLB) += bflb_uart.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c new file mode 100644 index 00000000000000..65f98ccf8fa81c --- /dev/null +++ b/drivers/tty/serial/bflb_uart.c @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Based on bflb_uart.c, by Bouffalolab team + * + * Copyright (C) 2022 Jisheng Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UART_UTX_CONFIG 0x00 +#define UART_CR_UTX_EN BIT(0) +#define UART_CR_UTX_CTS_EN BIT(1) +#define UART_CR_UTX_FRM_EN BIT(2) +#define UART_CR_UTX_PRT_EN BIT(4) +#define UART_CR_UTX_PRT_SEL BIT(5) +#define UART_CR_UTX_BIT_CNT_D_SFT 8 +#define UART_CR_UTX_BIT_CNT_D_MSK GENMASK(10, 8) +#define UART_CR_UTX_BIT_CNT_P_SFT 11 +#define UART_CR_UTX_BIT_CNT_P_MSK GENMASK(12, 11) +#define UART_URX_CONFIG 0x04 +#define UART_CR_URX_EN BIT(0) +#define UART_CR_URX_PRT_EN BIT(4) +#define UART_CR_URX_PRT_SEL BIT(5) +#define UART_CR_URX_BIT_CNT_D_SFT 8 +#define UART_CR_URX_BIT_CNT_D_MSK GENMASK(10, 8) +#define UART_BIT_PRD 0x08 +#define UART_CR_UTX_BIT_PRD GENMASK(15, 0) +#define UART_CR_URX_BIT_PRD GENMASK(31, 16) +#define UART_DATA_CONFIG 0x0c +#define UART_CR_UART_BIT_INV BIT(0) +#define UART_URX_RTO_TIMER 0x18 +#define UART_CR_URX_RTO_VALUE_MSK GENMASK(7, 0) +#define UART_SW_MODE 0x1c +#define UART_INT_STS (0x20) +#define UART_UTX_END_INT BIT(0) +#define UART_URX_END_INT BIT(1) +#define UART_UTX_FIFO_INT BIT(2) +#define UART_URX_FIFO_INT BIT(3) +#define UART_URX_RTO_INT BIT(4) +#define UART_URX_PCE_INT BIT(5) +#define UART_UTX_FER_INT BIT(6) +#define UART_URX_FER_INT BIT(7) +#define UART_URX_LSE_INT BIT(8) +#define UART_INT_MASK 0x24 +#define UART_INT_CLEAR 0x28 +#define UART_INT_EN 0x2c +#define UART_STATUS 0x30 +#define UART_STS_UTX_BUS_BUSY BIT(0) +#define UART_FIFO_CONFIG_0 (0x80) +#define UART_DMA_TX_EN BIT(0) +#define UART_DMA_RX_EN BIT(1) +#define UART_TX_FIFO_CLR BIT(2) +#define UART_RX_FIFO_CLR BIT(3) +#define UART_TX_FIFO_OVERFLOW BIT(4) +#define UART_TX_FIFO_UNDERFLOW BIT(5) +#define UART_RX_FIFO_OVERFLOW BIT(6) +#define UART_RX_FIFO_UNDERFLOW BIT(7) +#define UART_FIFO_CONFIG_1 (0x84) +#define UART_TX_FIFO_CNT_SFT 0 +#define UART_TX_FIFO_CNT_MSK GENMASK(5, 0) +#define UART_RX_FIFO_CNT_MSK GENMASK(13, 8) +#define UART_TX_FIFO_TH_SFT 16 +#define UART_TX_FIFO_TH_MSK GENMASK(20, 16) +#define UART_RX_FIFO_TH_SFT 24 +#define UART_RX_FIFO_TH_MSK GENMASK(28, 24) +#define UART_FIFO_WDATA 0x88 +#define UART_FIFO_RDATA 0x8c +#define UART_FIFO_RDATA_MSK GENMASK(7, 0) + +#define BFLB_UART_MAXPORTS 8 +#define BFLB_UART_BAUD 2000000 +#define BFLB_UART_RX_FIFO_TH 7 + +struct bflb_uart_port { + struct uart_port port; + struct clk *clk; +}; + +static struct bflb_uart_port *bflb_uart_ports[BFLB_UART_MAXPORTS]; + +static inline u32 rdl(struct uart_port *port, u32 reg) +{ + return readl_relaxed(port->membase + reg); +} + +static inline void wrl(struct uart_port *port, u32 reg, u32 value) +{ + writel_relaxed(value, port->membase + reg); +} + +static inline void wrb(struct uart_port *port, u32 reg, u8 value) +{ + writeb_relaxed(value, port->membase + reg); +} + +static unsigned int bflb_uart_tx_empty(struct uart_port *port) +{ + return (rdl(port, UART_FIFO_CONFIG_1) & UART_TX_FIFO_CNT_MSK) ? TIOCSER_TEMT : 0; +} + +static unsigned int bflb_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void bflb_uart_set_mctrl(struct uart_port *port, unsigned int sigs) +{ +} + +static void bflb_uart_start_tx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + + val = rdl(port, UART_INT_MASK); + val &= ~UART_UTX_END_INT; + wrl(port, UART_INT_MASK, val); + + val = rdl(port, UART_FIFO_CONFIG_1); + val &= ~UART_TX_FIFO_TH_MSK; + val |= 15 << UART_TX_FIFO_TH_SFT; + wrl(port, UART_FIFO_CONFIG_1, val); + + val = rdl(port, UART_INT_MASK); + val &= ~UART_UTX_FIFO_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_stop_tx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_INT_MASK); + val |= UART_UTX_END_INT | UART_UTX_FIFO_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_stop_rx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_URX_CONFIG); + val &= ~UART_CR_URX_EN; + wrl(port, UART_URX_CONFIG, val); + + val = rdl(port, UART_INT_MASK); + val |= UART_URX_FIFO_INT | UART_URX_RTO_INT | + UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_break_ctl(struct uart_port *port, int break_state) +{ +} + +static void bflb_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + unsigned long flags; + u32 valt, valr, val; + unsigned int baud, min; + + valt = valr = 0; + + spin_lock_irqsave(&port->lock, flags); + + /* set data length */ + val = tty_get_char_size(termios->c_cflag) - 1; + valt |= (val << UART_CR_UTX_BIT_CNT_D_SFT); + + /* calculate parity */ + termios->c_cflag &= ~CMSPAR; /* no support mark/space */ + if (termios->c_cflag & PARENB) { + valt |= UART_CR_UTX_PRT_EN; + if (termios->c_cflag & PARODD) + valr |= UART_CR_UTX_PRT_SEL; + } + + valr = valt; + + /* calculate stop bits */ + if (termios->c_cflag & CSTOPB) + val = 2; + else + val = 1; + valt |= (val << UART_CR_UTX_BIT_CNT_P_SFT); + + /* flow control */ + if (termios->c_cflag & CRTSCTS) + valt |= UART_CR_UTX_CTS_EN; + + /* enable TX freerunning mode */ + valt |= UART_CR_UTX_FRM_EN; + + valt |= UART_CR_UTX_EN; + valr |= UART_CR_URX_EN; + + wrl(port, UART_UTX_CONFIG, valt); + wrl(port, UART_URX_CONFIG, valr); + + min = port->uartclk / (UART_CR_UTX_BIT_PRD + 1); + baud = uart_get_baud_rate(port, termios, old, min, 4000000); + + val = DIV_ROUND_CLOSEST(port->uartclk, baud) - 1; + val &= UART_CR_UTX_BIT_PRD; + val |= (val << 16); + wrl(port, UART_BIT_PRD, val); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void bflb_uart_rx_chars(struct uart_port *port) +{ + unsigned char ch, flag; + unsigned long status; + + while ((status = rdl(port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { + ch = rdl(port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; + flag = TTY_NORMAL; + port->icount.rx++; + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, 0, 0, ch, flag); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); +} + +static void bflb_uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int pending, count; + + if (port->x_char) { + /* Send special char - probably flow control */ + wrl(port, UART_FIFO_WDATA, port->x_char); + port->x_char = 0; + port->icount.tx++; + return; + } + + pending = uart_circ_chars_pending(xmit); + if (pending > 0) { + count = (rdl(port, UART_FIFO_CONFIG_1) & + UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; + if (count > pending) + count = pending; + if (count > 0) { + pending -= count; + while (count--) { + wrl(port, UART_FIFO_WDATA, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + if (pending < WAKEUP_CHARS) + uart_write_wakeup(port); + } + } + + if (pending == 0) + bflb_uart_stop_tx(port); +} + +static irqreturn_t bflb_uart_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + u32 isr, val; + + isr = rdl(port, UART_INT_STS); + wrl(port, UART_INT_CLEAR, isr); + + isr &= ~rdl(port, UART_INT_MASK); + + spin_lock(&port->lock); + + if (isr & UART_URX_FER_INT) { + /* RX FIFO error interrupt */ + val = rdl(port, UART_FIFO_CONFIG_0); + if (val & UART_RX_FIFO_OVERFLOW) + port->icount.overrun++; + + val |= UART_RX_FIFO_CLR; + wrl(port, UART_FIFO_CONFIG_0, val); + } + + if (isr & (UART_URX_FIFO_INT | UART_URX_RTO_INT)) { + bflb_uart_rx_chars(port); + } + if (isr & (UART_UTX_FIFO_INT | UART_UTX_END_INT)) { + bflb_uart_tx_chars(port); + } + + spin_unlock(&port->lock); + + return IRQ_RETVAL(isr); +} + +static void bflb_uart_config_port(struct uart_port *port, int flags) +{ + u32 val; + + port->type = PORT_BFLB; + + /* Clear mask, so no surprise interrupts. */ + val = rdl(port, UART_INT_MASK); + val |= UART_UTX_END_INT; + val |= UART_UTX_FIFO_INT; + val |= UART_URX_FIFO_INT; + val |= UART_URX_RTO_INT; + val |= UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); +} + +static int bflb_uart_startup(struct uart_port *port) +{ + unsigned long flags; + int ret; + u32 val; + + ret = devm_request_irq(port->dev, port->irq, bflb_uart_interrupt, + IRQF_SHARED, port->name, port); + if (ret) { + dev_err(port->dev, "fail to request serial irq %d, ret=%d\n", + port->irq, ret); + return ret; + } + + spin_lock_irqsave(&port->lock, flags); + + val = rdl(port, UART_INT_MASK); + val |= 0xfff; + wrl(port, UART_INT_MASK, val); + + wrl(port, UART_DATA_CONFIG, 0); + wrl(port, UART_SW_MODE, 0); + wrl(port, UART_URX_RTO_TIMER, 0x4f); + + val = rdl(port, UART_FIFO_CONFIG_1); + val &= ~UART_RX_FIFO_TH_MSK; + val |= BFLB_UART_RX_FIFO_TH << UART_RX_FIFO_TH_SFT; + wrl(port, UART_FIFO_CONFIG_1, val); + + /* Unmask RX interrupts now */ + val = rdl(port, UART_INT_MASK); + val &= ~UART_URX_FIFO_INT; + val &= ~UART_URX_RTO_INT; + val &= ~UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + val = rdl(port, UART_URX_CONFIG); + val |= UART_CR_URX_EN; + wrl(port, UART_URX_CONFIG, val); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void bflb_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + /* mask all interrupts now */ + wrl(port, UART_INT_MASK, UART_UTX_END_INT | UART_URX_END_INT); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *bflb_uart_type(struct uart_port *port) +{ + return (port->type == PORT_BFLB) ? "BFLB UART" : NULL; +} + +static int bflb_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void bflb_uart_release_port(struct uart_port *port) +{ + /* Nothing to release... */ +} + +static int bflb_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_BFLB) + return -EINVAL; + return 0; +} + +static const struct uart_ops bflb_uart_ops = { + .tx_empty = bflb_uart_tx_empty, + .get_mctrl = bflb_uart_get_mctrl, + .set_mctrl = bflb_uart_set_mctrl, + .start_tx = bflb_uart_start_tx, + .stop_tx = bflb_uart_stop_tx, + .stop_rx = bflb_uart_stop_rx, + .break_ctl = bflb_uart_break_ctl, + .startup = bflb_uart_startup, + .shutdown = bflb_uart_shutdown, + .set_termios = bflb_uart_set_termios, + .type = bflb_uart_type, + .request_port = bflb_uart_request_port, + .release_port = bflb_uart_release_port, + .config_port = bflb_uart_config_port, + .verify_port = bflb_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_BFLB_CONSOLE +static void bflb_console_putchar(struct uart_port *port, unsigned char ch) +{ + while (!(rdl(port, UART_FIFO_CONFIG_1) & UART_TX_FIFO_CNT_MSK)) + cpu_relax(); + wrb(port, UART_FIFO_WDATA, ch); +} + +/* + * Interrupts are disabled on entering + */ +static void bflb_uart_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_port *port = &bflb_uart_ports[co->index]->port; + u32 status, reg, mask; + + /* save then disable interrupts */ + mask = rdl(port, UART_INT_MASK); + reg = -1; + wrl(port, UART_INT_MASK, reg); + + /* Make sure that tx is enabled */ + reg = rdl(port, UART_UTX_CONFIG); + reg |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, reg); + + uart_console_write(port, s, count, bflb_console_putchar); + + /* wait for TX done */ + do { + status = rdl(port, UART_STATUS); + } while ((status & UART_STS_UTX_BUS_BUSY)); + + /* restore IRQ mask */ + wrl(port, UART_INT_MASK, mask); +} + +static int bflb_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct bflb_uart_port *bp; + int baud = BFLB_UART_BAUD; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + u32 val; + + if (co->index >= BFLB_UART_MAXPORTS || co->index < 0) + return -EINVAL; + + bp = bflb_uart_ports[co->index]; + if (!bp) + /* Port not initialized yet - delay setup */ + return -ENODEV; + + port = &bp->port; + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver bflb_uart_driver; +static struct console bflb_uart_console = { + .name = "ttyS", + .write = bflb_uart_console_write, + .device = uart_console_device, + .setup = bflb_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bflb_uart_driver, +}; + +static int __init bflb_uart_console_init(void) +{ + register_console(&bflb_uart_console); + return 0; +} +console_initcall(bflb_uart_console_init); + +#define BFLB_UART_CONSOLE (&bflb_uart_console) + +static void bflb_uart_earlycon_write(struct console *co, const char *s, + unsigned int count) +{ + struct earlycon_device *dev = co->data; + + uart_console_write(&dev->port, s, count, bflb_console_putchar); +} + +static int __init bflb_uart_earlycon_setup(struct earlycon_device *dev, + const char *options) +{ + if (!dev->port.membase) + return -ENODEV; + + dev->con->write = bflb_uart_earlycon_write; + + return 0; +} +OF_EARLYCON_DECLARE(bflb_uart, "bouffalolab,uart", bflb_uart_earlycon_setup); + +#else + +#define BFLB_UART_CONSOLE NULL + +#endif /* CONFIG_SERIAL_BFLB_CONSOLE */ + +static struct uart_driver bflb_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "bflb_uart", + .dev_name = "ttyS", + .nr = BFLB_UART_MAXPORTS, + .cons = BFLB_UART_CONSOLE, +}; + +static int bflb_uart_probe(struct platform_device *pdev) +{ + struct uart_port *port; + struct bflb_uart_port *bp; + struct resource *res; + int index, irq; + + index = of_alias_get_id(pdev->dev.of_node, "serial"); + if (unlikely(index < 0 || index >= BFLB_UART_MAXPORTS)) { + dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index); + return -EINVAL; + } + + bp = devm_kzalloc(&pdev->dev, sizeof(*bp), GFP_KERNEL); + if (!bp) + return -ENOMEM; + + bflb_uart_ports[index] = bp; + platform_set_drvdata(pdev, bp); + port = &bp->port; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + port->mapbase = res->start; + port->irq = irq; + port->line = index; + port->type = PORT_BFLB; + port->iotype = UPIO_MEM; + port->fifosize = 32; + port->ops = &bflb_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_BFLB_CONSOLE); + + bp->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bp->clk)) + return PTR_ERR(bp->clk); + port->uartclk = clk_get_rate(bp->clk); + + return uart_add_one_port(&bflb_uart_driver, port); +} + +static int bflb_uart_remove(struct platform_device *pdev) +{ + struct bflb_uart_port *bp = platform_get_drvdata(pdev); + + uart_remove_one_port(&bflb_uart_driver, &bp->port); + bflb_uart_ports[bp->port.line] = NULL; + + return 0; +} + +static const struct of_device_id bflb_uart_match[] = { + { + .compatible = "bouffalolab,uart", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bflb_uart_match); + +static struct platform_driver bflb_uart_platform_driver = { + .probe = bflb_uart_probe, + .remove = bflb_uart_remove, + .driver = { + .name = "bflb_uart", + .of_match_table = of_match_ptr(bflb_uart_match), + }, +}; + +static int __init bflb_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&bflb_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&bflb_uart_platform_driver); + if (ret) + uart_unregister_driver(&bflb_uart_driver); + + return ret; +} + +static void __exit bflb_uart_exit(void) +{ + platform_driver_unregister(&bflb_uart_platform_driver); + uart_unregister_driver(&bflb_uart_driver); +} + +module_init(bflb_uart_init); +module_exit(bflb_uart_exit); + +MODULE_DESCRIPTION("Bouffalolab UART driver"); +MODULE_AUTHOR("Jisheng Zhang "); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 3ba34d8378bd0e..dabbb5ea285738 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -276,4 +276,7 @@ /* Sunplus UART */ #define PORT_SUNPLUS 123 +/* Bouffalolab UART */ +#define PORT_BFLB 124 + #endif /* _UAPILINUX_SERIAL_CORE_H */ From 4b71f54a5821e1ae0fac8c2a44e25123530c5e76 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:10 +0800 Subject: [PATCH 03/99] MAINTAINERS: add myself as a reviewer for Bouffalolab uart driver I want to maintain this Bouffalolab uart driver from now on. Signed-off-by: Jisheng Zhang --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea941dc469fa1f..dce6b97c4ed4d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3785,6 +3785,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* +BOUFFALOLAB UART DRIVER +M: Jisheng Zhang +S: Maintained +F: Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml +F: drivers/tty/serial/bflb_uart.c + BPF [GENERAL] (Safe Dynamic Programs and Tools) M: Alexei Starovoitov M: Daniel Borkmann From 87e493b1d6b25ef51ccf4edadbebe38bd8583222 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:11 +0800 Subject: [PATCH 04/99] riscv: add the Bouffalolab SoC family Kconfig option The Bouffalolab bl808 SoC contains three riscv CPUs, namely M0, D0 and LP. The D0 is 64bit RISC-V GC compatible, so can run linux. Signed-off-by: Jisheng Zhang --- arch/riscv/Kconfig.socs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 4b6deb2715f1c4..a68ab2172230e5 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -1,5 +1,11 @@ menu "SoC selection" +config SOC_BOUFFALOLAB + bool "Bouffalolab SoCs" + select SIFIVE_PLIC + help + This enables support for Bouffalolab SoC platforms. + config SOC_MICROCHIP_POLARFIRE bool "Microchip PolarFire SoCs" select MCHP_CLK_MPFS From 9492a693822a8c51351eaa04fca0666db140fe15 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:12 +0800 Subject: [PATCH 05/99] riscv: dts: bouffalolab: add the bl808 SoC base device tree Add a baisc dtsi for the bouffalolab bl808 SoC. Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 74 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808.dtsi diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index b0ff5fbabb0c9a..2d4376810bcc75 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +subdir-y += bouffalolab subdir-y += sifive subdir-y += starfive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi new file mode 100644 index 00000000000000..c98ebb14ee10a6 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +#include + +/ { + compatible = "bouffalolab,bl808"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + timebase-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "thead,c906", "riscv"; + device_type = "cpu"; + reg = <0>; + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <32768>; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <32768>; + mmu-type = "riscv,sv39"; + riscv,isa = "rv64imafdc"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + ranges; + interrupt-parent = <&plic>; + dma-noncoherent; + #address-cells = <1>; + #size-cells = <1>; + + uart0: serial@30002000 { + compatible = "bouffalolab,uart"; + reg = <0x30002000 0x1000>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + status = "disabled"; + }; + + plic: interrupt-controller@e0000000 { + compatible = "thead,c900-plic"; + reg = <0xe0000000 0x4000000>; + interrupts-extended = <&cpu0_intc 0xffffffff>, + <&cpu0_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <64>; + }; + }; +}; From d22d4a678ec3fb88015e458077de5e933d860513 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:13 +0800 Subject: [PATCH 06/99] riscv: dts: bouffalolab: add Sipeed M1S dock devicetree Sipeed manufactures a M1S system-on-module and dock board, add basic support for them. Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/bouffalolab/Makefile | 2 ++ .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 arch/riscv/boot/dts/bouffalolab/Makefile create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts diff --git a/arch/riscv/boot/dts/bouffalolab/Makefile b/arch/riscv/boot/dts/bouffalolab/Makefile new file mode 100644 index 00000000000000..42e17e1a97bd17 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-sipeed-m1s.dtb diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts new file mode 100644 index 00000000000000..64421fb2ad67d9 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" + +/ { + model = "Sipeed M1S"; + compatible = "sipeed,m1s", "bouffalolab,bl808"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; +}; + +&uart0 { + status = "okay"; +}; From e1525068345d782bc4626b5927781760639bd6aa Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:14 +0800 Subject: [PATCH 07/99] MAINTAINERS: add myself as Bouffalolab SoC entry maintainer I want to maintain this Bouffalolab riscv SoC entry from now on. Signed-off-by: Jisheng Zhang --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index dce6b97c4ed4d5..9508391b8dbe20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17961,6 +17961,12 @@ F: arch/riscv/ N: riscv K: riscv +RISC-V BOUFFALOLAB SOC SUPPORT +M: Jisheng Zhang +L: linux-riscv at lists.infradead.org +S: Maintained +F: arch/riscv/boot/dts/bouffalolab/ + RISC-V MICROCHIP FPGA SUPPORT M: Conor Dooley M: Daire McNamara From 4f79f75bcb01d0f90d30f54f18fac16cc25646b5 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 01:35:45 -0800 Subject: [PATCH 08/99] riscv: bl808: Add defconfig --- arch/riscv/configs/bl808_defconfig | 143 +++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 arch/riscv/configs/bl808_defconfig diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig new file mode 100644 index 00000000000000..8a441a64be1a85 --- /dev/null +++ b/arch/riscv/configs/bl808_defconfig @@ -0,0 +1,143 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_PERF_EVENTS=y +CONFIG_SOC_BOUFFALOLAB=y +CONFIG_SOC_VIRT=y +CONFIG_ERRATA_THEAD=y +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_RISCV_SBI_V01=y +# CONFIG_COMPAT is not set +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_PAGE_REPORTING=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_DNS_RESOLVER=y +CONFIG_NETLINK_DIAG=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK_RO=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_ROM=y +CONFIG_MTD_ABSENT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PHYSMAP_VERSATILE=y +CONFIG_MTD_PHYSMAP_GEMINI=y +CONFIG_MTD_PLATRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_VIRTIO=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +CONFIG_MDIO_DEVICE=y +# CONFIG_WLAN is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_BFLB=y +CONFIG_SERIAL_BFLB_CONSOLE=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_XILINX=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +CONFIG_I2C_DEBUG_BUS=y +CONFIG_FB=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_SYNC_FILE=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_VIRTIO=y +CONFIG_GENERIC_PHY=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_KEYS=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CRC16=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_XZ_DEC=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_VM_PGTABLE=y +CONFIG_DEBUG_TIMEKEEPING=y +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_RUNTIME_TESTING_MENU is not set +CONFIG_MEMTEST=y From 8e81e9413aaa7c01a73294df771e9e3b5d34289c Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 02:25:29 -0800 Subject: [PATCH 09/99] riscv: dts: bouffalolab: add bootargs/initrd --- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 64421fb2ad67d9..84e5aac6cbf851 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -17,6 +17,9 @@ chosen { stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; }; memory@50000000 { From c32fe195358bd4ad3c0e9653432150393e7cbaed Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 02:26:04 -0800 Subject: [PATCH 10/99] riscv: dts: bouffalolab: add xip_flash --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 84e5aac6cbf851..bdb502ea5a5489 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -26,6 +26,20 @@ device_type = "memory"; reg = <0x50000000 0x04000000>; }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + + rootfs@0 { + label = "rootfs"; + reg = <0x00000 0x280000>; + read-only; + }; + }; }; &uart0 { From 986848ef501b28ccbe48336dfa201ad54b0e1e34 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:14:53 -0800 Subject: [PATCH 11/99] WIP: add BFLB MBOX interrupt controller driver --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 + arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 14 + drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/bflb-ipc.c | 381 ++++++++++++++++++ include/dt-bindings/mailbox/bflb-ipc.h | 16 + 6 files changed, 426 insertions(+) create mode 100644 drivers/mailbox/bflb-ipc.c create mode 100644 include/dt-bindings/mailbox/bflb-ipc.h diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index bdb502ea5a5489..70259bad7dfd31 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -45,3 +45,7 @@ &uart0 { status = "okay"; }; + +&ipclic { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index c98ebb14ee10a6..c5cda8d74ccd9d 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -4,6 +4,7 @@ */ #include +#include / { compatible = "bouffalolab,bl808"; @@ -60,6 +61,19 @@ status = "disabled"; }; + ipclic: mailbox@30005000 { + compatible = "bouffalolab,bflb-ipc"; + reg = <0x30005000 0x20>, + <0x30005020 0x20>, + <0x2000a800 0x20>, + <0x2000a820 0x20>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + status = "disabled"; + }; + plic: interrupt-controller@e0000000 { compatible = "thead,c900-plic"; reg = <0xe0000000 0x4000000>; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 1495965bc394c0..c215da153fd7be 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -295,4 +295,13 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config BFLB_IPC + tristate "Bouffalo Lab IPC driver" + depends on OF + help + (IPC) driver for BL808 devices. The driver provides mailbox support for + sending interrupts to the clients. On the other hand, the driver also + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fc93761171113e..02bba5d03d4b2c 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o + +obj-$(CONFIG_BFLB_IPC) += bflb-ipc.o diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c new file mode 100644 index 00000000000000..692dd20e35a8d1 --- /dev/null +++ b/drivers/mailbox/bflb-ipc.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Allen Martin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* IPC Register offsets */ +#define IPC_REG_ISWR 0x00 /* Interrupt Set Write Register */ +#define IPC_REG_IRSRR 0x04 /* Interrupt raw status Register */ +#define IPC_REG_ICR 0x08 /* Interrupt Clear Register */ +#define IPC_REG_IUSR 0x0c /* Interrupt Unmask Set Register */ +#define IPC_REG_IUCR 0x10 /* Interrupt Unmask Clear Register */ +#define IPC_REG_ILSLR 0x14 /* Interrupt Line Sel Low Register */ +#define IPC_REG_ILSHR 0x18 /* Interrupt Line Sel High Register */ +#define IPC_REG_ISR 0x1c /* Interrupt status Register */ + +/** + * struct bflb_ipc_chan_info - Per-mailbox-channel info + * @client_id: The client-id to which the interrupt has to be triggered + * @signal_id: The signal-id to which the interrupt has to be triggered + */ +struct bflb_ipc_chan_info { + u16 client_id; + u16 signal_id; +}; + +/** + * struct bflb_ipc - Holder for the mailbox driver + * @dev: Device associated with this instance + * @base: Base address of each IPC frame (LP, M0) + * @irq_domain: The irq_domain associated with this instance + * @chans: The mailbox channels array + * @mchan: The per-mailbox channel info array + * @mbox: The mailbox controller + * @num_chans: Number of @chans elements + * @irq: Summary irq + */ +struct bflb_ipc { + struct device *dev; + void __iomem *base[4]; + struct irq_domain *irq_domain; + struct mbox_chan *chans; + struct bflb_ipc_chan_info *mchan; + struct mbox_controller mbox; + int num_chans; + int irq; +}; + +static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mbox) +{ + return container_of(mbox, struct bflb_ipc, mbox); +} + +static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device) +{ + pr_debug("%s: source: %u, device: %u\n", __func__, source, device); + + return device; +} + +#if 0 +static void bflb_ipc_dump_regs(struct bflb_ipc *ipc) +{ + int i; + for (i=0; i<4; i++) { + dev_dbg(ipc->dev, "base %px\n", ipc->base[i]); + dev_dbg(ipc->dev, "ISWR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISWR)); + dev_dbg(ipc->dev, "IRSRR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IRSRR)); + dev_dbg(ipc->dev, "ICR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ICR)); + dev_dbg(ipc->dev, "IUSR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IUSR)); + dev_dbg(ipc->dev, "IUCR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IUCR)); + dev_dbg(ipc->dev, "ILSLR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ILSLR)); + dev_dbg(ipc->dev, "ILSHR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ILSHR)); + dev_dbg(ipc->dev, "ISR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISR)); + } +} +#endif + +static irqreturn_t bflb_ipc_irq_fn(int irq, void *data) +{ + struct bflb_ipc *ipc = data; + unsigned long stat; + int pos; + + stat = readl(ipc->base[1] + IPC_REG_ISR); + for_each_set_bit(pos, &stat, 32) + generic_handle_domain_irq(ipc->irq_domain, pos); + writel(stat, ipc->base[1] + IPC_REG_ICR); + + /* EOI the irqs */ + writel(stat, ipc->base[2] + IPC_REG_ISWR); + + return IRQ_HANDLED; +} + +static void bflb_ipc_mask_irq(struct irq_data *irqd) +{ + struct bflb_ipc *ipc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(BIT(hwirq), ipc->base[1] + IPC_REG_IUCR); +} + +static void bflb_ipc_unmask_irq(struct irq_data *irqd) +{ + struct bflb_ipc *ipc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(BIT(hwirq), ipc->base[1] + IPC_REG_IUSR); +} + +static struct irq_chip bflb_ipc_irq_chip = { + .name = "BFLB MBOXIC", + .irq_mask = bflb_ipc_mask_irq, + .irq_unmask = bflb_ipc_unmask_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static int bflb_ipc_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct bflb_ipc *ipc = d->host_data; + + irq_set_chip_and_handler(irq, &bflb_ipc_irq_chip, handle_level_irq); + irq_set_chip_data(irq, ipc); + irq_set_noprobe(irq); + + return 0; +} + +static int bflb_ipc_domain_xlate(struct irq_domain *d, + struct device_node *node, const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (intsize != 3) + return -EINVAL; + + *out_hwirq = bflb_ipc_get_hwirq(intspec[0], intspec[1]); + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static const struct irq_domain_ops bflb_ipc_irq_ops = { + .map = bflb_ipc_domain_map, + .xlate = bflb_ipc_domain_xlate, +}; + +static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox); + struct bflb_ipc_chan_info *mchan = chan->con_priv; + u32 hwirq; + + hwirq = bflb_ipc_get_hwirq(mchan->client_id, mchan->signal_id); + + dev_dbg(ipc->dev, "%s: hwirq: %u\n", __func__, hwirq); + +// writel(hwirq, ipc->base + IPC_REG_SEND_ID); + + return 0; +} + +static void bflb_ipc_mbox_shutdown(struct mbox_chan *chan) +{ + pr_debug("%s\n", __func__); + chan->con_priv = NULL; +} + +static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *ph) +{ + struct bflb_ipc *ipc = to_bflb_ipc(mbox); + struct bflb_ipc_chan_info *mchan; + struct mbox_chan *chan; + struct device *dev; + int chan_id; + + dev = ipc->dev; + + dev_dbg(dev, "%s\n", __func__); + + if (ph->args_count != 2) + return ERR_PTR(-EINVAL); + + for (chan_id = 0; chan_id < mbox->num_chans; chan_id++) { + chan = &ipc->chans[chan_id]; + mchan = chan->con_priv; + + if (!mchan) + break; + else if (mchan->client_id == ph->args[0] && + mchan->signal_id == ph->args[1]) + return ERR_PTR(-EBUSY); + } + + if (chan_id >= mbox->num_chans) + return ERR_PTR(-EBUSY); + + mchan = devm_kzalloc(dev, sizeof(*mchan), GFP_KERNEL); + if (!mchan) + return ERR_PTR(-ENOMEM); + + mchan->client_id = ph->args[0]; + mchan->signal_id = ph->args[1]; + chan->con_priv = mchan; + + return chan; +} + +static const struct mbox_chan_ops ipc_mbox_chan_ops = { + .send_data = bflb_ipc_mbox_send_data, + .shutdown = bflb_ipc_mbox_shutdown, +}; + +static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, + struct device_node *controller_dn) +{ + struct of_phandle_args curr_ph; + struct device_node *client_dn; + struct mbox_controller *mbox; + struct device *dev = ipc->dev; + int i, j, ret; + + /* + * Find out the number of clients interested in this mailbox + * and create channels accordingly. + */ + ipc->num_chans = 0; + for_each_node_with_property(client_dn, "mboxes") { + if (!of_device_is_available(client_dn)) + continue; + i = of_count_phandle_with_args(client_dn, + "mboxes", "#mbox-cells"); + for (j = 0; j < i; j++) { + ret = of_parse_phandle_with_args(client_dn, "mboxes", + "#mbox-cells", j, &curr_ph); + of_node_put(curr_ph.np); + if (!ret && curr_ph.np == controller_dn) { + ipc->num_chans++; + break; + } + } + } + + /* If no clients are found, skip registering as a mbox controller */ + if (!ipc->num_chans) + return 0; + + ipc->chans = devm_kcalloc(dev, ipc->num_chans, + sizeof(struct mbox_chan), GFP_KERNEL); + if (!ipc->chans) + return -ENOMEM; + + mbox = &ipc->mbox; + mbox->dev = dev; + mbox->num_chans = ipc->num_chans; + mbox->chans = ipc->chans; + mbox->ops = &ipc_mbox_chan_ops; + mbox->of_xlate = bflb_ipc_mbox_xlate; + mbox->txdone_irq = false; + mbox->txdone_poll = false; + + return devm_mbox_controller_register(dev, mbox); +} + +static int bflb_ipc_pm_resume(struct device *dev) +{ + return 0; +} + +static int bflb_ipc_probe(struct platform_device *pdev) +{ + struct bflb_ipc *ipc; + static int id; + int i; + char *name; + int ret; + + ipc = devm_kzalloc(&pdev->dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return -ENOMEM; + + ipc->dev = &pdev->dev; + + for (i=0; i<4; i++) { + ipc->base[i] = devm_platform_ioremap_resource(pdev, i); + if (IS_ERR(ipc->base[i])) + return PTR_ERR(ipc->base[i]); + } + + ipc->irq = platform_get_irq(pdev, 0); + if (ipc->irq < 0) + return ipc->irq; + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "mboxic%d", id++); + if (!name) + return -ENOMEM; + + ipc->irq_domain = irq_domain_add_tree(pdev->dev.of_node, + &bflb_ipc_irq_ops, ipc); + if (!ipc->irq_domain) + return -ENOMEM; + + ret = bflb_ipc_setup_mbox(ipc, pdev->dev.of_node); + if (ret) + goto err_mbox; + + ret = devm_request_irq(&pdev->dev, ipc->irq, bflb_ipc_irq_fn, + IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND | + IRQF_NO_THREAD, name, ipc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register the irq: %d\n", ret); + goto err_req_irq; + } + + platform_set_drvdata(pdev, ipc); + + dev_info(&pdev->dev, "Bouffalo Lab IPC mailbox interrupt controller"); + return 0; + +err_req_irq: + if (ipc->num_chans) + mbox_controller_unregister(&ipc->mbox); +err_mbox: + irq_domain_remove(ipc->irq_domain); + + return ret; +} + +static int bflb_ipc_remove(struct platform_device *pdev) +{ + struct bflb_ipc *ipc = platform_get_drvdata(pdev); + + disable_irq_wake(ipc->irq); + irq_domain_remove(ipc->irq_domain); + + return 0; +} + +static const struct of_device_id bflb_ipc_of_match[] = { + { .compatible = "bouffalolab,bflb-ipc"}, + {} +}; +MODULE_DEVICE_TABLE(of, bflb_ipc_of_match); + +static const struct dev_pm_ops bflb_ipc_dev_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, bflb_ipc_pm_resume) +}; + +static struct platform_driver bflb_ipc_driver = { + .probe = bflb_ipc_probe, + .remove = bflb_ipc_remove, + .driver = { + .name = "bflb-ipc", + .of_match_table = bflb_ipc_of_match, + .suppress_bind_attrs = true, + .pm = pm_sleep_ptr(&bflb_ipc_dev_pm_ops), + }, +}; + +static int __init bflb_ipc_init(void) +{ + return platform_driver_register(&bflb_ipc_driver); +} +arch_initcall(bflb_ipc_init); + +MODULE_AUTHOR("Allen Martin "); +MODULE_DESCRIPTION("Bouffalo Lab IPC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h new file mode 100644 index 00000000000000..1d4c4be6292e97 --- /dev/null +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2023 Allen Martin + */ + +#ifndef __DT_BINDINGS_MAILBOX_BFLB_IPC_H +#define __DT_BINDINGS_MAILBOX_BFLB_IPC_H + +/* Source processor */ +#define BFLB_IPC_SOURCE_M0 0 +#define BFLB_IPC_SOURCE_LP 1 + +/* Peripheral device ID */ +#define BFLB_IPC_DEVICE_SDHCI 0 + +#endif From 14d10e1f6fd28f9c760c46b5fd1becd2f2b20f9a Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:16:51 -0800 Subject: [PATCH 12/99] WIP: sdhci: add BFLB sdhci driver --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 + arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 11 ++ drivers/mmc/host/Kconfig | 14 +++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-bflb.c | 117 ++++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 drivers/mmc/host/sdhci-bflb.c diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 70259bad7dfd31..effaeda67c3fb7 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -46,6 +46,10 @@ status = "okay"; }; +&sdhci0 { + status = "okay"; +}; + &ipclic { status = "okay"; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index c5cda8d74ccd9d..6f859194f82c36 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -61,6 +61,17 @@ status = "disabled"; }; + sdhci0: sdhci@20060000 { + compatible = "bouffalolab,bflb-sdhci"; + reg = <0x20060000 0x100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_SDHCI + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; + clocks = <&xtal>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bouffalolab,bflb-ipc"; reg = <0x30005000 0x20>, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5e19a961c34d7b..f3c4654bb376e0 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -413,6 +413,20 @@ config MMC_SDHCI_F_SDH30 If unsure, say N. +config MMC_SDHCI_BFLB + tristate "SDHCI support on Bouffalo Lab BL808 SoC" + depends on MMC_SDHCI_PLTFM + depends on OF + depends on COMMON_CLK + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Secure Digital Host Controller Interface in + Bouffalo Lab BL808 SoC. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_MILBEAUT tristate "SDHCI support for Socionext Milbeaut Serieas using F_SDH30" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ba0c6d0cd85d7a..626875dfb629a3 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -103,6 +103,7 @@ cqhci-y += cqhci-core.o cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o obj-$(CONFIG_MMC_HSQ) += mmc_hsq.o obj-$(CONFIG_MMC_LITEX) += litex_mmc.o +obj-$(CONFIG_MMC_SDHCI_BFLB) += sdhci-bflb.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c new file mode 100644 index 00000000000000..a67ecb2a380df4 --- /dev/null +++ b/drivers/mmc/host/sdhci-bflb.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +static u16 sdhci_bflb_readw(struct sdhci_host *host, int reg) +{ + u16 ret; + + switch (reg) { + case SDHCI_HOST_VERSION: + case SDHCI_SLOT_INT_STATUS: + /* those registers don't exist */ + return 0; + default: + ret = readw(host->ioaddr + reg); + } + return ret; +} + +static u32 sdhci_bflb_readl(struct sdhci_host *host, int reg) +{ + u32 ret; + + ret = readl(host->ioaddr + reg); + + switch (reg) { + case SDHCI_CAPABILITIES: + /* Mask the support for 3.0V */ + ret &= ~SDHCI_CAN_VDD_300; + break; + } + return ret; +} + +static const struct sdhci_ops sdhci_bflb_ops = { + .read_w = sdhci_bflb_readw, + .read_l = sdhci_bflb_readl, + .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data sdhci_bflb_pdata = { + .ops = &sdhci_bflb_ops, + .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | + SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_BROKEN_DMA | + SDHCI_QUIRK_BROKEN_ADMA | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +}; + +static int sdhci_bflb_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + int ret; + + host = sdhci_pltfm_init(pdev, &sdhci_bflb_pdata, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(pltfm_host->clk)) + clk_prepare_enable(pltfm_host->clk); + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_sdhci_add; + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; + + return 0; + +err_sdhci_add: + clk_disable_unprepare(pltfm_host->clk); + sdhci_pltfm_free(pdev); + return ret; +} + +static const struct of_device_id sdhci_bflb_of_match_table[] = { + { .compatible = "bouffalolab,bflb-sdhci", }, + {} +}; +MODULE_DEVICE_TABLE(of, sdhci_bflb_of_match_table); + +static struct platform_driver sdhci_bflb_driver = { + .driver = { + .name = "sdhci-bflb", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &sdhci_pltfm_pmops, + .of_match_table = sdhci_bflb_of_match_table, + }, + .probe = sdhci_bflb_probe, + .remove = sdhci_pltfm_unregister, +}; + +module_platform_driver(sdhci_bflb_driver); + +MODULE_DESCRIPTION("SDHCI driver for Bflb"); +MODULE_LICENSE("GPL v2"); From cb83beb6caf80f4cf52463472d17dee08208b89e Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:22:09 -0800 Subject: [PATCH 13/99] bl808_defconfig: enable sdhci driver --- arch/riscv/configs/bl808_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 8a441a64be1a85..049fe1c25d74ec 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -103,6 +103,10 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_HID_MICROSOFT is not set # CONFIG_HID_MONTEREY is not set # CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_BFLB=y CONFIG_RTC_CLASS=y CONFIG_SYNC_FILE=y # CONFIG_VIRTIO_MENU is not set From a8f49a4343c408ab54050bb078e7232bdcadcbad Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:22:29 -0800 Subject: [PATCH 14/99] bl808_defconfig: enable mailbox irqchip driver --- arch/riscv/configs/bl808_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 049fe1c25d74ec..d2786235830294 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -111,6 +111,8 @@ CONFIG_RTC_CLASS=y CONFIG_SYNC_FILE=y # CONFIG_VIRTIO_MENU is not set # CONFIG_VHOST_MENU is not set +CONFIG_MAILBOX=y +CONFIG_BFLB_IPC=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_VIRTIO=y From f3576355f728d3854eab1a063ee8610c8ffb866b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:23:03 -0800 Subject: [PATCH 15/99] bl808_defconfig: enable irq debugfs --- arch/riscv/configs/bl808_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index d2786235830294..0cc8c786a522b2 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -1,5 +1,6 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_GENERIC_IRQ_DEBUGFS=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y From 1561f91d7f7f2952f3789b560144cdd56180bfb4 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 03:02:41 -0800 Subject: [PATCH 16/99] disable card detection/dma/cap clock quirks --- drivers/mmc/host/sdhci-bflb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index a67ecb2a380df4..c9141ddd733176 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,11 +55,7 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_BROKEN_ADMA | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + SDHCI_QUIRK_NO_HISPD_BIT, }; static int sdhci_bflb_probe(struct platform_device *pdev) From d0578027489b1e697a1910b7182d152a136c0a4e Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:05:40 +0000 Subject: [PATCH 17/99] UART2 working under Linux! --- arch/riscv/boot/dts/bouffalolab/Makefile | 1 + .../dts/bouffalolab/bl808-pine64-ox64.dts | 60 +++++++++++++++++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 13 +++- include/dt-bindings/mailbox/bflb-ipc.h | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts diff --git a/arch/riscv/boot/dts/bouffalolab/Makefile b/arch/riscv/boot/dts/bouffalolab/Makefile index 42e17e1a97bd17..bc7aad3d560406 100644 --- a/arch/riscv/boot/dts/bouffalolab/Makefile +++ b/arch/riscv/boot/dts/bouffalolab/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-sipeed-m1s.dtb +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-pine64-ox64.dtb diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts new file mode 100644 index 00000000000000..a3b1ae9f04780d --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" + +/ { + model = "Pine64 Ox64"; + compatible = "sipeed,m1s", "bouffalolab,bl808"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + + rootfs@0 { + label = "rootfs"; + reg = <0x00000 0x280000>; + read-only; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&sdhci0 { + status = "okay"; +}; + +&ipclic { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 6f859194f82c36..755071f80b5904 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -60,7 +60,18 @@ clocks = <&xtal>; status = "disabled"; }; - + + uart1: serial@0x2000AA00 { + compatible = "bouffalolab,uart"; + reg = <0x2000AA00 0x0100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_UART2 + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2>; + clocks = <&xtal>; + status = "disabled"; + }; + sdhci0: sdhci@20060000 { compatible = "bouffalolab,bflb-sdhci"; reg = <0x20060000 0x100>; diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 1d4c4be6292e97..e96fe62cbeb9a2 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -12,5 +12,6 @@ /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 +#define BFLB_IPC_DEVICE_UART2 1 #endif From ffab227813189651186b3cf2cc568d365c0753d9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 14 Jan 2023 17:59:13 -0800 Subject: [PATCH 18/99] dts: bl808: add fake sdh clock at 96MHz --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 755071f80b5904..ecb285cd7763ed 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -45,6 +45,13 @@ #clock-cells = <0>; }; + sdh: sdh-clk { + compatible = "fixed-clock"; + clock-frequency = <96000000>; + clock-output-names = "sdh"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; ranges; @@ -79,7 +86,7 @@ BFLB_IPC_DEVICE_SDHCI IRQ_TYPE_EDGE_RISING>; mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; - clocks = <&xtal>; + clocks = <&sdh>; status = "disabled"; }; From 0f81618bb5609e7e79b3afb454e269a1f50c9952 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 01:07:35 -0800 Subject: [PATCH 19/99] sdhci-bflb: enable additional quirks Write protect polarity is confirmed backwards, the other quirks may not be needed. --- drivers/mmc/host/sdhci-bflb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index c9141ddd733176..f6cc40dcf61491 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,6 +55,10 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_BROKEN_DMA | + SDHCI_QUIRK_BROKEN_ADMA | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT | SDHCI_QUIRK_NO_HISPD_BIT, }; From 3eda4a6ac2bc9909e6fbd9204df0fe5747342e51 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sun, 15 Jan 2023 13:38:26 +0000 Subject: [PATCH 20/99] Disable flash rootfs for now, edit bootargs to use SDHCI ext4 partition 1 rootfs --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index a3b1ae9f04780d..d3d228c3d8c0ea 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p1 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; @@ -35,11 +35,11 @@ erase-size = <0x10000>; bank-width = <4>; - rootfs@0 { + /*rootfs@0 { label = "rootfs"; - reg = <0x00000 0x280000>; + reg = <0x00000 0x400000>; read-only; - }; + };*/ }; }; From bffd795cf96a70b2d4fae5e6ede6e30e715a690f Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sun, 15 Jan 2023 14:24:55 +0000 Subject: [PATCH 21/99] Update defconfig with EXT4 support for SD rootfs --- arch/riscv/configs/bl808_defconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 0cc8c786a522b2..2acab58e801b67 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -118,6 +118,7 @@ CONFIG_BFLB_IPC=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_VIRTIO=y CONFIG_GENERIC_PHY=y +CONFIG_EXT4_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -133,11 +134,8 @@ CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y CONFIG_KEYS=y CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y -CONFIG_CRC16=y CONFIG_CRC_ITU_T=y CONFIG_CRC7=y CONFIG_XZ_DEC=y From fb95c0a2b54a6a0f713fb09c69ac0edad9d0f8cc Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 02:38:06 -0800 Subject: [PATCH 22/99] usb: add bflb ehci controller --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 10 ++++++++++ include/dt-bindings/mailbox/bflb-ipc.h | 1 + 4 files changed, 19 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index d3d228c3d8c0ea..66a892f880c71a 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -58,3 +58,7 @@ &ipclic { status = "okay"; }; + +&ehci0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index effaeda67c3fb7..19155bcc269373 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -53,3 +53,7 @@ &ipclic { status = "okay"; }; + +&ehci0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index ecb285cd7763ed..f3e4f17e69c033 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -90,6 +90,16 @@ status = "disabled"; }; + ehci0: usb@20072000 { + compatible = "generic-ehci"; + reg = <0x20072010 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_USB + IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bouffalolab,bflb-ipc"; reg = <0x30005000 0x20>, diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index e96fe62cbeb9a2..327e150384b95f 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -13,5 +13,6 @@ /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 +#define BFLB_IPC_DEVICE_USB 2 #endif From a2d0fcba373706550330ce55e42476e49381c34b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 02:38:58 -0800 Subject: [PATCH 23/99] bl808_defconfig: enable USB and EHCI --- arch/riscv/configs/bl808_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 2acab58e801b67..c43e21711750c7 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -103,7 +103,9 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_HID_REDRAGON is not set # CONFIG_HID_MICROSOFT is not set # CONFIG_HID_MONTEREY is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From 7e19490622a341d94bc5163824a56c5d9baadbb8 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:06:40 -0800 Subject: [PATCH 24/99] dts: bl808: fix offset of ehci controller ehci controller registers are at address 0x20072000 not 0x20072010 --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index f3e4f17e69c033..5e90f3ee04d716 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -92,7 +92,7 @@ ehci0: usb@20072000 { compatible = "generic-ehci"; - reg = <0x20072010 0x1000>; + reg = <0x20072000 0x1000>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_USB IRQ_TYPE_EDGE_RISING>; From 139ee3b19767a5d53a39d7c85f13d46561a0dcf9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:10:37 -0800 Subject: [PATCH 25/99] ehci: rearrange registers to match bl808 bl808 does not follow the EHCI spec, rearrange the registers to match what they actually implemented --- include/linux/usb/ehci_def.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index fbabadd3b372c2..f51fc87e0110cd 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -101,21 +101,10 @@ struct ehci_regs { /* ASYNCLISTADDR: offset 0x18 */ u32 async_next; /* address of next async queue head */ - u32 reserved1[2]; - - /* TXFILLTUNING: offset 0x24 */ - u32 txfill_tuning; /* TX FIFO Tuning register */ -#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */ - - u32 reserved2[6]; - - /* CONFIGFLAG: offset 0x40 */ - u32 configured_flag; -#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ - + u32 reserved1[1]; union { - /* PORTSC: offset 0x44 */ - u32 port_status[HCS_N_PORTS_MAX]; /* up to N_PORTS */ + /* PORTSC: offset 0x20 */ + u32 port_status[1]; /* up to N_PORTS */ /* EHCI 1.1 addendum */ #define PORTSC_SUSPEND_STS_ACK 0 #define PORTSC_SUSPEND_STS_NYET 1 @@ -163,6 +152,17 @@ struct ehci_regs { #define USBMODE_CM_IDLE (0<<0) /* idle state */ }; + /* TXFILLTUNING: offset 0x24 */ + u32 txfill_tuning; /* TX FIFO Tuning register */ +#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */ + + u32 reserved2[6]; + + /* CONFIGFLAG: offset 0x40 */ + u32 configured_flag; +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + + /* Moorestown has some non-standard registers, partially due to the fact that * its EHCI controller has both TT and LPM support. HOSTPCx are extensions to * PORTSCx From e3dc5d23baa3d26e7199cccbced2b7b18c613c62 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:11:40 -0800 Subject: [PATCH 26/99] bl808_defconfig: enable USB serial and network devices --- arch/riscv/configs/bl808_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index c43e21711750c7..39ad1cb2b4bc55 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -106,6 +106,8 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From e1302246650878f35ad15566e5b0772598014601 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Fri, 20 Jan 2023 13:45:52 +0800 Subject: [PATCH 27/99] Rename DTS Files --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 8 +------- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 2 +- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 10 +++++----- drivers/mailbox/bflb-ipc.c | 2 +- drivers/mmc/host/sdhci-bflb.c | 2 +- drivers/tty/serial/bflb_uart.c | 4 ++-- 6 files changed, 11 insertions(+), 17 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 66a892f880c71a..eede26e4f043c0 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -9,7 +9,7 @@ / { model = "Pine64 Ox64"; - compatible = "sipeed,m1s", "bouffalolab,bl808"; + compatible = "sipeed,m1s", "bflb,bl808"; aliases { serial0 = &uart0; @@ -34,12 +34,6 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; - - /*rootfs@0 { - label = "rootfs"; - reg = <0x00000 0x400000>; - read-only; - };*/ }; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 19155bcc269373..ed2d18482920c6 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -9,7 +9,7 @@ / { model = "Sipeed M1S"; - compatible = "sipeed,m1s", "bouffalolab,bl808"; + compatible = "sipeed,m1s", "bflb,bl808"; aliases { serial0 = &uart0; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 5e90f3ee04d716..bdfed1bde043ff 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -7,7 +7,7 @@ #include / { - compatible = "bouffalolab,bl808"; + compatible = "bflb,bl808"; #address-cells = <1>; #size-cells = <1>; @@ -61,7 +61,7 @@ #size-cells = <1>; uart0: serial@30002000 { - compatible = "bouffalolab,uart"; + compatible = "bflb,bl808-uart"; reg = <0x30002000 0x1000>; interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; clocks = <&xtal>; @@ -69,7 +69,7 @@ }; uart1: serial@0x2000AA00 { - compatible = "bouffalolab,uart"; + compatible = "bflb,bl808-uart"; reg = <0x2000AA00 0x0100>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2 @@ -80,7 +80,7 @@ }; sdhci0: sdhci@20060000 { - compatible = "bouffalolab,bflb-sdhci"; + compatible = "bflb,bl808-sdhci"; reg = <0x20060000 0x100>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI @@ -101,7 +101,7 @@ }; ipclic: mailbox@30005000 { - compatible = "bouffalolab,bflb-ipc"; + compatible = "bflb,bl808-ipc"; reg = <0x30005000 0x20>, <0x30005020 0x20>, <0x2000a800 0x20>, diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c index 692dd20e35a8d1..06020cec3cbaec 100644 --- a/drivers/mailbox/bflb-ipc.c +++ b/drivers/mailbox/bflb-ipc.c @@ -350,7 +350,7 @@ static int bflb_ipc_remove(struct platform_device *pdev) } static const struct of_device_id bflb_ipc_of_match[] = { - { .compatible = "bouffalolab,bflb-ipc"}, + { .compatible = "bflb,bl808-ipc"}, {} }; MODULE_DEVICE_TABLE(of, bflb_ipc_of_match); diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index f6cc40dcf61491..aacf234387af88 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -95,7 +95,7 @@ static int sdhci_bflb_probe(struct platform_device *pdev) } static const struct of_device_id sdhci_bflb_of_match_table[] = { - { .compatible = "bouffalolab,bflb-sdhci", }, + { .compatible = "bflb,bl808-sdhci", }, {} }; MODULE_DEVICE_TABLE(of, sdhci_bflb_of_match_table); diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c index 65f98ccf8fa81c..b091ad7a891ae9 100644 --- a/drivers/tty/serial/bflb_uart.c +++ b/drivers/tty/serial/bflb_uart.c @@ -538,7 +538,7 @@ static int __init bflb_uart_earlycon_setup(struct earlycon_device *dev, return 0; } -OF_EARLYCON_DECLARE(bflb_uart, "bouffalolab,uart", bflb_uart_earlycon_setup); +OF_EARLYCON_DECLARE(bflb_uart, "bflb,bl808-uart", bflb_uart_earlycon_setup); #else @@ -615,7 +615,7 @@ static int bflb_uart_remove(struct platform_device *pdev) static const struct of_device_id bflb_uart_match[] = { { - .compatible = "bouffalolab,uart", + .compatible = "bflb,bl808-uart", }, {}, }; From 5405206e44a950ad712eae685234b66446ec6393 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 20 Jan 2023 19:01:49 -0800 Subject: [PATCH 28/99] dts: bl808-pine64-ox64: change rootfs to /dev/mmcblk0p2 --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index eede26e4f043c0..4e183098f171ec 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p1 rootwait rootfstype=ext4"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; From 21dd2b6821d171463407a77536ea8044dc64bbeb Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 20 Jan 2023 19:42:33 -0800 Subject: [PATCH 29/99] tty: serial: bflb_uart: fix leaked ISR registration -call devm_free_irq() in shutdown to release ISR registered in startup. -change many functions to take driver private bflb_uart_port * instead of serial_core uart_port * -add to_bflb_uart_port() to assist with above -switch to using uart_port_tx_limited() serial_core helper which is the preferred way to do transmission instead of accessing serial_core xmit buffer directly --- drivers/tty/serial/bflb_uart.c | 133 ++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c index b091ad7a891ae9..5911f489959c75 100644 --- a/drivers/tty/serial/bflb_uart.c +++ b/drivers/tty/serial/bflb_uart.c @@ -82,12 +82,17 @@ #define BFLB_UART_MAXPORTS 8 #define BFLB_UART_BAUD 2000000 #define BFLB_UART_RX_FIFO_TH 7 +#define BFLB_UART_TX_FIFO_DEPTH 32 struct bflb_uart_port { struct uart_port port; struct clk *clk; }; +#define to_bflb_uart_port(p) (container_of((p), \ + struct bflb_uart_port, \ + port)) + static struct bflb_uart_port *bflb_uart_ports[BFLB_UART_MAXPORTS]; static inline u32 rdl(struct uart_port *port, u32 reg) @@ -227,91 +232,104 @@ static void bflb_uart_set_termios(struct uart_port *port, spin_unlock_irqrestore(&port->lock, flags); } -static void bflb_uart_rx_chars(struct uart_port *port) +static void bflb_uart_rx_chars(struct bflb_uart_port *bp) { unsigned char ch, flag; unsigned long status; - while ((status = rdl(port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { - ch = rdl(port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; + while ((status = rdl(&bp->port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { + ch = rdl(&bp->port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; flag = TTY_NORMAL; - port->icount.rx++; + bp->port.icount.rx++; - if (uart_handle_sysrq_char(port, ch)) + if (uart_handle_sysrq_char(&bp->port, ch)) continue; - uart_insert_char(port, 0, 0, ch, flag); + uart_insert_char(&bp->port, 0, 0, ch, flag); } - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); + spin_unlock(&bp->port.lock); + tty_flip_buffer_push(&bp->port.state->port); + spin_lock(&bp->port.lock); } -static void bflb_uart_tx_chars(struct uart_port *port) +/** + * bflb_uart_txfifo_space() - How much space is left int the TX FIFO? + * @bp: pointer to a struct bflb_uart_port + * + * Read the transmit FIFO count to find out how much space is left + * + * Returns: UART_TX_FIFO_CNT - count of space left in the TX FIFO + */ +static int bflb_uart_txfifo_space(struct bflb_uart_port *bp) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int pending, count; + return (rdl(&bp->port, UART_FIFO_CONFIG_1) + & UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; +} - if (port->x_char) { - /* Send special char - probably flow control */ - wrl(port, UART_FIFO_WDATA, port->x_char); - port->x_char = 0; - port->icount.tx++; - return; - } +/** + * bflb_uart_tx_char() - enqueue a byte to transmit onto the TX FIFO + * @bp: pointer to a struct bflb_uart_port + * @ch: character to transmit + * + * Enqueue a byte @ch onto the transmit FIFO, given a pointer @bp to the + * struct bflb_uart_port * to transmit on. + * + * Context: Any context. + */ +static void bflb_uart_tx_char(struct bflb_uart_port *bp, int ch) +{ + wrl(&bp->port, UART_FIFO_WDATA, ch); +} - pending = uart_circ_chars_pending(xmit); - if (pending > 0) { - count = (rdl(port, UART_FIFO_CONFIG_1) & - UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; - if (count > pending) - count = pending; - if (count > 0) { - pending -= count; - while (count--) { - wrl(port, UART_FIFO_WDATA, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (pending < WAKEUP_CHARS) - uart_write_wakeup(port); - } - } +/** + * bflb_uart_tx_chars() - enqueue multiple bytes onto the TX FIFO + * @bp: pointer to a struct bflb_uart_port + * + * Transfer up to a TX FIFO size's worth of characters from the Linux serial + * transmit buffer to the BFLB UART TX FIFO. + * + * Context: Any context. Expects @bp->port.lock to be held by caller. + */ +static void bflb_uart_tx_chars(struct bflb_uart_port *bp) +{ + u8 ch; - if (pending == 0) - bflb_uart_stop_tx(port); + uart_port_tx_limited(&bp->port, ch, BFLB_UART_TX_FIFO_DEPTH, + bflb_uart_txfifo_space(bp), + bflb_uart_tx_char(bp, ch), + ({})); } static irqreturn_t bflb_uart_interrupt(int irq, void *data) { - struct uart_port *port = data; + struct bflb_uart_port *bp = data; u32 isr, val; - isr = rdl(port, UART_INT_STS); - wrl(port, UART_INT_CLEAR, isr); + isr = rdl(&bp->port, UART_INT_STS); + wrl(&bp->port, UART_INT_CLEAR, isr); - isr &= ~rdl(port, UART_INT_MASK); + isr &= ~rdl(&bp->port, UART_INT_MASK); - spin_lock(&port->lock); + spin_lock(&bp->port.lock); if (isr & UART_URX_FER_INT) { /* RX FIFO error interrupt */ - val = rdl(port, UART_FIFO_CONFIG_0); + val = rdl(&bp->port, UART_FIFO_CONFIG_0); if (val & UART_RX_FIFO_OVERFLOW) - port->icount.overrun++; + bp->port.icount.overrun++; val |= UART_RX_FIFO_CLR; - wrl(port, UART_FIFO_CONFIG_0, val); + wrl(&bp->port, UART_FIFO_CONFIG_0, val); } if (isr & (UART_URX_FIFO_INT | UART_URX_RTO_INT)) { - bflb_uart_rx_chars(port); + bflb_uart_rx_chars(bp); } if (isr & (UART_UTX_FIFO_INT | UART_UTX_END_INT)) { - bflb_uart_tx_chars(port); + bflb_uart_tx_chars(bp); } - spin_unlock(&port->lock); + spin_unlock(&bp->port.lock); return IRQ_RETVAL(isr); } @@ -335,19 +353,22 @@ static void bflb_uart_config_port(struct uart_port *port, int flags) static int bflb_uart_startup(struct uart_port *port) { unsigned long flags; - int ret; u32 val; + struct bflb_uart_port *bp = to_bflb_uart_port(port); + int ret; + + dev_dbg(port->dev, "startup %s\n", port->name); + + spin_lock_irqsave(&port->lock, flags); ret = devm_request_irq(port->dev, port->irq, bflb_uart_interrupt, - IRQF_SHARED, port->name, port); + IRQF_SHARED, port->name, bp); if (ret) { dev_err(port->dev, "fail to request serial irq %d, ret=%d\n", port->irq, ret); return ret; } - spin_lock_irqsave(&port->lock, flags); - val = rdl(port, UART_INT_MASK); val |= 0xfff; wrl(port, UART_INT_MASK, val); @@ -383,10 +404,14 @@ static int bflb_uart_startup(struct uart_port *port) static void bflb_uart_shutdown(struct uart_port *port) { unsigned long flags; + struct bflb_uart_port *bp = to_bflb_uart_port(port); + + dev_dbg(port->dev, "shutdown %s\n", port->name); spin_lock_irqsave(&port->lock, flags); /* mask all interrupts now */ wrl(port, UART_INT_MASK, UART_UTX_END_INT | UART_URX_END_INT); + devm_free_irq(port->dev, port->irq, bp); spin_unlock_irqrestore(&port->lock, flags); } @@ -589,7 +614,7 @@ static int bflb_uart_probe(struct platform_device *pdev) port->line = index; port->type = PORT_BFLB; port->iotype = UPIO_MEM; - port->fifosize = 32; + port->fifosize = BFLB_UART_TX_FIFO_DEPTH; port->ops = &bflb_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->dev = &pdev->dev; From 83dd2f89365b55df3901da4ecabeb38cdff102f5 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 21 Jan 2023 03:35:04 -0800 Subject: [PATCH 30/99] mmc: sdhci-bflb: remove unnecessary quirks Remove quirks that were added during bringup but are not required. This will enable DMA and ADMA on sdcard. --- drivers/mmc/host/sdhci-bflb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index aacf234387af88..1e590a151c04e5 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,11 +55,7 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_BROKEN_ADMA | - SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_NO_HISPD_BIT, + SDHCI_QUIRK_INVERTED_WRITE_PROTECT, }; static int sdhci_bflb_probe(struct platform_device *pdev) From 33f94b56d3849f99de4fe2f58eee5cb3565085d6 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:00:32 -0800 Subject: [PATCH 31/99] dts: bl808-pine64-ox64: disable secondary UART Pinmux for this device conflicts with EMAC, so disable it until pinmux is changed to some other pins. --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 4e183098f171ec..96cc039133cc04 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -41,10 +41,6 @@ status = "okay"; }; -&uart1 { - status = "okay"; -}; - &sdhci0 { status = "okay"; }; From ccf17a3a70039b19890deef0802d1e577dc817ef Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:02:40 -0800 Subject: [PATCH 32/99] dts: bl808: add entry for EMAC device Add device-tree node for EMAC ethernet device and fake clock node to represent 50MHz clock to the device. Add a virtualized interrupt bit for forwareded EMAC interrupts. --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 17 +++++++++++++++++ include/dt-bindings/mailbox/bflb-ipc.h | 1 + 2 files changed, 18 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index bdfed1bde043ff..dd795667dea68f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -52,6 +52,13 @@ #clock-cells = <0>; }; + enet: enet-clk { + compatible = "fixed-clock"; + clock-frequency = <50000000>; + clock-output-names = "enet"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; ranges; @@ -100,6 +107,16 @@ status = "disabled"; }; + enet0: emac@20070000 { + compatible = "opencores,ethoc"; + reg = <0x20070000 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_EMAC + IRQ_TYPE_EDGE_RISING>; + clocks = <&enet>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bflb,bl808-ipc"; reg = <0x30005000 0x20>, diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 327e150384b95f..0a3c6745a673c1 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -14,5 +14,6 @@ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 #define BFLB_IPC_DEVICE_USB 2 +#define BFLB_IPC_DEVICE_EMAC 3 #endif From 4c79e017fc0f8e9048ca3093ccb0e2dd12e220b6 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:04:52 -0800 Subject: [PATCH 33/99] net: ethoc: add bl808 specific ethoc bits Add MODER RGMII bit to configure MII/RGMII PHY interface. Add TX_BD_EOF End of Frame interrupt status bit. These were taken from smaeul's u-boot: https://github.com/u-boot/u-boot/commit/d19d78603e41dbc698e33d69a5189c23866d0426 --- drivers/net/ethernet/ethoc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 95cbad198b4b6e..011719c61ec644 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -70,6 +70,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); #define MODER_HUGE (1 << 14) /* huge packets enable */ #define MODER_PAD (1 << 15) /* padding enabled */ #define MODER_RSM (1 << 16) /* receive small packets */ +#define MODER_RMII (1 << 17) /* RMII mode enable */ /* interrupt source and mask registers */ #define INT_MASK_TXF (1 << 0) /* transmit frame */ @@ -138,6 +139,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); #define TX_BD_RETRY_MASK (0x00f0) #define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4) #define TX_BD_UR (1 << 8) /* transmitter underrun */ +#define TX_BD_EOF (1 << 10) /* End of Frame */ #define TX_BD_CRC (1 << 11) /* TX CRC enable */ #define TX_BD_PAD (1 << 12) /* pad enable for short packets */ #define TX_BD_WRAP (1 << 13) @@ -355,7 +357,7 @@ static int ethoc_reset(struct ethoc *dev) /* enable FCS generation and automatic padding */ mode = ethoc_read(dev, MODER); - mode |= MODER_CRC | MODER_PAD; + mode |= MODER_CRC | MODER_PAD | MODER_RMII; ethoc_write(dev, MODER, mode); /* set full-duplex mode */ @@ -907,8 +909,8 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) dest = priv->vma[entry]; memcpy_toio(dest, skb->data, skb->len); - bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); - bd.stat |= TX_BD_LEN(skb->len); + bd.stat &= ~(TX_BD_STATS | TX_BD_EOF | TX_BD_LEN_MASK); + bd.stat |= TX_BD_LEN(skb->len) | TX_BD_EOF; ethoc_write_bd(priv, entry, &bd); bd.stat |= TX_BD_READY; From 0c49062bf82b2326756f58488c69c924dd30acdc Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:09:52 -0800 Subject: [PATCH 34/99] net: ethoc: reverse the interrupt mask bits The bl808 EMAC INT_MASK register has reversed polarity, so flip all the bits in it everwhere it is used. --- drivers/net/ethernet/ethoc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 011719c61ec644..409ecbbbd59520 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -271,14 +271,14 @@ static inline void ethoc_write_bd(struct ethoc *dev, int index, static inline void ethoc_enable_irq(struct ethoc *dev, u32 mask) { u32 imask = ethoc_read(dev, INT_MASK); - imask |= mask; + imask &= ~mask; ethoc_write(dev, INT_MASK, imask); } static inline void ethoc_disable_irq(struct ethoc *dev, u32 mask) { u32 imask = ethoc_read(dev, INT_MASK); - imask &= ~mask; + imask |= mask; ethoc_write(dev, INT_MASK, imask); } @@ -566,7 +566,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id) */ mask = ethoc_read(priv, INT_MASK); pending = ethoc_read(priv, INT_SOURCE); - pending &= mask; + pending &= ~mask; if (unlikely(pending == 0)) return IRQ_NONE; From 9820c033b56583f685fbd149b8e7ee524edcaea5 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:12:08 -0800 Subject: [PATCH 35/99] net: ethoc: reduce RGMII interface clk to 1MHz PHY communication was not stable at 2.5MHz, so reduce down to 1MHz. --- drivers/net/ethernet/ethoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 409ecbbbd59520..49f2e71d9555ea 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1183,7 +1183,7 @@ static int ethoc_probe(struct platform_device *pdev) } } if (eth_clkfreq) { - u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1); + u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 1000000 + 1); if (!clkdiv) clkdiv = 2; From a6cc77c5731a8477433a5fc264e1d85d40e4561c Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:13:31 -0800 Subject: [PATCH 36/99] riscv: bl808_defconfig: enable ETHOC driver --- arch/riscv/configs/bl808_defconfig | 45 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 39ad1cb2b4bc55..d51f2d78c139d6 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -63,8 +63,48 @@ CONFIG_BLK_DEV_SD=y CONFIG_SCSI_VIRTIO=y CONFIG_NETDEVICES=y CONFIG_VIRTIO_NET=y -# CONFIG_ETHERNET is not set -CONFIG_MDIO_DEVICE=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_WANGXUN is not set +# CONFIG_NET_VENDOR_LITEX is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +CONFIG_ETHOC=y +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set # CONFIG_WLAN is not set CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_EVDEV=y @@ -88,6 +128,7 @@ CONFIG_I2C_SLAVE_EEPROM=y CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y +# CONFIG_PTP_1588_CLOCK is not set CONFIG_FB=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_VGA_CONSOLE is not set From c072b0b0094c89f9cbcc76446bccc27d2195d1a9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:14:05 -0800 Subject: [PATCH 37/99] dts: bl808: enable enet nodes --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 96cc039133cc04..f9ed636291f614 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -52,3 +52,7 @@ &ehci0 { status = "okay"; }; + +&enet0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index ed2d18482920c6..031c824f2061ae 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -57,3 +57,7 @@ &ehci0 { status = "okay"; }; + +&enet0 { + status = "okay"; +}; From d7022e457c750271fa2acabbfb432ac56f9c924e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 5 Feb 2023 16:13:42 -0600 Subject: [PATCH 38/99] riscv: dts: bflb: m1s: Fix address/size-cells The number of address cells needed here (one) does not match the implicitly-defined default number of cells. Signed-off-by: Samuel Holland --- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 031c824f2061ae..5307508e7a9462 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -33,6 +33,8 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; rootfs@0 { label = "rootfs"; From fc79d0beffc72950292e5adbe5e3481664e689d8 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 5 Feb 2023 20:18:50 -0800 Subject: [PATCH 39/99] riscv: dts: bflb: ox64: Fix address/size-cells The number of address cells needed here (one) does not match the implicitly-defined default number of cells. Signed-off-by: Allen Martin --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index f9ed636291f614..f1db126d88e76f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -34,6 +34,8 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; }; }; From ac995c3b89aa22d75da6d7baf5a3c659a9f47dcc Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Mon, 6 Feb 2023 13:38:55 +0800 Subject: [PATCH 40/99] Add timer node for OpenSBI 1.2 compatibility --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index dd795667dea68f..34652e17aece8f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -140,5 +140,12 @@ #interrupt-cells = <2>; riscv,ndev = <64>; }; + + clint: timer@e4000000 { + compatible = "thead,c900-clint"; + reg = <0xe4000000 0xc000>; + interrupts-extended = <&cpu0_intc 3>, + <&cpu0_intc 7>; + }; }; }; From b6635b506ad2a53cc8d0b786d741f9aa42ccc50b Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Mon, 6 Feb 2023 13:41:53 +0800 Subject: [PATCH 41/99] Tabstops are 8 chars, not 4 --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 34652e17aece8f..7cd033b6a1cf36 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -145,7 +145,7 @@ compatible = "thead,c900-clint"; reg = <0xe4000000 0xc000>; interrupts-extended = <&cpu0_intc 3>, - <&cpu0_intc 7>; + <&cpu0_intc 7>; }; }; }; From c57f5f4e3d9f3d2835e268481c976cbb8b901f3f Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:30:16 +0800 Subject: [PATCH 42/99] Add Support for mailboxes in bflb-ipc driver * Note: We should probably split the irq-forwarding and mailbox code into seperate modules. (especially when we start supporting mailboxes to LP core) * We probably need some locking around the actual mbox_send/EOI code in case other modules start using mailboxes to communicate with the other core. --- drivers/mailbox/bflb-ipc.c | 257 ++++++++++++++++++++----- include/dt-bindings/mailbox/bflb-ipc.h | 18 +- include/linux/bflb-mailbox.h | 19 ++ 3 files changed, 246 insertions(+), 48 deletions(-) create mode 100644 include/linux/bflb-mailbox.h diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c index 06020cec3cbaec..5dee44dc337d58 100644 --- a/drivers/mailbox/bflb-ipc.c +++ b/drivers/mailbox/bflb-ipc.c @@ -11,6 +11,7 @@ #include #include +#include #include /* IPC Register offsets */ @@ -25,12 +26,14 @@ /** * struct bflb_ipc_chan_info - Per-mailbox-channel info - * @client_id: The client-id to which the interrupt has to be triggered - * @signal_id: The signal-id to which the interrupt has to be triggered + * @cpu_id: The cpu_id is a identifier of what CPU is being called + * @service_id: The service_id is a identifier of what service is being called on the remote CPU + * @op_id: The operation we want to execute on the remote CPU */ struct bflb_ipc_chan_info { - u16 client_id; - u16 signal_id; + u8 cpu_id; + u16 service_id; + u16 op_id; }; /** @@ -39,7 +42,8 @@ struct bflb_ipc_chan_info { * @base: Base address of each IPC frame (LP, M0) * @irq_domain: The irq_domain associated with this instance * @chans: The mailbox channels array - * @mchan: The per-mailbox channel info array + * @outchat: The outbound (singal the other CPU) mailbox channel info + * @inchan: The inbound (receive the signal from the other CPU) mailbox channel info * @mbox: The mailbox controller * @num_chans: Number of @chans elements * @irq: Summary irq @@ -49,30 +53,32 @@ struct bflb_ipc { void __iomem *base[4]; struct irq_domain *irq_domain; struct mbox_chan *chans; - struct bflb_ipc_chan_info *mchan; - struct mbox_controller mbox; + struct bflb_ipc_chan_info *bflbchan; + struct mbox_controller mboxctlr; int num_chans; int irq; }; -static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mbox) +static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mboxctlr) { - return container_of(mbox, struct bflb_ipc, mbox); + return container_of(mboxctlr, struct bflb_ipc, mboxctlr); } static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device) { - pr_debug("%s: source: %u, device: %u\n", __func__, source, device); +// dev_dbg("%s: source: %u, device: %u\n", __func__, source, device); return device; } + #if 0 static void bflb_ipc_dump_regs(struct bflb_ipc *ipc) { int i; - for (i=0; i<4; i++) { - dev_dbg(ipc->dev, "base %px\n", ipc->base[i]); + + for (i = 0; i < 4; i++) { + dev_dbg(ipc->dev, "base %px %d\n", ipc->base[i], i); dev_dbg(ipc->dev, "ISWR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISWR)); dev_dbg(ipc->dev, "IRSRR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IRSRR)); dev_dbg(ipc->dev, "ICR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ICR)); @@ -85,6 +91,96 @@ static void bflb_ipc_dump_regs(struct bflb_ipc *ipc) } #endif +struct mbox_chan *bflb_mbox_find_chan(struct bflb_ipc *ipc, struct bflb_ipc_chan_info *chaninfo) +{ + struct bflb_ipc_chan_info *mchan; + struct mbox_controller *mboxctlr = &ipc->mboxctlr; + struct mbox_chan *chan; + struct device *dev; + int chan_id; + + dev = ipc->dev; + + for (chan_id = 0; chan_id < mboxctlr->num_chans; chan_id++) { + chan = &ipc->chans[chan_id]; + mchan = chan->con_priv; + + if (!mchan) + break; + else if (mchan->cpu_id == chaninfo->cpu_id && + mchan->service_id == chaninfo->service_id && + mchan->op_id == chaninfo->op_id) + return chan; + } + dev_err(dev, "%s: No channel found for cpu_id %d service_id %d op_id %d", + __func__, chaninfo->cpu_id, chaninfo->service_id, chaninfo->op_id); + + return ERR_PTR(-EINVAL); + +} + +/* called when we get a RX interrupt from another processor + * this indicates there is a message waitinf for us in + * IPC_REG_ILSHR and IPC_REG_ILSLR registers to process + */ +static void bflb_mbox_rx_irq_fn(int from_cpu, struct bflb_ipc *ipc) +{ + struct mbox_chan *chan; + struct bflb_ipc_chan_info bflbchan; + struct bflb_mbox_msg msg; + u32 sig_op; + + /* update this when we support LP */ + sig_op = readl(ipc->base[1] + IPC_REG_ILSHR); + msg.param = readl(ipc->base[1] + IPC_REG_ILSLR); + + WARN_ON(sig_op == 0); + + bflbchan.cpu_id = from_cpu; + bflbchan.service_id = (sig_op >> 16) & 0xFFFF; + bflbchan.op_id = sig_op & 0xFFFF; + + chan = bflb_mbox_find_chan(ipc, &bflbchan); + if (IS_ERR(chan)) { + dev_err(ipc->dev, "no channel for signal cpu_id: %d service: %d op: %d\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id); + return; + } + + dev_dbg(ipc->dev, "Got MBOX Signal cpu: %d service %d op %d param %x\r\n", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, msg.param); + + mbox_chan_received_data(chan, &msg); +} + +/* called when we get a interupt back on our TX IRQ. + * This is a EOI interupt + */ +static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc) +{ + struct mbox_chan *chan; + struct bflb_ipc_chan_info bflbchan; + + u32 sig_op = readl(ipc->base[2] + IPC_REG_ILSHR); + u32 param = readl(ipc->base[2] + IPC_REG_ILSLR); + + bflbchan.cpu_id = from_cpu; + bflbchan.service_id = (sig_op >> 16) & 0xFFFF; + bflbchan.op_id = sig_op & 0xFFFF; + + chan = bflb_mbox_find_chan(ipc, &bflbchan); + if (IS_ERR(chan)) { + dev_err(ipc->dev, "no channel for EOI signal cpu_id: %d service: %d op: %d Param: %d $$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); + return; + } + + dev_dbg(ipc->dev, "Got MBOX EOI Signal cpu: %d service %d op %d Param: %d $$$$$$$$$$$$$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); + + /* clear the IPC_REG_ILSLR and IPC_REG_ILSHR */ + writel(0, ipc->base[2] + IPC_REG_ILSLR); + writel(0, ipc->base[2] + IPC_REG_ILSHR); + + mbox_chan_txdone(chan, 0); +} + static irqreturn_t bflb_ipc_irq_fn(int irq, void *data) { struct bflb_ipc *ipc = data; @@ -92,12 +188,21 @@ static irqreturn_t bflb_ipc_irq_fn(int irq, void *data) int pos; stat = readl(ipc->base[1] + IPC_REG_ISR); - for_each_set_bit(pos, &stat, 32) - generic_handle_domain_irq(ipc->irq_domain, pos); + + for_each_set_bit(pos, &stat, 32) { + if (pos == BFLB_IPC_DEVICE_MBOX_RX) + bflb_mbox_rx_irq_fn(BFLB_IPC_SOURCE_M0, ipc); + else if (pos == BFLB_IPC_DEVICE_MBOX_TX) + /* we use target here as its a EOI from a send */ + bflb_mbox_tx_irq_fn(BFLB_IPC_TARGET_M0, ipc); + else + generic_handle_domain_irq(ipc->irq_domain, pos); + } writel(stat, ipc->base[1] + IPC_REG_ICR); - /* EOI the irqs */ - writel(stat, ipc->base[2] + IPC_REG_ISWR); + /* Signal EOI to the other processes except when we recieve a EOI ourselves */ + if (stat != (1 << BFLB_IPC_DEVICE_MBOX_TX)) + writel(stat, ipc->base[2] + IPC_REG_ISWR); return IRQ_HANDLED; } @@ -157,71 +262,119 @@ static const struct irq_domain_ops bflb_ipc_irq_ops = { .xlate = bflb_ipc_domain_xlate, }; +#if 0 +/* Shouldn't actually be fail as we clear the High/Low registers in a EOI + * but this protects if we screw up our mailbox handling + */ +static bool bflb_ipc_mbox_can_send(struct mbox_chan *chan) +{ + struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox); + + /* check the low register first as we clear that last in our EOI, so this + * should protected to a limited extent + */ + u32 mbox_low = readl(ipc->base[2] + IPC_REG_ILSLR); + u32 mbox_high = readl(ipc->base[2] + IPC_REG_ILSHR); + + + if (mbox_low | mbox_high) + dev_warn_ratelimited(ipc->dev, "%s: low: 0x%08x high: 0x%08x\r\n", __func__, mbox_low, mbox_high); + + writel(0, ipc->base[2] + IPC_REG_ILSLR); + writel(0, ipc->base[2] + IPC_REG_ILSHR); + + return !(mbox_low | mbox_high); +} +#endif + static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data) { struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox); struct bflb_ipc_chan_info *mchan = chan->con_priv; - u32 hwirq; + struct bflb_mbox_msg *msg = data; + u32 tmpVal = (mchan->service_id << 16) | (mchan->op_id & 0xFFFF); - hwirq = bflb_ipc_get_hwirq(mchan->client_id, mchan->signal_id); +#if 0 + if (!bflb_ipc_mbox_can_send(chan)) + return -EBUSY; +#endif - dev_dbg(ipc->dev, "%s: hwirq: %u\n", __func__, hwirq); + dev_dbg(ipc->dev, "%s %d: cpu: %d singal: %d op: %d (0x%x) param: %d", __func__, msg->id, mchan->cpu_id, mchan->service_id, mchan->op_id, tmpVal, msg->param); -// writel(hwirq, ipc->base + IPC_REG_SEND_ID); + // /* write our signal number to high register */ + writel(tmpVal, ipc->base[2] + IPC_REG_ILSHR); + // /* write our data to low register */ + writel(msg->param, ipc->base[2] + IPC_REG_ILSLR); + /* and now kick the remote processor */ + writel((1 << BFLB_IPC_DEVICE_MBOX_TX), ipc->base[2] + IPC_REG_ISWR); + dev_dbg(ipc->dev, "%s %d: done param: %d", __func__, msg->id, msg->param); return 0; } static void bflb_ipc_mbox_shutdown(struct mbox_chan *chan) { - pr_debug("%s\n", __func__); + struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox); + + dev_dbg(ipc->dev, "%s\n", __func__); chan->con_priv = NULL; } -static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mbox, +static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mboxctlr, const struct of_phandle_args *ph) { - struct bflb_ipc *ipc = to_bflb_ipc(mbox); + struct bflb_ipc *ipc = to_bflb_ipc(mboxctlr); struct bflb_ipc_chan_info *mchan; struct mbox_chan *chan; - struct device *dev; + struct device *dev = ipc->dev; int chan_id; - dev = ipc->dev; dev_dbg(dev, "%s\n", __func__); - if (ph->args_count != 2) + if (ph->args_count != 3) { + dev_err(dev, "invalid number of arguments"); return ERR_PTR(-EINVAL); + } - for (chan_id = 0; chan_id < mbox->num_chans; chan_id++) { + for (chan_id = 0; chan_id < mboxctlr->num_chans; chan_id++) { chan = &ipc->chans[chan_id]; mchan = chan->con_priv; if (!mchan) break; - else if (mchan->client_id == ph->args[0] && - mchan->signal_id == ph->args[1]) - return ERR_PTR(-EBUSY); + else if (mchan->cpu_id == ph->args[0] && + mchan->service_id == ph->args[1] && + mchan->op_id == ph->args[2]) { + dev_err(dev, "channel already in use %d %d %d", ph->args[0], ph->args[1], ph->args[2]); + return ERR_PTR(-EBUSY); + } } - if (chan_id >= mbox->num_chans) + if (chan_id >= mboxctlr->num_chans) { + dev_err(dev, "no free channels"); return ERR_PTR(-EBUSY); + } mchan = devm_kzalloc(dev, sizeof(*mchan), GFP_KERNEL); if (!mchan) return ERR_PTR(-ENOMEM); - mchan->client_id = ph->args[0]; - mchan->signal_id = ph->args[1]; + mchan->cpu_id = ph->args[0]; + mchan->service_id = ph->args[1]; + mchan->op_id = ph->args[2]; chan->con_priv = mchan; + dev_dbg(dev, "%s mbox %s: %d cpu: %d service: %d op: %d", __func__, ph->np->full_name, chan_id, mchan->cpu_id, mchan->service_id, mchan->op_id); + return chan; } + static const struct mbox_chan_ops ipc_mbox_chan_ops = { .send_data = bflb_ipc_mbox_send_data, .shutdown = bflb_ipc_mbox_shutdown, +// .last_tx_done = bflb_ipc_mbox_can_send, }; static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, @@ -229,7 +382,7 @@ static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, { struct of_phandle_args curr_ph; struct device_node *client_dn; - struct mbox_controller *mbox; + struct mbox_controller *mboxctlr; struct device *dev = ipc->dev; int i, j, ret; @@ -249,11 +402,11 @@ static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, of_node_put(curr_ph.np); if (!ret && curr_ph.np == controller_dn) { ipc->num_chans++; - break; + //break; } } } - + dev_dbg(dev, "%s: num_chans: %d", __func__, ipc->num_chans); /* If no clients are found, skip registering as a mbox controller */ if (!ipc->num_chans) return 0; @@ -263,16 +416,26 @@ static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, if (!ipc->chans) return -ENOMEM; - mbox = &ipc->mbox; - mbox->dev = dev; - mbox->num_chans = ipc->num_chans; - mbox->chans = ipc->chans; - mbox->ops = &ipc_mbox_chan_ops; - mbox->of_xlate = bflb_ipc_mbox_xlate; - mbox->txdone_irq = false; - mbox->txdone_poll = false; + mboxctlr = &ipc->mboxctlr; + mboxctlr->dev = dev; + mboxctlr->num_chans = ipc->num_chans; + mboxctlr->chans = ipc->chans; + mboxctlr->ops = &ipc_mbox_chan_ops; + mboxctlr->of_xlate = bflb_ipc_mbox_xlate; + mboxctlr->txdone_irq = true; +// mboxctlr->txdone_poll = false; + + + + /* clear the IPC_REG_ILSLR and IPC_REG_ILSHR */ + writel(0, ipc->base[2] + IPC_REG_ILSLR); + writel(0, ipc->base[2] + IPC_REG_ILSHR); + + /* unmask our interupt */ + writel(BIT(BFLB_IPC_DEVICE_MBOX_TX), ipc->base[1] + IPC_REG_IUSR); + writel(BIT(BFLB_IPC_DEVICE_MBOX_RX), ipc->base[1] + IPC_REG_IUSR); - return devm_mbox_controller_register(dev, mbox); + return devm_mbox_controller_register(dev, mboxctlr); } static int bflb_ipc_pm_resume(struct device *dev) @@ -294,7 +457,7 @@ static int bflb_ipc_probe(struct platform_device *pdev) ipc->dev = &pdev->dev; - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) { ipc->base[i] = devm_platform_ioremap_resource(pdev, i); if (IS_ERR(ipc->base[i])) return PTR_ERR(ipc->base[i]); @@ -332,7 +495,7 @@ static int bflb_ipc_probe(struct platform_device *pdev) err_req_irq: if (ipc->num_chans) - mbox_controller_unregister(&ipc->mbox); + mbox_controller_unregister(&ipc->mboxctlr); err_mbox: irq_domain_remove(ipc->irq_domain); diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 0a3c6745a673c1..02848cf7a30153 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -9,11 +9,27 @@ /* Source processor */ #define BFLB_IPC_SOURCE_M0 0 #define BFLB_IPC_SOURCE_LP 1 +#define BFLB_IPC_SOURCE_D0 2 /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 -#define BFLB_IPC_DEVICE_USB 2 +#define BFLB_IPC_DEVICE_USB 2 #define BFLB_IPC_DEVICE_EMAC 3 +#define BFLB_IPC_DEVICE_MBOX_RX 5 +#define BFLB_IPC_DEVICE_MBOX_TX 6 + +/* TARGET for Sending to other processors, continues from the BFLB_IPC_SOURCE_* range */ +#define BFLB_IPC_TARGET_M0 3 +#define BFLB_IPC_TARGET_LP 4 +#define BFLB_IPC_TARGET_D0 5 + +/* MailBox Service */ +#define BFLB_IPC_MBOX_VIRTIO 1 + + +/* Operations for MBOX_VIRTIO */ +#define BFLB_IPC_MBOX_VIRTIO_OP_KICK 1 + #endif diff --git a/include/linux/bflb-mailbox.h b/include/linux/bflb-mailbox.h new file mode 100644 index 00000000000000..0105678d52d8e0 --- /dev/null +++ b/include/linux/bflb-mailbox.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* + * BL808 mailbox message format + * + * Copyright (C) 2021 The Asahi Linux Contributors + */ + +#ifndef _LINUX_BFLB_MAILBOX_H_ +#define _LINUX_BFLB_MAILBOX_H_ + +#include + +/* encodes a single 32bit message sent over the single channel */ +struct bflb_mbox_msg { + u32 param; + u32 id; +}; + +#endif From f9b2c40b742cb9b26875407628bbe87cf5d5afc9 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:08 +0800 Subject: [PATCH 43/99] dt-bindings: serial: add bindings doc for Bouffalolab uart driver Add bindings doc for Bouffalolab UART Driver Signed-off-by: Jisheng Zhang --- .../bindings/serial/bouffalolab,uart.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml diff --git a/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml new file mode 100644 index 00000000000000..6cef956d33d25e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022 Jisheng Zhang +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/serial/bouffalolab,uart.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Bouffalolab UART Controller + +maintainers: + - Jisheng Zhang + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: bouffalolab,uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + aliases { + serial0 = &uart0; + }; + + uart0: serial@30002000 { + compatible = "bouffalolab,uart"; + reg = <0x30002000 0x1000>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + }; +... From 2c19a5bf97717be85036e886250502c2e35364ec Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:11 +0800 Subject: [PATCH 44/99] riscv: add the Bouffalolab SoC family Kconfig option The Bouffalolab bl808 SoC contains three riscv CPUs, namely M0, D0 and LP. The D0 is 64bit RISC-V GC compatible, so can run linux. Signed-off-by: Jisheng Zhang --- arch/riscv/Kconfig.socs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 4b6deb2715f1c4..a68ab2172230e5 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -1,5 +1,11 @@ menu "SoC selection" +config SOC_BOUFFALOLAB + bool "Bouffalolab SoCs" + select SIFIVE_PLIC + help + This enables support for Bouffalolab SoC platforms. + config SOC_MICROCHIP_POLARFIRE bool "Microchip PolarFire SoCs" select MCHP_CLK_MPFS From 77c6c7a056e0e02ccd5b182bf263ea27a71cc959 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:12 +0800 Subject: [PATCH 45/99] riscv: dts: bouffalolab: add the bl808 SoC base device tree Add a baisc dtsi for the bouffalolab bl808 SoC. Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 74 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808.dtsi diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index b0ff5fbabb0c9a..2d4376810bcc75 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +subdir-y += bouffalolab subdir-y += sifive subdir-y += starfive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi new file mode 100644 index 00000000000000..c98ebb14ee10a6 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +#include + +/ { + compatible = "bouffalolab,bl808"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + timebase-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "thead,c906", "riscv"; + device_type = "cpu"; + reg = <0>; + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <32768>; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <32768>; + mmu-type = "riscv,sv39"; + riscv,isa = "rv64imafdc"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + ranges; + interrupt-parent = <&plic>; + dma-noncoherent; + #address-cells = <1>; + #size-cells = <1>; + + uart0: serial@30002000 { + compatible = "bouffalolab,uart"; + reg = <0x30002000 0x1000>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + status = "disabled"; + }; + + plic: interrupt-controller@e0000000 { + compatible = "thead,c900-plic"; + reg = <0xe0000000 0x4000000>; + interrupts-extended = <&cpu0_intc 0xffffffff>, + <&cpu0_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <64>; + }; + }; +}; From cddacea7c8a17fdefacde5abd9974678e6f51058 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:13 +0800 Subject: [PATCH 46/99] riscv: dts: bouffalolab: add Sipeed M1S dock devicetree Sipeed manufactures a M1S system-on-module and dock board, add basic support for them. Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/bouffalolab/Makefile | 2 ++ .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 arch/riscv/boot/dts/bouffalolab/Makefile create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts diff --git a/arch/riscv/boot/dts/bouffalolab/Makefile b/arch/riscv/boot/dts/bouffalolab/Makefile new file mode 100644 index 00000000000000..42e17e1a97bd17 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-sipeed-m1s.dtb diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts new file mode 100644 index 00000000000000..64421fb2ad67d9 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" + +/ { + model = "Sipeed M1S"; + compatible = "sipeed,m1s", "bouffalolab,bl808"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; +}; + +&uart0 { + status = "okay"; +}; From 69f07729f4f5bd7aa4a9095976a45e5dd8c9b335 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:14 +0800 Subject: [PATCH 47/99] MAINTAINERS: add myself as Bouffalolab SoC entry maintainer I want to maintain this Bouffalolab riscv SoC entry from now on. Signed-off-by: Jisheng Zhang --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 135d93368d36ed..a8ee2a529ecb54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17975,6 +17975,12 @@ F: arch/riscv/ N: riscv K: riscv +RISC-V BOUFFALOLAB SOC SUPPORT +M: Jisheng Zhang +L: linux-riscv at lists.infradead.org +S: Maintained +F: arch/riscv/boot/dts/bouffalolab/ + RISC-V MICROCHIP FPGA SUPPORT M: Conor Dooley M: Daire McNamara From 398fa5f8dd0b26e2ef59c38db908ce4bae033017 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 01:35:45 -0800 Subject: [PATCH 48/99] riscv: bl808: Add defconfig --- arch/riscv/configs/bl808_defconfig | 143 +++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 arch/riscv/configs/bl808_defconfig diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig new file mode 100644 index 00000000000000..8a441a64be1a85 --- /dev/null +++ b/arch/riscv/configs/bl808_defconfig @@ -0,0 +1,143 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_PERF_EVENTS=y +CONFIG_SOC_BOUFFALOLAB=y +CONFIG_SOC_VIRT=y +CONFIG_ERRATA_THEAD=y +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_RISCV_SBI_V01=y +# CONFIG_COMPAT is not set +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_PAGE_REPORTING=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_DNS_RESOLVER=y +CONFIG_NETLINK_DIAG=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK_RO=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_ROM=y +CONFIG_MTD_ABSENT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PHYSMAP_VERSATILE=y +CONFIG_MTD_PHYSMAP_GEMINI=y +CONFIG_MTD_PLATRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_VIRTIO=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +CONFIG_MDIO_DEVICE=y +# CONFIG_WLAN is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_BFLB=y +CONFIG_SERIAL_BFLB_CONSOLE=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_XILINX=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +CONFIG_I2C_DEBUG_BUS=y +CONFIG_FB=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_SYNC_FILE=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_VIRTIO=y +CONFIG_GENERIC_PHY=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_KEYS=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CRC16=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_XZ_DEC=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_VM_PGTABLE=y +CONFIG_DEBUG_TIMEKEEPING=y +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_RUNTIME_TESTING_MENU is not set +CONFIG_MEMTEST=y From 87c20a57492ca7eeff77278c74385a9ba6d39f2a Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 02:25:29 -0800 Subject: [PATCH 49/99] riscv: dts: bouffalolab: add bootargs/initrd --- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 64421fb2ad67d9..84e5aac6cbf851 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -17,6 +17,9 @@ chosen { stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; }; memory@50000000 { From c463c23723ed8823f03a7d0417136b800154af9b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 8 Jan 2023 02:26:04 -0800 Subject: [PATCH 50/99] riscv: dts: bouffalolab: add xip_flash --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 84e5aac6cbf851..bdb502ea5a5489 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -26,6 +26,20 @@ device_type = "memory"; reg = <0x50000000 0x04000000>; }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + + rootfs@0 { + label = "rootfs"; + reg = <0x00000 0x280000>; + read-only; + }; + }; }; &uart0 { From 950fd2ac1cd7529abee5852773db654e617173d1 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:14:53 -0800 Subject: [PATCH 51/99] WIP: add BFLB MBOX interrupt controller driver --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index bdb502ea5a5489..70259bad7dfd31 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -45,3 +45,7 @@ &uart0 { status = "okay"; }; + +&ipclic { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index c98ebb14ee10a6..c5cda8d74ccd9d 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -4,6 +4,7 @@ */ #include +#include / { compatible = "bouffalolab,bl808"; @@ -60,6 +61,19 @@ status = "disabled"; }; + ipclic: mailbox@30005000 { + compatible = "bouffalolab,bflb-ipc"; + reg = <0x30005000 0x20>, + <0x30005020 0x20>, + <0x2000a800 0x20>, + <0x2000a820 0x20>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + status = "disabled"; + }; + plic: interrupt-controller@e0000000 { compatible = "thead,c900-plic"; reg = <0xe0000000 0x4000000>; From 661769605519fdb71bd4600663f8e0d5c810af7b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:16:51 -0800 Subject: [PATCH 52/99] WIP: sdhci: add BFLB sdhci driver --- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 70259bad7dfd31..effaeda67c3fb7 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -46,6 +46,10 @@ status = "okay"; }; +&sdhci0 { + status = "okay"; +}; + &ipclic { status = "okay"; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index c5cda8d74ccd9d..6f859194f82c36 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -61,6 +61,17 @@ status = "disabled"; }; + sdhci0: sdhci@20060000 { + compatible = "bouffalolab,bflb-sdhci"; + reg = <0x20060000 0x100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_SDHCI + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; + clocks = <&xtal>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bouffalolab,bflb-ipc"; reg = <0x30005000 0x20>, From 4b74d104b878abe090836f86e42475a0b80235c9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:22:09 -0800 Subject: [PATCH 53/99] bl808_defconfig: enable sdhci driver --- arch/riscv/configs/bl808_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 8a441a64be1a85..049fe1c25d74ec 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -103,6 +103,10 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_HID_MICROSOFT is not set # CONFIG_HID_MONTEREY is not set # CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_BFLB=y CONFIG_RTC_CLASS=y CONFIG_SYNC_FILE=y # CONFIG_VIRTIO_MENU is not set From 69e4d28bdf14e9a6c764f14ec7466c603d976094 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:22:29 -0800 Subject: [PATCH 54/99] bl808_defconfig: enable mailbox irqchip driver --- arch/riscv/configs/bl808_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 049fe1c25d74ec..d2786235830294 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -111,6 +111,8 @@ CONFIG_RTC_CLASS=y CONFIG_SYNC_FILE=y # CONFIG_VIRTIO_MENU is not set # CONFIG_VHOST_MENU is not set +CONFIG_MAILBOX=y +CONFIG_BFLB_IPC=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_VIRTIO=y From 3b946f78adcf9cd06ab60e444ce696aa3bab66d8 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 15:23:03 -0800 Subject: [PATCH 55/99] bl808_defconfig: enable irq debugfs --- arch/riscv/configs/bl808_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index d2786235830294..0cc8c786a522b2 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -1,5 +1,6 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_GENERIC_IRQ_DEBUGFS=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y From e4017e32952a79b01a829092298e558bee92681e Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:14:53 -0800 Subject: [PATCH 56/99] WIP: add BFLB MBOX interrupt controller driver --- include/dt-bindings/mailbox/bflb-ipc.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 include/dt-bindings/mailbox/bflb-ipc.h diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h new file mode 100644 index 00000000000000..1d4c4be6292e97 --- /dev/null +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2023 Allen Martin + */ + +#ifndef __DT_BINDINGS_MAILBOX_BFLB_IPC_H +#define __DT_BINDINGS_MAILBOX_BFLB_IPC_H + +/* Source processor */ +#define BFLB_IPC_SOURCE_M0 0 +#define BFLB_IPC_SOURCE_LP 1 + +/* Peripheral device ID */ +#define BFLB_IPC_DEVICE_SDHCI 0 + +#endif From 885fc70c6a228c9285c23ec4d7f07a98964f643f Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:05:40 +0000 Subject: [PATCH 57/99] UART2 working under Linux! --- arch/riscv/boot/dts/bouffalolab/Makefile | 1 + .../dts/bouffalolab/bl808-pine64-ox64.dts | 60 +++++++++++++++++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 13 +++- include/dt-bindings/mailbox/bflb-ipc.h | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts diff --git a/arch/riscv/boot/dts/bouffalolab/Makefile b/arch/riscv/boot/dts/bouffalolab/Makefile index 42e17e1a97bd17..bc7aad3d560406 100644 --- a/arch/riscv/boot/dts/bouffalolab/Makefile +++ b/arch/riscv/boot/dts/bouffalolab/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-sipeed-m1s.dtb +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-pine64-ox64.dtb diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts new file mode 100644 index 00000000000000..a3b1ae9f04780d --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" + +/ { + model = "Pine64 Ox64"; + compatible = "sipeed,m1s", "bouffalolab,bl808"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + + rootfs@0 { + label = "rootfs"; + reg = <0x00000 0x280000>; + read-only; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&sdhci0 { + status = "okay"; +}; + +&ipclic { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 6f859194f82c36..755071f80b5904 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -60,7 +60,18 @@ clocks = <&xtal>; status = "disabled"; }; - + + uart1: serial@0x2000AA00 { + compatible = "bouffalolab,uart"; + reg = <0x2000AA00 0x0100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_UART2 + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2>; + clocks = <&xtal>; + status = "disabled"; + }; + sdhci0: sdhci@20060000 { compatible = "bouffalolab,bflb-sdhci"; reg = <0x20060000 0x100>; diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 1d4c4be6292e97..e96fe62cbeb9a2 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -12,5 +12,6 @@ /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 +#define BFLB_IPC_DEVICE_UART2 1 #endif From 9a54e5b68abb12792cda5342b581a46356e57825 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 14 Jan 2023 17:59:13 -0800 Subject: [PATCH 58/99] dts: bl808: add fake sdh clock at 96MHz --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 755071f80b5904..ecb285cd7763ed 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -45,6 +45,13 @@ #clock-cells = <0>; }; + sdh: sdh-clk { + compatible = "fixed-clock"; + clock-frequency = <96000000>; + clock-output-names = "sdh"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; ranges; @@ -79,7 +86,7 @@ BFLB_IPC_DEVICE_SDHCI IRQ_TYPE_EDGE_RISING>; mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; - clocks = <&xtal>; + clocks = <&sdh>; status = "disabled"; }; From ad398a49333c425e52f8f46840d4276bdcbdc457 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sun, 15 Jan 2023 13:38:26 +0000 Subject: [PATCH 59/99] Disable flash rootfs for now, edit bootargs to use SDHCI ext4 partition 1 rootfs --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index a3b1ae9f04780d..d3d228c3d8c0ea 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p1 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; @@ -35,11 +35,11 @@ erase-size = <0x10000>; bank-width = <4>; - rootfs@0 { + /*rootfs@0 { label = "rootfs"; - reg = <0x00000 0x280000>; + reg = <0x00000 0x400000>; read-only; - }; + };*/ }; }; From b2fe2832f829538921d9c8ac3bbcbd053b776c6b Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Sun, 15 Jan 2023 14:24:55 +0000 Subject: [PATCH 60/99] Update defconfig with EXT4 support for SD rootfs --- arch/riscv/configs/bl808_defconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 0cc8c786a522b2..2acab58e801b67 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -118,6 +118,7 @@ CONFIG_BFLB_IPC=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_VIRTIO=y CONFIG_GENERIC_PHY=y +CONFIG_EXT4_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -133,11 +134,8 @@ CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y CONFIG_KEYS=y CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y -CONFIG_CRC16=y CONFIG_CRC_ITU_T=y CONFIG_CRC7=y CONFIG_XZ_DEC=y From 4c45c424d0d3e02b1d47b275d37d477f944d6914 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 02:38:06 -0800 Subject: [PATCH 61/99] usb: add bflb ehci controller --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 10 ++++++++++ include/dt-bindings/mailbox/bflb-ipc.h | 1 + 4 files changed, 19 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index d3d228c3d8c0ea..66a892f880c71a 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -58,3 +58,7 @@ &ipclic { status = "okay"; }; + +&ehci0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index effaeda67c3fb7..19155bcc269373 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -53,3 +53,7 @@ &ipclic { status = "okay"; }; + +&ehci0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index ecb285cd7763ed..f3e4f17e69c033 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -90,6 +90,16 @@ status = "disabled"; }; + ehci0: usb@20072000 { + compatible = "generic-ehci"; + reg = <0x20072010 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_USB + IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bouffalolab,bflb-ipc"; reg = <0x30005000 0x20>, diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index e96fe62cbeb9a2..327e150384b95f 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -13,5 +13,6 @@ /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 +#define BFLB_IPC_DEVICE_USB 2 #endif From 0a7184765d42e951d892e1c7b70c6eb08eb67ec9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 02:38:58 -0800 Subject: [PATCH 62/99] bl808_defconfig: enable USB and EHCI --- arch/riscv/configs/bl808_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 2acab58e801b67..c43e21711750c7 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -103,7 +103,9 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_HID_REDRAGON is not set # CONFIG_HID_MICROSOFT is not set # CONFIG_HID_MONTEREY is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From aa9ca42882bd51620df7d5b591bb0c368ea830e4 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:06:40 -0800 Subject: [PATCH 63/99] dts: bl808: fix offset of ehci controller ehci controller registers are at address 0x20072000 not 0x20072010 --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index f3e4f17e69c033..5e90f3ee04d716 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -92,7 +92,7 @@ ehci0: usb@20072000 { compatible = "generic-ehci"; - reg = <0x20072010 0x1000>; + reg = <0x20072000 0x1000>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_USB IRQ_TYPE_EDGE_RISING>; From 3258905a37d4e65b045453a0955a87a03469a6d2 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:11:40 -0800 Subject: [PATCH 64/99] bl808_defconfig: enable USB serial and network devices --- arch/riscv/configs/bl808_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index c43e21711750c7..39ad1cb2b4bc55 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -106,6 +106,8 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From dcecd699e76f054916fde5f661fecc410938c5f9 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Fri, 20 Jan 2023 13:45:52 +0800 Subject: [PATCH 65/99] Rename DTS Files --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 8 +------- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 2 +- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 10 +++++----- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 66a892f880c71a..eede26e4f043c0 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -9,7 +9,7 @@ / { model = "Pine64 Ox64"; - compatible = "sipeed,m1s", "bouffalolab,bl808"; + compatible = "sipeed,m1s", "bflb,bl808"; aliases { serial0 = &uart0; @@ -34,12 +34,6 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; - - /*rootfs@0 { - label = "rootfs"; - reg = <0x00000 0x400000>; - read-only; - };*/ }; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 19155bcc269373..ed2d18482920c6 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -9,7 +9,7 @@ / { model = "Sipeed M1S"; - compatible = "sipeed,m1s", "bouffalolab,bl808"; + compatible = "sipeed,m1s", "bflb,bl808"; aliases { serial0 = &uart0; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 5e90f3ee04d716..bdfed1bde043ff 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -7,7 +7,7 @@ #include / { - compatible = "bouffalolab,bl808"; + compatible = "bflb,bl808"; #address-cells = <1>; #size-cells = <1>; @@ -61,7 +61,7 @@ #size-cells = <1>; uart0: serial@30002000 { - compatible = "bouffalolab,uart"; + compatible = "bflb,bl808-uart"; reg = <0x30002000 0x1000>; interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; clocks = <&xtal>; @@ -69,7 +69,7 @@ }; uart1: serial@0x2000AA00 { - compatible = "bouffalolab,uart"; + compatible = "bflb,bl808-uart"; reg = <0x2000AA00 0x0100>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2 @@ -80,7 +80,7 @@ }; sdhci0: sdhci@20060000 { - compatible = "bouffalolab,bflb-sdhci"; + compatible = "bflb,bl808-sdhci"; reg = <0x20060000 0x100>; interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI @@ -101,7 +101,7 @@ }; ipclic: mailbox@30005000 { - compatible = "bouffalolab,bflb-ipc"; + compatible = "bflb,bl808-ipc"; reg = <0x30005000 0x20>, <0x30005020 0x20>, <0x2000a800 0x20>, From 5de10314906445dd50565284c6fb822e86e3490c Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 20 Jan 2023 19:01:49 -0800 Subject: [PATCH 66/99] dts: bl808-pine64-ox64: change rootfs to /dev/mmcblk0p2 --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index eede26e4f043c0..4e183098f171ec 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p1 rootwait rootfstype=ext4"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; From 37884166bce69b4289af44e9e1422b7b1078c463 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:00:32 -0800 Subject: [PATCH 67/99] dts: bl808-pine64-ox64: disable secondary UART Pinmux for this device conflicts with EMAC, so disable it until pinmux is changed to some other pins. --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 4e183098f171ec..96cc039133cc04 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -41,10 +41,6 @@ status = "okay"; }; -&uart1 { - status = "okay"; -}; - &sdhci0 { status = "okay"; }; From 92d66e03a0a0f921142c67472eec01cbbfde13b9 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:02:40 -0800 Subject: [PATCH 68/99] dts: bl808: add entry for EMAC device Add device-tree node for EMAC ethernet device and fake clock node to represent 50MHz clock to the device. Add a virtualized interrupt bit for forwareded EMAC interrupts. --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 17 +++++++++++++++++ include/dt-bindings/mailbox/bflb-ipc.h | 1 + 2 files changed, 18 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index bdfed1bde043ff..dd795667dea68f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -52,6 +52,13 @@ #clock-cells = <0>; }; + enet: enet-clk { + compatible = "fixed-clock"; + clock-frequency = <50000000>; + clock-output-names = "enet"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; ranges; @@ -100,6 +107,16 @@ status = "disabled"; }; + enet0: emac@20070000 { + compatible = "opencores,ethoc"; + reg = <0x20070000 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_EMAC + IRQ_TYPE_EDGE_RISING>; + clocks = <&enet>; + status = "disabled"; + }; + ipclic: mailbox@30005000 { compatible = "bflb,bl808-ipc"; reg = <0x30005000 0x20>, diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 327e150384b95f..0a3c6745a673c1 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -14,5 +14,6 @@ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 #define BFLB_IPC_DEVICE_USB 2 +#define BFLB_IPC_DEVICE_EMAC 3 #endif From 2ad217b4095e489b76e3d8f1d9c42a668c5e013b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:13:31 -0800 Subject: [PATCH 69/99] riscv: bl808_defconfig: enable ETHOC driver --- arch/riscv/configs/bl808_defconfig | 45 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index 39ad1cb2b4bc55..d51f2d78c139d6 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -63,8 +63,48 @@ CONFIG_BLK_DEV_SD=y CONFIG_SCSI_VIRTIO=y CONFIG_NETDEVICES=y CONFIG_VIRTIO_NET=y -# CONFIG_ETHERNET is not set -CONFIG_MDIO_DEVICE=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_WANGXUN is not set +# CONFIG_NET_VENDOR_LITEX is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +CONFIG_ETHOC=y +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set # CONFIG_WLAN is not set CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_EVDEV=y @@ -88,6 +128,7 @@ CONFIG_I2C_SLAVE_EEPROM=y CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y +# CONFIG_PTP_1588_CLOCK is not set CONFIG_FB=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_VGA_CONSOLE is not set From a7bbe72dd574b66708c0cc060898551f3917b74a Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:14:05 -0800 Subject: [PATCH 70/99] dts: bl808: enable enet nodes --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 96cc039133cc04..f9ed636291f614 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -52,3 +52,7 @@ &ehci0 { status = "okay"; }; + +&enet0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index ed2d18482920c6..031c824f2061ae 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -57,3 +57,7 @@ &ehci0 { status = "okay"; }; + +&enet0 { + status = "okay"; +}; From ee0931def8e7ff676e11ebe147c1128862e2c8f6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 5 Feb 2023 16:13:42 -0600 Subject: [PATCH 71/99] riscv: dts: bflb: m1s: Fix address/size-cells The number of address cells needed here (one) does not match the implicitly-defined default number of cells. Signed-off-by: Samuel Holland --- arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 031c824f2061ae..5307508e7a9462 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -33,6 +33,8 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; rootfs@0 { label = "rootfs"; From be296b48621098e41309ac433fc3ebdd3d64c4bd Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 5 Feb 2023 20:18:50 -0800 Subject: [PATCH 72/99] riscv: dts: bflb: ox64: Fix address/size-cells The number of address cells needed here (one) does not match the implicitly-defined default number of cells. Signed-off-by: Allen Martin --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index f9ed636291f614..f1db126d88e76f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -34,6 +34,8 @@ linux,mtd-name = "xip-flash.0"; erase-size = <0x10000>; bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; }; }; From d48d4b1210f8a99578a429fecc282e83d7f8bc92 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Mon, 6 Feb 2023 13:38:55 +0800 Subject: [PATCH 73/99] Add timer node for OpenSBI 1.2 compatibility --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index dd795667dea68f..34652e17aece8f 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -140,5 +140,12 @@ #interrupt-cells = <2>; riscv,ndev = <64>; }; + + clint: timer@e4000000 { + compatible = "thead,c900-clint"; + reg = <0xe4000000 0xc000>; + interrupts-extended = <&cpu0_intc 3>, + <&cpu0_intc 7>; + }; }; }; From b79eef5b82707b2fe5823dc6e5e30f3fd94561ff Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Mon, 6 Feb 2023 13:41:53 +0800 Subject: [PATCH 74/99] Tabstops are 8 chars, not 4 --- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 34652e17aece8f..7cd033b6a1cf36 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -145,7 +145,7 @@ compatible = "thead,c900-clint"; reg = <0xe4000000 0xc000>; interrupts-extended = <&cpu0_intc 3>, - <&cpu0_intc 7>; + <&cpu0_intc 7>; }; }; }; From 4fb02196485265eeb2c13868932219d3de09a809 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Thu, 16 Feb 2023 19:42:01 +0000 Subject: [PATCH 75/99] Update device trees for new GPIO and HWRNG drivers --- .../dts/bouffalolab/bl808-pine64-ox64.dts | 8 +++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 30 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index f1db126d88e76f..5050c80b6f1150 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -39,6 +39,14 @@ }; }; +&pinctrl { + status = "okay"; +}; + +&seceng { + status = "okay"; +}; + &uart0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 7cd033b6a1cf36..73a4e055c7a9e6 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -67,6 +67,36 @@ #address-cells = <1>; #size-cells = <1>; + pinctrl: pinctrl@0x200008C4 { + compatible = "bflb,pinctrl"; + //Last register is for gpio_cfg141 at 0x20000af8 + reg = <0x200008C4 0x1000>; + //clocks = <&gpio_clk>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 46>; + bflb,npins = <46>; + + status = "disabled"; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_GPIO IRQ_TYPE_EDGE_RISING>; + + sdh_pins: sdh-pins { + pins = "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5"; + function = "sdh"; + }; + }; + + seceng: seceng@0x20004000 { + compatible = "bflb,seceng"; + reg = <0x20004000 0x1000>; + status = "disabled"; + }; + uart0: serial@30002000 { compatible = "bflb,bl808-uart"; reg = <0x30002000 0x1000>; From 56820fe33133f4d37dc277a344c5a54bfeb502c3 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Tue, 14 Feb 2023 23:12:03 +0000 Subject: [PATCH 76/99] Update bl808_defconfig for new drivers --- arch/riscv/configs/bl808_defconfig | 40 ++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig index d51f2d78c139d6..9e234dcb5ec0d7 100644 --- a/arch/riscv/configs/bl808_defconfig +++ b/arch/riscv/configs/bl808_defconfig @@ -11,8 +11,10 @@ CONFIG_CGROUP_SCHED=y CONFIG_CFS_BANDWIDTH=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_CHECKPOINT_RESTORE=y +CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y CONFIG_SOC_BOUFFALOLAB=y CONFIG_SOC_VIRT=y @@ -129,21 +131,15 @@ CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y # CONFIG_PTP_1588_CLOCK is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BFLB_GPIO=y +CONFIG_GPIO_SYSFS=y CONFIG_FB=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -# CONFIG_HID_A4TECH is not set -# CONFIG_HID_BELKIN is not set -# CONFIG_HID_CHERRY is not set -# CONFIG_HID_CYPRESS is not set -# CONFIG_HID_EZKEY is not set -# CONFIG_HID_ITE is not set -# CONFIG_HID_KENSINGTON is not set -# CONFIG_HID_REDRAGON is not set -# CONFIG_HID_MICROSOFT is not set -# CONFIG_HID_MONTEREY is not set +CONFIG_HID_CHICONY=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y @@ -153,6 +149,27 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_BFLB=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_USER=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_MTD=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_ACTIVITY=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_TRANSIENT=y +CONFIG_LEDS_TRIGGER_CAMERA=y +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_NETDEV=y +CONFIG_LEDS_TRIGGER_PATTERN=y +CONFIG_LEDS_TRIGGER_AUDIO=y +CONFIG_LEDS_TRIGGER_TTY=y CONFIG_RTC_CLASS=y CONFIG_SYNC_FILE=y # CONFIG_VIRTIO_MENU is not set @@ -180,6 +197,7 @@ CONFIG_NLS_UTF8=y CONFIG_KEYS=y CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_DEV_BFLB_SECENG=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CRC_ITU_T=y CONFIG_CRC7=y @@ -187,7 +205,9 @@ CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_VM_PGTABLE=y +CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_TIMEKEEPING=y +# CONFIG_FTRACE is not set CONFIG_FUNCTION_ERROR_INJECTION=y # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_MEMTEST=y From 5bc30359db03519fe18fafbbf0b1f4c38dbebdf7 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Thu, 16 Feb 2023 19:43:15 +0000 Subject: [PATCH 77/99] Bring M1s device tree up to date with Ox64's changes, fix compatible string on the Ox64 device tree --- .../dts/bouffalolab/bl808-pine64-ox64.dts | 2 +- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 31 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index 5050c80b6f1150..c5b1e86310d983 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -9,7 +9,7 @@ / { model = "Pine64 Ox64"; - compatible = "sipeed,m1s", "bflb,bl808"; + compatible = "pine64,ox64", "bflb,bl808"; aliases { serial0 = &uart0; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 5307508e7a9462..ecdce792132336 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -6,9 +6,11 @@ /dts-v1/; #include "bl808.dtsi" +#include +#include / { - model = "Sipeed M1S"; + model = "Sipeed M1s"; compatible = "sipeed,m1s", "bflb,bl808"; aliases { @@ -17,7 +19,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; @@ -35,15 +37,30 @@ bank-width = <4>; #address-cells = <1>; #size-cells = <1>; + }; + + leds { + compatible = "gpio-leds"; + + led { + gpios = <&pinctrl 8 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&pinctrl { + status = "okay"; - rootfs@0 { - label = "rootfs"; - reg = <0x00000 0x280000>; - read-only; - }; + led { + pins = "GPIO8"; + function = "gpio"; }; }; +&seceng { + status = "okay"; +}; + &uart0 { status = "okay"; }; From 9a3c861dbbdd9a22bca61ebd3b1f09a61c439a75 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:09 +0800 Subject: [PATCH 78/99] serial: bflb_uart: add Bouffalolab UART Driver Add the driver for Bouffalolab UART IP which is found in Bouffalolab SoCs such as bl808. UART driver probe will create path named "/dev/ttySx". Signed-off-by: Jisheng Zhang --- drivers/tty/serial/Kconfig | 18 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/bflb_uart.c | 659 +++++++++++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 + 4 files changed, 681 insertions(+) create mode 100644 drivers/tty/serial/bflb_uart.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index c55b947f3cdbb7..4b1eb61436ae76 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -179,6 +179,24 @@ config SERIAL_ATMEL_TTYAT Say Y if you have an external 8250/16C550 UART. If unsure, say N. +config SERIAL_BFLB + tristate "Bouffalolab serial port support" + select SERIAL_CORE + depends on COMMON_CLK + help + This enables the driver for the Bouffalolab's serial. + +config SERIAL_BFLB_CONSOLE + bool "Support for console on Bouffalolab serial port" + depends on SERIAL_BFLB + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Say Y here if you wish to use a Bouffalolab UART 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) as /dev/ttySn. + config SERIAL_KGDB_NMI bool "Serial console over KGDB NMI debugger port" depends on KGDB_SERIAL_CONSOLE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 238a9557b4872e..8509cdc11d874c 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250/ obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o +obj-$(CONFIG_SERIAL_BFLB) += bflb_uart.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c new file mode 100644 index 00000000000000..65f98ccf8fa81c --- /dev/null +++ b/drivers/tty/serial/bflb_uart.c @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Based on bflb_uart.c, by Bouffalolab team + * + * Copyright (C) 2022 Jisheng Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UART_UTX_CONFIG 0x00 +#define UART_CR_UTX_EN BIT(0) +#define UART_CR_UTX_CTS_EN BIT(1) +#define UART_CR_UTX_FRM_EN BIT(2) +#define UART_CR_UTX_PRT_EN BIT(4) +#define UART_CR_UTX_PRT_SEL BIT(5) +#define UART_CR_UTX_BIT_CNT_D_SFT 8 +#define UART_CR_UTX_BIT_CNT_D_MSK GENMASK(10, 8) +#define UART_CR_UTX_BIT_CNT_P_SFT 11 +#define UART_CR_UTX_BIT_CNT_P_MSK GENMASK(12, 11) +#define UART_URX_CONFIG 0x04 +#define UART_CR_URX_EN BIT(0) +#define UART_CR_URX_PRT_EN BIT(4) +#define UART_CR_URX_PRT_SEL BIT(5) +#define UART_CR_URX_BIT_CNT_D_SFT 8 +#define UART_CR_URX_BIT_CNT_D_MSK GENMASK(10, 8) +#define UART_BIT_PRD 0x08 +#define UART_CR_UTX_BIT_PRD GENMASK(15, 0) +#define UART_CR_URX_BIT_PRD GENMASK(31, 16) +#define UART_DATA_CONFIG 0x0c +#define UART_CR_UART_BIT_INV BIT(0) +#define UART_URX_RTO_TIMER 0x18 +#define UART_CR_URX_RTO_VALUE_MSK GENMASK(7, 0) +#define UART_SW_MODE 0x1c +#define UART_INT_STS (0x20) +#define UART_UTX_END_INT BIT(0) +#define UART_URX_END_INT BIT(1) +#define UART_UTX_FIFO_INT BIT(2) +#define UART_URX_FIFO_INT BIT(3) +#define UART_URX_RTO_INT BIT(4) +#define UART_URX_PCE_INT BIT(5) +#define UART_UTX_FER_INT BIT(6) +#define UART_URX_FER_INT BIT(7) +#define UART_URX_LSE_INT BIT(8) +#define UART_INT_MASK 0x24 +#define UART_INT_CLEAR 0x28 +#define UART_INT_EN 0x2c +#define UART_STATUS 0x30 +#define UART_STS_UTX_BUS_BUSY BIT(0) +#define UART_FIFO_CONFIG_0 (0x80) +#define UART_DMA_TX_EN BIT(0) +#define UART_DMA_RX_EN BIT(1) +#define UART_TX_FIFO_CLR BIT(2) +#define UART_RX_FIFO_CLR BIT(3) +#define UART_TX_FIFO_OVERFLOW BIT(4) +#define UART_TX_FIFO_UNDERFLOW BIT(5) +#define UART_RX_FIFO_OVERFLOW BIT(6) +#define UART_RX_FIFO_UNDERFLOW BIT(7) +#define UART_FIFO_CONFIG_1 (0x84) +#define UART_TX_FIFO_CNT_SFT 0 +#define UART_TX_FIFO_CNT_MSK GENMASK(5, 0) +#define UART_RX_FIFO_CNT_MSK GENMASK(13, 8) +#define UART_TX_FIFO_TH_SFT 16 +#define UART_TX_FIFO_TH_MSK GENMASK(20, 16) +#define UART_RX_FIFO_TH_SFT 24 +#define UART_RX_FIFO_TH_MSK GENMASK(28, 24) +#define UART_FIFO_WDATA 0x88 +#define UART_FIFO_RDATA 0x8c +#define UART_FIFO_RDATA_MSK GENMASK(7, 0) + +#define BFLB_UART_MAXPORTS 8 +#define BFLB_UART_BAUD 2000000 +#define BFLB_UART_RX_FIFO_TH 7 + +struct bflb_uart_port { + struct uart_port port; + struct clk *clk; +}; + +static struct bflb_uart_port *bflb_uart_ports[BFLB_UART_MAXPORTS]; + +static inline u32 rdl(struct uart_port *port, u32 reg) +{ + return readl_relaxed(port->membase + reg); +} + +static inline void wrl(struct uart_port *port, u32 reg, u32 value) +{ + writel_relaxed(value, port->membase + reg); +} + +static inline void wrb(struct uart_port *port, u32 reg, u8 value) +{ + writeb_relaxed(value, port->membase + reg); +} + +static unsigned int bflb_uart_tx_empty(struct uart_port *port) +{ + return (rdl(port, UART_FIFO_CONFIG_1) & UART_TX_FIFO_CNT_MSK) ? TIOCSER_TEMT : 0; +} + +static unsigned int bflb_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void bflb_uart_set_mctrl(struct uart_port *port, unsigned int sigs) +{ +} + +static void bflb_uart_start_tx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + + val = rdl(port, UART_INT_MASK); + val &= ~UART_UTX_END_INT; + wrl(port, UART_INT_MASK, val); + + val = rdl(port, UART_FIFO_CONFIG_1); + val &= ~UART_TX_FIFO_TH_MSK; + val |= 15 << UART_TX_FIFO_TH_SFT; + wrl(port, UART_FIFO_CONFIG_1, val); + + val = rdl(port, UART_INT_MASK); + val &= ~UART_UTX_FIFO_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_stop_tx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_INT_MASK); + val |= UART_UTX_END_INT | UART_UTX_FIFO_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_stop_rx(struct uart_port *port) +{ + u32 val; + + val = rdl(port, UART_URX_CONFIG); + val &= ~UART_CR_URX_EN; + wrl(port, UART_URX_CONFIG, val); + + val = rdl(port, UART_INT_MASK); + val |= UART_URX_FIFO_INT | UART_URX_RTO_INT | + UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); +} + +static void bflb_uart_break_ctl(struct uart_port *port, int break_state) +{ +} + +static void bflb_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + unsigned long flags; + u32 valt, valr, val; + unsigned int baud, min; + + valt = valr = 0; + + spin_lock_irqsave(&port->lock, flags); + + /* set data length */ + val = tty_get_char_size(termios->c_cflag) - 1; + valt |= (val << UART_CR_UTX_BIT_CNT_D_SFT); + + /* calculate parity */ + termios->c_cflag &= ~CMSPAR; /* no support mark/space */ + if (termios->c_cflag & PARENB) { + valt |= UART_CR_UTX_PRT_EN; + if (termios->c_cflag & PARODD) + valr |= UART_CR_UTX_PRT_SEL; + } + + valr = valt; + + /* calculate stop bits */ + if (termios->c_cflag & CSTOPB) + val = 2; + else + val = 1; + valt |= (val << UART_CR_UTX_BIT_CNT_P_SFT); + + /* flow control */ + if (termios->c_cflag & CRTSCTS) + valt |= UART_CR_UTX_CTS_EN; + + /* enable TX freerunning mode */ + valt |= UART_CR_UTX_FRM_EN; + + valt |= UART_CR_UTX_EN; + valr |= UART_CR_URX_EN; + + wrl(port, UART_UTX_CONFIG, valt); + wrl(port, UART_URX_CONFIG, valr); + + min = port->uartclk / (UART_CR_UTX_BIT_PRD + 1); + baud = uart_get_baud_rate(port, termios, old, min, 4000000); + + val = DIV_ROUND_CLOSEST(port->uartclk, baud) - 1; + val &= UART_CR_UTX_BIT_PRD; + val |= (val << 16); + wrl(port, UART_BIT_PRD, val); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void bflb_uart_rx_chars(struct uart_port *port) +{ + unsigned char ch, flag; + unsigned long status; + + while ((status = rdl(port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { + ch = rdl(port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; + flag = TTY_NORMAL; + port->icount.rx++; + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, 0, 0, ch, flag); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); +} + +static void bflb_uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int pending, count; + + if (port->x_char) { + /* Send special char - probably flow control */ + wrl(port, UART_FIFO_WDATA, port->x_char); + port->x_char = 0; + port->icount.tx++; + return; + } + + pending = uart_circ_chars_pending(xmit); + if (pending > 0) { + count = (rdl(port, UART_FIFO_CONFIG_1) & + UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; + if (count > pending) + count = pending; + if (count > 0) { + pending -= count; + while (count--) { + wrl(port, UART_FIFO_WDATA, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + if (pending < WAKEUP_CHARS) + uart_write_wakeup(port); + } + } + + if (pending == 0) + bflb_uart_stop_tx(port); +} + +static irqreturn_t bflb_uart_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + u32 isr, val; + + isr = rdl(port, UART_INT_STS); + wrl(port, UART_INT_CLEAR, isr); + + isr &= ~rdl(port, UART_INT_MASK); + + spin_lock(&port->lock); + + if (isr & UART_URX_FER_INT) { + /* RX FIFO error interrupt */ + val = rdl(port, UART_FIFO_CONFIG_0); + if (val & UART_RX_FIFO_OVERFLOW) + port->icount.overrun++; + + val |= UART_RX_FIFO_CLR; + wrl(port, UART_FIFO_CONFIG_0, val); + } + + if (isr & (UART_URX_FIFO_INT | UART_URX_RTO_INT)) { + bflb_uart_rx_chars(port); + } + if (isr & (UART_UTX_FIFO_INT | UART_UTX_END_INT)) { + bflb_uart_tx_chars(port); + } + + spin_unlock(&port->lock); + + return IRQ_RETVAL(isr); +} + +static void bflb_uart_config_port(struct uart_port *port, int flags) +{ + u32 val; + + port->type = PORT_BFLB; + + /* Clear mask, so no surprise interrupts. */ + val = rdl(port, UART_INT_MASK); + val |= UART_UTX_END_INT; + val |= UART_UTX_FIFO_INT; + val |= UART_URX_FIFO_INT; + val |= UART_URX_RTO_INT; + val |= UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); +} + +static int bflb_uart_startup(struct uart_port *port) +{ + unsigned long flags; + int ret; + u32 val; + + ret = devm_request_irq(port->dev, port->irq, bflb_uart_interrupt, + IRQF_SHARED, port->name, port); + if (ret) { + dev_err(port->dev, "fail to request serial irq %d, ret=%d\n", + port->irq, ret); + return ret; + } + + spin_lock_irqsave(&port->lock, flags); + + val = rdl(port, UART_INT_MASK); + val |= 0xfff; + wrl(port, UART_INT_MASK, val); + + wrl(port, UART_DATA_CONFIG, 0); + wrl(port, UART_SW_MODE, 0); + wrl(port, UART_URX_RTO_TIMER, 0x4f); + + val = rdl(port, UART_FIFO_CONFIG_1); + val &= ~UART_RX_FIFO_TH_MSK; + val |= BFLB_UART_RX_FIFO_TH << UART_RX_FIFO_TH_SFT; + wrl(port, UART_FIFO_CONFIG_1, val); + + /* Unmask RX interrupts now */ + val = rdl(port, UART_INT_MASK); + val &= ~UART_URX_FIFO_INT; + val &= ~UART_URX_RTO_INT; + val &= ~UART_URX_FER_INT; + wrl(port, UART_INT_MASK, val); + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + val = rdl(port, UART_URX_CONFIG); + val |= UART_CR_URX_EN; + wrl(port, UART_URX_CONFIG, val); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void bflb_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + /* mask all interrupts now */ + wrl(port, UART_INT_MASK, UART_UTX_END_INT | UART_URX_END_INT); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *bflb_uart_type(struct uart_port *port) +{ + return (port->type == PORT_BFLB) ? "BFLB UART" : NULL; +} + +static int bflb_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void bflb_uart_release_port(struct uart_port *port) +{ + /* Nothing to release... */ +} + +static int bflb_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_BFLB) + return -EINVAL; + return 0; +} + +static const struct uart_ops bflb_uart_ops = { + .tx_empty = bflb_uart_tx_empty, + .get_mctrl = bflb_uart_get_mctrl, + .set_mctrl = bflb_uart_set_mctrl, + .start_tx = bflb_uart_start_tx, + .stop_tx = bflb_uart_stop_tx, + .stop_rx = bflb_uart_stop_rx, + .break_ctl = bflb_uart_break_ctl, + .startup = bflb_uart_startup, + .shutdown = bflb_uart_shutdown, + .set_termios = bflb_uart_set_termios, + .type = bflb_uart_type, + .request_port = bflb_uart_request_port, + .release_port = bflb_uart_release_port, + .config_port = bflb_uart_config_port, + .verify_port = bflb_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_BFLB_CONSOLE +static void bflb_console_putchar(struct uart_port *port, unsigned char ch) +{ + while (!(rdl(port, UART_FIFO_CONFIG_1) & UART_TX_FIFO_CNT_MSK)) + cpu_relax(); + wrb(port, UART_FIFO_WDATA, ch); +} + +/* + * Interrupts are disabled on entering + */ +static void bflb_uart_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_port *port = &bflb_uart_ports[co->index]->port; + u32 status, reg, mask; + + /* save then disable interrupts */ + mask = rdl(port, UART_INT_MASK); + reg = -1; + wrl(port, UART_INT_MASK, reg); + + /* Make sure that tx is enabled */ + reg = rdl(port, UART_UTX_CONFIG); + reg |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, reg); + + uart_console_write(port, s, count, bflb_console_putchar); + + /* wait for TX done */ + do { + status = rdl(port, UART_STATUS); + } while ((status & UART_STS_UTX_BUS_BUSY)); + + /* restore IRQ mask */ + wrl(port, UART_INT_MASK, mask); +} + +static int bflb_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct bflb_uart_port *bp; + int baud = BFLB_UART_BAUD; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + u32 val; + + if (co->index >= BFLB_UART_MAXPORTS || co->index < 0) + return -EINVAL; + + bp = bflb_uart_ports[co->index]; + if (!bp) + /* Port not initialized yet - delay setup */ + return -ENODEV; + + port = &bp->port; + + val = rdl(port, UART_UTX_CONFIG); + val |= UART_CR_UTX_EN; + wrl(port, UART_UTX_CONFIG, val); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver bflb_uart_driver; +static struct console bflb_uart_console = { + .name = "ttyS", + .write = bflb_uart_console_write, + .device = uart_console_device, + .setup = bflb_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bflb_uart_driver, +}; + +static int __init bflb_uart_console_init(void) +{ + register_console(&bflb_uart_console); + return 0; +} +console_initcall(bflb_uart_console_init); + +#define BFLB_UART_CONSOLE (&bflb_uart_console) + +static void bflb_uart_earlycon_write(struct console *co, const char *s, + unsigned int count) +{ + struct earlycon_device *dev = co->data; + + uart_console_write(&dev->port, s, count, bflb_console_putchar); +} + +static int __init bflb_uart_earlycon_setup(struct earlycon_device *dev, + const char *options) +{ + if (!dev->port.membase) + return -ENODEV; + + dev->con->write = bflb_uart_earlycon_write; + + return 0; +} +OF_EARLYCON_DECLARE(bflb_uart, "bouffalolab,uart", bflb_uart_earlycon_setup); + +#else + +#define BFLB_UART_CONSOLE NULL + +#endif /* CONFIG_SERIAL_BFLB_CONSOLE */ + +static struct uart_driver bflb_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "bflb_uart", + .dev_name = "ttyS", + .nr = BFLB_UART_MAXPORTS, + .cons = BFLB_UART_CONSOLE, +}; + +static int bflb_uart_probe(struct platform_device *pdev) +{ + struct uart_port *port; + struct bflb_uart_port *bp; + struct resource *res; + int index, irq; + + index = of_alias_get_id(pdev->dev.of_node, "serial"); + if (unlikely(index < 0 || index >= BFLB_UART_MAXPORTS)) { + dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index); + return -EINVAL; + } + + bp = devm_kzalloc(&pdev->dev, sizeof(*bp), GFP_KERNEL); + if (!bp) + return -ENOMEM; + + bflb_uart_ports[index] = bp; + platform_set_drvdata(pdev, bp); + port = &bp->port; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + port->mapbase = res->start; + port->irq = irq; + port->line = index; + port->type = PORT_BFLB; + port->iotype = UPIO_MEM; + port->fifosize = 32; + port->ops = &bflb_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_BFLB_CONSOLE); + + bp->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bp->clk)) + return PTR_ERR(bp->clk); + port->uartclk = clk_get_rate(bp->clk); + + return uart_add_one_port(&bflb_uart_driver, port); +} + +static int bflb_uart_remove(struct platform_device *pdev) +{ + struct bflb_uart_port *bp = platform_get_drvdata(pdev); + + uart_remove_one_port(&bflb_uart_driver, &bp->port); + bflb_uart_ports[bp->port.line] = NULL; + + return 0; +} + +static const struct of_device_id bflb_uart_match[] = { + { + .compatible = "bouffalolab,uart", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bflb_uart_match); + +static struct platform_driver bflb_uart_platform_driver = { + .probe = bflb_uart_probe, + .remove = bflb_uart_remove, + .driver = { + .name = "bflb_uart", + .of_match_table = of_match_ptr(bflb_uart_match), + }, +}; + +static int __init bflb_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&bflb_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&bflb_uart_platform_driver); + if (ret) + uart_unregister_driver(&bflb_uart_driver); + + return ret; +} + +static void __exit bflb_uart_exit(void) +{ + platform_driver_unregister(&bflb_uart_platform_driver); + uart_unregister_driver(&bflb_uart_driver); +} + +module_init(bflb_uart_init); +module_exit(bflb_uart_exit); + +MODULE_DESCRIPTION("Bouffalolab UART driver"); +MODULE_AUTHOR("Jisheng Zhang "); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 3ba34d8378bd0e..dabbb5ea285738 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -276,4 +276,7 @@ /* Sunplus UART */ #define PORT_SUNPLUS 123 +/* Bouffalolab UART */ +#define PORT_BFLB 124 + #endif /* _UAPILINUX_SERIAL_CORE_H */ From 6d91402cf4ffc129e3088f3bb26495946d76cf95 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 20 Nov 2022 16:21:10 +0800 Subject: [PATCH 79/99] MAINTAINERS: add myself as a reviewer for Bouffalolab uart driver I want to maintain this Bouffalolab uart driver from now on. Signed-off-by: Jisheng Zhang --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a8ee2a529ecb54..952099139569fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3788,6 +3788,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* +BOUFFALOLAB UART DRIVER +M: Jisheng Zhang +S: Maintained +F: Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml +F: drivers/tty/serial/bflb_uart.c + BPF [GENERAL] (Safe Dynamic Programs and Tools) M: Alexei Starovoitov M: Daniel Borkmann From 31e8d58250820f8a14d6c12bbf8c8db9fd4df453 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:14:53 -0800 Subject: [PATCH 80/99] WIP: add BFLB MBOX interrupt controller driver --- drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/bflb-ipc.c | 381 +++++++++++++++++++++++++++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 drivers/mailbox/bflb-ipc.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 1495965bc394c0..c215da153fd7be 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -295,4 +295,13 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config BFLB_IPC + tristate "Bouffalo Lab IPC driver" + depends on OF + help + (IPC) driver for BL808 devices. The driver provides mailbox support for + sending interrupts to the clients. On the other hand, the driver also + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fc93761171113e..02bba5d03d4b2c 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o + +obj-$(CONFIG_BFLB_IPC) += bflb-ipc.o diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c new file mode 100644 index 00000000000000..692dd20e35a8d1 --- /dev/null +++ b/drivers/mailbox/bflb-ipc.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Allen Martin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* IPC Register offsets */ +#define IPC_REG_ISWR 0x00 /* Interrupt Set Write Register */ +#define IPC_REG_IRSRR 0x04 /* Interrupt raw status Register */ +#define IPC_REG_ICR 0x08 /* Interrupt Clear Register */ +#define IPC_REG_IUSR 0x0c /* Interrupt Unmask Set Register */ +#define IPC_REG_IUCR 0x10 /* Interrupt Unmask Clear Register */ +#define IPC_REG_ILSLR 0x14 /* Interrupt Line Sel Low Register */ +#define IPC_REG_ILSHR 0x18 /* Interrupt Line Sel High Register */ +#define IPC_REG_ISR 0x1c /* Interrupt status Register */ + +/** + * struct bflb_ipc_chan_info - Per-mailbox-channel info + * @client_id: The client-id to which the interrupt has to be triggered + * @signal_id: The signal-id to which the interrupt has to be triggered + */ +struct bflb_ipc_chan_info { + u16 client_id; + u16 signal_id; +}; + +/** + * struct bflb_ipc - Holder for the mailbox driver + * @dev: Device associated with this instance + * @base: Base address of each IPC frame (LP, M0) + * @irq_domain: The irq_domain associated with this instance + * @chans: The mailbox channels array + * @mchan: The per-mailbox channel info array + * @mbox: The mailbox controller + * @num_chans: Number of @chans elements + * @irq: Summary irq + */ +struct bflb_ipc { + struct device *dev; + void __iomem *base[4]; + struct irq_domain *irq_domain; + struct mbox_chan *chans; + struct bflb_ipc_chan_info *mchan; + struct mbox_controller mbox; + int num_chans; + int irq; +}; + +static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mbox) +{ + return container_of(mbox, struct bflb_ipc, mbox); +} + +static inline u32 bflb_ipc_get_hwirq(u16 source, u16 device) +{ + pr_debug("%s: source: %u, device: %u\n", __func__, source, device); + + return device; +} + +#if 0 +static void bflb_ipc_dump_regs(struct bflb_ipc *ipc) +{ + int i; + for (i=0; i<4; i++) { + dev_dbg(ipc->dev, "base %px\n", ipc->base[i]); + dev_dbg(ipc->dev, "ISWR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISWR)); + dev_dbg(ipc->dev, "IRSRR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IRSRR)); + dev_dbg(ipc->dev, "ICR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ICR)); + dev_dbg(ipc->dev, "IUSR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IUSR)); + dev_dbg(ipc->dev, "IUCR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_IUCR)); + dev_dbg(ipc->dev, "ILSLR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ILSLR)); + dev_dbg(ipc->dev, "ILSHR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ILSHR)); + dev_dbg(ipc->dev, "ISR: 0x%08x\n", readl(ipc->base[i] + IPC_REG_ISR)); + } +} +#endif + +static irqreturn_t bflb_ipc_irq_fn(int irq, void *data) +{ + struct bflb_ipc *ipc = data; + unsigned long stat; + int pos; + + stat = readl(ipc->base[1] + IPC_REG_ISR); + for_each_set_bit(pos, &stat, 32) + generic_handle_domain_irq(ipc->irq_domain, pos); + writel(stat, ipc->base[1] + IPC_REG_ICR); + + /* EOI the irqs */ + writel(stat, ipc->base[2] + IPC_REG_ISWR); + + return IRQ_HANDLED; +} + +static void bflb_ipc_mask_irq(struct irq_data *irqd) +{ + struct bflb_ipc *ipc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(BIT(hwirq), ipc->base[1] + IPC_REG_IUCR); +} + +static void bflb_ipc_unmask_irq(struct irq_data *irqd) +{ + struct bflb_ipc *ipc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(BIT(hwirq), ipc->base[1] + IPC_REG_IUSR); +} + +static struct irq_chip bflb_ipc_irq_chip = { + .name = "BFLB MBOXIC", + .irq_mask = bflb_ipc_mask_irq, + .irq_unmask = bflb_ipc_unmask_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static int bflb_ipc_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct bflb_ipc *ipc = d->host_data; + + irq_set_chip_and_handler(irq, &bflb_ipc_irq_chip, handle_level_irq); + irq_set_chip_data(irq, ipc); + irq_set_noprobe(irq); + + return 0; +} + +static int bflb_ipc_domain_xlate(struct irq_domain *d, + struct device_node *node, const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (intsize != 3) + return -EINVAL; + + *out_hwirq = bflb_ipc_get_hwirq(intspec[0], intspec[1]); + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static const struct irq_domain_ops bflb_ipc_irq_ops = { + .map = bflb_ipc_domain_map, + .xlate = bflb_ipc_domain_xlate, +}; + +static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct bflb_ipc *ipc = to_bflb_ipc(chan->mbox); + struct bflb_ipc_chan_info *mchan = chan->con_priv; + u32 hwirq; + + hwirq = bflb_ipc_get_hwirq(mchan->client_id, mchan->signal_id); + + dev_dbg(ipc->dev, "%s: hwirq: %u\n", __func__, hwirq); + +// writel(hwirq, ipc->base + IPC_REG_SEND_ID); + + return 0; +} + +static void bflb_ipc_mbox_shutdown(struct mbox_chan *chan) +{ + pr_debug("%s\n", __func__); + chan->con_priv = NULL; +} + +static struct mbox_chan *bflb_ipc_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *ph) +{ + struct bflb_ipc *ipc = to_bflb_ipc(mbox); + struct bflb_ipc_chan_info *mchan; + struct mbox_chan *chan; + struct device *dev; + int chan_id; + + dev = ipc->dev; + + dev_dbg(dev, "%s\n", __func__); + + if (ph->args_count != 2) + return ERR_PTR(-EINVAL); + + for (chan_id = 0; chan_id < mbox->num_chans; chan_id++) { + chan = &ipc->chans[chan_id]; + mchan = chan->con_priv; + + if (!mchan) + break; + else if (mchan->client_id == ph->args[0] && + mchan->signal_id == ph->args[1]) + return ERR_PTR(-EBUSY); + } + + if (chan_id >= mbox->num_chans) + return ERR_PTR(-EBUSY); + + mchan = devm_kzalloc(dev, sizeof(*mchan), GFP_KERNEL); + if (!mchan) + return ERR_PTR(-ENOMEM); + + mchan->client_id = ph->args[0]; + mchan->signal_id = ph->args[1]; + chan->con_priv = mchan; + + return chan; +} + +static const struct mbox_chan_ops ipc_mbox_chan_ops = { + .send_data = bflb_ipc_mbox_send_data, + .shutdown = bflb_ipc_mbox_shutdown, +}; + +static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, + struct device_node *controller_dn) +{ + struct of_phandle_args curr_ph; + struct device_node *client_dn; + struct mbox_controller *mbox; + struct device *dev = ipc->dev; + int i, j, ret; + + /* + * Find out the number of clients interested in this mailbox + * and create channels accordingly. + */ + ipc->num_chans = 0; + for_each_node_with_property(client_dn, "mboxes") { + if (!of_device_is_available(client_dn)) + continue; + i = of_count_phandle_with_args(client_dn, + "mboxes", "#mbox-cells"); + for (j = 0; j < i; j++) { + ret = of_parse_phandle_with_args(client_dn, "mboxes", + "#mbox-cells", j, &curr_ph); + of_node_put(curr_ph.np); + if (!ret && curr_ph.np == controller_dn) { + ipc->num_chans++; + break; + } + } + } + + /* If no clients are found, skip registering as a mbox controller */ + if (!ipc->num_chans) + return 0; + + ipc->chans = devm_kcalloc(dev, ipc->num_chans, + sizeof(struct mbox_chan), GFP_KERNEL); + if (!ipc->chans) + return -ENOMEM; + + mbox = &ipc->mbox; + mbox->dev = dev; + mbox->num_chans = ipc->num_chans; + mbox->chans = ipc->chans; + mbox->ops = &ipc_mbox_chan_ops; + mbox->of_xlate = bflb_ipc_mbox_xlate; + mbox->txdone_irq = false; + mbox->txdone_poll = false; + + return devm_mbox_controller_register(dev, mbox); +} + +static int bflb_ipc_pm_resume(struct device *dev) +{ + return 0; +} + +static int bflb_ipc_probe(struct platform_device *pdev) +{ + struct bflb_ipc *ipc; + static int id; + int i; + char *name; + int ret; + + ipc = devm_kzalloc(&pdev->dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return -ENOMEM; + + ipc->dev = &pdev->dev; + + for (i=0; i<4; i++) { + ipc->base[i] = devm_platform_ioremap_resource(pdev, i); + if (IS_ERR(ipc->base[i])) + return PTR_ERR(ipc->base[i]); + } + + ipc->irq = platform_get_irq(pdev, 0); + if (ipc->irq < 0) + return ipc->irq; + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "mboxic%d", id++); + if (!name) + return -ENOMEM; + + ipc->irq_domain = irq_domain_add_tree(pdev->dev.of_node, + &bflb_ipc_irq_ops, ipc); + if (!ipc->irq_domain) + return -ENOMEM; + + ret = bflb_ipc_setup_mbox(ipc, pdev->dev.of_node); + if (ret) + goto err_mbox; + + ret = devm_request_irq(&pdev->dev, ipc->irq, bflb_ipc_irq_fn, + IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND | + IRQF_NO_THREAD, name, ipc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register the irq: %d\n", ret); + goto err_req_irq; + } + + platform_set_drvdata(pdev, ipc); + + dev_info(&pdev->dev, "Bouffalo Lab IPC mailbox interrupt controller"); + return 0; + +err_req_irq: + if (ipc->num_chans) + mbox_controller_unregister(&ipc->mbox); +err_mbox: + irq_domain_remove(ipc->irq_domain); + + return ret; +} + +static int bflb_ipc_remove(struct platform_device *pdev) +{ + struct bflb_ipc *ipc = platform_get_drvdata(pdev); + + disable_irq_wake(ipc->irq); + irq_domain_remove(ipc->irq_domain); + + return 0; +} + +static const struct of_device_id bflb_ipc_of_match[] = { + { .compatible = "bouffalolab,bflb-ipc"}, + {} +}; +MODULE_DEVICE_TABLE(of, bflb_ipc_of_match); + +static const struct dev_pm_ops bflb_ipc_dev_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, bflb_ipc_pm_resume) +}; + +static struct platform_driver bflb_ipc_driver = { + .probe = bflb_ipc_probe, + .remove = bflb_ipc_remove, + .driver = { + .name = "bflb-ipc", + .of_match_table = bflb_ipc_of_match, + .suppress_bind_attrs = true, + .pm = pm_sleep_ptr(&bflb_ipc_dev_pm_ops), + }, +}; + +static int __init bflb_ipc_init(void) +{ + return platform_driver_register(&bflb_ipc_driver); +} +arch_initcall(bflb_ipc_init); + +MODULE_AUTHOR("Allen Martin "); +MODULE_DESCRIPTION("Bouffalo Lab IPC driver"); +MODULE_LICENSE("GPL v2"); From 226ae45e5f2f530f71b0e3b3a042281e3ebf5213 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Wed, 11 Jan 2023 18:16:51 -0800 Subject: [PATCH 81/99] WIP: sdhci: add BFLB sdhci driver --- drivers/mmc/host/Kconfig | 14 ++++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-bflb.c | 117 ++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 drivers/mmc/host/sdhci-bflb.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5e19a961c34d7b..f3c4654bb376e0 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -413,6 +413,20 @@ config MMC_SDHCI_F_SDH30 If unsure, say N. +config MMC_SDHCI_BFLB + tristate "SDHCI support on Bouffalo Lab BL808 SoC" + depends on MMC_SDHCI_PLTFM + depends on OF + depends on COMMON_CLK + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Secure Digital Host Controller Interface in + Bouffalo Lab BL808 SoC. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_MILBEAUT tristate "SDHCI support for Socionext Milbeaut Serieas using F_SDH30" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ba0c6d0cd85d7a..626875dfb629a3 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -103,6 +103,7 @@ cqhci-y += cqhci-core.o cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o obj-$(CONFIG_MMC_HSQ) += mmc_hsq.o obj-$(CONFIG_MMC_LITEX) += litex_mmc.o +obj-$(CONFIG_MMC_SDHCI_BFLB) += sdhci-bflb.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c new file mode 100644 index 00000000000000..a67ecb2a380df4 --- /dev/null +++ b/drivers/mmc/host/sdhci-bflb.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +static u16 sdhci_bflb_readw(struct sdhci_host *host, int reg) +{ + u16 ret; + + switch (reg) { + case SDHCI_HOST_VERSION: + case SDHCI_SLOT_INT_STATUS: + /* those registers don't exist */ + return 0; + default: + ret = readw(host->ioaddr + reg); + } + return ret; +} + +static u32 sdhci_bflb_readl(struct sdhci_host *host, int reg) +{ + u32 ret; + + ret = readl(host->ioaddr + reg); + + switch (reg) { + case SDHCI_CAPABILITIES: + /* Mask the support for 3.0V */ + ret &= ~SDHCI_CAN_VDD_300; + break; + } + return ret; +} + +static const struct sdhci_ops sdhci_bflb_ops = { + .read_w = sdhci_bflb_readw, + .read_l = sdhci_bflb_readl, + .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data sdhci_bflb_pdata = { + .ops = &sdhci_bflb_ops, + .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | + SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_BROKEN_DMA | + SDHCI_QUIRK_BROKEN_ADMA | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +}; + +static int sdhci_bflb_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + int ret; + + host = sdhci_pltfm_init(pdev, &sdhci_bflb_pdata, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(pltfm_host->clk)) + clk_prepare_enable(pltfm_host->clk); + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_sdhci_add; + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; + + return 0; + +err_sdhci_add: + clk_disable_unprepare(pltfm_host->clk); + sdhci_pltfm_free(pdev); + return ret; +} + +static const struct of_device_id sdhci_bflb_of_match_table[] = { + { .compatible = "bouffalolab,bflb-sdhci", }, + {} +}; +MODULE_DEVICE_TABLE(of, sdhci_bflb_of_match_table); + +static struct platform_driver sdhci_bflb_driver = { + .driver = { + .name = "sdhci-bflb", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &sdhci_pltfm_pmops, + .of_match_table = sdhci_bflb_of_match_table, + }, + .probe = sdhci_bflb_probe, + .remove = sdhci_pltfm_unregister, +}; + +module_platform_driver(sdhci_bflb_driver); + +MODULE_DESCRIPTION("SDHCI driver for Bflb"); +MODULE_LICENSE("GPL v2"); From de3ed97b314c326b3138e02446f23c9db5a6687a Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 13 Jan 2023 03:02:41 -0800 Subject: [PATCH 82/99] disable card detection/dma/cap clock quirks --- drivers/mmc/host/sdhci-bflb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index a67ecb2a380df4..c9141ddd733176 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,11 +55,7 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_BROKEN_ADMA | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + SDHCI_QUIRK_NO_HISPD_BIT, }; static int sdhci_bflb_probe(struct platform_device *pdev) From d28e6970c57c4c49c162582a380aeaf8d215cacc Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 01:07:35 -0800 Subject: [PATCH 83/99] sdhci-bflb: enable additional quirks Write protect polarity is confirmed backwards, the other quirks may not be needed. --- drivers/mmc/host/sdhci-bflb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index c9141ddd733176..f6cc40dcf61491 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,6 +55,10 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_BROKEN_DMA | + SDHCI_QUIRK_BROKEN_ADMA | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT | SDHCI_QUIRK_NO_HISPD_BIT, }; From eb37752176c9fcfefaf4b79dff85d5ba2cb15a50 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Fri, 20 Jan 2023 13:45:52 +0800 Subject: [PATCH 84/99] Rename DTS Files --- drivers/mailbox/bflb-ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c index 692dd20e35a8d1..06020cec3cbaec 100644 --- a/drivers/mailbox/bflb-ipc.c +++ b/drivers/mailbox/bflb-ipc.c @@ -350,7 +350,7 @@ static int bflb_ipc_remove(struct platform_device *pdev) } static const struct of_device_id bflb_ipc_of_match[] = { - { .compatible = "bouffalolab,bflb-ipc"}, + { .compatible = "bflb,bl808-ipc"}, {} }; MODULE_DEVICE_TABLE(of, bflb_ipc_of_match); From 2e8977e82f00a8b1bfb79c3a90278512e6c749b9 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Fri, 20 Jan 2023 13:45:52 +0800 Subject: [PATCH 85/99] Rename DTS Files --- drivers/mmc/host/sdhci-bflb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index f6cc40dcf61491..aacf234387af88 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -95,7 +95,7 @@ static int sdhci_bflb_probe(struct platform_device *pdev) } static const struct of_device_id sdhci_bflb_of_match_table[] = { - { .compatible = "bouffalolab,bflb-sdhci", }, + { .compatible = "bflb,bl808-sdhci", }, {} }; MODULE_DEVICE_TABLE(of, sdhci_bflb_of_match_table); From f83ddcbbd9b0b474fab71c953f196f89512a6b4d Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Fri, 20 Jan 2023 13:45:52 +0800 Subject: [PATCH 86/99] Rename DTS Files --- drivers/tty/serial/bflb_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c index 65f98ccf8fa81c..b091ad7a891ae9 100644 --- a/drivers/tty/serial/bflb_uart.c +++ b/drivers/tty/serial/bflb_uart.c @@ -538,7 +538,7 @@ static int __init bflb_uart_earlycon_setup(struct earlycon_device *dev, return 0; } -OF_EARLYCON_DECLARE(bflb_uart, "bouffalolab,uart", bflb_uart_earlycon_setup); +OF_EARLYCON_DECLARE(bflb_uart, "bflb,bl808-uart", bflb_uart_earlycon_setup); #else @@ -615,7 +615,7 @@ static int bflb_uart_remove(struct platform_device *pdev) static const struct of_device_id bflb_uart_match[] = { { - .compatible = "bouffalolab,uart", + .compatible = "bflb,bl808-uart", }, {}, }; From e944b126eb7cc56d3640f3777e00b605691b0f32 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Fri, 20 Jan 2023 19:42:33 -0800 Subject: [PATCH 87/99] tty: serial: bflb_uart: fix leaked ISR registration -call devm_free_irq() in shutdown to release ISR registered in startup. -change many functions to take driver private bflb_uart_port * instead of serial_core uart_port * -add to_bflb_uart_port() to assist with above -switch to using uart_port_tx_limited() serial_core helper which is the preferred way to do transmission instead of accessing serial_core xmit buffer directly --- drivers/tty/serial/bflb_uart.c | 133 ++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c index b091ad7a891ae9..5911f489959c75 100644 --- a/drivers/tty/serial/bflb_uart.c +++ b/drivers/tty/serial/bflb_uart.c @@ -82,12 +82,17 @@ #define BFLB_UART_MAXPORTS 8 #define BFLB_UART_BAUD 2000000 #define BFLB_UART_RX_FIFO_TH 7 +#define BFLB_UART_TX_FIFO_DEPTH 32 struct bflb_uart_port { struct uart_port port; struct clk *clk; }; +#define to_bflb_uart_port(p) (container_of((p), \ + struct bflb_uart_port, \ + port)) + static struct bflb_uart_port *bflb_uart_ports[BFLB_UART_MAXPORTS]; static inline u32 rdl(struct uart_port *port, u32 reg) @@ -227,91 +232,104 @@ static void bflb_uart_set_termios(struct uart_port *port, spin_unlock_irqrestore(&port->lock, flags); } -static void bflb_uart_rx_chars(struct uart_port *port) +static void bflb_uart_rx_chars(struct bflb_uart_port *bp) { unsigned char ch, flag; unsigned long status; - while ((status = rdl(port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { - ch = rdl(port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; + while ((status = rdl(&bp->port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) { + ch = rdl(&bp->port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK; flag = TTY_NORMAL; - port->icount.rx++; + bp->port.icount.rx++; - if (uart_handle_sysrq_char(port, ch)) + if (uart_handle_sysrq_char(&bp->port, ch)) continue; - uart_insert_char(port, 0, 0, ch, flag); + uart_insert_char(&bp->port, 0, 0, ch, flag); } - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); + spin_unlock(&bp->port.lock); + tty_flip_buffer_push(&bp->port.state->port); + spin_lock(&bp->port.lock); } -static void bflb_uart_tx_chars(struct uart_port *port) +/** + * bflb_uart_txfifo_space() - How much space is left int the TX FIFO? + * @bp: pointer to a struct bflb_uart_port + * + * Read the transmit FIFO count to find out how much space is left + * + * Returns: UART_TX_FIFO_CNT - count of space left in the TX FIFO + */ +static int bflb_uart_txfifo_space(struct bflb_uart_port *bp) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int pending, count; + return (rdl(&bp->port, UART_FIFO_CONFIG_1) + & UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; +} - if (port->x_char) { - /* Send special char - probably flow control */ - wrl(port, UART_FIFO_WDATA, port->x_char); - port->x_char = 0; - port->icount.tx++; - return; - } +/** + * bflb_uart_tx_char() - enqueue a byte to transmit onto the TX FIFO + * @bp: pointer to a struct bflb_uart_port + * @ch: character to transmit + * + * Enqueue a byte @ch onto the transmit FIFO, given a pointer @bp to the + * struct bflb_uart_port * to transmit on. + * + * Context: Any context. + */ +static void bflb_uart_tx_char(struct bflb_uart_port *bp, int ch) +{ + wrl(&bp->port, UART_FIFO_WDATA, ch); +} - pending = uart_circ_chars_pending(xmit); - if (pending > 0) { - count = (rdl(port, UART_FIFO_CONFIG_1) & - UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT; - if (count > pending) - count = pending; - if (count > 0) { - pending -= count; - while (count--) { - wrl(port, UART_FIFO_WDATA, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (pending < WAKEUP_CHARS) - uart_write_wakeup(port); - } - } +/** + * bflb_uart_tx_chars() - enqueue multiple bytes onto the TX FIFO + * @bp: pointer to a struct bflb_uart_port + * + * Transfer up to a TX FIFO size's worth of characters from the Linux serial + * transmit buffer to the BFLB UART TX FIFO. + * + * Context: Any context. Expects @bp->port.lock to be held by caller. + */ +static void bflb_uart_tx_chars(struct bflb_uart_port *bp) +{ + u8 ch; - if (pending == 0) - bflb_uart_stop_tx(port); + uart_port_tx_limited(&bp->port, ch, BFLB_UART_TX_FIFO_DEPTH, + bflb_uart_txfifo_space(bp), + bflb_uart_tx_char(bp, ch), + ({})); } static irqreturn_t bflb_uart_interrupt(int irq, void *data) { - struct uart_port *port = data; + struct bflb_uart_port *bp = data; u32 isr, val; - isr = rdl(port, UART_INT_STS); - wrl(port, UART_INT_CLEAR, isr); + isr = rdl(&bp->port, UART_INT_STS); + wrl(&bp->port, UART_INT_CLEAR, isr); - isr &= ~rdl(port, UART_INT_MASK); + isr &= ~rdl(&bp->port, UART_INT_MASK); - spin_lock(&port->lock); + spin_lock(&bp->port.lock); if (isr & UART_URX_FER_INT) { /* RX FIFO error interrupt */ - val = rdl(port, UART_FIFO_CONFIG_0); + val = rdl(&bp->port, UART_FIFO_CONFIG_0); if (val & UART_RX_FIFO_OVERFLOW) - port->icount.overrun++; + bp->port.icount.overrun++; val |= UART_RX_FIFO_CLR; - wrl(port, UART_FIFO_CONFIG_0, val); + wrl(&bp->port, UART_FIFO_CONFIG_0, val); } if (isr & (UART_URX_FIFO_INT | UART_URX_RTO_INT)) { - bflb_uart_rx_chars(port); + bflb_uart_rx_chars(bp); } if (isr & (UART_UTX_FIFO_INT | UART_UTX_END_INT)) { - bflb_uart_tx_chars(port); + bflb_uart_tx_chars(bp); } - spin_unlock(&port->lock); + spin_unlock(&bp->port.lock); return IRQ_RETVAL(isr); } @@ -335,19 +353,22 @@ static void bflb_uart_config_port(struct uart_port *port, int flags) static int bflb_uart_startup(struct uart_port *port) { unsigned long flags; - int ret; u32 val; + struct bflb_uart_port *bp = to_bflb_uart_port(port); + int ret; + + dev_dbg(port->dev, "startup %s\n", port->name); + + spin_lock_irqsave(&port->lock, flags); ret = devm_request_irq(port->dev, port->irq, bflb_uart_interrupt, - IRQF_SHARED, port->name, port); + IRQF_SHARED, port->name, bp); if (ret) { dev_err(port->dev, "fail to request serial irq %d, ret=%d\n", port->irq, ret); return ret; } - spin_lock_irqsave(&port->lock, flags); - val = rdl(port, UART_INT_MASK); val |= 0xfff; wrl(port, UART_INT_MASK, val); @@ -383,10 +404,14 @@ static int bflb_uart_startup(struct uart_port *port) static void bflb_uart_shutdown(struct uart_port *port) { unsigned long flags; + struct bflb_uart_port *bp = to_bflb_uart_port(port); + + dev_dbg(port->dev, "shutdown %s\n", port->name); spin_lock_irqsave(&port->lock, flags); /* mask all interrupts now */ wrl(port, UART_INT_MASK, UART_UTX_END_INT | UART_URX_END_INT); + devm_free_irq(port->dev, port->irq, bp); spin_unlock_irqrestore(&port->lock, flags); } @@ -589,7 +614,7 @@ static int bflb_uart_probe(struct platform_device *pdev) port->line = index; port->type = PORT_BFLB; port->iotype = UPIO_MEM; - port->fifosize = 32; + port->fifosize = BFLB_UART_TX_FIFO_DEPTH; port->ops = &bflb_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->dev = &pdev->dev; From 5f57cf035a3d8d4789185ba151187dda6d7d9962 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 21 Jan 2023 03:35:04 -0800 Subject: [PATCH 88/99] mmc: sdhci-bflb: remove unnecessary quirks Remove quirks that were added during bringup but are not required. This will enable DMA and ADMA on sdcard. --- drivers/mmc/host/sdhci-bflb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-bflb.c b/drivers/mmc/host/sdhci-bflb.c index aacf234387af88..1e590a151c04e5 100644 --- a/drivers/mmc/host/sdhci-bflb.c +++ b/drivers/mmc/host/sdhci-bflb.c @@ -55,11 +55,7 @@ static const struct sdhci_pltfm_data sdhci_bflb_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_BROKEN_ADMA | - SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_NO_HISPD_BIT, + SDHCI_QUIRK_INVERTED_WRITE_PROTECT, }; static int sdhci_bflb_probe(struct platform_device *pdev) From 8141c2e56453f6942c000e2572b4a89afcca4c6e Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sun, 15 Jan 2023 21:10:37 -0800 Subject: [PATCH 89/99] ehci: rearrange registers to match bl808 bl808 does not follow the EHCI spec, rearrange the registers to match what they actually implemented --- include/linux/usb/ehci_def.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index fbabadd3b372c2..f51fc87e0110cd 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -101,21 +101,10 @@ struct ehci_regs { /* ASYNCLISTADDR: offset 0x18 */ u32 async_next; /* address of next async queue head */ - u32 reserved1[2]; - - /* TXFILLTUNING: offset 0x24 */ - u32 txfill_tuning; /* TX FIFO Tuning register */ -#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */ - - u32 reserved2[6]; - - /* CONFIGFLAG: offset 0x40 */ - u32 configured_flag; -#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ - + u32 reserved1[1]; union { - /* PORTSC: offset 0x44 */ - u32 port_status[HCS_N_PORTS_MAX]; /* up to N_PORTS */ + /* PORTSC: offset 0x20 */ + u32 port_status[1]; /* up to N_PORTS */ /* EHCI 1.1 addendum */ #define PORTSC_SUSPEND_STS_ACK 0 #define PORTSC_SUSPEND_STS_NYET 1 @@ -163,6 +152,17 @@ struct ehci_regs { #define USBMODE_CM_IDLE (0<<0) /* idle state */ }; + /* TXFILLTUNING: offset 0x24 */ + u32 txfill_tuning; /* TX FIFO Tuning register */ +#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */ + + u32 reserved2[6]; + + /* CONFIGFLAG: offset 0x40 */ + u32 configured_flag; +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + + /* Moorestown has some non-standard registers, partially due to the fact that * its EHCI controller has both TT and LPM support. HOSTPCx are extensions to * PORTSCx From 21ef01e1b8160af70fe45c58e07eb51387aae6e5 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:04:52 -0800 Subject: [PATCH 90/99] net: ethoc: add bl808 specific ethoc bits Add MODER RGMII bit to configure MII/RGMII PHY interface. Add TX_BD_EOF End of Frame interrupt status bit. These were taken from smaeul's u-boot: https://github.com/u-boot/u-boot/commit/d19d78603e41dbc698e33d69a5189c23866d0426 --- drivers/net/ethernet/ethoc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 95cbad198b4b6e..011719c61ec644 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -70,6 +70,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); #define MODER_HUGE (1 << 14) /* huge packets enable */ #define MODER_PAD (1 << 15) /* padding enabled */ #define MODER_RSM (1 << 16) /* receive small packets */ +#define MODER_RMII (1 << 17) /* RMII mode enable */ /* interrupt source and mask registers */ #define INT_MASK_TXF (1 << 0) /* transmit frame */ @@ -138,6 +139,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); #define TX_BD_RETRY_MASK (0x00f0) #define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4) #define TX_BD_UR (1 << 8) /* transmitter underrun */ +#define TX_BD_EOF (1 << 10) /* End of Frame */ #define TX_BD_CRC (1 << 11) /* TX CRC enable */ #define TX_BD_PAD (1 << 12) /* pad enable for short packets */ #define TX_BD_WRAP (1 << 13) @@ -355,7 +357,7 @@ static int ethoc_reset(struct ethoc *dev) /* enable FCS generation and automatic padding */ mode = ethoc_read(dev, MODER); - mode |= MODER_CRC | MODER_PAD; + mode |= MODER_CRC | MODER_PAD | MODER_RMII; ethoc_write(dev, MODER, mode); /* set full-duplex mode */ @@ -907,8 +909,8 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) dest = priv->vma[entry]; memcpy_toio(dest, skb->data, skb->len); - bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); - bd.stat |= TX_BD_LEN(skb->len); + bd.stat &= ~(TX_BD_STATS | TX_BD_EOF | TX_BD_LEN_MASK); + bd.stat |= TX_BD_LEN(skb->len) | TX_BD_EOF; ethoc_write_bd(priv, entry, &bd); bd.stat |= TX_BD_READY; From 1c4745d4e385645f71768b6609b32a4d4842c8a6 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:09:52 -0800 Subject: [PATCH 91/99] net: ethoc: reverse the interrupt mask bits The bl808 EMAC INT_MASK register has reversed polarity, so flip all the bits in it everwhere it is used. --- drivers/net/ethernet/ethoc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 011719c61ec644..409ecbbbd59520 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -271,14 +271,14 @@ static inline void ethoc_write_bd(struct ethoc *dev, int index, static inline void ethoc_enable_irq(struct ethoc *dev, u32 mask) { u32 imask = ethoc_read(dev, INT_MASK); - imask |= mask; + imask &= ~mask; ethoc_write(dev, INT_MASK, imask); } static inline void ethoc_disable_irq(struct ethoc *dev, u32 mask) { u32 imask = ethoc_read(dev, INT_MASK); - imask &= ~mask; + imask |= mask; ethoc_write(dev, INT_MASK, imask); } @@ -566,7 +566,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id) */ mask = ethoc_read(priv, INT_MASK); pending = ethoc_read(priv, INT_SOURCE); - pending &= mask; + pending &= ~mask; if (unlikely(pending == 0)) return IRQ_NONE; From 7a87990017ec9e8a02d2244526877a3d3afcd42d Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Tue, 24 Jan 2023 17:12:08 -0800 Subject: [PATCH 92/99] net: ethoc: reduce RGMII interface clk to 1MHz PHY communication was not stable at 2.5MHz, so reduce down to 1MHz. --- drivers/net/ethernet/ethoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 409ecbbbd59520..49f2e71d9555ea 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1183,7 +1183,7 @@ static int ethoc_probe(struct platform_device *pdev) } } if (eth_clkfreq) { - u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1); + u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 1000000 + 1); if (!clkdiv) clkdiv = 2; From b9595ae86079168be9389006f090fd046f91111a Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:44:18 +0000 Subject: [PATCH 93/99] Add GPIO/PINCTRL and HWRNG/Crypto drivers --- include/dt-bindings/mailbox/bflb-ipc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h index 0a3c6745a673c1..9763460edbcc75 100644 --- a/include/dt-bindings/mailbox/bflb-ipc.h +++ b/include/dt-bindings/mailbox/bflb-ipc.h @@ -13,7 +13,8 @@ /* Peripheral device ID */ #define BFLB_IPC_DEVICE_SDHCI 0 #define BFLB_IPC_DEVICE_UART2 1 -#define BFLB_IPC_DEVICE_USB 2 +#define BFLB_IPC_DEVICE_USB 2 #define BFLB_IPC_DEVICE_EMAC 3 +#define BFLB_IPC_DEVICE_GPIO 4 #endif From ab66f49c1c7b0f4e86abb94a855717a800c947d8 Mon Sep 17 00:00:00 2001 From: Alexander Horner <33007665+alexhorner@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:44:18 +0000 Subject: [PATCH 94/99] Add GPIO/PINCTRL and HWRNG/Crypto drivers --- drivers/crypto/Kconfig | 11 + drivers/crypto/Makefile | 1 + drivers/crypto/bflb-seceng.c | 670 ++++++++++++++++++++++++++++++ drivers/pinctrl/Kconfig | 16 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-bflb.c | 719 +++++++++++++++++++++++++++++++++ 6 files changed, 1418 insertions(+) create mode 100644 drivers/crypto/bflb-seceng.c create mode 100644 drivers/pinctrl/pinctrl-bflb.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index dfb103f81a64b3..e8de3d60ffd863 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -13,6 +13,17 @@ if CRYPTO_HW source "drivers/crypto/allwinner/Kconfig" +config CRYPTO_DEV_BFLB_SECENG + tristate "Bouffalo Lab Secure Engine Driver" + depends on SOC_BOUFFALOLAB + select CRYPTO_RNG + help + This driver provides support for the Random Number + Generator hardware found on Bouffalo Lab BL808 SoCs. + + To compile this driver as a module, choose M here. The + module will be called bflb-seceng. If unsure, say N. + config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" depends on X86 && !UML diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index fa8bf1be1a8cde..1b5c60587c436f 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o +obj-$(CONFIG_CRYPTO_DEV_BFLB_SECENG) += bflb-seceng.o obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ diff --git a/drivers/crypto/bflb-seceng.c b/drivers/crypto/bflb-seceng.c new file mode 100644 index 00000000000000..3e450f06ddeaea --- /dev/null +++ b/drivers/crypto/bflb-seceng.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Bouffalo Lab SoC Secure Engine driver +// +// Based on qcom-rng.c +// Copyright (c) 2017-18 Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Register map +//se_sha_0_ctrl +#define REG_SECENG_SHA_0_CTRL 0 //Offset from base address +#define REG_SECENG_SHA_0_CTRL_MSG_LEN GENMASK(31, 16) +#define REG_SECENG_SHA_0_CTRL_LINK_MODE BIT(15) +#define REG_SECENG_SHA_0_CTRL_MODE_EXT GENMASK(13, 12) +#define REG_SECENG_SHA_0_CTRL_INT_MASK BIT(11) +#define REG_SECENG_SHA_0_CTRL_INT_SET_1T BIT(10) +#define REG_SECENG_SHA_0_CTRL_INT_CLR_1T BIT(9) +#define REG_SECENG_SHA_0_CTRL_INT BIT(8) +#define REG_SECENG_SHA_0_CTRL_HASH_SEL BIT(6) +#define REG_SECENG_SHA_0_CTRL_EN BIT(5) +#define REG_SECENG_SHA_0_CTRL_MODE GENMASK(4, 2) +#define REG_SECENG_SHA_0_CTRL_INT_TRIG_1T BIT(1) +#define REG_SECENG_SHA_0_CTRL_BUSY BIT(0) + +//se_sha_0_msa +#define REG_SECENG_SHA_0_MSA 4 + +//se_sha_0_status +#define REG_SECENG_SHA_0_STATUS 8 + +//se_sha_0_endian +#define REG_SECENG_SHA_0_ENDIAN 12 +#define REG_SECENG_SHA_0_ENDIAN_VAL BIT(0) + +//se_sha_0_hash_l_0 +#define REG_SECENG_SHA_0_HASH_L_0 16 + +//se_sha_0_hash_l_1 +#define REG_SECENG_SHA_0_HASH_L_1 20 + +//se_sha_0_hash_l_2 +#define REG_SECENG_SHA_0_HASH_L_2 24 + +//se_sha_0_hash_l_3 +#define REG_SECENG_SHA_0_HASH_L_3 28 + +//se_sha_0_hash_l_4 +#define REG_SECENG_SHA_0_HASH_L_4 32 + +//se_sha_0_hash_l_5 +#define REG_SECENG_SHA_0_HASH_L_5 36 + +//se_sha_0_hash_l_6 +#define REG_SECENG_SHA_0_HASH_L_6 40 + +//se_sha_0_hash_l_7 +#define REG_SECENG_SHA_0_HASH_L_7 44 + +//se_sha_0_hash_h_0 +#define REG_SECENG_SHA_0_HASH_H_0 48 + +//se_sha_0_hash_h_1 +#define REG_SECENG_SHA_0_HASH_H_1 52 + +//se_sha_0_hash_h_2 +#define REG_SECENG_SHA_0_HASH_H_2 56 + +//se_sha_0_hash_h_3 +#define REG_SECENG_SHA_0_HASH_H_3 60 + +//se_sha_0_hash_h_4 +#define REG_SECENG_SHA_0_HASH_H_4 64 + +//se_sha_0_hash_h_5 +#define REG_SECENG_SHA_0_HASH_H_5 68 + +//se_sha_0_hash_h_6 +#define REG_SECENG_SHA_0_HASH_H_6 72 + +//se_sha_0_hash_h_7 +#define REG_SECENG_SHA_0_HASH_H_7 76 + +//se_sha_0_link +#define REG_SECENG_SHA_0_LINK 80 + +//se_sha_0_ctrl_prot +#define REG_SECENG_SHA_0_CTRL_PROT 252 +#define REG_SECENG_SHA_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_SHA_0_CTRL_PROT_ID0_EN BIT(1) + +//se_aes_0_ctrl +#define REG_SECENG_AES_0_CTRL 256 +#define REG_SECENG_AES_0_CTRL_MSG_LEN GENMASK(31, 16) +#define REG_SECENG_AES_0_CTRL_LINK_MODE BIT(15) +#define REG_SECENG_AES_0_CTRL_IV_SEL BIT(14) +#define REG_SECENG_AES_0_CTRL_BLOCK_MODE GENMASK(13, 12) +#define REG_SECENG_AES_0_CTRL_INT_MASK BIT(11) +#define REG_SECENG_AES_0_CTRL_INT_SET_1T BIT(10) +#define REG_SECENG_AES_0_CTRL_INT_CLR_1T BIT(9) +#define REG_SECENG_AES_0_CTRL_INT BIT(8) +#define REG_SECENG_AES_0_CTRL_HW_KEY_EN BIT(7) +#define REG_SECENG_AES_0_CTRL_DEC_KEY_SEL BIT(6) +#define REG_SECENG_AES_0_CTRL_DEC_EN BIT(5) +#define REG_SECENG_AES_0_CTRL_MODE GENMASK(4, 3) +#define REG_SECENG_AES_0_CTRL_EN BIT(2) +#define REG_SECENG_AES_0_CTRL_TRIG_1T BIT(1) +#define REG_SECENG_AES_0_CTRL_BUSY BIT(0) + +//se_aes_0_msa +#define REG_SECENG_AES_0_MSA 260 + +//se_aes_0_mda +#define REG_SECENG_AES_0_MDA 264 + +//se_aes_0_status +#define REG_SECENG_AES_0_STATUS 268 + +//se_aes_0_iv_0 +#define REG_SECENG_AES_0_IV_0 272 + +//se_aes_0_iv_1 +#define REG_SECENG_AES_0_IV_1 276 + +//se_aes_0_iv_2 +#define REG_SECENG_AES_0_IV_2 280 + +//se_aes_0_iv_3 +#define REG_SECENG_AES_0_IV_3 284 + +//se_aes_0_key_0 +#define REG_SECENG_AES_0_KEY_0 288 + +//se_aes_0_key_1 +#define REG_SECENG_AES_0_KEY_1 292 + +//se_aes_0_key_2 +#define REG_SECENG_AES_0_KEY_2 296 + +//se_aes_0_key_3 +#define REG_SECENG_AES_0_KEY_3 300 + +//se_aes_0_key_4 +#define REG_SECENG_AES_0_KEY_4 304 + +//se_aes_0_key_5 +#define REG_SECENG_AES_0_KEY_5 308 + +//se_aes_0_key_6 +#define REG_SECENG_AES_0_KEY_6 312 + +//se_aes_0_key_7 +#define REG_SECENG_AES_0_KEY_7 316 + +//se_aes_0_key_sel +#define REG_SECENG_AES_0_KEY_SEL 320 +#define REG_SECENG_AES_0_KEY_SEL_VAL GENMASK(1, 0) + +//se_aes_1_key_sel +#define REG_SECENG_AES_1_KEY_SEL 324 +#define REG_SECENG_AES_01KEY_SEL_VAL GENMASK(1, 0) + +//se_aes_0_endian +#define REG_SECENG_AES_0_ENDIAN 328 +#define REG_SECENG_AES_0_ENDIAN_CTR_LEN GENMASK(31, 30) +#define REG_SECENG_AES_0_ENDIAN_TWK BIT(4) +#define REG_SECENG_AES_0_ENDIAN_IV BIT(3) +#define REG_SECENG_AES_0_ENDIAN_KEY BIT(2) +#define REG_SECENG_AES_0_ENDIAN_DIN BIT(1) +#define REG_SECENG_AES_0_ENDIAN_DOUT BIT(0) + +//se_aes_sboot +#define REG_SECENG_AES_SBOOT 332 +#define REG_SECENG_AES_SBOOT_UNI_LEN GENMASK(31, 16) +#define REG_SECENG_AES_SBOOT_XTS_MODE BIT(15) +#define REG_SECENG_AES_SBOOT_KEY_SEL BIT(0) + +//se_aes_0_link +#define REG_SECENG_AES_0_LINK 336 + +//se_aes_0_ctrl_prot +#define REG_SECENG_AES_0_CTRL_PROT 508 +#define REG_SECENG_AES_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_AES_0_CTRL_PROT_ID0_EN BIT(1) + +//se_trng_0_ctrl_0 +#define REG_SECENG_TRNG_0_CTRL_0 512 +#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_EN BIT(15) +#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_RESEED BIT(14) +#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_FUN_SEL BIT(13) +#define REG_SECENG_TRNG_0_CTRL_0_INT_MASK BIT(11) +#define REG_SECENG_TRNG_0_CTRL_0_INT_SET_1T BIT(10) +#define REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T BIT(9) +#define REG_SECENG_TRNG_0_CTRL_0_INT BIT(8) +#define REG_SECENG_TRNG_0_CTRL_0_HT_ERROR BIT(4) +#define REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T BIT(3) +#define REG_SECENG_TRNG_0_CTRL_0_EN BIT(2) +#define REG_SECENG_TRNG_0_CTRL_0_TRIG_1T BIT(1) +#define REG_SECENG_TRNG_0_CTRL_0_BUSY BIT(0) + +//se_trng_0_status +#define REG_SECENG_TRNG_0_STATUS 516 + +//se_trng_0_dout_0 +#define REG_SECENG_TRNG_0_DOUT_0 520 + +//se_trng_0_dout_1 +#define REG_SECENG_TRNG_0_DOUT_1 524 + +//se_trng_0_dout_2 +#define REG_SECENG_TRNG_0_DOUT_2 528 + +//se_trng_0_dout_3 +#define REG_SECENG_TRNG_0_DOUT_3 532 + +//se_trng_0_dout_4 +#define REG_SECENG_TRNG_0_DOUT_4 536 + +//se_trng_0_dout_5 +#define REG_SECENG_TRNG_0_DOUT_5 540 + +//se_trng_0_dout_6 +#define REG_SECENG_TRNG_0_DOUT_6 544 + +//se_trng_0_dout_7 +#define REG_SECENG_TRNG_0_DOUT_7 548 + +//se_trng_0_test +#define REG_SECENG_TRNG_0_TEST 552 +#define REG_SECENG_TRNG_0_TEST_HT_ALARM_N GENMASK(11, 4) +#define REG_SECENG_TRNG_0_TEST_HT_DIS BIT(3) +#define REG_SECENG_TRNG_0_TEST_CP_BYPASS BIT(2) +#define REG_SECENG_TRNG_0_TEST_CP_TEST_EN BIT(1) +#define REG_SECENG_TRNG_0_TEST_TEST_EN BIT(0) + +//se_trng_0_ctrl_1 +#define REG_SECENG_TRNG_0_CTRL_1_RESEED_N_LSB 556 + +//se_trng_0_ctrl_2 +#define REG_SECENG_TRNG_0_CTRL_2_RESEED_N_MSB 560 +#define REG_SECENG_TRNG_0_CTRL_1_RESEED_N_MSB_VALUE GENMASK(15, 0) + +//se_trng_0_ctrl_3 +#define REG_SECENG_TRNG_0_CTRL_3 564 +#define REG_SECENG_TRNG_0_CTRL_3_ROSC_EN BIT(31) +#define REG_SECENG_TRNG_0_CTRL_3_HT_OD_EN BIT(26) +#define REG_SECENG_TRNG_0_CTRL_3_HT_APT_C GENMASK(25, 16) +#define REG_SECENG_TRNG_0_CTRL_3_HT_RCT_C GENMASK(15, 8) +#define REG_SECENG_TRNG_0_CTRL_3_CP_RATIO GENMASK(7, 0) + +//se_trng_0_test_out_0 +#define REG_SECENG_TRNG_0_TEST_OUT_0 576 + +//se_trng_0_test_out_1 +#define REG_SECENG_TRNG_0_TEST_OUT_1 580 + +//se_trng_0_test_out_2 +#define REG_SECENG_TRNG_0_TEST_OUT_2 584 + +//se_trng_0_test_out_3 +#define REG_SECENG_TRNG_0_TEST_OUT_3 588 + +//se_trng_0_ctrl_prot +#define REG_SECENG_TRNG_0_CTRL_PROT 764 +#define REG_SECENG_TRNG_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_TRNG_0_CTRL_PROT_ID0_EN BIT(1) + +//se_pka_0_ctrl_0 +#define REG_SECENG_PKA_0_CTRL_0 768 +#define REG_SECENG_PKA_0_CTRL_0_STATUS GENMASK(31, 16) +#define REG_SECENG_PKA_0_CTRL_0_STATUS_CLR_1T BIT(15) +#define REG_SECENG_PKA_0_CTRL_0_RAM_CLR_MD BIT(13) +#define REG_SECENG_PKA_0_CTRL_0_ENDIAN BIT(12) +#define REG_SECENG_PKA_0_CTRL_0_INT_MASK BIT(11) +#define REG_SECENG_PKA_0_CTRL_0_INT_SET BIT(10) +#define REG_SECENG_PKA_0_CTRL_0_INT_CLR_1T BIT(9) +#define REG_SECENG_PKA_0_CTRL_0_INT BIT(8) +#define REG_SECENG_PKA_0_CTRL_0_PROT_MD GENMASK(7, 4) +#define REG_SECENG_PKA_0_CTRL_0_EN BIT(3) +#define REG_SECENG_PKA_0_CTRL_0_BUSY BIT(2) +#define REG_SECENG_PKA_0_CTRL_0_DONE_CLR_1T BIT(1) +#define REG_SECENG_PKA_0_CTRL_0_DONE BIT(0) + +//se_pka_0_seed +#define REG_SECENG_PKA_0_SEED 780 + +//se_pka_0_ctrl_1 +#define REG_SECENG_PKA_0_CTRL_1 784 +#define REG_SECENG_PKA_0_CTRL_1_HBYPASS BIT(3) +#define REG_SECENG_PKA_0_CTRL_1_HBURST GENMASK(2, 0) + +//se_pka_0_rw +#define REG_SECENG_PKA_0_RW 832 +//This is a confusing register which I have not mapped because +//"BL808 Reference Manual 1.2 EN" seems wrong + +//se_pka_0_rw_burst +#define REG_SECENG_PKA_0_RW_BURST 864 +//This is a confusing register which I have not mapped because +//"BL808 Reference Manual 1.2 EN" seems wrong + +//se_pka_0_ctrl_prot +#define REG_SECENG_PKA_0_CTRL_PROT 1020 +#define REG_SECENG_PKA_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_PKA_0_CTRL_PROT_ID0_EN BIT(1) + +//se_cdet_0_ctrl_0 +#define REG_SECENG_CDET_0_CTRL_0 1024 +#define REG_SECENG_CDET_0_CTRL_0_G_LOOP_MIN GENMASK(31, 24) +#define REG_SECENG_CDET_0_CTRL_0_G_LOOP_MAX GENMASK(23, 16) +#define REG_SECENG_CDET_0_CTRL_0_STATUS GENMASK(15, 2) +#define REG_SECENG_CDET_0_CTRL_0_ERROR BIT(1) +#define REG_SECENG_CDET_0_CTRL_0_EN BIT(0) + +//se_cdet_0_ctrl_1 +#define REG_SECENG_CDET_0_CTRL_1 1028 +#define REG_SECENG_CDET_0_CTRL_1_G_SLP_N GENMASK(23, 16) +#define REG_SECENG_CDET_0_CTRL_1_T_DLY_N GENMASK(15, 8) +#define REG_SECENG_CDET_0_CTRL_1_T_LOOP_N GENMASK(7, 0) + +//se_cdet_0_ctrl_prot +#define REG_SECENG_CDET_0_CTRL_PROT 1276 +#define REG_SECENG_CDET_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_CDET_0_CTRL_PROT_ID0_EN BIT(1) +#define REG_SECENG_CDET_0_CTRL_PROT_PROT_EN BIT(0) + +//se_gmac_0_ctrl_0 +#define REG_SECENG_GMAC_0_CTRL_0 1280 +#define REG_SECENG_GMAC_0_CTRL_0_X_ENDIAN BIT(14) +#define REG_SECENG_GMAC_0_CTRL_0_H_ENDIAN BIT(13) +#define REG_SECENG_GMAC_0_CTRL_0_T_ENDIAN BIT(12) +#define REG_SECENG_GMAC_0_CTRL_0_INT_MASK BIT(11) +#define REG_SECENG_GMAC_0_CTRL_0_INT_SET_1T BIT(10) +#define REG_SECENG_GMAC_0_CTRL_0_INT_CLR_1T BIT(9) +#define REG_SECENG_GMAC_0_CTRL_0_INT BIT(8) +#define REG_SECENG_GMAC_0_CTRL_0_EN BIT(2) +#define REG_SECENG_GMAC_0_CTRL_0_TRIG_1T BIT(1) +#define REG_SECENG_GMAC_0_CTRL_0_BUSY BIT(0) + +//se_gmac_0_lca +#define REG_SECENG_GMAC_0_LCA 1284 + +//se_gmac_0_status +#define REG_SECENG_GMAC_0_STATUS 1288 + +//se_gmac_0_ctrl_prot +#define REG_SECENG_GMAC_0_CTRL_PROT 1532 +#define REG_SECENG_GMAC_0_CTRL_PROT_ID1_EN BIT(2) +#define REG_SECENG_GMAC_0_CTRL_PROT_ID0_EN BIT(1) + +//se_ctrl_prot_rd +#define REG_SECENG_CTRL_PROT_RD 3840 +#define REG_SECENG_CTRL_PROT_RD_DBG_DIS BIT(31) +#define REG_SECENG_CTRL_PROT_RD_GMAC_ID1_EN_RD BIT(11) +#define REG_SECENG_CTRL_PROT_RD_GMAC_ID0_EN_RD BIT(10) +#define REG_SECENG_CTRL_PROT_RD_CDET_ID1_EN_RD BIT(9) +#define REG_SECENG_CTRL_PROT_RD_CDET_ID0_EN_RD BIT(8) +#define REG_SECENG_CTRL_PROT_RD_PKA_ID1_EN_RD BIT(7) +#define REG_SECENG_CTRL_PROT_RD_PKA_ID0_EN_RD BIT(6) +#define REG_SECENG_CTRL_PROT_RD_TRNG_ID1_EN_RD BIT(5) +#define REG_SECENG_CTRL_PROT_RD_TRNG_ID0_EN_RD BIT(4) +#define REG_SECENG_CTRL_PROT_RD_AES_ID1_EN_RD BIT(3) +#define REG_SECENG_CTRL_PROT_RD_AES_ID0_EN_RD BIT(2) +#define REG_SECENG_CTRL_PROT_RD_SHA_ID1_EN_RD BIT(1) +#define REG_SECENG_CTRL_PROT_RD_SHA_ID0_EN_RD BIT(0) + +struct bflb_seceng { + struct mutex lock; + struct device *dev; + void __iomem *base; + struct regmap *map; + unsigned int initialised; + + struct hwrng hwrng; +}; + +struct bflb_seceng_ctx { + struct bflb_seceng *seceng; +}; + +struct regmap_config bflb_seceng_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_FLAT, + .max_register = 512 * sizeof(u32), + .num_reg_defaults_raw = 512, + .use_relaxed_mmio = true, + .use_raw_spinlock = true, +}; + +static struct bflb_seceng *bflb_seceng_dev; + +static void bflb_seceng_trng_wait_ready(void) +{ + while (readl_relaxed(bflb_seceng_dev->base + REG_SECENG_TRNG_0_CTRL_0) & + REG_SECENG_TRNG_0_CTRL_0_BUSY) { + dev_dbg(bflb_seceng_dev->dev, "Waiting for TRNG ready"); + schedule(); + } +} + +static void bflb_seceng_trng_init(void) +{ + regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0, + REG_SECENG_TRNG_0_CTRL_0_EN | REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_EN, 1) | + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, 1)); + + bflb_seceng_trng_wait_ready(); +} + +static void bflb_seceng_trng_refresh(void) +{ + regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0, + REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, 1)); //Clear DOUT + + bflb_seceng_trng_wait_ready(); + + regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0, + REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, 0)); //Reset clear DOUT + + regmap_update_bits(bflb_seceng_dev->map, + REG_SECENG_TRNG_0_CTRL_0, REG_SECENG_TRNG_0_CTRL_0_TRIG_1T, + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_TRIG_1T, 1)); //Force TRNG refresh + + bflb_seceng_trng_wait_ready(); + + regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0, + REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, + FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, 1)); //Clear INT + + dev_dbg(bflb_seceng_dev->dev, "Refreshed TRNG"); +} + +static unsigned int bflb_seceng_trng_read_dout(struct bflb_seceng *seceng, + unsigned int doutreg) +{ + return readl_relaxed(seceng->base + REG_SECENG_TRNG_0_DOUT_0 + + (doutreg * 4)); +} + +static inline unsigned int bflb_seceng_trng_read32(void) +{ + static u8 doutreg = 8; + u32 val; + + if (doutreg >= 8) { + //If we have read all available registers (of starting anew), + //refresh them and start again + doutreg = 0; + + bflb_seceng_trng_refresh(); + } + + dev_dbg(bflb_seceng_dev->dev, "Selected TRNG DOUT register %u", doutreg); + + //Read selected register + val = bflb_seceng_trng_read_dout(bflb_seceng_dev, doutreg); + doutreg++; //Move on to next register + + dev_dbg(bflb_seceng_dev->dev, "TRNG DOUT register produced %u", val); + + return val; +} + +static inline u8 bflb_seceng_trng_read8(void) +{ + static unsigned int lastread; + static u8 shift = 4; + + if (shift == 4) { + shift = 0; + + lastread = bflb_seceng_trng_read32(); + } + + return (lastread >> (shift++ * 8)) & 0xFF; +} + +static void bflb_seceng_trng_fill_buffer(u8 *buff, unsigned long bufflen) +{ + unsigned long i; + + for (i = 0; i < bufflen; i++) + buff[i] = bflb_seceng_trng_read8(); +} + +static int bflb_seceng_trng_hwrng_read(struct hwrng *rng, void *data, + size_t max, bool wait) +{ + //Currently ignoring wait + + mutex_lock(&bflb_seceng_dev->lock); + + dev_dbg(bflb_seceng_dev->dev, "Starting TRNG hwrng read for %lu bytes...", + max); + + bflb_seceng_trng_fill_buffer(data, max); + + mutex_unlock(&bflb_seceng_dev->lock); + + //We're always going to fill the buffer, so just return what was asked for + return max; +} + +static int bflb_seceng_trng_crypto_generate(struct crypto_rng *tfm, + const u8 *src, unsigned int slen, u8 *dstn, unsigned int dlen) +{ + struct bflb_seceng_ctx *ctx = crypto_rng_ctx(tfm); + struct bflb_seceng *seceng = ctx->seceng; + + mutex_lock(&seceng->lock); + + dev_dbg(seceng->dev, + "Starting TRNG crypto buffer filling read for %u bytes...", dlen); + + bflb_seceng_trng_fill_buffer(dstn, dlen); + + mutex_unlock(&seceng->lock); + + return 0; +} + +static int bflb_seceng_trng_crypto_seed(struct crypto_rng *tfm, const u8 *seed, + unsigned int slen) +{ + return 0; +} + +static int bflb_seceng_trng_crypto_init(struct crypto_tfm *tfm) +{ + struct bflb_seceng_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->seceng = bflb_seceng_dev; + + //Skip actual initialisation of the hardware if we have already done so + if (bflb_seceng_dev->initialised) + return 0; + + bflb_seceng_trng_init(); + + dev_dbg(bflb_seceng_dev->dev, "Initialised TRNG via crypto"); + + bflb_seceng_dev->initialised = 1; + return 0; +} + +static int bflb_seceng_trng_hwrng_init(struct hwrng *rng) +{ + if (bflb_seceng_dev->initialised) + return 0; + + bflb_seceng_trng_init(); + + dev_dbg(bflb_seceng_dev->dev, "Initialised TRNG via hwrng"); + + bflb_seceng_dev->initialised = 1; + return 0; +} + +static struct rng_alg bflb_seceng_trng_alg = { + .generate = bflb_seceng_trng_crypto_generate, + .seed = bflb_seceng_trng_crypto_seed, + .seedsize = 0, + .base = { + .cra_name = "stdrng", + .cra_driver_name = "bflb-seceng", + .cra_flags = CRYPTO_ALG_TYPE_RNG, + .cra_priority = 300, + .cra_ctxsize = sizeof(struct bflb_seceng_ctx), + .cra_module = THIS_MODULE, + .cra_init = bflb_seceng_trng_crypto_init, + } +}; + +static struct hwrng bflb_hwrng = { + .name = "bflb-seceng", + .init = bflb_seceng_trng_hwrng_init, + .read = bflb_seceng_trng_hwrng_read, +}; + +static int bflb_seceng_probe(struct platform_device *pdev) +{ + struct bflb_seceng *seceng; + int ret; + + seceng = devm_kzalloc(&pdev->dev, sizeof(*seceng), GFP_KERNEL); + + if (!seceng) + return -ENOMEM; + + seceng->dev = &pdev->dev; + + platform_set_drvdata(pdev, seceng); + mutex_init(&seceng->lock); + + seceng->base = devm_platform_ioremap_resource(pdev, 0); + + if (IS_ERR(seceng->base)) + return PTR_ERR(seceng->base); + + seceng->map = devm_regmap_init_mmio(&pdev->dev, seceng->base, + &bflb_seceng_regmap_config); + + if (IS_ERR(seceng->map)) + return dev_err_probe(&pdev->dev, PTR_ERR(seceng->map), + "Failed to create regmap\n"); + + bflb_seceng_dev = seceng; //Assign driver static + + ret = crypto_register_rng(&bflb_seceng_trng_alg); + + if (ret) + dev_err_probe(&pdev->dev, ret, + "Failed to register as a crypto random number generator\n"); + + seceng->hwrng = bflb_hwrng; + + ret = hwrng_register(&seceng->hwrng); + + if (ret) + dev_err_probe(&pdev->dev, ret, + "Failed to register as a hardware random number generator\n"); + + dev_info(&pdev->dev, "Bouffalo Lab Secure Engine"); + + return ret; +} + +static int bflb_seceng_remove(struct platform_device *pdev) +{ + hwrng_unregister(&bflb_seceng_dev->hwrng); + crypto_unregister_rng(&bflb_seceng_trng_alg); + + bflb_seceng_dev = NULL; + + return 0; +} + +static const struct of_device_id __maybe_unused bflb_seceng_of_match[] = { + { .compatible = "bflb,seceng", .data = (const void *)0, }, + {} +}; +MODULE_DEVICE_TABLE(of, bflb_seceng_of_match); + +static struct platform_driver bflb_seceng_driver = { + .probe = bflb_seceng_probe, + .remove = bflb_seceng_remove, + .driver = { + .name = "bflb-seceng", + .of_match_table = bflb_seceng_of_match, + .suppress_bind_attrs = true, + } +}; +module_platform_driver(bflb_seceng_driver); + +MODULE_DESCRIPTION("Bouffalo BL808 Secure Engine driver"); +MODULE_AUTHOR("Alexander Horner "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7d5f5458c72ed2..9120cd4b761f6a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -127,6 +127,22 @@ config PINCTRL_AXP209 selected. Say Y to enable pinctrl and GPIO support for the AXP209 PMIC. +config PINCTRL_BFLB_GPIO + tristate "Bouffalo Lab SoC GPIO pin controller driver" + depends on SOC_BOUFFALOLAB + select PINMUX + select GPIOLIB + select GPIOLIB_IRQCHIP + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select OF_GPIO + help + This is the driver for the GPIO controller found on Bouffalo Lab RISC-V SoCs. + + This driver can also be built as a module. If so, the module + will be called pinctrl-bflb-gpio. + config PINCTRL_BM1880 bool "Bitmain BM1880 Pinctrl driver" depends on OF && (ARCH_BITMAIN || COMPILE_TEST) diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d5939840bb2ad5..9f7c89ed4bb40f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o +obj-$(CONFIG_PINCTRL_BFLB_GPIO) += pinctrl-bflb.o obj-$(CONFIG_PINCTRL_BM1880) += pinctrl-bm1880.o obj-$(CONFIG_PINCTRL_CY8C95X0) += pinctrl-cy8c95x0.o obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o diff --git a/drivers/pinctrl/pinctrl-bflb.c b/drivers/pinctrl/pinctrl-bflb.c new file mode 100644 index 00000000000000..4223fcc18ed591 --- /dev/null +++ b/drivers/pinctrl/pinctrl-bflb.c @@ -0,0 +1,719 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Bouffalo Lab SoC pinctrl+GPIO+external IRQ driver + * + * Based on: pinctrl-apple-gpio.c + * Copyright (C) The Asahi Linux Contributors + * Copyright (C) 2020 Corellium LLC + * + * Based on: pinctrl-pistachio.c + * Copyright (C) 2014 Imagination Technologies Ltd. + * Copyright (C) 2014 Google, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pinctrl-utils.h" +#include "core.h" +#include "pinmux.h" + +struct bflb_gpio_pinctrl { + struct device *dev; + struct pinctrl_dev *pctldev; + + void __iomem *base; + struct regmap *map; + + struct pinctrl_desc pinctrl_desc; + struct gpio_chip gpio_chip; + + void *irqsunmasked; + u8 irqgrps[]; +}; + +//Register indexing +#define REG_GPIO(x) (4 * (x)) + +//Register map +#define REG_GPIOx_MODE GENMASK(31, 30) +#define REG_GPIOx_I BIT(28) +#define REG_GPIOx_CLR BIT(26) +#define REG_GPIOx_SET BIT(25) +#define REG_GPIOx_O BIT(24) +#define REG_GPIOx_INT_MASK BIT(22) +#define REG_GPIOx_INT_STAT BIT(21) +#define REG_GPIOx_INT_CLR BIT(20) +#define REG_GPIOx_INT_MODE_SET GENMASK(29, 16) +#define REG_GPIOx_FUNC_SEL GENMASK(12, 8) +#define REG_GPIOx_OE BIT(6) +#define REG_GPIOx_PD BIT(5) +#define REG_GPIOx_PU BIT(4) +#define REG_GPIOx_DRV GENMASK(3, 2) +#define REG_GPIOx_SMT BIT(1) +#define REG_GPIOx_IE BIT(0) + +//Interrupt trigger modes +#define BFLB_IRQ_MODE_SYNC_EDGE_FALLING 0 +#define BFLB_IRQ_MODE_SYNC_EDGE_RISING 1 +#define BFLB_IRQ_MODE_SYNC_LEVEL_LOW 2 +#define BFLB_IRQ_MODE_SYNC_LEVEL_HIGH 3 +#define BFLB_IRQ_MODE_SYNC_EDGE_BOTH 4 + +#define BFLB_IRQ_MODE_ASYNC_EDGE_FALLING 8 +#define BFLB_IRQ_MODE_ASYNC_EDGE_RISING 9 +#define BFLB_IRQ_MODE_ASYNC_LEVEL_LOW 10 +#define BFLB_IRQ_MODE_ASYNC_LEVEL_HIGH 11 + +static const char * const pinmux_functions[] = { + //AH: As taken from smaeul's pinctrl-bflb.c for U-Boot + [0] = "sdh", + [1] = "spi0", + [2] = "flash", + [3] = "i2s", + [4] = "pdm", + [5] = "i2c0", + [6] = "i2c1", + [7] = "uart", + [8] = "emac", + [9] = "cam", + [10] = "analog", + [11] = "gpio", + [16] = "pwm0", + [17] = "pwm1", + [18] = "spi1", // mm_spi + [19] = "i2c2", // mm_i2c0 + [20] = "i2c3", // mm_i2c1 + [21] = "mm_uart", + [22] = "dbi_b", + [23] = "dbi_c", + [24] = "dpi", + [25] = "jtag_lp", + [26] = "jtag_m0", + [27] = "jtag_d0", + [31] = "clock", +}; + +struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_FLAT, + .max_register = 512 * sizeof(u32), + .num_reg_defaults_raw = 512, + .use_relaxed_mmio = true, + .use_raw_spinlock = true, +}; + +//AH: Set raw gpio config register bits based on mask +static void bflb_gpio_set_reg(struct bflb_gpio_pinctrl *pctl, unsigned int pin, + u32 mask, u32 value) +{ + regmap_update_bits(pctl->map, REG_GPIO(pin), mask, value); +} + +//AH: Get raw gpio config register bits +static u32 bflb_gpio_get_reg(struct bflb_gpio_pinctrl *pctl, unsigned int pin) +{ + int ret; + u32 val; + + ret = regmap_read(pctl->map, REG_GPIO(pin), &val); + + if (ret) + return 0; + + return val; +} + +/* Pin controller functions */ + +static const struct pinctrl_ops bflb_gpio_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +/* Pin multiplexer functions */ + +//AH: Configure gpio modes and features +static int bflb_gpio_pinmux_set(struct pinctrl_dev *pctldev, unsigned int func, + unsigned int group) +{ + struct bflb_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + + bflb_gpio_set_reg(pctl, group, REG_GPIOx_FUNC_SEL, + FIELD_PREP(REG_GPIOx_FUNC_SEL, func)); + + dev_dbg(pctl->dev, "Pin %u set to function %u", group, func); + + return 0; +} + +static const struct pinmux_ops bflb_gpio_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = bflb_gpio_pinmux_set, + .strict = true, +}; + +/* GPIO chip functions */ + +//AH: Get the current gpio direction +static int bflb_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + unsigned int reg = bflb_gpio_get_reg(pctl, offset); + + if (FIELD_GET(REG_GPIOx_OE, reg) == 1 && + FIELD_GET(REG_GPIOx_IE, reg) == 0) { + return GPIO_LINE_DIRECTION_OUT; + } else if (FIELD_GET(REG_GPIOx_IE, reg) == 1 && + FIELD_GET(REG_GPIOx_OE, reg) == 0) { + return GPIO_LINE_DIRECTION_IN; + } + + return -EIO; +} + +//AH: Get the incoming input or outgoing output value for the specified GPIO +static int bflb_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + unsigned int reg = bflb_gpio_get_reg(pctl, offset); + + if (FIELD_GET(REG_GPIOx_OE, reg) == 1 && + FIELD_GET(REG_GPIOx_IE, reg) == 0) { + reg = readl_relaxed(pctl->base + REG_GPIO(offset)); + return !!(reg & REG_GPIOx_O); + } else if (FIELD_GET(REG_GPIOx_IE, reg) == 1 && + FIELD_GET(REG_GPIOx_OE, reg) == 0) { + reg = readl_relaxed(pctl->base + REG_GPIO(offset)); + return !!(reg & REG_GPIOx_I); + } + + return -EIO; +} + +//AH: Set the specified GPIO's output state +static void bflb_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_O, value ? + FIELD_PREP(REG_GPIOx_O, 1) : 0); + + dev_dbg(pctl->dev, "Pin %u set to value %u", offset, value); +} + +//AH: Set the specified gpio direction to input +static int bflb_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE | REG_GPIOx_IE | REG_GPIOx_SMT, + FIELD_PREP(REG_GPIOx_OE, 0) | FIELD_PREP(REG_GPIOx_IE, 1) | + FIELD_PREP(REG_GPIOx_SMT, 1)); + + dev_dbg(pctl->dev, "Pin %u set to direction input", offset); + + return 0; +} + +//AH: Set the specified gpio direction to output +static int bflb_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU | REG_GPIOx_OE | + REG_GPIOx_IE | REG_GPIOx_SMT | REG_GPIOx_MODE, + FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0) | + FIELD_PREP(REG_GPIOx_OE, 1) | FIELD_PREP(REG_GPIOx_IE, 0) | + FIELD_PREP(REG_GPIOx_SMT, 1) | FIELD_PREP(REG_GPIOx_MODE, 0)); + + dev_dbg(pctl->dev, "Pin %u set to direction output", offset); + + bflb_gpio_set(chip, offset, value); //Set the initially passed value + + return 0; +} + +//AH: Configure pin electrical characteristics +static int bflb_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + enum pin_config_param param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU, + FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0)); + break; + + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (arg) { + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU, + FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0)); + } + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg) { + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU, + FIELD_PREP(REG_GPIOx_PD, 1) | FIELD_PREP(REG_GPIOx_PU, 0)); + } + break; + + case PIN_CONFIG_BIAS_PULL_UP: + if (arg) { + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU, + FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 1)); + } + break; + + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU | + REG_GPIOx_IE | REG_GPIOx_OE, FIELD_PREP(REG_GPIOx_PD, 0) | + FIELD_PREP(REG_GPIOx_PU, 0) | FIELD_PREP(REG_GPIOx_IE, 0) | + FIELD_PREP(REG_GPIOx_OE, 0)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_IE, + FIELD_PREP(REG_GPIOx_IE, !!arg)); + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_SMT, + FIELD_PREP(REG_GPIOx_SMT, !!arg)); + break; + + case PIN_CONFIG_OUTPUT: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE | REG_GPIOx_O, + FIELD_PREP(REG_GPIOx_OE, 1) | FIELD_PREP(REG_GPIOx_O, !!arg)); + break; + + case PIN_CONFIG_OUTPUT_ENABLE: + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE, + FIELD_PREP(REG_GPIOx_OE, 1)); + break; + + default: return -ENOTSUPP; + } + + dev_dbg(pctl->dev, "Pin %u config set to %lu (param %u, arg %u)", offset, + config, param, arg); + + return 0; +} + +/* IRQ chip functions */ + +//AH: Clear the interrupt for the specified GPIO +static void bflb_gpio_irq_ack(struct irq_data *data) +{ + struct bflb_gpio_pinctrl *pctl = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR, + FIELD_PREP(REG_GPIOx_INT_CLR, 1)); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR, + FIELD_PREP(REG_GPIOx_INT_CLR, 0)); + + dev_dbg(pctl->dev, "Pin %lu IRQ ACK", data->hwirq); +} + +//AH: Find the correct value for the type of interrupts we want to receive +//for a GPIO +static unsigned int bflb_gpio_irq_type(unsigned int type) +{ + unsigned int selected; + + switch (type & IRQ_TYPE_SENSE_MASK) { + + case IRQ_TYPE_EDGE_RISING: + selected = BFLB_IRQ_MODE_SYNC_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + selected = BFLB_IRQ_MODE_SYNC_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_BOTH: + selected = BFLB_IRQ_MODE_SYNC_EDGE_BOTH; + break; + + case IRQ_TYPE_LEVEL_HIGH: + selected = BFLB_IRQ_MODE_SYNC_LEVEL_HIGH; + break; + + case IRQ_TYPE_LEVEL_LOW: + selected = BFLB_IRQ_MODE_SYNC_LEVEL_LOW; + break; + + //No "off" available on BL808, set to default IRQ_TYPE_EDGE_FALLING and + //then we'll need to mask + default: + selected = BFLB_IRQ_MODE_SYNC_EDGE_FALLING; + break; + } + + return selected; +} + +//AH: Disable the specified GPIO's interrupt +static void bflb_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(gc); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MASK, + FIELD_PREP(REG_GPIOx_INT_MASK, 1)); + + clear_bit(data->hwirq, pctl->irqsunmasked); + gpiochip_disable_irq(gc, data->hwirq); + + dev_dbg(pctl->dev, "Pin %lu IRQ Mask", data->hwirq); +} + +//AH: Enable the specified GPIO's interrupt +static void bflb_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(gc); + unsigned int irqtype = bflb_gpio_irq_type(irqd_get_trigger_type(data)); + + gpiochip_enable_irq(gc, data->hwirq); + set_bit(data->hwirq, pctl->irqsunmasked); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MASK | + REG_GPIOx_INT_MODE_SET, FIELD_PREP(REG_GPIOx_INT_MASK, 0) | + FIELD_PREP(REG_GPIOx_INT_MODE_SET, irqtype)); + + dev_dbg(pctl->dev, "Pin %lu IRQ Unmask", data->hwirq); +} + +//AH: Initialise the specified GPIO's interrupt +static unsigned int bflb_gpio_irq_startup(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR, + FIELD_PREP(REG_GPIOx_INT_CLR, 1)); + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR, + FIELD_PREP(REG_GPIOx_INT_CLR, 0)); + + bflb_gpio_irq_unmask(data); + + dev_dbg(pctl->dev, "Pin %lu IRQ Started", data->hwirq); + + return 0; +} + +//AH: Set the specified GPIO's interrupt mode +static int bflb_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct bflb_gpio_pinctrl *pctl = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + + unsigned int irqtype = bflb_gpio_irq_type(type); + + if (irqtype == 0) + return -EINVAL; + + bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MODE_SET, + FIELD_PREP(REG_GPIOx_INT_MODE_SET, irqtype)); + + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(data, handle_level_irq); + else + irq_set_handler_locked(data, handle_edge_irq); + + dev_dbg(pctl->dev, "Pin %lu IRQ type set to %u", data->hwirq, irqtype); + + return 0; +} + +//AH: Handle GPIO interrupts on this controller +static void bflb_gpio_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + u8 *grpp = irq_desc_get_handler_data(desc); + struct bflb_gpio_pinctrl *pctl; + unsigned int pinh; + unsigned long reg; + struct gpio_chip *gc; + + pctl = container_of(grpp - *grpp, typeof(*pctl), irqgrps[0]); + gc = &pctl->gpio_chip; + + chained_irq_enter(chip, desc); + + //We must go through each individual GPIO register to read its interrupt + //status. There is no gpio_cfg128+ helper register for interrupts + //(looking at BL808 RM) + for (pinh = 0; pinh < gc->ngpio; pinh += 1) { + if (test_bit(pinh, pctl->irqsunmasked)) { + dev_dbg(pctl->dev, "Reading IRQ status of pin %u", pinh); + + reg = readl_relaxed(pctl->base + REG_GPIO(pinh)); + + if (reg & REG_GPIOx_INT_STAT) { + generic_handle_domain_irq(gc->irq.domain, pinh); + dev_dbg(pctl->dev, "Pin %u IRQ Fire", pinh); + } + } else { + dev_dbg(pctl->dev, "Ignoring IRQ status of masked pin %u", pinh); + } + } + + chained_irq_exit(chip, desc); +} + +static const struct irq_chip bflb_gpio_irqchip = { + .name = "bflb-gpio", + .irq_startup = bflb_gpio_irq_startup, + .irq_ack = bflb_gpio_irq_ack, + .irq_mask = bflb_gpio_irq_mask, + .irq_unmask = bflb_gpio_irq_unmask, + .irq_set_type = bflb_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int bflb_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip); + + ret = pinctrl_gpio_request(chip->base + offset); + + if (ret) + return ret; + + bflb_gpio_set_reg(pctl, offset, REG_GPIOx_FUNC_SEL, + FIELD_PREP(REG_GPIOx_FUNC_SEL, 11/*SWGPIO*/)); + + dev_dbg(pctl->dev, "Pin %u set to function GPIO as part of request", + offset); + + return 0; +} + +/* Probe & register */ + +static int bflb_gpio_register(struct bflb_gpio_pinctrl *pctl) +{ + struct gpio_irq_chip *girq = &pctl->gpio_chip.irq; + void **irq_data = NULL; + int ret; + + pctl->gpio_chip.label = dev_name(pctl->dev); + pctl->gpio_chip.request = bflb_gpio_request; + pctl->gpio_chip.free = gpiochip_generic_free; + pctl->gpio_chip.get_direction = bflb_gpio_get_direction; + pctl->gpio_chip.direction_input = bflb_gpio_direction_input; + pctl->gpio_chip.direction_output = bflb_gpio_direction_output; + pctl->gpio_chip.get = bflb_gpio_get; + pctl->gpio_chip.set = bflb_gpio_set; + pctl->gpio_chip.set_config = bflb_gpio_set_config; + pctl->gpio_chip.base = -1; + pctl->gpio_chip.ngpio = pctl->pinctrl_desc.npins; + pctl->gpio_chip.parent = pctl->dev; + + if (girq->num_parents) { + int i; + + gpio_irq_chip_set_chip(girq, &bflb_gpio_irqchip); + + girq->parent_handler = bflb_gpio_irq_handler; + + girq->parents = kmalloc_array(girq->num_parents, sizeof(*girq->parents), + GFP_KERNEL); + irq_data = kmalloc_array(girq->num_parents, sizeof(*irq_data), + GFP_KERNEL); + + if (!girq->parents || !irq_data) { + ret = -ENOMEM; + goto out_free_irq_data; + } + + for (i = 0; i < girq->num_parents; i++) { + ret = platform_get_irq(to_platform_device(pctl->dev), i); + + if (ret < 0) + goto out_free_irq_data; + + girq->parents[i] = ret; + pctl->irqgrps[i] = i; + irq_data[i] = &pctl->irqgrps[i]; + } + + girq->parent_handler_data_array = irq_data; + girq->per_parent_data = true; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + } + + ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl); + +out_free_irq_data: + kfree(girq->parents); + kfree(irq_data); + + return ret; +} + +static int bflb_gpio_pinctrl_probe(struct platform_device *pdev) +{ + struct bflb_gpio_pinctrl *pctl; + struct pinctrl_pin_desc *pins; + + unsigned int npins; + const char **pin_names; + unsigned int *pin_nums; + unsigned int i, nirqs = 0; + int res; + + if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) { + res = platform_irq_count(pdev); + if (res > 0) + nirqs = res; + } + + pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); + + if (!pctl) + return -ENOMEM; + + pctl->dev = &pdev->dev; + pctl->gpio_chip.irq.num_parents = nirqs; + + dev_set_drvdata(&pdev->dev, pctl); + + if (of_property_read_u32(pdev->dev.of_node, "bflb,npins", &npins)) + return dev_err_probe(&pdev->dev, -EINVAL, + "bflb,npins property not found\n"); + + pctl->irqsunmasked = devm_bitmap_zalloc(&pdev->dev, npins, GFP_KERNEL); + + pins = devm_kmalloc_array(&pdev->dev, npins, sizeof(pins[0]), GFP_KERNEL); + pin_names = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_names[0]), + GFP_KERNEL); + pin_nums = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_nums[0]), + GFP_KERNEL); + + if (!pins || !pin_names || !pin_nums) + return -ENOMEM; + + pctl->base = devm_platform_ioremap_resource(pdev, 0); + + if (IS_ERR(pctl->base)) + return PTR_ERR(pctl->base); + + pctl->map = devm_regmap_init_mmio(&pdev->dev, pctl->base, ®map_config); + + if (IS_ERR(pctl->map)) + return dev_err_probe(&pdev->dev, PTR_ERR(pctl->map), + "Failed to create regmap\n"); + + for (i = 0; i < npins; i++) { + pins[i].number = i; + pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "GPIO%u", i); + pins[i].drv_data = pctl; + pin_names[i] = pins[i].name; + pin_nums[i] = i; + } + + pctl->pinctrl_desc.name = dev_name(pctl->dev); + pctl->pinctrl_desc.pins = pins; + pctl->pinctrl_desc.npins = npins; + pctl->pinctrl_desc.pctlops = &bflb_gpio_pinctrl_ops; + pctl->pinctrl_desc.pmxops = &bflb_gpio_pinmux_ops; + + pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc, + pctl); + + if (IS_ERR(pctl->pctldev)) + return dev_err_probe(&pdev->dev, PTR_ERR(pctl->pctldev), + "Failed to register pinctrl device.\n"); + + for (i = 0; i < npins; i++) { + res = pinctrl_generic_add_group(pctl->pctldev, + pins[i].name, pin_nums + i, 1, pctl); + + dev_dbg(&pdev->dev, "Registered pin %s with numeric %u", + pins[i].name, i); + + if (res < 0) + return dev_err_probe(pctl->dev, res, "Failed to register group"); + } + + for (i = 0; i < ARRAY_SIZE(pinmux_functions); ++i) { + if (pinmux_functions[i]) { + res = pinmux_generic_add_function(pctl->pctldev, + pinmux_functions[i], pin_names, npins, pctl); + + dev_dbg(&pdev->dev, "Registered function %s with numeric %u", + pinmux_functions[i], i); + + if (res < 0) + return dev_err_probe(pctl->dev, res, + "Failed to register function."); + } + } + + dev_info(&pdev->dev, "Bouffalo Lab pinctrl+GPIO(+interrupt) controller - " + "Registered %lu function(s) for %u pin(s)", + + ARRAY_SIZE(pinmux_functions), npins); + + return bflb_gpio_register(pctl); +} + +static const struct of_device_id bflb_gpio_pinctrl_of_match[] = { + { .compatible = "bflb,pinctrl", }, + { } +}; + +MODULE_DEVICE_TABLE(of, bflb_gpio_pinctrl_of_match); + +static struct platform_driver bflb_gpio_pinctrl_driver = { + .driver = { + .name = "bflb-gpio-pinctrl", + .of_match_table = bflb_gpio_pinctrl_of_match, + .suppress_bind_attrs = true, + }, + .probe = bflb_gpio_pinctrl_probe, +}; + +module_platform_driver(bflb_gpio_pinctrl_driver); + +MODULE_DESCRIPTION("Bouffalo BL808 pinctrl/GPIO driver"); +MODULE_AUTHOR("Alexander Horner "); +MODULE_LICENSE("GPL v2"); From 43d37df6df601c11504fe9cb787df94b459139bf Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:32:29 +0800 Subject: [PATCH 95/99] Update DT for mailbox * Change cells to 3 * remove unused mailboxes for SDHCI and UART --- arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 4 ++++ arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 4 +--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index f1db126d88e76f..f1fa82ac772b1d 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -58,3 +58,7 @@ &enet0 { status = "okay"; }; + +&rproc { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 5307508e7a9462..8b6f54d96c588b 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -63,3 +63,7 @@ &enet0 { status = "okay"; }; + +&rproc { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index 7cd033b6a1cf36..f17059bfa4371a 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -81,7 +81,6 @@ interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2 IRQ_TYPE_EDGE_RISING>; - mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2>; clocks = <&xtal>; status = "disabled"; }; @@ -92,7 +91,6 @@ interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI IRQ_TYPE_EDGE_RISING>; - mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; clocks = <&sdh>; status = "disabled"; }; @@ -126,7 +124,7 @@ interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; interrupt-controller; #interrupt-cells = <3>; - #mbox-cells = <2>; + #mbox-cells = <3>; status = "disabled"; }; From bfbf4abfe734f6c97245ea69a7686a73a61ae0c9 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:35:02 +0800 Subject: [PATCH 96/99] Add BL808 Remoteproc Driver * Only supports attaching to M0 core atm. --- drivers/mailbox/bflb-ipc.c | 16 +- drivers/remoteproc/Kconfig | 9 + drivers/remoteproc/Makefile | 2 + drivers/remoteproc/bl808_remoteproc.c | 495 ++++++++++++++++++++++++++ 4 files changed, 519 insertions(+), 3 deletions(-) create mode 100644 drivers/remoteproc/bl808_remoteproc.c diff --git a/drivers/mailbox/bflb-ipc.c b/drivers/mailbox/bflb-ipc.c index 5dee44dc337d58..7b25110c577461 100644 --- a/drivers/mailbox/bflb-ipc.c +++ b/drivers/mailbox/bflb-ipc.c @@ -57,6 +57,7 @@ struct bflb_ipc { struct mbox_controller mboxctlr; int num_chans; int irq; + spinlock_t tx_lock }; static inline struct bflb_ipc *to_bflb_ipc(struct mbox_controller *mboxctlr) @@ -168,11 +169,11 @@ static void bflb_mbox_tx_irq_fn(u8 from_cpu, struct bflb_ipc *ipc) chan = bflb_mbox_find_chan(ipc, &bflbchan); if (IS_ERR(chan)) { - dev_err(ipc->dev, "no channel for EOI signal cpu_id: %d service: %d op: %d Param: %d $$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); + dev_err(ipc->dev, "no channel for EOI signal cpu_id: %d service: %d op: %d Param: %d", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); return; } - dev_dbg(ipc->dev, "Got MBOX EOI Signal cpu: %d service %d op %d Param: %d $$$$$$$$$$$$$$$$$$$$", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); + dev_dbg(ipc->dev, "Got MBOX EOI Signal cpu: %d service %d op %d Param: %d", bflbchan.cpu_id, bflbchan.service_id, bflbchan.op_id, param); /* clear the IPC_REG_ILSLR and IPC_REG_ILSHR */ writel(0, ipc->base[2] + IPC_REG_ILSLR); @@ -300,7 +301,7 @@ static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data) #endif dev_dbg(ipc->dev, "%s %d: cpu: %d singal: %d op: %d (0x%x) param: %d", __func__, msg->id, mchan->cpu_id, mchan->service_id, mchan->op_id, tmpVal, msg->param); - + spin_lock(&ipc->tx_lock); // /* write our signal number to high register */ writel(tmpVal, ipc->base[2] + IPC_REG_ILSHR); // /* write our data to low register */ @@ -308,6 +309,7 @@ static int bflb_ipc_mbox_send_data(struct mbox_chan *chan, void *data) /* and now kick the remote processor */ writel((1 << BFLB_IPC_DEVICE_MBOX_TX), ipc->base[2] + IPC_REG_ISWR); + spin_unlock(&ipc->tx_lock); dev_dbg(ipc->dev, "%s %d: done param: %d", __func__, msg->id, msg->param); return 0; } @@ -426,6 +428,8 @@ static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, // mboxctlr->txdone_poll = false; + spin_lock(&ipc->tx_lock); + /* clear the IPC_REG_ILSLR and IPC_REG_ILSHR */ writel(0, ipc->base[2] + IPC_REG_ILSLR); @@ -435,6 +439,9 @@ static int bflb_ipc_setup_mbox(struct bflb_ipc *ipc, writel(BIT(BFLB_IPC_DEVICE_MBOX_TX), ipc->base[1] + IPC_REG_IUSR); writel(BIT(BFLB_IPC_DEVICE_MBOX_RX), ipc->base[1] + IPC_REG_IUSR); + spin_unlock(&ipc->tx_lock); + + return devm_mbox_controller_register(dev, mboxctlr); } @@ -480,6 +487,9 @@ static int bflb_ipc_probe(struct platform_device *pdev) if (ret) goto err_mbox; + spin_lock_init(&ipc->tx_lock); + + ret = devm_request_irq(&pdev->dev, ipc->irq, bflb_ipc_irq_fn, IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND | IRQF_NO_THREAD, name, ipc); diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index a850e9f486dd63..330936417029ed 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -161,6 +161,15 @@ config PRU_REMOTEPROC processors on various TI SoCs. It's safe to say N here if you're not interested in the PRU or if you are unsure. +config BFLB_REMOTEPROC + tristate "BL808 remoteproc support" + select MAILBOX + help + Support for Bouffalo Labs BL808 remote processors M0/LP + subsystem via the remote processor framework. + + Say Y or M here to enable + config QCOM_PIL_INFO tristate diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 91314a9b43cefc..6f76dac72eb9cb 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -39,3 +39,5 @@ obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o obj-$(CONFIG_XLNX_R5_REMOTEPROC) += xlnx_r5_remoteproc.o +obj-$(CONFIG_BFLB_REMOTEPROC) += bl808_remoteproc.o + diff --git a/drivers/remoteproc/bl808_remoteproc.c b/drivers/remoteproc/bl808_remoteproc.c new file mode 100644 index 00000000000000..4670b5e1316b06 --- /dev/null +++ b/drivers/remoteproc/bl808_remoteproc.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Remote processor machine-specific module for bflb + * + * Copyright (C) 2023 Justin Hammond + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "remoteproc_internal.h" + +/** + * struct bflb_mbox - bflb mailbox instance state + * @name: the name of the mailbox + * @client: the mailbox client + * @chan: the mailbox channel + * @vq_work: the workqueue for the virtqueue + * @vq_id: the virtqueue id + */ + +struct bflb_mbox { + unsigned char name[10]; + struct mbox_client client; + struct mbox_chan *chan; + struct work_struct vq_work; + int vq_id; +}; + + +/** + * struct bflb_rproc - bflb remote processor instance state + * @rproc: rproc handle + * @mbox: the mailbox channel + * @client: the mailbox client + */ +struct bflb_rproc { + struct rproc *rproc; + struct bflb_mbox mbox_rx; + struct bflb_mbox mbox_tx; + struct workqueue_struct *workqueue; +}; + +/* We have to fundge the resource table for the M0 + * as its already running firmware by the time Linux Loads + * and its not a ELF image, so these setup the Virtqueue, + * and RPMSG structures to communicate with it + */ + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ + +#define FW_RSC_U32_ADDR_ANY 0xFFFFFFFFUL + +#define RPMSG_VDEV_DFEATURES (1 << VIRTIO_RPMSG_F_NS) + +/* VirtIO rpmsg device id */ +#define VIRTIO_ID_RPMSG_ 7 + +/* Resource table entries */ +#define NUM_VRINGS 0x02 +#define VRING_ALIGN 0x1000 +#define RING_TX FW_RSC_U32_ADDR_ANY +#define RING_RX FW_RSC_U32_ADDR_ANY +/* VRING_SIZE is the number of VRINGS per TX/RX ring, so + * actual number is double this. Size of the space needed + * is VRING_SIZE * 2 * MAX_RPMSG_BUF_SIZE + */ +#define VRING_SIZE 8 +#define NUM_TABLE_ENTRIES 1 +#define NO_RESOURCE_ENTRIES 1 + +/* this is the structure of the Resource Table normally + * loaded from a ELF header. + * its setup for just 1 VDEV entry, which is the RPMSG + * structure. We manually setup the vring's and vbuffers + * in our prepre op below. + */ +struct remote_resource_table { + u32 version; + u32 num; + u32 reserved[2]; + u32 offset[NO_RESOURCE_ENTRIES]; + u32 type; /* the vdev type that follows */ + struct fw_rsc_vdev rpmsg_vdev; + struct fw_rsc_vdev_vring rpmsg_vring0; + struct fw_rsc_vdev_vring rpmsg_vring1; +} __packed; + +/* Setup one RPMSG VDEV and two VRINGs */ +struct remote_resource_table resources = { + /* Version */ + .version = 1, + + /* NUmber of table entries */ + .num = NUM_TABLE_ENTRIES, + + /* reserved fields */ + .reserved = {0, 0,}, + + /* Offsets of rsc entries */ + .offset[0] = offsetof(struct remote_resource_table, type), + + .type = RSC_VDEV, + /* Virtio device entry */ + { + VIRTIO_ID_RPMSG_, 0, RPMSG_VDEV_DFEATURES, 0, 0, 0, + NUM_VRINGS, {0, 0}, + }, + + /* Vring rsc entry - part of vdev rsc entry */ + {FW_RSC_U32_ADDR_ANY, VRING_ALIGN, VRING_SIZE, 0, 0}, + {FW_RSC_U32_ADDR_ANY, VRING_ALIGN, VRING_SIZE, 1, 0}, +}; + +/* return a pointer to our resource table */ +struct resource_table *bflb_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *size) +{ + *size = sizeof(resources); + return (struct resource_table *)&resources; +} + +/* allocate vdev0buffer */ +static int bflb_rproc_mem_alloc(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + struct device *dev = rproc->dev.parent; + void *va; + + va = ioremap_wc(mem->dma, mem->len); + if (!va) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", + &mem->dma, mem->len); + return -ENOMEM; + } + + /* Update memory entry va */ + mem->va = va; + + return 0; +} + +/* release vdev0buffer */ +static int bflb_rproc_mem_release(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + iounmap(mem->va); + + return 0; +} + +/* + * Pull the memory ranges for virtio from the device tree and register them. + * Called as prepare. + */ +static int bflb_rproc_setupmem(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + struct device_node *np = dev->of_node; + struct rproc_mem_entry *mem; + struct reserved_mem *rmem; + struct of_phandle_iterator it; + int index = 0; + + dev_dbg(dev, "%s %s", __func__, np->name); + + of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); + while (of_phandle_iterator_next(&it) == 0) { + rmem = of_reserved_mem_lookup(it.node); + if (!rmem) { + dev_err(dev, "unable to acquire memory-region\n"); + return -EINVAL; + } + + /* No need to map vdev buffer */ + if (strcmp(it.node->name, "vdev0buffer")) { + /* Register memory region */ + mem = rproc_mem_entry_init(dev, NULL, + (dma_addr_t)rmem->base, + rmem->size, rmem->base, + bflb_rproc_mem_alloc, + bflb_rproc_mem_release, + it.node->name); + } else { + /* Register reserved memory for vdev buffer allocation */ + mem = rproc_of_resm_mem_entry_init(dev, index, + rmem->size, + rmem->base, + it.node->name); + } + + if (!mem) { + dev_err(dev, "unable to allocate memory entry %s", it.node->name); + return -ENOMEM; + } + rproc_add_carveout(rproc, mem); + index++; + } + return 0; +} + + +/* M0 is already started. Do Nothing + */ +static int bflb_rproc_start(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + + dev_dbg(dev, "bflb_rproc_start"); + + return 0; +} + +/* We don't want to stop M0, as it will crash. Do Nothing */ +static int bflb_rproc_stop(struct rproc *rproc) +{ + struct device *dev = rproc->dev.parent; + + dev_dbg(dev, "bflb_rproc_stop"); + + return 0; +} + +/* kick the virtqueue to let M0 know there is a update to the vring */ +static void bflb_rproc_send_kick(struct rproc *rproc, int vqid) +{ + struct device *dev = rproc->dev.parent; + struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv; + struct bflb_mbox *mb = &drproc->mbox_tx; + struct mbox_chan *chan = mb->chan; + struct bflb_mbox_msg *msg; + int ret; + int i; + static int count; + + /* just for debugging atm */ + count++; + + msg = kzalloc(sizeof(struct bflb_mbox_msg), GFP_KERNEL); + if (!msg) + return; + + /* we need a small delay before kicking the other side + * (I assume to allow the ring to update/flush etc?) + * without this, we get lots of "empty ring" messages on the + * other side + */ + mdelay(1); + + msg->param = vqid; + msg->id = count; + /* Kick the other CPU to let it know the vrings are updated */ + dev_dbg(dev, "%s %d Mailbox: %s %d", __func__, msg->id, mb->name, msg->param); + /* we occasionally get a EOI timeout, so retry upto 3 times */ + for (i = 0; i < 3; i++) { + ret = mbox_send_message(chan, msg); + if (ret >= 0) + goto done; + dev_warn(dev, "%s %d Mailbox %s sending %d Failed: %d - Retrying %d", __func__, msg->id, mb->name, msg->param, ret, i); + } +done: + dev_dbg(dev, "%s %d Mailbox %s done %d: %d", __func__, msg->id, mb->name, msg->param, ret); + kfree(msg); +} + +static void bflb_rproc_recv_kick(struct work_struct *work) +{ + struct bflb_mbox *mb = container_of(work, struct bflb_mbox, vq_work); + struct rproc *rproc = dev_get_drvdata(mb->client.dev); + + dev_dbg(rproc->dev.parent, "%s mailbox: %s: %d", __func__, mb->name, mb->vq_id); + + /* not a bad thing if there is no messages, probably + * means that the previous ring kick processed the message + */ + if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) + dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); +} + +/* M0 signaled us there is a update on the vring, check it + */ +static void bflb_rproc_rx_mbox_callback(struct mbox_client *client, void *data) +{ + struct device *dev = client->dev; + struct rproc *rproc = dev_get_drvdata(dev); + struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv; + struct bflb_mbox *mb = &drproc->mbox_rx; + struct bflb_mbox_msg *msg = data; + + mb->vq_id = msg->param; + + dev_dbg(dev, "%s mailbox %s: %d", __func__, mb->name, mb->vq_id); + + queue_work(drproc->workqueue, &mb->vq_work); + mbox_chan_txdone(mb->chan, 0); +} + +/* M0 is already running when we boot + * so just attach to it. + * we also register a mailbox to get kicks from M0 when vrings are updated + */ +static int bflb_rproc_attach(struct rproc *rproc) +{ + return 0; +} + +/* Detach. Do Nothing? */ +static int bflb_rproc_detach(struct rproc *rproc) +{ + return 0; +} + +static const struct rproc_ops bflb_rproc_ops = { + .start = bflb_rproc_start, + .stop = bflb_rproc_stop, + .attach = bflb_rproc_attach, + .detach = bflb_rproc_detach, + .kick = bflb_rproc_send_kick, + .prepare = bflb_rproc_setupmem, + .get_loaded_rsc_table = bflb_rproc_get_loaded_rsc_table, +}; + +static int bflb_rproc_setup_mbox(struct rproc *rproc) +{ + struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv; + + struct bflb_mbox *tx_bflb_mbox = &drproc->mbox_tx; + struct mbox_client *tx_mbox_cl = &tx_bflb_mbox->client; + + struct bflb_mbox *rx_bflb_mbox = &drproc->mbox_rx; + struct mbox_client *rx_mbox_cl = &rx_bflb_mbox->client; + + struct device *dev = &rproc->dev; + int ret = 0; + + dev_dbg(dev, "bflb_rpoc_setup_mbox"); + + /* request the TX mailboxs */ + tx_mbox_cl->dev = dev->parent; + tx_mbox_cl->tx_block = true; + tx_mbox_cl->tx_tout = 200; + strncpy(tx_bflb_mbox->name, "virtio-tx", sizeof(tx_bflb_mbox->name)); + tx_bflb_mbox->chan = mbox_request_channel_byname(tx_mbox_cl, "virtio-tx"); + if (IS_ERR(tx_bflb_mbox->chan)) { + ret = -EBUSY; + dev_err(dev, "mbox_request_channel tx failed: %ld\n", + PTR_ERR(tx_bflb_mbox->chan)); + goto del_rx_mbox; + } + + /* request the RX mailboxs */ + rx_mbox_cl->dev = dev->parent; + rx_mbox_cl->rx_callback = bflb_rproc_rx_mbox_callback; + rx_mbox_cl->tx_block = true; + strncpy(rx_bflb_mbox->name, "virtio-rx", sizeof(rx_bflb_mbox->name)); + + rx_bflb_mbox->chan = mbox_request_channel_byname(rx_mbox_cl, "virtio-rx"); + if (IS_ERR(rx_bflb_mbox->chan)) { + ret = -EBUSY; + dev_err(dev, "mbox_request_channel rx failed: %ld\n", + PTR_ERR(rx_bflb_mbox->chan)); + goto del_tx_mbox; + } + INIT_WORK(&rx_bflb_mbox->vq_work, bflb_rproc_recv_kick); + + dev_dbg(dev, "bflb_rpoc_setup_mbox done"); + + return ret; + +del_tx_mbox: + mbox_free_channel(tx_bflb_mbox->chan); +del_rx_mbox: + mbox_free_channel(rx_bflb_mbox->chan); + return ret; +} + +static int bflb_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bflb_rproc *drproc; + struct rproc *rproc; + int ret; + + dev_dbg(dev, "bflb_rproc_probe"); + + rproc = rproc_alloc(dev, "M0", &bflb_rproc_ops, NULL, + sizeof(*drproc)); + if (!rproc) { + ret = -ENOMEM; + goto free_mem; + } + + /* error recovery is not supported at present */ + rproc->recovery_disabled = true; + + /* M0 is running when linux boots */ + //atomic_inc(&rproc->power); + rproc->state = RPROC_DETACHED; + + drproc = rproc->priv; + drproc->rproc = rproc; + rproc->has_iommu = false; + rproc->sysfs_read_only = true; + + platform_set_drvdata(pdev, rproc); + + drproc->workqueue = create_workqueue(dev_name(dev)); + if (!drproc->workqueue) { + dev_err(dev, "cannot create workqueue\n"); + ret = -ENOMEM; + goto free_wkq; + } + + ret = bflb_rproc_setup_mbox(rproc); + if (ret) { + dev_err(dev, "bflb_rpoc_setup_mbox failed: %d\n", ret); + goto free_rproc; + } + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "rproc_add failed: %d\n", ret); + goto free_rproc; + } + + dev_info(dev, "Bouffalo Labs Remote Processor Control Driver Started"); + + return 0; + +free_rproc: + rproc_free(rproc); +free_wkq: + destroy_workqueue(drproc->workqueue); +free_mem: + if (dev->of_node) + of_reserved_mem_device_release(dev); + return ret; +} + +static int bflb_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + struct bflb_rproc *drproc = (struct bflb_rproc *)rproc->priv; + struct bflb_mbox *tx_bflb_mbox = &drproc->mbox_tx; + struct bflb_mbox *rx_bflb_mbox = &drproc->mbox_rx; + struct device *dev = &pdev->dev; + + dev_info(dev, "Bouffalo Labs Remote Processor Control Driver Removed"); + + + mbox_free_channel(tx_bflb_mbox->chan); + mbox_free_channel(rx_bflb_mbox->chan); + destroy_workqueue(drproc->workqueue); + + rproc_del(rproc); + rproc_free(rproc); + if (dev->of_node) + of_reserved_mem_device_release(dev); + + return 0; +} + +static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { + { .compatible = "bflb,bflb-rproc", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); + +static struct platform_driver bflb_rproc_driver = { + .probe = bflb_rproc_probe, + .remove = bflb_rproc_remove, + .driver = { + .name = "bflb-rproc", + .of_match_table = of_match_ptr(davinci_rproc_of_match), + }, +}; + +module_platform_driver(bflb_rproc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("justin@dynam.ac"); +MODULE_DESCRIPTION("bflb Remote Processor control driver"); From a5945ddb57e2ddd54f5b25bdb5a97a9ec4078c75 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:39:52 +0800 Subject: [PATCH 97/99] add remoteproc nodes and reserved memory to dts --- .../boot/dts/bouffalolab/bl808-sipeed-m1s.dts | 2 +- arch/riscv/boot/dts/bouffalolab/bl808.dtsi | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts index 8b6f54d96c588b..5069a50080ebe9 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -17,7 +17,7 @@ chosen { stdout-path = "serial0:2000000n8"; - bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mtdblock0 ro rootfstype=squashfs"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; linux,initrd-start = <0x0 0x52000000>; linux,initrd-end = <0x0 0x52941784>; }; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi index f17059bfa4371a..f41c6b2e7f1935 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -59,6 +59,29 @@ #clock-cells = <0>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + /* putting this at the top of uncached WRAM for the moment */ + vdev0vring0: vdev0vring0@22048000 { + compatible = "shared-dma-pool"; + reg = <0x22048000 0x4000>; + no-map; + }; + vdev0vring1: vdev0vring1@2204C000 { + compatible = "shared-dma-pool"; + reg = <0x2204C000 0x4000>; + no-map; + }; + vdev0buffer: vdev0buffer@22050000 { + compatible = "shared-dma-pool"; + reg = <0x22050000 0x8000>; + no-map; + }; + }; + + soc { compatible = "simple-bus"; ranges; @@ -145,5 +168,16 @@ interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; }; + + rproc: rproc@22054000 { + compatible = "bflb,bflb-rproc"; + reg = <0x22054000 0x4000>; + memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipclic BFLB_IPC_TARGET_M0 BFLB_IPC_MBOX_VIRTIO BFLB_IPC_MBOX_VIRTIO_OP_KICK>, + <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_MBOX_VIRTIO BFLB_IPC_MBOX_VIRTIO_OP_KICK>; + mbox-names = "virtio-tx", "virtio-rx"; + + status = "disabled"; + }; }; }; From 0a00c2fe6f9c6b124615e10fb5d6284ba513e8d9 Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:45:50 +0800 Subject: [PATCH 98/99] update rpmsg code: * increase MTU size for RPMSG data to 2032 (buffer size is 2048 minus 16 bytes for vring headers). This allows us to transmit faster and especially important for the next patch where we introduce a rpmsg-net (ethernet over rpmsg) driver and don't want to fragment packets down to ~490 bytes) * regardless of source address, we need to announce new rpmsg devices back to M0 for enumeration. * rpmsg-tty device should rettry if there are no buffers available, as the M0 can be slower in processing vrings, causing frequent -ENOMEM errors on the linux side. (this patch is debatable if it should upstream) --- drivers/rpmsg/virtio_rpmsg_bus.c | 9 +++++++-- drivers/tty/rpmsg_tty.c | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 905ac7910c98f3..5444d00c9aa4b0 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -127,8 +127,11 @@ struct virtio_rpmsg_channel { * can change this without changing anything in the firmware of the remote * processor. */ +/* for BL808, lets use a large buffer size so we can do ethernet frames + * eventually + */ #define MAX_RPMSG_NUM_BUFS (512) -#define MAX_RPMSG_BUF_SIZE (512) +#define MAX_RPMSG_BUF_SIZE (2032) /* * Local addresses are dynamically allocated on-demand. @@ -422,7 +425,9 @@ static struct rpmsg_device *__rpmsg_create_channel(struct virtproc_info *vrp, * rpmsg server channels has predefined local address (for now), * and their existence needs to be announced remotely */ - rpdev->announce = rpdev->src != RPMSG_ADDR_ANY; + /* rpmsg-lite never sends a ADDR_ANY address, without this, we have to wait + * for linux to send the first message... */ + rpdev->announce = 1; strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE); diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c index 29db413bbc0308..f3ec046b6203cd 100644 --- a/drivers/tty/rpmsg_tty.c +++ b/drivers/tty/rpmsg_tty.c @@ -92,7 +92,8 @@ static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len) * Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not * hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM. */ - ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size); + /* for bl808, we only have a few small buffers, and a slow M0 CPU, so lets use rpmsg_send */ + ret = rpmsg_send(rpdev->ept, (void *)buf, msg_size); if (ret) { dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret); return ret; From 9646ecaba86ad8307b462b34775c6f0e4c78611c Mon Sep 17 00:00:00 2001 From: Justin Hammond Date: Sun, 12 Feb 2023 08:47:09 +0800 Subject: [PATCH 99/99] WIP: add rpmsg-net driver * found on the Net. It works but needs some TLC --- .../dts/bouffalolab/bl808-pine64-ox64.dts | 2 +- drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/rpmsg-net.c | 626 ++++++++++++++++++ 4 files changed, 634 insertions(+), 1 deletion(-) create mode 100644 drivers/net/rpmsg-net.c diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts index f1fa82ac772b1d..a7e4aeb240b806 100644 --- a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -52,7 +52,7 @@ }; &ehci0 { - status = "okay"; + status = "disabled"; }; &enet0 { diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9e63b8c43f3e2e..9dce0d2a42df9f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -416,6 +416,12 @@ config VIRTIO_NET This is the virtual network driver for virtio. It can be used with QEMU based VMMs (like KVM or Xen). Say Y or M. +config RPMSG_NET + tristate "RPMSG network driver" + depends on RPMSG + help + This is a virtual network driver for rpmsg bus. + config NLMON tristate "Virtual netlink monitoring device" help diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6ce076462dbfd2..5cbd5ffc870637 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -89,3 +89,4 @@ thunderbolt-net-y += thunderbolt.o obj-$(CONFIG_USB4_NET) += thunderbolt-net.o obj-$(CONFIG_NETDEVSIM) += netdevsim/ obj-$(CONFIG_NET_FAILOVER) += net_failover.o +obj-$(CONFIG_RPMSG_NET) += rpmsg-net.o diff --git a/drivers/net/rpmsg-net.c b/drivers/net/rpmsg-net.c new file mode 100644 index 00000000000000..b3d773a66a8414 --- /dev/null +++ b/drivers/net/rpmsg-net.c @@ -0,0 +1,626 @@ +/** + * @file rpmsg_net.c + * + * @brief RPMsg Network Driver + * + * This Linux kernel module exchanges Ethernet frames over the RPMsg bus, providing a virtual + * point-to-point network connection between two cores. The virtual network interface is named + * rpmsgN, where N starts at 0. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("James Tavares "); +MODULE_DESCRIPTION("point-to-point network interface over RPMsg bus"); + +// Module parameters +static int debug = 0; +module_param(debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(debug, "debug level, with 0 = none, 1 = rx/tx events, 2 = packet payload, 3 = insane"); + +enum DBG_LEVEL { + DBG_NONE, + DBG_RX_TX, + DBG_PACKET, + DBG_INSANE, +}; + +// Defines + +// Linux's RPMsg stack doesn't export MAX_RPMSG_BUF_SIZE or sizeof(rpmsg_hdr), +// so we need to hard code it here. Ugh. Keep this in sync with RPMsg implementation! +// NOTE: we have modified the kernel's RPMsg stack to use buffers of 2048 bytes +#define MAX_RPMSG_BUF_SIZE 2048 +#define RPMSG_HEADER_SIZE 16 +#define MAX_RPMSG_PAYLOAD_SIZE (MAX_RPMSG_BUF_SIZE-RPMSG_HEADER_SIZE) + +// The maximum number of simultaneous rpmsg_net instances this driver supports. +#define RPMSG_NET_MAX_DEVICES 8 + +// RPMsg MTU is lesser of the max RPMsg payload size, or 1500 (standard ethernet) +#define RPMSG_NET_L2_MTU (MAX_RPMSG_PAYLOAD_SIZE > 1492 ? 1492 : MAX_RPMSG_PAYLOAD_SIZE) + +// Size of the layer 2 header. For now, we just use full ethernet header. TODO: consider optimizing? +// Note: ETH_HLEN does not include room for a VLAN identifier. We do not support VLANs. +#define RPMSG_NET_L2_HEADER_SIZE ETH_HLEN + +// Checksum size +#define RPMSG_NET_L2_CHECKSUM_SIZE ETH_FCS_LEN + +// Pad the layer 2 header so that the IP header starts on a 16 byte boundary +#define RPMSG_NET_SKB_PADDING_SIZE (16 - (RPMSG_NET_L2_HEADER_SIZE & 0xf)) + +// Prototypes - RPMsg Driver API +static int rpmsg_probe(struct rpmsg_device *rpdev); +static int rpmsg_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src); +static void rpmsg_remove(struct rpmsg_device *rpdev); + +// Prototypes - Network Driver API +static void net_setup(struct net_device *ndev); +static int net_open(struct net_device *ndev); +static int net_close(struct net_device *ndev); +static void net_xmit_delayed_work_handler(struct work_struct *work); +static void net_xmit_work_handler(struct work_struct *work); +static int net_xmit(struct sk_buff *skb, struct net_device *ndev); + +// Prototypes - Module API +static int __init rpmsg_net_module_init(void); +static void __exit rpmsg_net_module_exit(void); + +/** @brief rpmsg_net driver instance state */ +struct rpmsg_net_priv { + /** + * Driver index number. Index into rpmsg_net_device[] array, and basis for `rpmsgN` interface + * name. + */ + int idx; + + /** Pointer to the RPMsg stack device handle */ + struct rpmsg_device *rpdev; + + /** Pointer to the network device stack device handle */ + struct net_device *ndev; + + /** + * A work queue to process net device transmit events (Net->RPMsg) packets in a process context, + * rather than the ISR context provided by the net xmit callback. + */ + struct work_struct immediate; + + /** + * A work queue to provide for net device transmit retries in the event that the RPMsg ring + * buffer is full at the time we attempt to transmit. + */ + struct delayed_work delayed; + + /** The current skb that is being transmitted from net device to RPMsg */ + struct sk_buff *skb; + + /** A boolean indicating that we are retrying a failed skb transmission */ + bool is_delayed; + + /** A lock for the net device transmitter. Used to avoid race condition on shutdown */ + spinlock_t shutdown_lock; + + /** A flag indicating whether the interace is shutdown, or not */ + bool is_shutdown; +}; + +/** + * rpmsg_net driver instance state pointers, by device index + */ +static struct rpmsg_net_priv *rpmsg_net_device[RPMSG_NET_MAX_DEVICES]; + + +////////////////////// +// RPMsg Driver API // +////////////////////// + + +/** Registration table for RPMsg back-end */ +static struct rpmsg_device_id rpmsg_net_id_table[] = { + { .name = "rpmsg-net" }, + { } +}; + +MODULE_DEVICE_TABLE(rpmsg, rpmsg_net_id_table); + +/** RPMsg operations object */ +static struct rpmsg_driver rpmsg_net_client = { + .drv.name = KBUILD_MODNAME, + .id_table = rpmsg_net_id_table, + .probe = rpmsg_probe, + .callback = rpmsg_callback, + .remove = rpmsg_remove, +}; + +/** + * @brief Called by the RPMsg stack upon RPMsg device attachment. Creates and registers the + * corresponding `rpmsgN` virtual network device. + * + * @param rpdev RPMsg device + * + * @return 0 on success, -1 on error + */ +static int rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct net_device *ndev = NULL; + struct rpmsg_net_priv *priv = NULL; + char name[IFNAMSIZ]; + u8 addr[ETH_ALEN]; + int i; + + // find an open rpmsg_net_device slot + for (i = 0; idev, "unable to bind channel 0x%x -> 0x%x: reached maximum rpmsg_net device count of %d\n", + rpdev->src, rpdev->dst, RPMSG_NET_MAX_DEVICES); + // TODO return real error here + return -1; + } + + // allocate the network device + snprintf(name, sizeof(name), "rpmsg%d", i); + + ndev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, net_setup); + if (ndev == NULL) { + dev_err(&rpdev->dev, "unable to bind channel 0x%x -> 0x%x: unable to allocate netdevice\n", + rpdev->src, rpdev->dst); + // TODO return real error here + return -1; + } + + // setup our private area, and let the network driver know of rpmsg driver + priv = netdev_priv(ndev); + memset(priv, 0x00, sizeof(*priv)); + priv->idx = i; + priv->ndev = ndev; + priv->rpdev = rpdev; + INIT_WORK(&priv->immediate, net_xmit_work_handler); + INIT_DELAYED_WORK(&priv->delayed, net_xmit_delayed_work_handler); + priv->skb = NULL; + priv->is_delayed = false; + spin_lock_init(&priv->shutdown_lock); + priv->is_shutdown = false; + + // let RPMsg driver know of the network driver + rpdev->ept->priv = priv; + + addr[0] = 0x00; + addr[1] = 0x01; + addr[2] = 0x00; + addr[3] = 0x01; + addr[4] = 0X08; + addr[5] = 0xff; + eth_hw_addr_set(ndev, addr); + + eth_random_addr(ndev->perm_addr); + + // register the net device + register_netdev(ndev); + + // success + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x bound to interface %s\n", + rpdev->src, rpdev->dst, ndev->name); + + rpmsg_net_device[i] = priv; + + return 0; +} + +/** + * @brief Called when an Ethernet frame has been received from the remote processor. Injects the + * frame into the virtual network interface's input queue. + * + * @param rpdev RPMsg device + * @param data RPMsg payload (incoming Ethernet frame) + * @param len Length of the payload + * @param priv_in Private data (pointer to rpmsg_net_priv instance) + * @param src Source RPMsg address + * + * @return 0 on success, -1 on error + */ +static int rpmsg_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv_in, u32 src) +{ + unsigned int maxLen; + struct rpmsg_net_priv *priv; + struct sk_buff *skb; + + (void)src; + + if (debug >= DBG_INSANE) { + printk(KERN_INFO "rpmsg_callback: in_interrupt:%lu [in_irq:%lu in_softirq:%lu] in_atomic:%u in_task:%u\n", + in_interrupt(), in_irq(), in_softirq(), in_atomic(), in_task()); + } + + if (debug >= DBG_RX_TX) { + dev_info(&rpdev->dev, "recv packet on channel 0x%x -> 0x%x, len:%d\n", + rpdev->src, rpdev->dst, len); + } + + if (debug >= DBG_PACKET) { + // TODO print packet data + } + + if (priv_in == NULL) { + dev_err(&rpdev->dev, "ignoring callback on channel 0x%x -> 0x%x with NULL private pointer\n", + rpdev->src, rpdev->dst); + return -1; + } + + priv = (struct rpmsg_net_priv*)priv_in; + + if (priv->ndev == NULL) { + dev_err(&rpdev->dev, "ignoring callback on channel 0x%x -> 0x%x with no netdev interface\n", + rpdev->src, rpdev->dst); + return -1; + } + + // Sanity check RPMsg payload length vs. maximum-permitted length for our net device + maxLen = RPMSG_NET_L2_HEADER_SIZE + READ_ONCE(priv->ndev->mtu) + RPMSG_NET_L2_CHECKSUM_SIZE; + if (len > maxLen) { + dev_err(&rpdev->dev, "ignoring packet on channel 0x%x -> 0x%x with len %d > %d\n", + rpdev->src, rpdev->dst, len, maxLen); + return -1; + } + + // silenty drop packet if interface is closed + if (netif_queue_stopped(priv->ndev)) { + return 0; + } + + + skb = dev_alloc_skb(RPMSG_NET_SKB_PADDING_SIZE + RPMSG_NET_L2_HEADER_SIZE + RPMSG_NET_L2_MTU); + if (skb == NULL) { + dev_err(&rpdev->dev, "out of memory, dropping packet"); + priv->ndev->stats.rx_errors++; + // TODO stats (dropped rx packet) + return -1; + } + + skb_reserve(skb, RPMSG_NET_SKB_PADDING_SIZE); // Align IP on 16 byte boundary + + skb->dev = priv->ndev; + memcpy(skb_put(skb, len), data, len); + skb->protocol = eth_type_trans(skb, priv->ndev); + + // inject incoming RPMsg frame into the network device's input queue (non-interrupt context) + netif_rx(skb); + + priv->ndev->stats.rx_bytes += skb->len; + priv->ndev->stats.rx_packets++; + + + dev_dbg(&rpdev->dev, "rx done\r\n"); + return 0; +} + +/** + * @brief Called when an RPMsg device has been removed. Shuts down the network interface and + * cleans up resources. + * + * @param rpdev RPMsg device + */ +static void rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct rpmsg_net_priv *priv = (struct rpmsg_net_priv*)rpdev->ept->priv; + unsigned long flags; + + // prevent any in-flight transmissions from being injected into the work queue + spin_lock_irqsave(&priv->shutdown_lock, flags); + priv->is_shutdown = true; + netif_stop_queue(priv->ndev); + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + + // invariant: since is_shutdown=true and we are on other side of critical section, all work has + // already been scheduled, or will not be scheduled (frame dropped). + + // cancel all outstanding scheduled work and/or wait for existing work to finish + cancel_delayed_work_sync(&priv->delayed); + cancel_work_sync(&priv->immediate); + + // invariant: there may still be a lingering net_xmit, but it won't start a work queue, and it + // won't set priv->skb because is_shutdown is true. + + // free skb, in case it was abandoned by a cancelled work queue request + if (priv->skb != NULL) { + dev_consume_skb_any(priv->skb); + priv->skb = NULL; + } + + // remove the net device + unregister_netdev(priv->ndev); + + // clear our local cache so that the index can be reused by subsequent rpmsg_probe + rpmsg_net_device[priv->idx] = NULL; + + dev_info(&rpdev->dev, "removed channel: 0x%x -> 0x%x and unbound from interface rpmsg%d\n", + rpdev->src, rpdev->dst, priv->idx); + + // cleanup + free_netdev(priv->ndev); +} + +//////////////////////// +// Network Driver API // +//////////////////////// + +/** Network device driver operations object */ +static const struct net_device_ops netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = net_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + //FUTURE: .ndo_get_stats64 = sl_get_stats64, + //FUTURE allow user to alter MTU within allowable range of RPMsg bus +}; + +/** Network device driver header operations object */ +const struct header_ops header_ops = { + .create = eth_header, + .parse = eth_header_parse, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + +/** + * @brief Network setup callback. Called by the network stack when we register a new `rpmsgN` + * device. Job is to initialize the network device structure. + * + * @param ndev Network device to be initialized. + */ +static void net_setup(struct net_device *ndev) +{ + ndev->netdev_ops = &netdev_ops; + ndev->header_ops = &header_ops; + ndev->type = ARPHRD_ETHER; + ndev->hard_header_len = RPMSG_NET_L2_HEADER_SIZE; + ndev->min_header_len = RPMSG_NET_L2_HEADER_SIZE; + ndev->mtu = RPMSG_NET_L2_MTU; + //not available in 4.9: ndev->min_mtu = ndev->mtu; //ETH_MIN_MTU; + //not available in 4.9: ndev->max_mtu = ndev->mtu; //ETH_DATA_LEN; + ndev->addr_len = ETH_ALEN; + ndev->tx_queue_len = 5; //DEFAULT_TX_QUEUE_LEN; + // future: consider IFF_POINTTOPOINT and IFF_NOARP flags? + // is there a flag to signify that link is is always up? + ndev->flags = IFF_BROADCAST; + ndev->priv_flags |= IFF_TX_SKB_SHARING; + + // future: add NETIF_F_NO_CSUM feature to disable checksumming + + eth_broadcast_addr(ndev->broadcast); +} + +/** + * @brief Called when the network device is opened. Starts the transmission queue. + * + * @param ndev Network device to open + * + * @return 0 on success, -1 on error + */ +static int net_open(struct net_device *ndev) +{ + netif_start_queue(ndev); + return 0; +} + +/** + * @brief Called when the network device is closed. Stops the transmission queue. + * + * @param ndev Network device to close + * + * @return 0 on success, -1 on error + */ +static int net_close(struct net_device *ndev) +{ + netif_stop_queue(ndev); + return 0; +} + +/** + * @brief Called in workqueue context to re-try a previously failed transmission. Activates the + * `immediate` work queue to perform the actual work. + * + * @param work Work queue we were called on + */ +static void net_xmit_delayed_work_handler(struct work_struct *work) +{ + struct rpmsg_net_priv *priv = container_of(work, struct rpmsg_net_priv, delayed.work); + unsigned long flags; + + spin_lock_irqsave(&priv->shutdown_lock, flags); + if (priv->is_delayed && !priv->is_shutdown) { + schedule_work(&priv->immediate); + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + } else { + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + + dev_info(&priv->rpdev->dev, "delayed work handler skipping kick of immediate due to shutdown request\n"); + } +} + +/** + * @brief Called in workqueue context to attempt transmission of a network device skb. We attempt + * to send the packet via RPMsg bus to the other processor. On failure, we schedule one + * retransmission attempt in the future, before dropping the packet. + * + * @param work Work queue we were called on + */ +static void net_xmit_work_handler(struct work_struct *work) +{ + struct rpmsg_net_priv *priv = container_of(work, struct rpmsg_net_priv, immediate); + unsigned long flags; + int err; + + if (priv->skb == NULL) { + dev_err(&priv->rpdev->dev, "net_xmit_work_handler called with NULL skb\n"); + goto cleanup; + } + + err = rpmsg_trysend(priv->rpdev->ept, priv->skb->data, priv->skb->len); + if (err) { + priv->ndev->stats.tx_errors++; + priv->ndev->stats.tx_aborted_errors++; + if (priv->is_delayed) { + // this is already our second attempt + dev_err(&priv->rpdev->dev, "RPMsg send retry failed with error %d; dropping packet\n", err); + + // normal cleanup + goto cleanup; + } else { + // first attempt failed; attempt retry if not shutdown + spin_lock_irqsave(&priv->shutdown_lock, flags); + if (!priv->is_shutdown) { + priv->is_delayed = true; + // Our goal is to sleep long enough to free at least one (1) packet in the RPMsg + // ring buffer. When HZ is 100 (lowest setting), our minimum resolution is 10ms (1 + // jiffy). On Kestrel-M4, flood ping clocked in at ~600 1400-bytes packets per + // second on an unloaded system, and ~200 packets/sec on a loaded system. So, 10ms + // should give us at least one packet. + schedule_delayed_work(&priv->delayed, (unsigned long)(0.5 + (0.010 * HZ))); + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + + dev_err(&priv->rpdev->dev, "RPMsg send failed with error %d; will retry\n", err); + } else { + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + + dev_info(&priv->rpdev->dev, "skipping RPMsg send retry due to shutdown request\n"); + } + + // leave priv->skb populated, either for retry, or if under shutdown, to be freed by + // rpmsg_remove() + return; + } + } + + priv->ndev->stats.tx_packets++; + priv->ndev->stats.tx_bytes += priv->skb->len; + + + if (debug >= DBG_RX_TX) { + dev_info(&priv->rpdev->dev, "sent packet on channel 0x%x -> 0x%x, len:%d\n", + priv->rpdev->src, priv->rpdev->dst, priv->skb->len); + } + + if (debug >= DBG_PACKET) { + // TODO build up packet debug message + } + +cleanup: + // return the skb to the network stack + if (priv->skb != NULL) { + dev_consume_skb_any(priv->skb); + priv->skb = NULL; + } + + priv->is_delayed = false; + + // if not shutdown, re-activate the network stack xmit queue + spin_lock_irqsave(&priv->shutdown_lock, flags); + if (!priv->is_shutdown) { + netif_wake_queue(priv->ndev); + } + spin_unlock_irqrestore(&priv->shutdown_lock, flags); +} + +/** + * @brief Called in ISR context by the network stack when the network device wants to transmit a + * frame. Our goal is to send this skb (frame) on the RPMsg stack. Since RPMsg send may block + * (sleep), we funnel this request over to the `immedate` workqueue, which runs in process + * context. Since RPMsg lacks a mechanism to poll the outbound queue state (we can't know if + * our next send will succeed, or fail), we always inhibit the net device's transmitter upon + * receipt of an skb. The workqueue handler will re-enable the net device's transmitter upon + * RPMsg send success (or eventual failure). + * + * @param skb Frame to be sent + * @param ndev Network device that originated the frame + * + * @return NETDEV_TX_OK on success, NETDEV_TX_BUSY on hard (unrecoverable) error + */ +static int net_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct rpmsg_net_priv *priv = netdev_priv(ndev); + unsigned long flags; + + if (debug >= DBG_INSANE) { + dev_info(&priv->rpdev->dev, "net_xmit: in_interrupt:%lu [in_irq:%lu in_softirq:%lu] in_atomic:%u in_task:%u\n", + in_interrupt(), in_irq(), in_softirq(), in_atomic(), in_task()); + } + + if (priv->skb != NULL) { + // Hard (unrecoverable) error. When returning NETDEV_TX_BUSY, we must not keep a + // reference to the skb, and we must not free it. + + dev_err(&priv->rpdev->dev, "net_xmit: error: previous skb still in progress! this can't happen.\n"); + return NETDEV_TX_BUSY; + } + + // stop the net device transmitter. will be re-enabled by the work queue. + netif_stop_queue(priv->ndev); + + // schedule work, unless we are shutdown + spin_lock_irqsave(&priv->shutdown_lock, flags); + if (!priv->is_shutdown) { + priv->skb = skb; + schedule_work(&priv->immediate); + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + } else { + // we're shut down. drop packet. leave queue stopped. + spin_unlock_irqrestore(&priv->shutdown_lock, flags); + + dev_consume_skb_any(skb); + dev_info(&priv->rpdev->dev, "net_xmit: dropping packet due to shutdown request (race)\n"); + } + + return NETDEV_TX_OK; +} + +/////////////////////// +// Kernel Module API // +////////////////////// + +/** + * @brief Initializes the rpmsg_net kernel module, registering it with the RPMsg stack. + * + * @return 0 on success, -1 on failure + */ +static int __init rpmsg_net_module_init(void) +{ + printk(KERN_INFO "rpmsg_net: module starting\n"); + + // initialize global state + memset(rpmsg_net_device, 0x00, sizeof(rpmsg_net_device)); + + return register_rpmsg_driver(&rpmsg_net_client); +} + +/** + * @brief De-initializes the rpmsg_net kernel module, unregistering with the RPMsg stack. This, + * in turn, invokes the remove callback handler for all channels. Each remove callback will, + * in turn, unregister the associated netdevice from the network device stack. + */ +static void __exit rpmsg_net_module_exit(void) +{ + unregister_rpmsg_driver(&rpmsg_net_client); + + printk(KERN_INFO "rpmsg_net: module unloaded\n"); +} + +module_init(rpmsg_net_module_init); +module_exit(rpmsg_net_module_exit);