Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Apr 2016 20:26:46 +0000 (UTC)
From:      Jared McNeill <jmcneill@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297496 - in head/sys: arm/conf arm/mv conf dev/uart
Message-ID:  <201604012026.u31KQkRG087006@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmcneill
Date: Fri Apr  1 20:26:45 2016
New Revision: 297496
URL: https://svnweb.freebsd.org/changeset/base/297496

Log:
  Move support for Synopsys Designware APB UART out of ns8250 and into a
  separate driver. Add support for activating clock and hwreset resources
  for these devices when the EXT_RESOURCES option is present.
  
  Reviewed by:		andrew, mmel, Emmanuel Vadot <manu@bidouilliste.com>
  Approved by:		adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D5749

Added:
  head/sys/dev/uart/uart_dev_snps.c   (contents, props changed)
Modified:
  head/sys/arm/conf/A10
  head/sys/arm/conf/A20
  head/sys/arm/conf/ARMADA38X
  head/sys/arm/conf/RK3188
  head/sys/arm/mv/files.mv
  head/sys/conf/files
  head/sys/dev/uart/uart_dev_ns8250.c

Modified: head/sys/arm/conf/A10
==============================================================================
--- head/sys/arm/conf/A10	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/arm/conf/A10	Fri Apr  1 20:26:45 2016	(r297496)
@@ -61,7 +61,7 @@ device		ahci			# AHCI-compatible SATA co
 
 # Console and misc
 device		uart
-device		uart_ns8250
+device		uart_snps
 device		pty
 device		snp
 device		md

Modified: head/sys/arm/conf/A20
==============================================================================
--- head/sys/arm/conf/A20	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/arm/conf/A20	Fri Apr  1 20:26:45 2016	(r297496)
@@ -71,7 +71,7 @@ device		ahci			# AHCI-compatible SATA co
 
 # Console and misc
 device		uart
-device		uart_ns8250
+device		uart_snps
 device		pty
 device		snp
 device		md

Modified: head/sys/arm/conf/ARMADA38X
==============================================================================
--- head/sys/arm/conf/ARMADA38X	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/arm/conf/ARMADA38X	Fri Apr  1 20:26:45 2016	(r297496)
@@ -48,7 +48,7 @@ device		md
 
 # Serial ports
 device		uart
-device		uart_ns8250
+device		uart_snps
 
 # Network
 device		ether

Modified: head/sys/arm/conf/RK3188
==============================================================================
--- head/sys/arm/conf/RK3188	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/arm/conf/RK3188	Fri Apr  1 20:26:45 2016	(r297496)
@@ -59,7 +59,7 @@ device		dwmmc
 
 # Console and misc
 device		uart
-device		uart_ns8250
+device		uart_snps
 device		pty
 device		snp
 device		md

Modified: head/sys/arm/mv/files.mv
==============================================================================
--- head/sys/arm/mv/files.mv	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/arm/mv/files.mv	Fri Apr  1 20:26:45 2016	(r297496)
@@ -26,6 +26,7 @@ dev/mge/if_mge.c		optional	mge
 dev/nand/nfc_mv.c		optional	nand
 dev/mvs/mvs_soc.c		optional	mvs
 dev/uart/uart_dev_ns8250.c	optional	uart
+dev/uart/uart_dev_snps.c	optional	uart
 dev/usb/controller/ehci_mv.c	optional	ehci
 dev/usb/controller/xhci_mv.c	optional	xhci
 

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/conf/files	Fri Apr  1 20:26:45 2016	(r297496)
@@ -2555,11 +2555,12 @@ dev/uart/uart_bus_puc.c		optional uart p
 dev/uart/uart_bus_scc.c		optional uart scc
 dev/uart/uart_core.c		optional uart
 dev/uart/uart_dbg.c		optional uart gdb
-dev/uart/uart_dev_ns8250.c	optional uart uart_ns8250
+dev/uart/uart_dev_ns8250.c	optional uart uart_ns8250 | uart uart_snps
 dev/uart/uart_dev_pl011.c	optional uart pl011
 dev/uart/uart_dev_quicc.c	optional uart quicc
 dev/uart/uart_dev_sab82532.c	optional uart uart_sab82532
 dev/uart/uart_dev_sab82532.c	optional uart scc
+dev/uart/uart_dev_snps.c	optional uart uart_snps
 dev/uart/uart_dev_z8530.c	optional uart uart_z8530
 dev/uart/uart_dev_z8530.c	optional uart scc
 dev/uart/uart_if.m		optional uart

