From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 03:04:41 +0000
Subject: [PATCH] rk3568 rt init

---
 kernel/drivers/soc/rockchip/rk_fiq_debugger.c |  181 ++++++++++++++++++++++++++++++++++++--------
 1 files changed, 146 insertions(+), 35 deletions(-)

diff --git a/kernel/drivers/soc/rockchip/rk_fiq_debugger.c b/kernel/drivers/soc/rockchip/rk_fiq_debugger.c
index 375375c..7cd77c3 100644
--- a/kernel/drivers/soc/rockchip/rk_fiq_debugger.c
+++ b/kernel/drivers/soc/rockchip/rk_fiq_debugger.c
@@ -45,14 +45,14 @@
 #ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
 #include <linux/rockchip/rockchip_sip.h>
 #endif
-
-#define UART_USR	0x1f	/* In: UART Status Register */
+#define UART_USR			0x1f /* In: UART Status Register */
 #define UART_USR_RX_FIFO_FULL		0x10 /* Receive FIFO full */
 #define UART_USR_RX_FIFO_NOT_EMPTY	0x08 /* Receive FIFO not empty */
 #define UART_USR_TX_FIFO_EMPTY		0x04 /* Transmit FIFO empty */
 #define UART_USR_TX_FIFO_NOT_FULL	0x02 /* Transmit FIFO not full */
 #define UART_USR_BUSY			0x01 /* UART busy indicator */
 #define UART_SRR			0x22 /* software reset register */
+#define RK_UART_RFL			0x21 /* UART Receive Fifo Level Register */
 
 struct rk_fiq_debugger {
 	int irq;
@@ -150,7 +150,7 @@
 
 static int debug_getc(struct platform_device *pdev)
 {
-	unsigned int lsr;
+	unsigned int lsr, usr, rfl, iir;
 	struct rk_fiq_debugger *t;
 	unsigned int temp;
 	static unsigned int n;
@@ -160,8 +160,22 @@
 	/*
 	 * Clear uart interrupt status
 	 */
-	rk_fiq_read(t, UART_USR);
+	iir = rk_fiq_read(t, UART_IIR);
+	usr = rk_fiq_read(t, UART_USR);
 	lsr = rk_fiq_read_lsr(t);
+
+	/*
+	 * There are ways to get Designware-based UARTs into a state where
+	 * they are asserting UART_IIR_RX_TIMEOUT but there is no actual
+	 * data available.  If we see such a case then we'll do a bogus
+	 * read.  If we don't do this then the "RX TIMEOUT" interrupt will
+	 * fire forever.
+	 */
+	if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
+		rfl = rk_fiq_read(t, RK_UART_RFL);
+		if (!(lsr & (UART_LSR_DR | UART_LSR_BI)) && !(usr & 0x1) && (rfl == 0))
+			rk_fiq_read(t, UART_RX);
+	}
 
 	if (lsr & UART_LSR_DR) {
 		temp = rk_fiq_read(t, UART_RX);
@@ -215,22 +229,32 @@
 
 #ifdef CONFIG_RK_CONSOLE_THREAD
 #define FIFO_SIZE SZ_64K
-#define LINE_MAX 1024
+#define TTY_FIFO_SIZE SZ_64K
 static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);
-static char console_buf[LINE_MAX]; /* avoid FRAME WARN */
-static bool console_thread_stop;
+static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE);
+static bool console_thread_stop; /* write on console_write */
+static bool console_thread_running; /* write on console_thread */
 static unsigned int console_dropped_messages;
+
+static int write_room(struct platform_device *pdev)
+{
+	return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo));
+}
 
 static void console_putc(struct platform_device *pdev, unsigned int c)
 {
 	struct rk_fiq_debugger *t;
-	unsigned int count = 500;
+	unsigned int count = 2;		/* loop 2 times is enough */
+	unsigned long us = 400;		/* the time to send 60 byte for baudrate 1500000 */
 
 	t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
 
+	if (t->baudrate == 115200)
+		us = 5160;	/* the time to send 60 byte for baudrate 115200 */
+
 	while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) &&
 	       count--)
-		usleep_range(200, 210);
+		usleep_range(us, us + us / 20);
 
 	rk_fiq_write(t, c, UART_TX);
 }
@@ -238,12 +262,16 @@
 static void console_flush(struct platform_device *pdev)
 {
 	struct rk_fiq_debugger *t;
-	unsigned int count = 500;
+	unsigned int count = 2;		/* loop 2 times is enough */
+	unsigned long us = 428;		/* the time to send 64 byte for baudrate 1500000 */
 
 	t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
 
+	if (t->baudrate == 115200)
+		us = 5500;	/* the time to send 64 byte for baudrate 115200 */
+
 	while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT) && count--)
