/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2021 Brandon Bergren <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/cdefs.h>2829#include <sys/param.h>30#include <sys/systm.h>31#include <sys/kernel.h>32#include <sys/module.h>33#include <sys/bus.h>3435#include <dev/ofw/ofw_bus.h>36#include <dev/ofw/openfirm.h>3738#include <powerpc/powermac/macgpiovar.h>39#include <powerpc/powermac/platform_powermac.h>4041static int tbgpio_probe(device_t);42static int tbgpio_attach(device_t);43static void tbgpio_freeze_timebase(device_t, bool);4445static device_method_t tbgpio_methods[] = {46/* Device interface */47DEVMETHOD(device_probe, tbgpio_probe),48DEVMETHOD(device_attach, tbgpio_attach),49DEVMETHOD_END50};5152struct tbgpio_softc {53uint32_t sc_value;54uint32_t sc_mask;55};5657static driver_t tbgpio_driver = {58"tbgpio",59tbgpio_methods,60sizeof(struct tbgpio_softc)61};6263EARLY_DRIVER_MODULE(tbgpio, macgpio, tbgpio_driver, 0, 0, BUS_PASS_CPU);6465static int66tbgpio_probe(device_t dev)67{68phandle_t node;69const char *name;70pcell_t pfunc[32];71int res;7273name = ofw_bus_get_name(dev);74node = ofw_bus_get_node(dev);7576if (strcmp(name, "timebase-enable") != 0)77return (ENXIO);7879res = OF_getencprop(node, "platform-do-cpu-timebase", pfunc,80sizeof(pfunc));81if (res == -1)82return (ENXIO);8384/*85* If this doesn't look like a simple gpio_write pfunc,86* complain about it so we can collect the pfunc.87*/88if (res != 20 || pfunc[2] != 0x01) {89printf("\nUnknown platform function detected!\n");90printf("Please send a PR including the following data:\n");91printf("===================\n");92printf("Func: platform-do-cpu-timebase\n");93hexdump(pfunc, res, NULL, HD_OMIT_CHARS);94printf("===================\n");95return (ENXIO);96}9798device_set_desc(dev, "CPU Timebase Control");99return (BUS_PROBE_SPECIFIC);100}101102static int103tbgpio_attach(device_t dev)104{105phandle_t node;106struct tbgpio_softc *sc;107108/*109* Structure of pfunc:110* pfunc[0]: phandle to /cpus111* pfunc[1]: flags112* pfunc[2]: 0x1 == CMD_WRITE_GPIO113* pfunc[3]: value114* pfunc[4]: mask115*/116pcell_t pfunc[5];117118sc = device_get_softc(dev);119node = ofw_bus_get_node(dev);120121OF_getencprop(node, "platform-do-cpu-timebase", pfunc, sizeof(pfunc));122123sc->sc_value = pfunc[3];124sc->sc_mask = pfunc[4];125126powermac_register_timebase(dev, tbgpio_freeze_timebase);127return (0);128}129130static void131tbgpio_freeze_timebase(device_t dev, bool freeze)132{133struct tbgpio_softc *sc;134uint32_t val;135136sc = device_get_softc(dev);137138val = sc->sc_value;139if (freeze)140val = ~val;141val &= sc->sc_mask;142143macgpio_write(dev, val);144}145146147