From nobody Mon Feb 9 13:03:00 2026 Received: from fllvem-ot04.ext.ti.com (fllvem-ot04.ext.ti.com [198.47.19.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF56619D06B; Thu, 1 May 2025 00:31:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746059483; cv=none; b=lijnZKfI2Pv4Dq9MmoF4QmOUC9KTu3bcJiE3f7u78eELnn11zBkglrmnST44YCKw3XT6L2OFN7/h3URHdehgpd2piieN0Xcf6KR7eUhwyC3erkotxyxlHlUpiDGUb1YmV2+asUTL4kcJvvbZXHKHOjOgfRbX8VuXnogje1j3HGM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746059483; c=relaxed/simple; bh=LvanHOPyM2JN7bhHF59iVdTrLY3ZOqVzlIGEaj8SM4s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JaW/R2NB0Q3lz56+kVGiozn0K7e0y7xoUBBOQjnkdqC3+LDeUn6eivFxpwizJAsS9u35hY2h3rtu0NTXLIX0iKBxdSkvdqChPpkn0zmZtgSZgJ4SyJLDsOss5d8ic7KI8W+0qnzXYEssZtspZKhCZukGf1CqeSLo9/RAY7+mYyI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=VRxfAR7R; arc=none smtp.client-ip=198.47.19.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="VRxfAR7R" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllvem-ot04.ext.ti.com (8.15.2/8.15.2) with ESMTPS id 5410VDOd4105596 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 30 Apr 2025 19:31:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1746059474; bh=OBSTd4za5cq8I9nRIjd/m7xslvR8Qwnvh95KzZ9t7vA=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=VRxfAR7RygfuJT2AVVi+pcXnzOKskG+YmM7y+N9BgFyVVc40pqBf6tu3x7DGEP7A8 PiwAkv0YL7LpOaRNwOQ6pIQldKwgcRo4C3k3Ek9IMKOBFcLBPwv446qxlKT6cskj5q fyp7s5v4BFy9csEpU6CzJRuzfkGIPup6v0BMnTQ0= Received: from DLEE103.ent.ti.com (dlee103.ent.ti.com [157.170.170.33]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 5410VDAE109460 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 30 Apr 2025 19:31:13 -0500 Received: from DLEE112.ent.ti.com (157.170.170.23) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 30 Apr 2025 19:31:13 -0500 Received: from lelvsmtp5.itg.ti.com (10.180.75.250) by DLEE112.ent.ti.com (157.170.170.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 30 Apr 2025 19:31:13 -0500 Received: from judy-hp.dhcp.ti.com (judy-hp.dhcp.ti.com [128.247.81.105]) by lelvsmtp5.itg.ti.com (8.15.2/8.15.2) with ESMTP id 5410VDaE044266; Wed, 30 Apr 2025 19:31:13 -0500 From: Judith Mendez To: Judith Mendez , Greg Kroah-Hartman , Kevin Hilman CC: Jiri Slaby , Andy Shevchenko , , , Hari Nagalla Subject: [PATCH RFC 2/2] serial: 8250: Add PRUSS UART driver Date: Wed, 30 Apr 2025 19:31:13 -0500 Message-ID: <20250501003113.1609342-3-jm@ti.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250501003113.1609342-1-jm@ti.com> References: <20250501003113.1609342-1-jm@ti.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea Content-Type: text/plain; charset="utf-8" From: Bin Liu This adds a new serial 8250 driver that supports the UART in PRUSS module. The PRUSS has a UART sub-module which is based on the industry standard TL16C550 UART controller, which has 16-bytes FIFO and supports 16x and 13x over samplings. Signed-off-by: Bin Liu Signed-off-by: Judith Mendez --- drivers/tty/serial/8250/8250_pruss.c | 213 +++++++++++++++++++++++++++ drivers/tty/serial/8250/Kconfig | 10 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 224 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_pruss.c diff --git a/drivers/tty/serial/8250/8250_pruss.c b/drivers/tty/serial/8250= /8250_pruss.c new file mode 100644 index 000000000000..2943bf7d6645 --- /dev/null +++ b/drivers/tty/serial/8250/8250_pruss.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Serial Port driver for PRUSS UART on TI platforms + * + * Copyright (C) 2020-2021 by Texas Instruments Incorporated - http://www= .ti.com/ + * Author: Bin Liu + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "8250.h" + +#define DEFAULT_CLK_SPEED 192000000 + +/* extra registers */ +#define PRUSS_UART_PEREMU_MGMT 12 +#define PRUSS_UART_TX_EN BIT(14) +#define PRUSS_UART_RX_EN BIT(13) +#define PRUSS_UART_FREE_RUN BIT(0) + +#define PRUSS_UART_MDR 13 +#define PRUSS_UART_MDR_OSM_SEL_MASK BIT(0) +#define PRUSS_UART_MDR_16X_MODE 0 +#define PRUSS_UART_MDR_13X_MODE 1 + +struct pruss8250_info { + int type; + int line; +}; + +static inline void uart_writel(struct uart_port *p, u32 offset, int value) +{ + writel(value, p->membase + (offset << p->regshift)); +} + +static int pruss8250_startup(struct uart_port *port) +{ + int ret; + + uart_writel(port, PRUSS_UART_PEREMU_MGMT, 0); + + ret =3D serial8250_do_startup(port); + if (!ret) + uart_writel(port, PRUSS_UART_PEREMU_MGMT, PRUSS_UART_TX_EN | + PRUSS_UART_RX_EN | + PRUSS_UART_FREE_RUN); + return ret; +} + +static unsigned int pruss8250_get_divisor(struct uart_port *port, + unsigned int baud, + unsigned int *frac) +{ + unsigned int uartclk =3D port->uartclk; + unsigned int div_13, div_16; + unsigned int abs_d13, abs_d16; + u16 quot; + + /* Old custom speed handling */ + if (baud =3D=3D 38400 && (port->flags & UPF_SPD_MASK) =3D=3D UPF_SPD_CUST= ) { + quot =3D port->custom_divisor & UART_DIV_MAX; + if (port->custom_divisor & (1 << 16)) + *frac =3D PRUSS_UART_MDR_13X_MODE; + else + *frac =3D PRUSS_UART_MDR_16X_MODE; + + return quot; + } + + div_13 =3D DIV_ROUND_CLOSEST(uartclk, 13 * baud); + div_16 =3D DIV_ROUND_CLOSEST(uartclk, 16 * baud); + div_13 =3D div_13 ? : 1; + div_16 =3D div_16 ? : 1; + + abs_d13 =3D abs(baud - uartclk / 13 / div_13); + abs_d16 =3D abs(baud - uartclk / 16 / div_16); + + if (abs_d13 >=3D abs_d16) { + *frac =3D PRUSS_UART_MDR_16X_MODE; + quot =3D div_16; + } else { + *frac =3D PRUSS_UART_MDR_13X_MODE; + quot =3D div_13; + } + + return quot; +} + +static void pruss8250_set_divisor(struct uart_port *port, unsigned int bau= d, + unsigned int quot, unsigned int quot_frac) +{ + serial8250_do_set_divisor(port, baud, quot); + /* + * quot_frac holds the MDR over-sampling mode + * which is set in pruss8250_get_divisor() + */ + quot_frac &=3D PRUSS_UART_MDR_OSM_SEL_MASK; + serial_port_out(port, PRUSS_UART_MDR, quot_frac); +} + +static int pruss8250_probe(struct platform_device *pdev) +{ + struct device_node *np =3D pdev->dev.of_node; + struct uart_8250_port port8250; + struct uart_port *up =3D &port8250.port; + struct pruss8250_info *info; + struct resource resource; + unsigned int port_type; + struct clk *clk; + int ret; + + port_type =3D (unsigned long)of_device_get_match_data(&pdev->dev); + if (port_type =3D=3D PORT_UNKNOWN) + return -EINVAL; + + info =3D devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(&port8250, 0, sizeof(port8250)); + + ret =3D of_address_to_resource(np, 0, &resource); + if (ret) { + dev_err(&pdev->dev, "invalid address\n"); + return ret; + } + + ret =3D of_alias_get_id(np, "serial"); + if (ret > 0) + up->line =3D ret; + + clk =3D devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) =3D=3D -EPROBE_DEFER) + return -EPROBE_DEFER; + up->uartclk =3D DEFAULT_CLK_SPEED; + } else { + up->uartclk =3D clk_get_rate(clk); + devm_clk_put(&pdev->dev, clk); + } + + up->dev =3D &pdev->dev; + up->mapbase =3D resource.start; + up->mapsize =3D resource_size(&resource); + up->type =3D port_type; + up->iotype =3D UPIO_MEM; + up->regshift =3D 2; + up->flags =3D UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | + UPF_FIXED_TYPE | UPF_IOREMAP; + up->irqflags |=3D IRQF_SHARED; + up->startup =3D pruss8250_startup; + up->rs485_config =3D serial8250_em485_config; + up->get_divisor =3D pruss8250_get_divisor; + up->set_divisor =3D pruss8250_set_divisor; + + ret =3D of_irq_get(np, 0); + if (ret < 0) { + if (ret !=3D -EPROBE_DEFER) + dev_err(&pdev->dev, "missing irq\n"); + return ret; + } + + up->irq =3D ret; + spin_lock_init(&port8250.port.lock); + port8250.capabilities =3D UART_CAP_FIFO | UART_CAP_AFE; + + ret =3D serial8250_register_8250_port(&port8250); + if (ret < 0) + goto err_dispose; + + info->type =3D port_type; + info->line =3D ret; + platform_set_drvdata(pdev, info); + + return 0; + +err_dispose: + irq_dispose_mapping(port8250.port.irq); + return ret; +} + +static void pruss8250_remove(struct platform_device *pdev) +{ + struct pruss8250_info *info =3D platform_get_drvdata(pdev); + + serial8250_unregister_port(info->line); +} + +static const struct of_device_id pruss8250_table[] =3D { + { .compatible =3D "ti,pruss-uart", .data =3D (void *)PORT_16550A, }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, pruss8250_table); + +static struct platform_driver pruss8250_driver =3D { + .driver =3D { + .name =3D "pruss8250", + .of_match_table =3D pruss8250_table, + }, + .probe =3D pruss8250_probe, + .remove =3D pruss8250_remove, +}; + +module_platform_driver(pruss8250_driver); + +MODULE_AUTHOR("Bin Liu