-		usleep_range(200, 210);
+		usleep_range(us, us + us / 20);
 }
 
 static void console_put(struct platform_device *pdev,
@@ -266,33 +294,79 @@
 	}
 }
 
+static void wake_up_console_thread(struct task_struct *console_task)
+{
+	/*
+	 * Avoid dead lock on console_task->pi_lock and console_lock
+	 * when call printk() in try_to_wake_up().
+	 *
+	 * cpu0 hold console_lock, then try lock pi_lock fail:
+	 *   printk()->vprintk_emit()->console_unlock()->try_to_wake_up()
+	 *   ->lock(pi_lock)->deadlock
+	 *
+	 * cpu1 hold pi_lock, then try lock console_lock fail:
+	 *   console_thread()->console_put()->usleep_range()->run_hrtimer()
+	 *   ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
+	 *   ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock
+	 *
+	 * if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock:
+	 *   ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
+	 *   ->vprintk_emit()->console_unlock()->try_to_wake_up()
+	 *   ->lock(pi_lock)->deadlock
+	 *
+	 * so when console_task is running on usleep_range(), printk()
+	 * should not wakeup console_task to avoid lock(pi_lock) again,
+	 * as run_hrtimer() will wakeup console_task later.
+	 * console_thread_running==false guarantee that console_task
+	 * is not running on usleep_range().
+	 */
+	if (!READ_ONCE(console_thread_running))
+		wake_up_process(console_task);
+}
+
 static int console_thread(void *data)
 {
 	struct platform_device *pdev = data;
-	char *buf = console_buf;
-	unsigned int len;
+	char buf[64], c = 0;
+	unsigned int len = 0, len_tty = 0;
 
 	while (1) {
 		unsigned int dropped;
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (kfifo_is_empty(&fifo))
+		if (console_thread_stop || (kfifo_is_empty(&fifo) && kfifo_is_empty(&tty_fifo))) {
+			smp_store_mb(console_thread_running, false);
 			schedule();
+			smp_store_mb(console_thread_running, true);
+		}
 		if (kthread_should_stop())
 			break;
 		set_current_state(TASK_RUNNING);
-		while (!console_thread_stop) {
-			len = kfifo_out(&fifo, buf, LINE_MAX);
-			if (!len)
-				break;
-			console_put(pdev, buf, len);
+
+		while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) {
+			while (!console_thread_stop && kfifo_get(&fifo, &c)) {
+				console_put(pdev, &c, 1);
+				if (c == '\n')
+					break;
+			}
+
+			while (!console_thread_stop && kfifo_get(&tty_fifo, &c)) {
+				console_putc(pdev, c);
+				len_tty++;
+				if (c == '\n')
+					break;
+			}
 		}
+
+		if (len_tty > 0)
+			fiq_tty_wake_up(pdev);
+		len_tty = 0;
+
 		dropped = console_dropped_messages;
 		if (dropped && !console_thread_stop) {
 			console_dropped_messages = 0;
 			smp_wmb();
-			len = snprintf(buf, LINE_MAX,
-				       "** %u console messages dropped **\n",
+			len = sprintf(buf, "** %u console messages dropped **\n",
 				       dropped);
 			console_put(pdev, buf, len);
 		}
@@ -328,18 +402,37 @@
 	} else if (count) {
 		unsigned int ret = 0;
 
-		if (kfifo_len(&fifo) + count < FIFO_SIZE)
+		if (kfifo_len(&fifo) + count <= FIFO_SIZE)
 			ret = kfifo_in(&fifo, s, count);
 		if (!ret) {
 			console_dropped_messages++;
 			smp_wmb();
 		} else {
-			wake_up_process(t->console_task);
+			wake_up_console_thread(t->console_task);
 		}
 	}
 }
-#endif
 
+static int tty_write(struct platform_device *pdev, const char *s, int count)
+{
+	unsigned int ret = 0;
+	struct rk_fiq_debugger *t;
+
+	if (console_thread_stop)
+		return count;
+	t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+	if (count > 0) {
+		if (kfifo_len(&tty_fifo) + count <= TTY_FIFO_SIZE)
+			ret = kfifo_in(&tty_fifo, s, count);
+
+		if (ret <= 0)
+			return 0;
+		wake_up_console_thread(t->console_task);
+	}
+	return count;
+}
+#endif
 
 static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on)
 {
@@ -371,7 +464,7 @@
 	return rk_fiq_sdei.fiq_en;
 }
 
