1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *
4  *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
5  */
6 
7 #include <linux/io.h>
8 #include <linux/serial_reg.h>
9 
10 #include <asm/addrspace.h>
11 #include <asm/setup.h>
12 
13 #ifdef CONFIG_SOC_RT288X
14 #define EARLY_UART_BASE		0x300c00
15 #define CHIPID_BASE		0x300004
16 #elif defined(CONFIG_SOC_MT7621)
17 #define EARLY_UART_BASE		0x1E000c00
18 #define CHIPID_BASE		0x1E000004
19 #else
20 #define EARLY_UART_BASE		0x10000c00
21 #define CHIPID_BASE		0x10000004
22 #endif
23 
24 #define MT7628_CHIP_NAME1	0x20203832
25 
26 #define UART_REG_TX		0x04
27 #define UART_REG_LCR		0x0c
28 #define UART_REG_LSR		0x14
29 #define UART_REG_LSR_RT2880	0x1c
30 
31 static __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE);
32 static __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE);
33 static int init_complete;
34 
uart_w32(u32 val,unsigned reg)35 static inline void uart_w32(u32 val, unsigned reg)
36 {
37 	__raw_writel(val, uart_membase + reg);
38 }
39 
uart_r32(unsigned reg)40 static inline u32 uart_r32(unsigned reg)
41 {
42 	return __raw_readl(uart_membase + reg);
43 }
44 
soc_is_mt7628(void)45 static inline int soc_is_mt7628(void)
46 {
47 	return IS_ENABLED(CONFIG_SOC_MT7620) &&
48 		(__raw_readl(chipid_membase) == MT7628_CHIP_NAME1);
49 }
50 
find_uart_base(void)51 static void find_uart_base(void)
52 {
53 	int i;
54 
55 	if (!soc_is_mt7628())
56 		return;
57 
58 	for (i = 0; i < 3; i++) {
59 		u32 reg = uart_r32(UART_REG_LCR + (0x100 * i));
60 
61 		if (!reg)
62 			continue;
63 
64 		uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE +
65 							  (0x100 * i));
66 		break;
67 	}
68 }
69 
prom_putchar(char ch)70 void prom_putchar(char ch)
71 {
72 	if (!init_complete) {
73 		find_uart_base();
74 		init_complete = 1;
75 	}
76 
77 	if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) {
78 		uart_w32((unsigned char)ch, UART_TX);
79 		while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0)
80 			;
81 	} else {
82 		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
83 			;
84 		uart_w32((unsigned char)ch, UART_REG_TX);
85 		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
86 			;
87 	}
88 }
89