Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea700541 authored by Chandana Kishori Chiluveru's avatar Chandana Kishori Chiluveru
Browse files

serial: msm_geni_serial: Don't depend on clock freq table to set baud rate



Current uart driver depends on predefined root clock frequency table to
select a suitable root clock frequency and configure the clock divider
to get the required baud rate. Setting a clock frequency from the
statically defined list of frequencies may not be supported by
the clock controller driver for that SE clock.

This change is to query the supported clock frequencies at runtime
and configure the clock divider based on the available
supported frequencies.

Change-Id: Iede604ee8d18528b66d57edac83eb54ae2619f5b
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
parent e710aa3f
Loading
Loading
Loading
Loading
+54 −29
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/bitmap.h>
@@ -1912,30 +1912,6 @@ static int msm_geni_serial_startup(struct uart_port *uport)
	return ret;
}

static int get_clk_cfg(unsigned long clk_freq, unsigned long *ser_clk)
{
	unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
		32000000, 48000000, 64000000, 80000000, 96000000, 100000000,
		102400000, 112000000, 120000000, 128000000};
	int i;
	int match = -1;

	for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
		if (clk_freq > root_freq[i])
			continue;

		if (!(root_freq[i] % clk_freq)) {
			match = i;
			break;
		}
	}
	if (match != -1)
		*ser_clk = root_freq[match];
	else
		pr_err("clk_freq %ld\n", clk_freq);
	return match;
}

static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
		u32 tx_trans_cfg, u32 tx_parity_cfg, u32 rx_trans_cfg,
		u32 rx_parity_cfg, u32 bits_per_char, u32 stop_bit_len,
@@ -1961,6 +1937,31 @@ static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
	geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG);
}

#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
static int get_clk_cfg(unsigned long clk_freq, unsigned long *ser_clk)
{
	unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
		32000000, 48000000, 64000000, 80000000, 96000000, 100000000,
		102400000, 112000000, 120000000, 128000000};
	int i;
	int match = -1;

	for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
		if (clk_freq > root_freq[i])
			continue;

		if (!(root_freq[i] % clk_freq)) {
			match = i;
			break;
		}
	}
	if (match != -1)
		*ser_clk = root_freq[match];
	else
		pr_err("clk_freq %ld\n", clk_freq);
	return match;
}

static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate)
{
	unsigned long ser_clk;
@@ -1981,6 +1982,7 @@ static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate)
exit_get_clk_div_rate:
	return clk_div;
}
#endif

static void msm_geni_serial_set_termios(struct uart_port *uport,
				struct ktermios *termios, struct ktermios *old)
@@ -1992,11 +1994,15 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
	unsigned int rx_trans_cfg;
	unsigned int rx_parity_cfg;
	unsigned int stop_bit_len;
	int clk_div;
	int clk_div, ret;
	unsigned long ser_clk_cfg = 0;
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	unsigned long clk_rate;
	unsigned long flags;
	unsigned long desired_rate;
	unsigned int clk_idx;
	int uart_sampling;
	int clk_freq_diff;

	if (!uart_console(uport)) {
		int ret = msm_geni_serial_power_on(uport);
@@ -2020,12 +2026,31 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
	/* baud rate */
	baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
	port->cur_baud = baud;
	clk_div = get_clk_div_rate(baud, &clk_rate);
	uart_sampling = IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING) ?
				UART_OVERSAMPLING / 2 : UART_OVERSAMPLING;
	desired_rate = baud * uart_sampling;

	/*
	 * Request for nearest possible required frequency instead of the exact
	 * required frequency.
	 */
	ret = geni_se_clk_freq_match(&port->serial_rsc, desired_rate,
			&clk_idx, &clk_rate, false);
	if (ret) {
		dev_err(uport->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
				__func__, ret, baud);
		goto exit_set_termios;
	}

	clk_div = DIV_ROUND_UP(clk_rate, desired_rate);
	if (clk_div <= 0)
		goto exit_set_termios;

	if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING))
		clk_div *= 2;
	clk_freq_diff =  (desired_rate - (clk_rate / clk_div));
	if (clk_freq_diff)
		IPC_LOG_MSG(port->ipc_log_misc,
			"src_clk freq_diff:%d baud:%d clk_rate:%d clk_div:%d\n",
			clk_freq_diff, baud, clk_rate, clk_div);

	uport->uartclk = clk_rate;
	clk_set_rate(port->serial_rsc.se_clk, clk_rate);