The branch main has been updated by jhibbits:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c583b02587285535d1af8691be2d83ac3916f083

commit c583b02587285535d1af8691be2d83ac3916f083
Author:     Brandon Bergren <[email protected]>
AuthorDate: 2021-12-23 21:45:24 +0000
Commit:     Justin Hibbits <[email protected]>
CommitDate: 2021-12-23 22:06:07 +0000

    [PowerPC] PowerMac timebase sync for G4
    
    Summary:
    Disable timebase on (some) AIM platforms (tested on PowerMac G4) prior
    to synchronization.
    
    Some platforms use a GPIO to enable and disable timebase, while others
    use a platform function.
    
    This mirrors 0d69f00b on mpc85xx.
    
    Todo:
     * Implement various G5 timebase controls.
     * Print out platform code on unknown G5s so we can collect it.
     * Change API to be give/take pairs like Linux does so it's possible to
       do a software sync protocol.
    
    Reviewed By: #powerpc, jhibbits
    Subscribers: mikael, markmi_dsl-only.net, luporl, alfredo
    Tags: #powerpc
    Differential Revision: https://reviews.freebsd.org/D29136
---
 sys/conf/files.powerpc                   |   1 +
 sys/powerpc/powermac/macio.c             |  42 +++++++++
 sys/powerpc/powermac/platform_powermac.c |  59 +++++++++++-
 sys/powerpc/powermac/platform_powermac.h |  34 +++++++
 sys/powerpc/powermac/tbgpio.c            | 148 +++++++++++++++++++++++++++++++
 5 files changed, 283 insertions(+), 1 deletion(-)

diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 25fdfea388b9..f904c17b2294 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -216,6 +216,7 @@ powerpc/powermac/pswitch.c  optional        powermac pswitch
 powerpc/powermac/pmu.c         optional        powermac pmu 
 powerpc/powermac/smu.c         optional        powermac smu 
 powerpc/powermac/smusat.c      optional        powermac smu
+powerpc/powermac/tbgpio.c      optional        powermac pci smp
 powerpc/powermac/uninorth.c    optional        powermac
 powerpc/powermac/uninorthpci.c optional        powermac pci
 powerpc/powermac/vcoregpio.c   optional        powermac 
diff --git a/sys/powerpc/powermac/macio.c b/sys/powerpc/powermac/macio.c
index b475277be816..3e5007973726 100644
--- a/sys/powerpc/powermac/macio.c
+++ b/sys/powerpc/powermac/macio.c
@@ -54,6 +54,7 @@
 #include <dev/ofw/openfirm.h>
 
 #include <powerpc/powermac/maciovar.h>
+#include <powerpc/powermac/platform_powermac.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
@@ -70,6 +71,9 @@ struct macio_softc {
        /* FCR registers */
        int          sc_memrid;
        struct resource *sc_memr;
+
+       /* GPIO offsets */
+       int          sc_timebase;
 };
 
 static MALLOC_DEFINE(M_MACIO, "macio", "macio device information");
@@ -89,6 +93,9 @@ static int  macio_release_resource(device_t, device_t, int, 
int,
                                   struct resource *);
 static struct resource_list *macio_get_resource_list (device_t, device_t);
 static ofw_bus_get_devinfo_t macio_get_devinfo;
+#if !defined(__powerpc64__) && defined(SMP)
+static void macio_freeze_timebase(device_t, bool);
+#endif
 
 /*
  * Bus interface definition
@@ -430,6 +437,26 @@ macio_attach(device_t dev)
                }
        }
 
+#if !defined(__powerpc64__) && defined(SMP)
+       /*
+        * Detect an SMP G4 machine.
+        *
+        * On SMP G4, timebase freeze is via a GPIO on macio.
+        *
+        * When we are on an SMP G4, we need to install a handler to
+        * perform timebase freeze/unfreeze on behalf of the platform.
+        */
+       if ((child = OF_finddevice("/cpus/PowerPC,G4@0")) != -1 &&
+           OF_peer(child) != -1) {
+               if (OF_getprop(child, "timebase-enable", &sc->sc_timebase,
+                   sizeof(sc->sc_timebase)) <= 0)
+                       sc->sc_timebase = KEYLARGO_GPIO_BASE + 0x09;
+               powermac_register_timebase(dev, macio_freeze_timebase);
+                device_printf(dev, "GPIO timebase control at 0x%x\n",
+                   sc->sc_timebase);
+       }
+#endif
+
        return (bus_generic_attach(dev));
 }
 
