18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
118c2ecf20Sopenharmony_ci#include <asm/setup.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifdef CONFIG_SOC_RT288X
148c2ecf20Sopenharmony_ci#define EARLY_UART_BASE		0x300c00
158c2ecf20Sopenharmony_ci#define CHIPID_BASE		0x300004
168c2ecf20Sopenharmony_ci#elif defined(CONFIG_SOC_MT7621)
178c2ecf20Sopenharmony_ci#define EARLY_UART_BASE		0x1E000c00
188c2ecf20Sopenharmony_ci#define CHIPID_BASE		0x1E000004
198c2ecf20Sopenharmony_ci#else
208c2ecf20Sopenharmony_ci#define EARLY_UART_BASE		0x10000c00
218c2ecf20Sopenharmony_ci#define CHIPID_BASE		0x10000004
228c2ecf20Sopenharmony_ci#endif
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define MT7628_CHIP_NAME1	0x20203832
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define UART_REG_TX		0x04
278c2ecf20Sopenharmony_ci#define UART_REG_LCR		0x0c
288c2ecf20Sopenharmony_ci#define UART_REG_LSR		0x14
298c2ecf20Sopenharmony_ci#define UART_REG_LSR_RT2880	0x1c
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE);
328c2ecf20Sopenharmony_cistatic __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE);
338c2ecf20Sopenharmony_cistatic int init_complete;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline void uart_w32(u32 val, unsigned reg)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	__raw_writel(val, uart_membase + reg);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline u32 uart_r32(unsigned reg)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	return __raw_readl(uart_membase + reg);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic inline int soc_is_mt7628(void)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_SOC_MT7620) &&
488c2ecf20Sopenharmony_ci		(__raw_readl(chipid_membase) == MT7628_CHIP_NAME1);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void find_uart_base(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int i;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (!soc_is_mt7628())
568c2ecf20Sopenharmony_ci		return;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
598c2ecf20Sopenharmony_ci		u32 reg = uart_r32(UART_REG_LCR + (0x100 * i));
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		if (!reg)
628c2ecf20Sopenharmony_ci			continue;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE +
658c2ecf20Sopenharmony_ci							  (0x100 * i));
668c2ecf20Sopenharmony_ci		break;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_civoid prom_putchar(char ch)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	if (!init_complete) {
738c2ecf20Sopenharmony_ci		find_uart_base();
748c2ecf20Sopenharmony_ci		init_complete = 1;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) {
788c2ecf20Sopenharmony_ci		uart_w32((unsigned char)ch, UART_TX);
798c2ecf20Sopenharmony_ci		while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0)
808c2ecf20Sopenharmony_ci			;
818c2ecf20Sopenharmony_ci	} else {
828c2ecf20Sopenharmony_ci		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
838c2ecf20Sopenharmony_ci			;
848c2ecf20Sopenharmony_ci		uart_w32((unsigned char)ch, UART_REG_TX);
858c2ecf20Sopenharmony_ci		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
868c2ecf20Sopenharmony_ci			;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci}
89