-int fiq_sdei_event_callback(u32 event, struct pt_regs *regs, void *arg)
+static int fiq_sdei_event_callback(u32 event, struct pt_regs *regs, void *arg)
 {
 	int cpu_id = get_logical_index(read_cpuid_mpidr() &
 				       MPIDR_HWID_BITMASK);
@@ -380,7 +473,7 @@
 	return 0;
 }
 
-void rk_fiq_sdei_event_sw_cpu(int wait_disable)
+static void rk_fiq_sdei_event_sw_cpu(int wait_disable)
 {
 	unsigned long affinity;
 	int cnt = 100000;
@@ -402,7 +495,7 @@
 	rk_fiq_sdei.cur_cpu = rk_fiq_sdei.sw_cpu;
 }
 
-int fiq_sdei_sw_cpu_event_callback(u32 event, struct pt_regs *regs, void *arg)
+static int fiq_sdei_sw_cpu_event_callback(u32 event, struct pt_regs *regs, void *arg)
 {
 	int cnt = 10000;
 	int ret = 0;
@@ -454,7 +547,7 @@
 	int cnt = 10000;
 
 	if (rk_fiq_sdei.cur_cpu == cpu) {
-		target_cpu = cpumask_first(cpu_online_mask);
+		target_cpu = cpumask_any_but(cpu_online_mask, cpu);
 		_rk_fiq_dbg_sdei_switch_cpu(target_cpu, 1);
 
 		while (rk_fiq_sdei.cur_cpu == cpu && cnt) {
@@ -495,6 +588,7 @@
 static int fiq_debugger_sdei_enable(struct rk_fiq_debugger *t)
 {
 	int ret, cpu, i;
+	int is_dyn_event = false;
 
 	ret = sip_fiq_debugger_sdei_get_event_id(&rk_fiq_sdei.event_id,
 						 &rk_fiq_sdei.cpu_sw_event_id,
@@ -503,6 +597,17 @@
 	if (ret) {
 		pr_err("%s: get event id error!\n", __func__);
 		return ret;
+	}
+
+	/* If we can't get a valid fiq event, use dynamic event instead */
+	if (rk_fiq_sdei.event_id == 0) {
+		ret = sdei_interrupt_bind(serial_hwirq, &rk_fiq_sdei.event_id);
+		if (ret) {
+			pr_err("%s: bind intr:%d error!\n", __func__, serial_hwirq);
+			return ret;
+		}
+
+		is_dyn_event = true;
 	}
 
 	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
@@ -583,6 +688,9 @@
 	unregister_pm_notifier(&fiq_dbg_sdei_pm_nb);
 	sdei_event_unregister(rk_fiq_sdei.event_id);
 
+	if (is_dyn_event)
+		sdei_interrupt_release(rk_fiq_sdei.event_id);
+
 	return ret;
 }
 
@@ -604,7 +712,7 @@
 	sip_fiq_debugger_enable_debug(val);
 }
 
-static void fiq_debugger_uart_irq_tf(struct pt_regs *_pt_regs, uint32_t cpu)
+static void fiq_debugger_uart_irq_tf(struct pt_regs *_pt_regs, unsigned long cpu)
 {
 	fiq_debugger_fiq(_pt_regs, cpu);
 }
@@ -652,7 +760,7 @@
 
 	if ((sip_fiq_debugger_is_enabled()) &&
 	    (sip_fiq_debugger_get_target_cpu() == cpu)) {
-		target_cpu = cpumask_first(cpu_online_mask);
+		target_cpu = cpumask_any_but(cpu_online_mask, cpu);
 		sip_fiq_debugger_switch_cpu(target_cpu);
 	}
 
@@ -730,9 +838,9 @@
 }
 #endif
 
-void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base,
-			  int irq, int signal_irq,
-			  int wakeup_irq, unsigned int baudrate)
+static void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base,
+				 int irq, int signal_irq,
+				 int wakeup_irq, unsigned int baudrate)
 {
 	struct rk_fiq_debugger *t = NULL;
 	struct platform_device *pdev = NULL;
@@ -831,8 +939,11 @@
 
 #ifdef CONFIG_RK_CONSOLE_THREAD
 	t->console_task = kthread_run(console_thread, pdev, "kconsole");
-	if (!IS_ERR(t->console_task))
+	if (!IS_ERR(t->console_task)) {
 		t->pdata.console_write = console_write;
+		t->pdata.tty_write = tty_write;
+		t->pdata.write_room = write_room;
+	}
 #endif
 
 	pdev->name = "fiq_debugger";
@@ -854,7 +965,7 @@
 	kfree(t);
 }
 
-void rk_serial_debug_init_dummy(void)
+static void rk_serial_debug_init_dummy(void)
 {
 	struct rk_fiq_debugger *t = NULL;
 	struct platform_device *pdev = NULL;

--
Gitblit v1.6.2