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 <m...@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 <jmcne...@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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to