Update source to Armbian-dev-202610.A311Y3
This commit is contained in:
@@ -87,6 +87,9 @@ static void meson_uart_enable_tx_engine(struct uart_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
val |= AML_UART_TX_EN;
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
@@ -110,10 +113,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
bool locked = true;
|
||||
u32 val, tmp;
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
locked = uart_port_trylock_irqsave(port, &flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
|
||||
@@ -123,7 +129,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
}
|
||||
|
||||
static void meson_serial_early_console_write(struct console *co,
|
||||
|
||||
@@ -90,10 +90,8 @@ static unsigned int xtal_tick_en;
|
||||
|
||||
struct meson_uart_port {
|
||||
struct uart_port port;
|
||||
spinlock_t wr_lock; /* protect write */
|
||||
unsigned long baud;
|
||||
struct pinctrl *p;
|
||||
unsigned long for_bt;
|
||||
};
|
||||
|
||||
static struct meson_uart_port *meson_ports[AML_UART_PORT_MAX];
|
||||
@@ -113,6 +111,9 @@ static unsigned int meson_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!port->membase)
|
||||
return 0;
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_STATUS);
|
||||
return (val & AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
@@ -124,6 +125,9 @@ static void meson_uart_stop_tx(struct uart_port *port)
|
||||
if (port->line == 0)
|
||||
return;
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
val &= ~AML_UART_TX_EN;
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
@@ -133,6 +137,9 @@ static void meson_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
val &= ~AML_UART_RX_EN;
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
@@ -146,6 +153,10 @@ static void meson_uart_shutdown(struct uart_port *port)
|
||||
if (port->line == 0)
|
||||
return;
|
||||
|
||||
/* uart_port_lock_irqsave() dereferences port->state, guard against NULL */
|
||||
if (!port->state || !port->membase)
|
||||
return;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
@@ -159,12 +170,13 @@ static void meson_uart_shutdown(struct uart_port *port)
|
||||
|
||||
static void meson_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct meson_uart_port *mup = to_meson_port(port);
|
||||
struct tty_port *tport;
|
||||
unsigned char ch;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mup->wr_lock, flags);
|
||||
if (!port->state || !port->membase)
|
||||
return;
|
||||
|
||||
tport = &port->state->port;
|
||||
|
||||
while (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
if (readl_relaxed(port->membase + AML_UART_STATUS)
|
||||
@@ -176,17 +188,19 @@ static void meson_uart_start_tx(struct uart_port *port)
|
||||
|
||||
writel_relaxed(ch, port->membase + AML_UART_WFIFO);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&mup->wr_lock, flags);
|
||||
}
|
||||
|
||||
static void meson_transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct meson_uart_port *mup = to_meson_port(port);
|
||||
struct tty_port *tport;
|
||||
unsigned char ch;
|
||||
int count = 256;
|
||||
|
||||
if (!port->state || !port->membase)
|
||||
return;
|
||||
|
||||
tport = &port->state->port;
|
||||
|
||||
if (port->x_char) {
|
||||
writel_relaxed(port->x_char, port->membase + AML_UART_WFIFO);
|
||||
port->icount.tx++;
|
||||
@@ -197,8 +211,6 @@ static void meson_transmit_chars(struct uart_port *port)
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
spin_lock(&mup->wr_lock);
|
||||
|
||||
while (!kfifo_is_empty(&tport->xmit_fifo) && count-- > 0) {
|
||||
if (readl_relaxed(port->membase + AML_UART_STATUS)
|
||||
& AML_UART_TX_FULL)
|
||||
@@ -210,8 +222,6 @@ static void meson_transmit_chars(struct uart_port *port)
|
||||
writel_relaxed(ch, port->membase + AML_UART_WFIFO);
|
||||
}
|
||||
|
||||
spin_unlock(&mup->wr_lock);
|
||||
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
@@ -220,10 +230,15 @@ static void meson_transmit_chars(struct uart_port *port)
|
||||
|
||||
static void meson_receive_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct tty_port *tport;
|
||||
char flag;
|
||||
u32 status, ch, mode;
|
||||
|
||||
if (!port->state || !port->membase)
|
||||
return;
|
||||
|
||||
tport = &port->state->port;
|
||||
|
||||
do {
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
@@ -283,6 +298,9 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)dev_id;
|
||||
|
||||
if (!port || !port->membase)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
uart_port_lock(port);
|
||||
|
||||
if (!(readl_relaxed(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
|
||||
@@ -307,6 +325,9 @@ static int meson_uart_startup(struct uart_port *port)
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!port->membase)
|
||||
return -EINVAL;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
@@ -334,6 +355,9 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
|
||||
struct meson_uart_port *mup = to_meson_port(port);
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
while (!(readl_relaxed(port->membase + AML_UART_STATUS) & AML_UART_TX_EMPTY))
|
||||
cpu_relax();
|
||||
|
||||
@@ -386,6 +410,9 @@ static void meson_uart_set_termios(struct uart_port *port,
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (!port->state || !port->membase || !port->dev)
|
||||
return;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
cflags = termios->c_cflag;
|
||||
@@ -474,58 +501,46 @@ static int meson_uart_verify_port(struct uart_port *port,
|
||||
|
||||
static void meson_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
devm_iounmap(port->dev, port->membase);
|
||||
port->membase = NULL;
|
||||
devm_release_mem_region(port->dev, port->mapbase, port->mapsize);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static cpumask_t meson_irq_hint_mask;
|
||||
|
||||
static inline void meson_uart_set_irq_affinity(struct uart_port *port)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (port->line == 1) {
|
||||
cpumask_clear(&meson_irq_hint_mask);
|
||||
|
||||
for (cpu = 1; cpu < nr_cpu_ids; cpu++) {
|
||||
if (cpu_online(cpu)) {
|
||||
cpumask_set_cpu(cpu, &meson_irq_hint_mask);
|
||||
irq_set_affinity_hint(port->irq, &meson_irq_hint_mask);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpumask_empty(&meson_irq_hint_mask))
|
||||
irq_set_affinity_hint(port->irq, NULL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void meson_uart_set_irq_affinity(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int meson_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct meson_uart_port *mup = to_meson_port(port);
|
||||
struct resource *res;
|
||||
int size, ret;
|
||||
u32 val;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "cannot obtain I/O memory region");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
|
||||
if (!devm_request_mem_region(port->dev, port->mapbase, size, dev_name(port->dev))) {
|
||||
dev_err(port->dev, "Memory region busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
port->membase = devm_ioremap(port->dev, port->mapbase, size);
|
||||
if (!port->membase)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "==uart%d reg addr = 0x%llx\n", port->line, (unsigned long long)port->mapbase);
|
||||
|
||||
val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
|
||||
writel_relaxed(val, port->membase + AML_UART_MISC);
|
||||
|
||||
writel_relaxed(readl_relaxed(port->membase + AML_UART_CONTROL) | AML_UART_INV_RTS,
|
||||
port->membase + AML_UART_CONTROL);
|
||||
|
||||
if (mup->for_bt)
|
||||
ret = devm_request_threaded_irq(port->dev, port->irq, NULL,
|
||||
meson_uart_interrupt,
|
||||
IRQF_ONESHOT | IRQF_SHARED,
|
||||
meson_uart_type(port), port);
|
||||
else
|
||||
ret = devm_request_irq(port->dev, port->irq, meson_uart_interrupt,
|
||||
IRQF_SHARED, port->name, port);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_uart_config_port(struct uart_port *port, int flags)
|
||||
@@ -547,6 +562,9 @@ static int meson_uart_poll_get_char(struct uart_port *port)
|
||||
u32 c;
|
||||
unsigned long flags;
|
||||
|
||||
if (!port->membase)
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)
|
||||
@@ -565,6 +583,9 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
/* Wait until FIFO is empty or timeout */
|
||||
@@ -680,6 +701,9 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
else
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
if (!port->membase)
|
||||
goto out;
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
|
||||
writel_relaxed(tmp, port->membase + AML_UART_CONTROL);
|
||||
@@ -687,6 +711,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
uart_console_write(port, s, count, meson_console_putchar);
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
|
||||
out:
|
||||
if (locked)
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
}
|
||||
@@ -774,6 +799,9 @@ static int meson_uart_freeze(struct device *dev)
|
||||
pdev = to_platform_device(dev);
|
||||
port = platform_get_drvdata(pdev);
|
||||
|
||||
if (!port || !port->membase)
|
||||
return -EINVAL;
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
val = readl_relaxed(port->membase + AML_UART_CONTROL);
|
||||
@@ -814,6 +842,9 @@ static int meson_uart_restore(struct device *dev)
|
||||
pdev = to_platform_device(dev);
|
||||
port = platform_get_drvdata(pdev);
|
||||
|
||||
if (!port || !port->membase)
|
||||
return -EINVAL;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
if (port->line == 0) {
|
||||
@@ -893,13 +924,8 @@ static int meson_uart_probe(struct platform_device *pdev)
|
||||
if (!mup)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&mup->wr_lock);
|
||||
port = &mup->port;
|
||||
|
||||
prop = of_get_property(pdev->dev.of_node, "uart_for_bt", NULL);
|
||||
if (prop)
|
||||
mup->for_bt = of_read_ulong(prop, 1);
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "clk_gate");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_dbg(&pdev->dev, "%s: clock gate not found\n", dev_name(&pdev->dev));
|
||||
@@ -953,6 +979,15 @@ static int meson_uart_probe(struct platform_device *pdev)
|
||||
/* return -1; */
|
||||
}
|
||||
|
||||
if (!port->membase) {
|
||||
port->membase = devm_ioremap_resource(&pdev->dev, res_mem);
|
||||
if (IS_ERR(port->membase)) {
|
||||
meson_ports[pdev->id] = NULL;
|
||||
return PTR_ERR(port->membase);
|
||||
}
|
||||
port->flags &= ~UPF_IOREMAP;
|
||||
}
|
||||
|
||||
prop = of_get_property(pdev->dev.of_node, "support-sysrq", NULL);
|
||||
if (prop) {
|
||||
support_sysrq = of_read_ulong(prop, 1);
|
||||
@@ -960,9 +995,29 @@ static int meson_uart_probe(struct platform_device *pdev)
|
||||
port->has_sysrq = 1;
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&meson_uart_driver, port);
|
||||
if (ret)
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
ret = devm_request_irq(&pdev->dev, port->irq, meson_uart_interrupt,
|
||||
IRQF_SHARED, dev_name(&pdev->dev), port);
|
||||
|
||||
meson_uart_set_irq_affinity(port);
|
||||
#else
|
||||
ret = devm_request_threaded_irq(&pdev->dev, port->irq, NULL,
|
||||
meson_uart_interrupt,
|
||||
IRQF_ONESHOT | IRQF_SHARED,
|
||||
dev_name(&pdev->dev), port);
|
||||
#endif
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request irq %d failed: %d\n", port->irq, ret);
|
||||
meson_ports[pdev->id] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&meson_uart_driver, port);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "uart_add_one_port failed: %d\n", ret);
|
||||
meson_ports[pdev->id] = NULL;
|
||||
devm_free_irq(&pdev->dev, port->irq, port);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -972,6 +1027,9 @@ static void meson_uart_remove(struct platform_device *pdev)
|
||||
struct uart_port *port;
|
||||
|
||||
port = platform_get_drvdata(pdev);
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
uart_remove_one_port(&meson_uart_driver, port);
|
||||
meson_ports[pdev->id] = NULL;
|
||||
}
|
||||
@@ -997,6 +1055,8 @@ static int meson_uart_resume(struct platform_device *pdev)
|
||||
writel_relaxed(val, port->membase + AML_UART_CONTROL);
|
||||
}
|
||||
|
||||
meson_uart_set_irq_affinity(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user