root/sys/dev/clk/xilinx/zynqmp_reset.c
/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
 *
 * 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/malloc.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <machine/bus.h>

#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>

#include <dev/hwreset/hwreset.h>

#include <dev/firmware/xilinx/pm_defs.h>

#include "hwreset_if.h"
#include "zynqmp_firmware_if.h"

#define ZYNQMP_RESET_PCIE_CFG           0
#define ZYNQMP_RESET_PCIE_BRIDGE        1
#define ZYNQMP_RESET_PCIE_CTRL          2
#define ZYNQMP_RESET_DP                 3
#define ZYNQMP_RESET_SWDT_CRF           4
#define ZYNQMP_RESET_AFI_FM5            5
#define ZYNQMP_RESET_AFI_FM4            6
#define ZYNQMP_RESET_AFI_FM3            7
#define ZYNQMP_RESET_AFI_FM2            8
#define ZYNQMP_RESET_AFI_FM1            9
#define ZYNQMP_RESET_AFI_FM0            10
#define ZYNQMP_RESET_GDMA               11
#define ZYNQMP_RESET_GPU_PP1            12
#define ZYNQMP_RESET_GPU_PP0            13
#define ZYNQMP_RESET_GPU                14
#define ZYNQMP_RESET_GT                 15
#define ZYNQMP_RESET_SATA               16
#define ZYNQMP_RESET_ACPU3_PWRON        17
#define ZYNQMP_RESET_ACPU2_PWRON        18
#define ZYNQMP_RESET_ACPU1_PWRON        19
#define ZYNQMP_RESET_ACPU0_PWRON        20
#define ZYNQMP_RESET_APU_L2             21
#define ZYNQMP_RESET_ACPU3              22
#define ZYNQMP_RESET_ACPU2              23
#define ZYNQMP_RESET_ACPU1              24
#define ZYNQMP_RESET_ACPU0              25
#define ZYNQMP_RESET_DDR                26
#define ZYNQMP_RESET_APM_FPD            27
#define ZYNQMP_RESET_SOFT               28
#define ZYNQMP_RESET_GEM0               29
#define ZYNQMP_RESET_GEM1               30
#define ZYNQMP_RESET_GEM2               31
#define ZYNQMP_RESET_GEM3               32
#define ZYNQMP_RESET_QSPI               33
#define ZYNQMP_RESET_UART0              34
#define ZYNQMP_RESET_UART1              35
#define ZYNQMP_RESET_SPI0               36
#define ZYNQMP_RESET_SPI1               37
#define ZYNQMP_RESET_SDIO0              38
#define ZYNQMP_RESET_SDIO1              39
#define ZYNQMP_RESET_CAN0               40
#define ZYNQMP_RESET_CAN1               41
#define ZYNQMP_RESET_I2C0               42
#define ZYNQMP_RESET_I2C1               43
#define ZYNQMP_RESET_TTC0               44
#define ZYNQMP_RESET_TTC1               45
#define ZYNQMP_RESET_TTC2               46
#define ZYNQMP_RESET_TTC3               47
#define ZYNQMP_RESET_SWDT_CRL           48
#define ZYNQMP_RESET_NAND               49
#define ZYNQMP_RESET_ADMA               50
#define ZYNQMP_RESET_GPIO               51
#define ZYNQMP_RESET_IOU_CC             52
#define ZYNQMP_RESET_TIMESTAMP          53
#define ZYNQMP_RESET_RPU_R50            54
#define ZYNQMP_RESET_RPU_R51            55
#define ZYNQMP_RESET_RPU_AMBA           56
#define ZYNQMP_RESET_OCM                57
#define ZYNQMP_RESET_RPU_PGE            58
#define ZYNQMP_RESET_USB0_CORERESET     59
#define ZYNQMP_RESET_USB1_CORERESET     60
#define ZYNQMP_RESET_USB0_HIBERRESET    61
#define ZYNQMP_RESET_USB1_HIBERRESET    62
#define ZYNQMP_RESET_USB0_APB           63
#define ZYNQMP_RESET_USB1_APB           64
#define ZYNQMP_RESET_IPI                65
#define ZYNQMP_RESET_APM_LPD            66
#define ZYNQMP_RESET_RTC                67
#define ZYNQMP_RESET_SYSMON             68
#define ZYNQMP_RESET_AFI_FM6            69
#define ZYNQMP_RESET_LPD_SWDT           70
#define ZYNQMP_RESET_FPD                71
#define ZYNQMP_RESET_RPU_DBG1           72
#define ZYNQMP_RESET_RPU_DBG0           73
#define ZYNQMP_RESET_DBG_LPD            74
#define ZYNQMP_RESET_DBG_FPD            75
#define ZYNQMP_RESET_APLL               76
#define ZYNQMP_RESET_DPLL               77
#define ZYNQMP_RESET_VPLL               78
#define ZYNQMP_RESET_IOPLL              79
#define ZYNQMP_RESET_RPLL               80
#define ZYNQMP_RESET_GPO3_PL_0          81
#define ZYNQMP_RESET_GPO3_PL_1          82
#define ZYNQMP_RESET_GPO3_PL_2          83
#define ZYNQMP_RESET_GPO3_PL_3          84
#define ZYNQMP_RESET_GPO3_PL_4          85
#define ZYNQMP_RESET_GPO3_PL_5          86
#define ZYNQMP_RESET_GPO3_PL_6          87
#define ZYNQMP_RESET_GPO3_PL_7          88
#define ZYNQMP_RESET_GPO3_PL_8          89
#define ZYNQMP_RESET_GPO3_PL_9          90
#define ZYNQMP_RESET_GPO3_PL_10         91
#define ZYNQMP_RESET_GPO3_PL_11         92
#define ZYNQMP_RESET_GPO3_PL_12         93
#define ZYNQMP_RESET_GPO3_PL_13         94
#define ZYNQMP_RESET_GPO3_PL_14         95
#define ZYNQMP_RESET_GPO3_PL_15         96
#define ZYNQMP_RESET_GPO3_PL_16         97
#define ZYNQMP_RESET_GPO3_PL_17         98
#define ZYNQMP_RESET_GPO3_PL_18         99
#define ZYNQMP_RESET_GPO3_PL_19         100
#define ZYNQMP_RESET_GPO3_PL_20         101
#define ZYNQMP_RESET_GPO3_PL_21         102
#define ZYNQMP_RESET_GPO3_PL_22         103
#define ZYNQMP_RESET_GPO3_PL_23         104
#define ZYNQMP_RESET_GPO3_PL_24         105
#define ZYNQMP_RESET_GPO3_PL_25         106
#define ZYNQMP_RESET_GPO3_PL_26         107
#define ZYNQMP_RESET_GPO3_PL_27         108
#define ZYNQMP_RESET_GPO3_PL_28         109
#define ZYNQMP_RESET_GPO3_PL_29         110
#define ZYNQMP_RESET_GPO3_PL_30         111
#define ZYNQMP_RESET_GPO3_PL_31         112
#define ZYNQMP_RESET_RPU_LS             113
#define ZYNQMP_RESET_PS_ONLY            114
#define ZYNQMP_RESET_PL                 115
#define ZYNQMP_RESET_PS_PL0             116
#define ZYNQMP_RESET_PS_PL1             117
#define ZYNQMP_RESET_PS_PL2             118
#define ZYNQMP_RESET_PS_PL3             119
#define ZYNQMP_RESET_MAX                ZYNQMP_RESET_PS_PL3

