18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * TI DaVinci serial driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Texas Instruments.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
118c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/clk.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <mach/serial.h>
188c2ecf20Sopenharmony_ci#include <mach/cputype.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
218c2ecf20Sopenharmony_ci				    int value)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	offset <<= p->regshift;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	WARN_ONCE(!p->membase, "unmapped write: uart[%d]\n", offset);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	__raw_writel(value, p->membase + offset);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void __init davinci_serial_reset(struct plat_serial8250_port *p)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned int pwremu = 0;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	serial_write_reg(p, UART_IER, 0);  /* disable all interrupts */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* reset both transmitter and receiver: bits 14,13 = UTRST, URRST */
378c2ecf20Sopenharmony_ci	serial_write_reg(p, UART_DAVINCI_PWREMU, pwremu);
388c2ecf20Sopenharmony_ci	mdelay(10);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	pwremu |= (0x3 << 13);
418c2ecf20Sopenharmony_ci	pwremu |= 0x1;
428c2ecf20Sopenharmony_ci	serial_write_reg(p, UART_DAVINCI_PWREMU, pwremu);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (cpu_is_davinci_dm646x())
458c2ecf20Sopenharmony_ci		serial_write_reg(p, UART_DM646X_SCR,
468c2ecf20Sopenharmony_ci				 UART_DM646X_SCR_TX_WATERMARK);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciint __init davinci_serial_init(struct platform_device *serial_dev)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	int i, ret = 0;
528c2ecf20Sopenharmony_ci	struct device *dev;
538c2ecf20Sopenharmony_ci	struct plat_serial8250_port *p;
548c2ecf20Sopenharmony_ci	struct clk *clk;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * Make sure the serial ports are muxed on at this point.
588c2ecf20Sopenharmony_ci	 * You have to mux them off in device drivers later on if not needed.
598c2ecf20Sopenharmony_ci	 */
608c2ecf20Sopenharmony_ci	for (i = 0; serial_dev[i].dev.platform_data != NULL; i++) {
618c2ecf20Sopenharmony_ci		dev = &serial_dev[i].dev;
628c2ecf20Sopenharmony_ci		p = dev->platform_data;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		ret = platform_device_register(&serial_dev[i]);
658c2ecf20Sopenharmony_ci		if (ret)
668c2ecf20Sopenharmony_ci			continue;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		clk = clk_get(dev, NULL);
698c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
708c2ecf20Sopenharmony_ci			pr_err("%s:%d: failed to get UART%d clock\n",
718c2ecf20Sopenharmony_ci			       __func__, __LINE__, i);
728c2ecf20Sopenharmony_ci			continue;
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		clk_prepare_enable(clk);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		p->uartclk = clk_get_rate(clk);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		if (!p->membase && p->mapbase) {
808c2ecf20Sopenharmony_ci			p->membase = ioremap(p->mapbase, SZ_4K);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci			if (p->membase)
838c2ecf20Sopenharmony_ci				p->flags &= ~UPF_IOREMAP;
848c2ecf20Sopenharmony_ci			else
858c2ecf20Sopenharmony_ci				pr_err("uart regs ioremap failed\n");
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		if (p->membase && p->type != PORT_AR7)
898c2ecf20Sopenharmony_ci			davinci_serial_reset(p);
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci	return ret;
928c2ecf20Sopenharmony_ci}
93