Modified: head/sys/dev/uart/uart_dev_ns8250.c
==============================================================================
--- head/sys/dev/uart/uart_dev_ns8250.c	Fri Apr  1 18:45:04 2016	(r297495)
+++ head/sys/dev/uart/uart_dev_ns8250.c	Fri Apr  1 20:26:45 2016	(r297496)
@@ -398,7 +398,6 @@ struct uart_class uart_ns8250_class = {
 static struct ofw_compat_data compat_data[] = {
 	{"ns16550",		(uintptr_t)&uart_ns8250_class},
 	{"ns16550a",		(uintptr_t)&uart_ns8250_class},
-	{"snps,dw-apb-uart",	(uintptr_t)&uart_ns8250_class},
 	{NULL,			(uintptr_t)NULL},
 };
 UART_FDT_CLASS_AND_DEVICE(compat_data);
@@ -451,19 +450,9 @@ ns8250_bus_attach(struct uart_softc *sc)
 	pcell_t cell;
 #endif
 
-	ns8250->busy_detect = 0;
-
 #ifdef FDT
-	/* 
-	 * Check whether uart requires to read USR reg when IIR_BUSY and 
-	 * has broken txfifo. 
-	 */
-	ns8250->busy_detect = ofw_bus_is_compatible(sc->sc_dev, "snps,dw-apb-uart");
+	/* Check whether uart has a broken txfifo. */
 	node = ofw_bus_get_node(sc->sc_dev);
-	/* XXX: This is kept for a short time for compatibility with older device trees */
-	if ((OF_getencprop(node, "busy-detect", &cell, sizeof(cell))) > 0
-	    && cell != 0)
-		ns8250->busy_detect = 1;
 	if ((OF_getencprop(node, "broken-txfifo", &cell, sizeof(cell))) > 0)
 		broken_txfifo =  cell ? 1 : 0;
 #endif

Added: head/sys/dev/uart/uart_dev_snps.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/uart/uart_dev_snps.c	Fri Apr  1 20:26:45 2016	(r297496)
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu_fdt.h>
+#include <dev/uart/uart_dev_ns8250.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#endif
+
+#include "uart_if.h"
+
+struct snps_softc {
+	struct ns8250_softc	ns8250;
+
+#ifdef EXT_RESOURCES
+	clk_t			baudclk;
+	clk_t			apb_pclk;
+	hwreset_t		reset;
+#endif
+};
+
+static int
+snps_uart_attach(struct uart_softc *uart_sc)
+{
+	struct snps_softc *sc;
+
+	sc = (struct snps_softc *)uart_sc;
+
+	/* UART requires to read USR reg when IIR_BUSY */
+	sc->ns8250.busy_detect = 1;
+
+	return (ns8250_bus_attach(uart_sc));
+}
+
+static kobj_method_t snps_methods[] = {
+	KOBJMETHOD(uart_probe,		ns8250_bus_probe),
+	KOBJMETHOD(uart_attach,		snps_uart_attach),
+	KOBJMETHOD(uart_detach,		ns8250_bus_detach),
+	KOBJMETHOD(uart_flush,		ns8250_bus_flush),
+	KOBJMETHOD(uart_getsig,		ns8250_bus_getsig),
+	KOBJMETHOD(uart_ioctl,		ns8250_bus_ioctl),
+	KOBJMETHOD(uart_ipend,		ns8250_bus_ipend),
+	KOBJMETHOD(uart_param,		ns8250_bus_param),
+	KOBJMETHOD(uart_receive,	ns8250_bus_receive),
+	KOBJMETHOD(uart_setsig,		ns8250_bus_setsig),
+	KOBJMETHOD(uart_transmit,	ns8250_bus_transmit),
+	KOBJMETHOD(uart_grab,		ns8250_bus_grab),
+	KOBJMETHOD(uart_ungrab,		ns8250_bus_ungrab),
+	KOBJMETHOD_END
+};
+
+struct uart_class uart_snps_class = {
+	"snps",
+	snps_methods,
+	sizeof(struct snps_softc),
+	.uc_ops = &uart_ns8250_ops,
+	.uc_range = 8,
+	.uc_rclk = 0,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "snps,dw-apb-uart",		(uintptr_t)&uart_snps_class },
+	{ NULL,				(uintptr_t)NULL }
+};
+UART_FDT_CLASS(compat_data);
+
+#ifdef EXT_RESOURCES
+static int
+snps_get_clocks(device_t dev, clk_t *baudclk, clk_t *apb_pclk)
+{
+	struct snps_softc *sc;
+
+	sc = device_get_softc(dev);
+	*baudclk = NULL;
+	*apb_pclk = NULL;
+
+	/* Baud clock is either named "baudclk", or there is a single
+	 * unnamed clock.
+	 */
+	if (clk_get_by_ofw_name(dev, "baudclk", baudclk) != 0 &&
+	    clk_get_by_ofw_index(dev, 0, baudclk) != 0)
+		return (ENOENT);
+
+	/* APB peripheral clock is optional */
+	(void)clk_get_by_ofw_name(dev, "apb_pclk", apb_pclk);
+
+	return (0);
+}
+#endif
+
+static int
+snps_probe(device_t dev)
+{
+	struct snps_softc *sc;
+	struct uart_class *uart_class;
+	phandle_t node;
+	uint32_t shift, clock;
+	uint64_t freq;
+	int error;
+#ifdef EXT_RESOURCES
+	clk_t baudclk, apb_pclk;
+	hwreset_t reset;
+#endif
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	uart_class = (struct uart_class *)ofw_bus_search_compatible(dev,
+	    compat_data)->ocd_data;
+	if (uart_class == NULL)
+		return (ENXIO);
+
+	freq = 0;
+	sc = device_get_softc(dev);
+	sc->ns8250.base.sc_class = uart_class;
+
+	node = ofw_bus_get_node(dev);
+	if (OF_getencprop(node, "reg-shift", &shift, sizeof(shift)) <= 0)
+		shift = 0;
+	if (OF_getencprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0)
+		clock = 0;
+
+#ifdef EXT_RESOURCES
+	if (hwreset_get_by_ofw_idx(dev, 0, &reset) == 0) {
+		error = hwreset_deassert(reset);
+		if (error != 0) {
+			device_printf(dev, "cannot de-assert reset\n");
+			return (error);
+		}
+	}
+
+	if (snps_get_clocks(dev, &baudclk, &apb_pclk) == 0) {
+		error = clk_enable(baudclk);
+		if (error != 0) {
+			device_printf(dev, "cannot enable baud clock\n");
+			return (error);
+		}
+		if (apb_pclk != NULL) {
+			error = clk_enable(apb_pclk);
+			if (error != 0) {
+				device_printf(dev,
+				    "cannot enable peripheral clock\n");
+				return (error);
+			}
+		}
+
+		if (clock == 0) {
+			error = clk_get_freq(baudclk, &freq);
+			if (error != 0) {
+				device_printf(dev, "cannot get frequency\n");
+				return (error);
+			}
+			clock = (uint32_t)freq;
+		}
+	}
+#endif
+
+	if (bootverbose && clock == 0)
+		device_printf(dev, "could not determine frequency\n");
+
+	error = uart_bus_probe(dev, (int)shift, (int)clock, 0, 0);
+	if (error != 0)
+		return (error);
+
+#ifdef EXT_RESOURCES
+	/* XXX uart_bus_probe has changed the softc, so refresh it */
+	sc = device_get_softc(dev);
+
+	/* Store clock and reset handles for detach */
+	sc->baudclk = baudclk;
+	sc->apb_pclk = apb_pclk;
+	sc->reset = reset;
+#endif
+
+	return (0);
+}
+
+static int
+snps_detach(device_t dev)
+{
+#ifdef EXT_RESOURCES
+	struct snps_softc *sc;
+	clk_t baudclk, apb_pclk;
+	hwreset_t reset;
+#endif
+	int error;
+
+#ifdef EXT_RESOURCES
+	sc = device_get_softc(dev);
+	baudclk = sc->baudclk;
+	apb_pclk = sc->apb_pclk;
+	reset = sc->reset;
+#endif
+
+	error = uart_bus_detach(dev);
+	if (error != 0)
+		return (error);
+
+#ifdef EXT_RESOURCES
+	if (reset != NULL) {
+		error = hwreset_assert(reset);
+		if (error != 0) {
+			device_printf(dev, "cannot assert reset\n");
+			return (error);
+		}
+		hwreset_release(reset);
+	}
+	if (apb_pclk != NULL) {
+		error = clk_release(apb_pclk);
+		if (error != 0) {
+			device_printf(dev, "cannot release peripheral clock\n");
+			return (error);
+		}
+	}
+	if (baudclk != NULL) {
+		error = clk_release(baudclk);
+		if (error != 0) {
+			device_printf(dev, "cannot release baud clock\n");
+			return (error);
+		}
+	}
+#endif
+
+	return (0);
+}
+
+static device_method_t snps_bus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		snps_probe),
+	DEVMETHOD(device_attach,	uart_bus_attach),
+	DEVMETHOD(device_detach, 	snps_detach),
+	DEVMETHOD_END
+};
+
+static driver_t snps_uart_driver = {
+	uart_driver_name,
+	snps_bus_methods,
+	sizeof(struct snps_softc)
+};
+
+DRIVER_MODULE(uart_snps, simplebus, snps_uart_driver, uart_devclass, 0, 0);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604012026.u31KQkRG087006>