@@ -693,3 +720,18 @@ macio_enable_wireless(device_t dev, bool enable)
 
        return (0);
 }
+
+#if !defined(__powerpc64__) && defined(SMP)
+static void
+macio_freeze_timebase(device_t dev, bool freeze)
+{
+       struct macio_softc *sc = device_get_softc(dev);
+
+       if (freeze) {
+               bus_write_1(sc->sc_memr, sc->sc_timebase, 4);
+       } else {
+               bus_write_1(sc->sc_memr, sc->sc_timebase, 0);
+       }
+       bus_read_1(sc->sc_memr, sc->sc_timebase);
+}
+#endif
diff --git a/sys/powerpc/powermac/platform_powermac.c 
b/sys/powerpc/powermac/platform_powermac.c
index 7f78bc63c1ab..3e12a758d0b0 100644
--- a/sys/powerpc/powermac/platform_powermac.c
+++ b/sys/powerpc/powermac/platform_powermac.c
@@ -53,9 +53,15 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/openfirm.h>
 #include <machine/ofw_machdep.h>
 
+#include <powerpc/powermac/platform_powermac.h>
+
 #include "platform_if.h"
 
-extern void *ap_pcpu;
+extern volatile void *ap_pcpu;
+
+static void dummy_timebase(device_t, bool);
+static device_t powermac_tb_dev;
+static void (*freeze_timebase)(device_t, bool) = dummy_timebase;
 
 static int powermac_probe(platform_t);
 static int powermac_attach(platform_t);
@@ -395,11 +401,62 @@ powermac_smp_start_cpu(platform_t plat, struct pcpu *pc)
 #endif
 }
 
+void
+powermac_register_timebase(device_t dev, powermac_tb_disable_t cb)
+{
+       powermac_tb_dev = dev;
+       freeze_timebase = cb;
+}
+
 static void
 powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
 {
+       static volatile bool tb_ready;
+       static volatile int cpu_done;
 
+       /*
+        * XXX Temporary fallback for platforms we don't know how to freeze.
+        *
+        * This needs to be replaced with a cpu-to-cpu software sync
+        * protocol, because this is not a consistent way to sync timebase.
+        */
        mttb(tb);
+       if (freeze_timebase == dummy_timebase)
+               return;
+
+       if (ap) {
+               /* APs.  Hold off until we get a stable timebase. */
+               critical_enter();
+               while (!tb_ready)
+                       atomic_thread_fence_seq_cst();
+               mttb(tb);
+               atomic_add_int(&cpu_done, 1);
+               while (cpu_done < mp_ncpus)
+                       atomic_thread_fence_seq_cst();
+               critical_exit();
+       } else {
+               /* BSP */
+               critical_enter();
+               /* Ensure cpu_done is zeroed so we can resync at runtime */
+               atomic_set_int(&cpu_done, 0);
+               freeze_timebase(powermac_tb_dev, true);
+               tb_ready = true;
+               mttb(tb);
+               atomic_add_int(&cpu_done, 1);
+               while (cpu_done < mp_ncpus)
+                       atomic_thread_fence_seq_cst();
+               freeze_timebase(powermac_tb_dev, false);
+               /* Reset tb_ready so we can resync at runtime */
+               tb_ready = false;
+               critical_exit();
+       }
+}
+
+/* Fallback freeze. In case no real handler is found in the device tree. */
+static void
+dummy_timebase(device_t dev, bool freeze)
+{
+       /* Nothing to do here, move along. */
 }
 
 static void
