162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/io.h>
862306a36Sopenharmony_ci#include <linux/serial_reg.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/addrspace.h>
1162306a36Sopenharmony_ci#include <asm/setup.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifdef CONFIG_SOC_RT288X
1462306a36Sopenharmony_ci#define EARLY_UART_BASE		0x300c00
1562306a36Sopenharmony_ci#define CHIPID_BASE		0x300004
1662306a36Sopenharmony_ci#elif defined(CONFIG_SOC_MT7621)
1762306a36Sopenharmony_ci#define EARLY_UART_BASE		0x1E000c00
1862306a36Sopenharmony_ci#define CHIPID_BASE		0x1E000004
1962306a36Sopenharmony_ci#else
2062306a36Sopenharmony_ci#define EARLY_UART_BASE		0x10000c00
2162306a36Sopenharmony_ci#define CHIPID_BASE		0x10000004
2262306a36Sopenharmony_ci#endif
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MT7628_CHIP_NAME1	0x20203832
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define UART_REG_TX		0x04
2762306a36Sopenharmony_ci#define UART_REG_LCR		0x0c
2862306a36Sopenharmony_ci#define UART_REG_LSR		0x14
2962306a36Sopenharmony_ci#define UART_REG_LSR_RT2880	0x1c
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE);
3262306a36Sopenharmony_cistatic __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE);
3362306a36Sopenharmony_cistatic int init_complete;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline void uart_w32(u32 val, unsigned reg)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	__raw_writel(val, uart_membase + reg);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic inline u32 uart_r32(unsigned reg)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return __raw_readl(uart_membase + reg);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline int soc_is_mt7628(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_SOC_MT7620) &&
4862306a36Sopenharmony_ci		(__raw_readl(chipid_membase) == MT7628_CHIP_NAME1);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void find_uart_base(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int i;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!soc_is_mt7628())
5662306a36Sopenharmony_ci		return;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
5962306a36Sopenharmony_ci		u32 reg = uart_r32(UART_REG_LCR + (0x100 * i));
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (!reg)
6262306a36Sopenharmony_ci			continue;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE +
6562306a36Sopenharmony_ci							  (0x100 * i));
6662306a36Sopenharmony_ci		break;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_civoid prom_putchar(char ch)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	if (!init_complete) {
7362306a36Sopenharmony_ci		find_uart_base();
7462306a36Sopenharmony_ci		init_complete = 1;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) {
7862306a36Sopenharmony_ci		uart_w32((unsigned char)ch, UART_TX);
7962306a36Sopenharmony_ci		while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0)
8062306a36Sopenharmony_ci			;
8162306a36Sopenharmony_ci	} else {
8262306a36Sopenharmony_ci		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
8362306a36Sopenharmony_ci			;
8462306a36Sopenharmony_ci		uart_w32((unsigned char)ch, UART_REG_TX);
8562306a36Sopenharmony_ci		while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0)
8662306a36Sopenharmony_ci			;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci}
89