struct zynqmp_reset_softc {
        device_t        dev;
        device_t        parent;
};

static int
zynqmp_reset_assert(device_t dev, intptr_t id, bool reset)
{
        struct zynqmp_reset_softc *sc;
        int rv;

        if (id > ZYNQMP_RESET_MAX)
                return (EINVAL);
        sc = device_get_softc(dev);
        rv = ZYNQMP_FIRMWARE_RESET_ASSERT(sc->parent, id, reset);
        return (rv);
}

static int
zynqmp_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
{
        struct zynqmp_reset_softc *sc;
        int rv;

        if (id > ZYNQMP_RESET_MAX)
                return (EINVAL);
        sc = device_get_softc(dev);
        rv = ZYNQMP_FIRMWARE_RESET_GET_STATUS(sc->parent, id, reset);

        return (rv);
}

static int
zynqmp_reset_probe(device_t dev)
{

        if (!ofw_bus_status_okay(dev))
                return (ENXIO);
        if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-reset"))
                return (ENXIO);
        device_set_desc(dev, "ZynqMP Reset Controller");

        return (BUS_PROBE_DEFAULT);
}

static int
zynqmp_reset_attach(device_t dev)
{
        struct zynqmp_reset_softc *sc;

        sc = device_get_softc(dev);
        sc->dev = dev;
        sc->parent = device_get_parent(dev);

        /* register our self as a reset provider */
        hwreset_register_ofw_provider(dev);

        return (0);
}

static device_method_t zynqmp_reset_methods[] = {
        /* device_if */
        DEVMETHOD(device_probe,         zynqmp_reset_probe),
        DEVMETHOD(device_attach,        zynqmp_reset_attach),

        /* Reset interface */
        DEVMETHOD(hwreset_assert,       zynqmp_reset_assert),
        DEVMETHOD(hwreset_is_asserted,  zynqmp_reset_is_asserted),

        DEVMETHOD_END
};

static driver_t zynqmp_reset_driver = {
        "zynqmp_reset",
        zynqmp_reset_methods,
        sizeof(struct zynqmp_reset_softc),
};

EARLY_DRIVER_MODULE(zynqmp_reset, simplebus, zynqmp_reset_driver, 0, 0,
    BUS_PASS_BUS + BUS_PASS_ORDER_LAST);