diff --git a/sys/powerpc/powermac/platform_powermac.h 
b/sys/powerpc/powermac/platform_powermac.h
new file mode 100644
index 000000000000..3a85d12feea2
--- /dev/null
+++ b/sys/powerpc/powermac/platform_powermac.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Brandon Bergren <[email protected]>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#ifndef _PLATFORM_POWERMAC_H_
+#define _PLATFORM_POWERMAC_H_
+
+typedef void (*powermac_tb_disable_t)(device_t, bool);
+extern void powermac_register_timebase(device_t, powermac_tb_disable_t);
+
+#endif /* _PLATFORM_POWERMAC_H_ */
diff --git a/sys/powerpc/powermac/tbgpio.c b/sys/powerpc/powermac/tbgpio.c
new file mode 100644
index 000000000000..348a8d26b688
--- /dev/null
+++ b/sys/powerpc/powermac/tbgpio.c
@@ -0,0 +1,148 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Brandon Bergren <[email protected]>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/openfirm.h>
+
+#include <powerpc/powermac/macgpiovar.h>
+#include <powerpc/powermac/platform_powermac.h>
+
+static int     tbgpio_probe(device_t);
+static int     tbgpio_attach(device_t);
+static void    tbgpio_freeze_timebase(device_t, bool);
+
+static device_method_t tbgpio_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         tbgpio_probe),
+       DEVMETHOD(device_attach,        tbgpio_attach),
+       DEVMETHOD_END
+};
+
+struct tbgpio_softc {
+       uint32_t        sc_value;
+       uint32_t        sc_mask;
+};
+
+static driver_t tbgpio_driver = {
+       "tbgpio",
+       tbgpio_methods,
+       sizeof(struct tbgpio_softc)
+};
+
+static devclass_t tbgpio_devclass;
+
+EARLY_DRIVER_MODULE(tbgpio, macgpio, tbgpio_driver, tbgpio_devclass, 0, 0,
+    BUS_PASS_CPU);
+
+static int
+tbgpio_probe(device_t dev)
+{
+       phandle_t node;
+       const char *name;
+       pcell_t pfunc[32];
+       int res;
+
+       name = ofw_bus_get_name(dev);
+       node = ofw_bus_get_node(dev);
+
+       if (strcmp(name, "timebase-enable") != 0)
+               return (ENXIO);
+
+       res = OF_getencprop(node, "platform-do-cpu-timebase", pfunc,
+           sizeof(pfunc));
+       if (res == -1)
+               return (ENXIO);
+
+       /*
+        * If this doesn't look like a simple gpio_write pfunc,
+        * complain about it so we can collect the pfunc.
+        */
+       if (res != 20 || pfunc[2] != 0x01) {
+               printf("\nUnknown platform function detected!\n");
+               printf("Please send a PR including the following data:\n");
+               printf("===================\n");
+               printf("Func: platform-do-cpu-timebase\n");
+               hexdump(pfunc, res, NULL, HD_OMIT_CHARS);
+               printf("===================\n");
+               return (ENXIO);
+       }
+
+       device_set_desc(dev, "CPU Timebase Control");
+       return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+tbgpio_attach(device_t dev)
+{
+       phandle_t node;
+       struct tbgpio_softc *sc;
+
+       /*
+        * Structure of pfunc:
+        * pfunc[0]: phandle to /cpus
+        * pfunc[1]: flags
+        * pfunc[2]: 0x1 == CMD_WRITE_GPIO
+        * pfunc[3]: value
+        * pfunc[4]: mask
+        */
+       pcell_t pfunc[5];
+
+       sc = device_get_softc(dev);
+       node = ofw_bus_get_node(dev);
+
+       OF_getencprop(node, "platform-do-cpu-timebase", pfunc, sizeof(pfunc));
+
+       sc->sc_value = pfunc[3];
+       sc->sc_mask = pfunc[4];
+
+       powermac_register_timebase(dev, tbgpio_freeze_timebase);
+       return (0);
+}
+
+static void
+tbgpio_freeze_timebase(device_t dev, bool freeze)
+{
+       struct tbgpio_softc *sc;
+       uint32_t val;
+
+       sc = device_get_softc(dev);
+
+       val = sc->sc_value;
+       if (freeze)
+               val = ~val;
+       val &= sc->sc_mask;
+
+       macgpio_write(dev, val);
+}

Reply via email to