root/sys/arch/arm/amlogic/mesong12_clkc.c
/* $NetBSD: mesong12_clkc.c,v 1.6 2021/02/04 22:55:36 joerg Exp $ */

/*-
 * Copyright (c) 2019 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mesong12_clkc.c,v 1.6 2021/02/04 22:55:36 joerg Exp $");

#include <sys/param.h>
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/device.h>

#include <dev/fdt/fdtvar.h>

#include <arm/amlogic/meson_clk.h>
#include <arm/amlogic/mesong12_clkc.h>

#define CBUS_REG(x)             ((x) << 2)

#define HHI_GP0_PLL_CNTL0       CBUS_REG(0x10)
#define HHI_GP0_PLL_CNTL1       CBUS_REG(0x11)
#define HHI_GP0_PLL_CNTL2       CBUS_REG(0x12)
#define HHI_GP0_PLL_CNTL3       CBUS_REG(0x13)
#define HHI_GP0_PLL_CNTL4       CBUS_REG(0x14)
#define HHI_GP0_PLL_CNTL5       CBUS_REG(0x15)
#define HHI_GP0_PLL_CNTL6       CBUS_REG(0x16)
#define HHI_GP1_PLL_CNTL0       CBUS_REG(0x18)
#define HHI_GP1_PLL_CNTL1       CBUS_REG(0x19)
#define HHI_PCIE_PLL_CNTL0      CBUS_REG(0x26)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_LOCK              __BIT(31)
#define  HHI_PCIE_PLL_CNTL0_PCIE_HCSL_CAL_DONE          __BIT(30)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_RESET             __BIT(29)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_EN                __BIT(28)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_VCO_DIV_SEL       __BIT(27)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_AFC_START         __BIT(26)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_OD                __BITS(20,16)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_PREDIV_SEL        __BITS(14,10)
#define  HHI_PCIE_PLL_CNTL0_PCIE_APLL_FBKDIV            __BITS(7,0)
#define HHI_PCIE_PLL_CNTL1      CBUS_REG(0x27)
#define  HHI_PCIE_PLL_CNTL1_PCIE_APLL_SDM_EN            __BIT(12)
#define  HHI_PCIE_PLL_CNTL1_PCIE_APLL_SDM_FRAC          __BITS(11,0)
#define HHI_PCIE_PLL_CNTL2      CBUS_REG(0x28)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_SSC_DEP_SEL       __BITS(31,28)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_SSC_FREF_SEL      __BITS(25,24)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_SSC_MODE          __BITS(23,22)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_SSC_OFFSET        __BITS(21,20)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_STR_M             __BITS(19,18)
#define  HHI_PCIE_PLL_CNTL2_PCIE_APLL_RESERVE           __BITS(15,0)
#define HHI_PCIE_PLL_CNTL3      CBUS_REG(0x29)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_BYPASS_EN     __BIT(31)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_HOLD_T        __BITS(29,28)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_IN            __BITS(26,20)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_NT            __BIT(19)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_DIV           __BITS(18,17)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_BIAS_LPF_EN       __BIT(16)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_CP_ICAP           __BITS(15,12)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_CP_IRES           __BITS(11,8)
#define  HHI_PCIE_PLL_CNTL3_PCIE_APLL_CPI               __BITS(5,4)
#define HHI_PCIE_PLL_CNTL4      CBUS_REG(0x2a)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_SHIFT_EN          __BIT(31)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_SHIFT_T           __BITS(27,26)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_SHIFT_V           __BITS(25,24)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_VCTRL_MON_EN      __BIT(23)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LPF_CAP           __BITS(21,20)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LPF_CAPADJ        __BITS(19,16)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LPF_RES           __BITS(13,12)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LPF_SF            __BIT(11)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LVR_OD_EN         __BIT(10)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_REFCLK_MON_EN     __BIT(9)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_FBKCLK_MON_EN     __BIT(8)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LOAD              __BIT(7)
#define  HHI_PCIE_PLL_CNTL4_PCIE_APLL_LOAD_EN           __BIT(6)
#define HHI_PCIE_PLL_CNTL5      CBUS_REG(0x2b)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_ADJ_LDO           __BITS(30,28)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BGP_EN            __BIT(27)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BGR_ADJ           __BITS(24,20)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BGR_START         __BIT(19)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BGR_VREF          __BITS(16,12)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BY_IMP_IN         __BITS(11,8)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BY_IMP            __BIT(7)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_CAL_EN            __BIT(6)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_CAL_RSTN          __BIT(5)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_EDGEDRV_EN        __BIT(4)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_EN0               __BIT(3)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_IN_EN             __BIT(2)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_SEL_PW            __BIT(1)
#define  HHI_PCIE_PLL_CNTL5_PCIE_HCSL_SEL_STR           __BIT(0)

#define HHI_HIFI_PLL_CNTL0      CBUS_REG(0x36)
#define HHI_HIFI_PLL_CNTL1      CBUS_REG(0x37)
#define HHI_HIFI_PLL_CNTL2      CBUS_REG(0x38)
#define HHI_HIFI_PLL_CNTL3      CBUS_REG(0x39)
#define HHI_HIFI_PLL_CNTL4      CBUS_REG(0x3a)
#define HHI_HIFI_PLL_CNTL5      CBUS_REG(0x3b)
#define HHI_HIFI_PLL_CNTL6      CBUS_REG(0x3c)
#define HHI_MEM_PD_REG0         CBUS_REG(0x40)
#define HHI_GCLK_MPEG0          CBUS_REG(0x50)
#define HHI_GCLK_MPEG1          CBUS_REG(0x51)
#define HHI_GCLK_MPEG2          CBUS_REG(0x52)
#define HHI_GCLK_OTHER          CBUS_REG(0x54)
#define HHI_GCLK_OTHER2         CBUS_REG(0x55)
#define HHI_SYS_CPU_CLK_CNTL1   CBUS_REG(0x57)
#define HHI_MPEG_CLK_CNTL       CBUS_REG(0x5d)
#define HHI_TS_CLK_CNTL         CBUS_REG(0x64)
#define HHI_SYS_CPU_CLK_CNTL0   CBUS_REG(0x67)
#define HHI_VID_PLL_CLK_DIV     CBUS_REG(0x68)
#define HHI_SYS_CPUB_CLK_CNTL1  CBUS_REG(0x80)
#define HHI_SYS_CPUB_CLK_CNTL   CBUS_REG(0x82)
#define HHI_NAND_CLK_CNTL       CBUS_REG(0x97)
#define HHI_SD_EMMC_CLK_CNTL    CBUS_REG(0x99)
#define HHI_MPLL_CNTL0          CBUS_REG(0x9e)
#define HHI_MPLL_CNTL1          CBUS_REG(0x9f)
#define HHI_MPLL_CNTL2          CBUS_REG(0xa0)
#define HHI_MPLL_CNTL3          CBUS_REG(0xa1)
#define HHI_MPLL_CNTL4          CBUS_REG(0xa2)
#define HHI_MPLL_CNTL5          CBUS_REG(0xa3)
#define HHI_MPLL_CNTL6          CBUS_REG(0xa4)
#define HHI_MPLL_CNTL7          CBUS_REG(0xa5)
#define HHI_MPLL_CNTL8          CBUS_REG(0xa6)
#define HHI_FIX_PLL_CNTL0       CBUS_REG(0xa8)
#define HHI_FIX_PLL_CNTL1       CBUS_REG(0xa9)
#define HHI_FIX_PLL_CNTL2       CBUS_REG(0xaa)
#define HHI_FIX_PLL_CNTL3       CBUS_REG(0xab)
#define HHI_SYS_PLL_CNTL0       CBUS_REG(0xbd)
#define HHI_SYS_PLL_CNTL1       CBUS_REG(0xbe)
#define HHI_SYS_PLL_CNTL2       CBUS_REG(0xbf)
#define HHI_SYS_PLL_CNTL3       CBUS_REG(0xc0)
#define HHI_SYS_PLL_CNTL4       CBUS_REG(0xc1)
#define HHI_SYS_PLL_CNTL5       CBUS_REG(0xc2)
#define HHI_SYS_PLL_CNTL6       CBUS_REG(0xc3)
#define HHI_HDMI_PLL_CNTL0      CBUS_REG(0xc8)
#define HHI_HDMI_PLL_CNTL1      CBUS_REG(0xc9)
#define HHI_SYS1_PLL_CNTL0      CBUS_REG(0xe0)
#define HHI_SYS1_PLL_CNTL1      CBUS_REG(0xe1)
#define HHI_SYS1_PLL_CNTL2      CBUS_REG(0xe2)
#define HHI_SYS1_PLL_CNTL3      CBUS_REG(0xe3)
#define HHI_SYS1_PLL_CNTL4      CBUS_REG(0xe4)
#define HHI_SYS1_PLL_CNTL5      CBUS_REG(0xe5)
#define HHI_SYS1_PLL_CNTL6      CBUS_REG(0xe6)

static int mesong12_clkc_match(device_t, cfdata_t, void *);
static void mesong12_clkc_attach(device_t, device_t, void *);

static u_int mesong12_cpuclk_get_rate(struct meson_clk_softc *,
    struct meson_clk_clk *);
static int mesong12_cpuclk_set_rate(struct meson_clk_softc *,
    struct meson_clk_clk *, u_int);
static int mesong12_clk_pcie_pll_set_rate(struct meson_clk_softc *,
    struct meson_clk_clk *, u_int);

struct mesong12_clkc_config {
        const char *name;
        struct meson_clk_clk *clks;
        int nclks;
};

#define PARENTS(args...)        ((const char *[]){ args })

/* fixed pll */
#define G12_CLK_fixed_pll_dco                                           \
        MESON_CLK_PLL(MESONG12_CLOCK_FIXED_PLL_DCO, "fixed_pll_dco",    \
            "xtal",                                             /* parent */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL0, __BIT(28)),    /* enable */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL0, __BITS(7,0)),  /* m */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL0, __BITS(14,10)),/* n */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL1, __BITS(16,0)), /* frac */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL0, __BIT(31)),    /* l */ \
            MESON_CLK_PLL_REG(HHI_FIX_PLL_CNTL0, __BIT(29)),    /* reset */ \
            0)
#define G12_CLK_fixed_pll                                               \
        MESON_CLK_DIV(MESONG12_CLOCK_FIXED_PLL, "fixed_pll",            \
            "fixed_pll_dco",            /* parent */                    \
            HHI_FIX_PLL_CNTL0,          /* reg */                       \
            __BITS(17,16),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO)

/* sys pll */
#define G12_CLK_sys_pll_dco                                             \
        MESON_CLK_PLL(MESONG12_CLOCK_SYS_PLL_DCO, "sys_pll_dco",        \
            "xtal",                                             /* parent */ \
            MESON_CLK_PLL_REG(HHI_SYS_PLL_CNTL0, __BIT(28)),    /* enable */ \
            MESON_CLK_PLL_REG(HHI_SYS_PLL_CNTL0, __BITS(7,0)),  /* m */ \
            MESON_CLK_PLL_REG(HHI_SYS_PLL_CNTL0, __BITS(14,10)),/* n */ \
            MESON_CLK_PLL_REG_INVALID,                          /* frac */ \
            MESON_CLK_PLL_REG(HHI_SYS_PLL_CNTL0, __BIT(31)),    /* l */ \
            MESON_CLK_PLL_REG(HHI_SYS_PLL_CNTL0, __BIT(29)),    /* reset */ \
            0)
#define G12_CLK_sys_pll                                                 \
        MESON_CLK_DIV(MESONG12_CLOCK_SYS_PLL, "sys_pll",                \
            "sys_pll_dco",              /* parent */                    \
            HHI_SYS_PLL_CNTL0,          /* reg */                       \
            __BITS(18,16),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO | MESON_CLK_DIV_SET_RATE_PARENT)

/* sys1 pll */
#define G12B_CLK_sys1_pll_dco                                           \
        MESON_CLK_PLL(MESONG12_CLOCK_SYS1_PLL_DCO, "sys1_pll_dco",      \
            "xtal",                                             /* parent */ \
            MESON_CLK_PLL_REG(HHI_SYS1_PLL_CNTL0, __BIT(28)),   /* enable */ \
            MESON_CLK_PLL_REG(HHI_SYS1_PLL_CNTL0, __BITS(7,0)), /* m */ \
            MESON_CLK_PLL_REG(HHI_SYS1_PLL_CNTL0, __BITS(14,10)),/* n */ \
            MESON_CLK_PLL_REG_INVALID,                          /* frac */ \
            MESON_CLK_PLL_REG(HHI_SYS1_PLL_CNTL0, __BIT(31)),   /* l */ \
            MESON_CLK_PLL_REG(HHI_SYS1_PLL_CNTL0, __BIT(29)),   /* reset */ \
            0)
#define G12B_CLK_sys1_pll                                               \
        MESON_CLK_DIV(MESONG12_CLOCK_SYS1_PLL, "sys1_pll",              \
            "sys1_pll_dco",             /* parent */                    \
            HHI_SYS1_PLL_CNTL0,         /* reg */                       \
            __BITS(18,16),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO | MESON_CLK_DIV_SET_RATE_PARENT)

/* fclk div */
#define G12_CLK_fclk_div2_div                                           \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV2_DIV, "fclk_div2_div", \
            "fixed_pll",                /* parent */                    \
            2,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div2                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_FCLK_DIV2, "fclk_div2",           \
            "fclk_div2_div",            /* parent */                    \
            HHI_FIX_PLL_CNTL1,          /* reg */                       \
            24)                         /* bit */
#define G12_CLK_fclk_div2p5_div                                         \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV2P5_DIV,          \
            "fclk_div2p5_div",                                          \
            "fixed_pll_dco",            /* parent */                    \
            5,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div3_div                                           \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV3_DIV,            \
            "fclk_div3_div",                                            \
            "fixed_pll",                /* parent */                    \
            3,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div3                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_FCLK_DIV3, "fclk_div3",           \
            "fclk_div3_div",            /* parent */                    \
            HHI_FIX_PLL_CNTL1,          /* reg */                       \
            20)                         /* bit */
#define G12_CLK_fclk_div4_div                                           \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV4_DIV, "fclk_div4_div", \
            "fixed_pll",                /* parent */                    \
            4,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div4                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_FCLK_DIV4, "fclk_div4",           \
            "fclk_div4_div",            /* parent */                    \
            HHI_FIX_PLL_CNTL1,          /* reg */                       \
            21)                         /* bit */
#define G12_CLK_fclk_div5_div                                           \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV5_DIV, "fclk_div5_div", \
            "fixed_pll",                /* parent */                    \
            5,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div5                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_FCLK_DIV5, "fclk_div5",           \
            "fclk_div5_div",            /* parent */                    \
            HHI_FIX_PLL_CNTL1,          /* reg */                       \
            22)                         /* bit */
#define G12_CLK_fclk_div7_div                                           \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_FCLK_DIV7_DIV, "fclk_div7_div", \
            "fixed_pll",                /* parent */                    \
            7,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_fclk_div7                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_FCLK_DIV7, "fclk_div7",           \
            "fclk_div7_div",            /* parent */                    \
            HHI_FIX_PLL_CNTL1,          /* reg */                       \
            23)                         /* bit */

/* mpll */
#define G12_CLK_mpll_prediv                                             \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_MPLL_PREDIV, "mpll_prediv", \
            "fixed_pll_dco",            /* parent */                    \
            2,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_mpll0_div                                               \
        MESON_CLK_MPLL(MESONG12_CLOCK_MPLL0_DIV, "mpll0_div",           \
            "mpll_prediv",                                      /* parent */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL1, __BITS(13,0)),    /* sdm */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL1, __BIT(30)), /* sdm_enable */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL1, __BITS(28,20)),   /* n2 */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL1, __BIT(29)),       /* ssen */ \
            0)
#define G12_CLK_mpll1_div                                               \
        MESON_CLK_MPLL(MESONG12_CLOCK_MPLL1_DIV, "mpll1_div",           \
            "mpll_prediv",                                      /* parent */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL3, __BITS(13,0)),    /* sdm */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL3, __BIT(30)), /* sdm_enable */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL3, __BITS(28,20)),   /* n2 */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL3, __BIT(29)),       /* ssen */ \
            0)
#define G12_CLK_mpll2_div                                               \
        MESON_CLK_MPLL(MESONG12_CLOCK_MPLL2_DIV, "mpll2_div",           \
            "mpll_prediv",                                      /* parent */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL5, __BITS(13,0)),    /* sdm */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL5, __BIT(30)), /* sdm_enable */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL5, __BITS(28,20)),   /* n2 */ \
            MESON_CLK_PLL_REG(HHI_MPLL_CNTL5, __BIT(29)),       /* ssen */ \
            0)
#define G12_CLK_mpll0                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_MPLL0, "mpll0",                   \
            "mpll0_div",                /* parent */                    \
            HHI_MPLL_CNTL1,             /* reg */                       \
            31)                         /* bit */
#define G12_CLK_mpll1                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_MPLL1, "mpll1",                   \
            "mpll1_div",                /* parent */                    \
            HHI_MPLL_CNTL3,             /* reg */                       \
            31)                         /* bit */
#define G12_CLK_mpll2                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_MPLL2, "mpll2",                   \
            "mpll2_div",                /* parent */                    \
            HHI_MPLL_CNTL5,             /* reg */                       \
            31)                         /* bit */
#define G12_CLK_mpll_50m_div                                            \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_MPLL_50M_DIV, "mpll_50m_div", \
            "fixed_pll_dco",            /* parent */                    \
            80,                         /* div */                       \
            1)                          /* mult */
#define G12_CLK_mpll_50m                                                \
        MESON_CLK_MUX(MESONG12_CLOCK_MPLL_50M, "mpll_50m",              \
            PARENTS("mpll_50m_div", "xtal"),                            \
            HHI_FIX_PLL_CNTL3,          /* reg */                       \
            __BIT(5),                   /* sel */                       \
            0)

/* sd/emmc */
#define G12_CLK_sd_emmc_a_clk0_sel                                      \
        MESON_CLK_MUX(MESONG12_CLOCK_SD_EMMC_A_CLK0_SEL, "sd_emmc_a_clk0_sel", \
            PARENTS("xtal", "fclk_div2", "fclk_div3",                   \
            "fclk_div5", "fclk_div7"),                                  \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            __BITS(11,9),               /* sel */                       \
            0)
#define G12_CLK_sd_emmc_b_clk0_sel                                      \
        MESON_CLK_MUX(MESONG12_CLOCK_SD_EMMC_B_CLK0_SEL, "sd_emmc_b_clk0_sel", \
            PARENTS("xtal", "fclk_div2", "fclk_div3",                   \
            "fclk_div5", "fclk_div7"),                                  \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            __BITS(27,25),              /* sel */                       \
            0)
#define G12_CLK_sd_emmc_c_clk0_sel                                      \
        MESON_CLK_MUX(MESONG12_CLOCK_SD_EMMC_C_CLK0_SEL, "sd_emmc_c_clk0_sel", \
            PARENTS("xtal", "fclk_div2", "fclk_div3",                   \
            "fclk_div5", "fclk_div7"),                                  \
            HHI_NAND_CLK_CNTL,          /* reg */                       \
            __BITS(11,9),               /* sel */                       \
            0)
#define G12_CLK_sd_emmc_a_clk0_div                                      \
        MESON_CLK_DIV(MESONG12_CLOCK_SD_EMMC_A_CLK0_DIV, "sd_emmc_a_clk0_div", \
            "sd_emmc_a_clk0_sel",       /* parent */                    \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            __BITS(6,0),                /* div */                       \
            0)
#define G12_CLK_sd_emmc_b_clk0_div                                      \
        MESON_CLK_DIV(MESONG12_CLOCK_SD_EMMC_B_CLK0_DIV, "sd_emmc_b_clk0_div", \
            "sd_emmc_b_clk0_sel",       /* parent */                    \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            __BITS(22,16),              /* div */                       \
            0)
#define G12_CLK_sd_emmc_c_clk0_div                                      \
        MESON_CLK_DIV(MESONG12_CLOCK_SD_EMMC_C_CLK0_DIV, "sd_emmc_c_clk0_div", \
            "sd_emmc_c_clk0_sel",       /* parent */                    \
            HHI_NAND_CLK_CNTL,          /* reg */                       \
            __BITS(6,0),                /* div */                       \
            0)
#define G12_CLK_sd_emmc_a_clk0                                          \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_A_CLK0, "sd_emmc_a_clk0", \
            "sd_emmc_a_clk0_div",       /* parent */                    \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            7)                          /* bit */
#define G12_CLK_sd_emmc_b_clk0                                          \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_B_CLK0, "sd_emmc_b_clk0", \
            "sd_emmc_b_clk0_div",       /* parent */                    \
            HHI_SD_EMMC_CLK_CNTL,       /* reg */                       \
            23)                         /* bit */
#define G12_CLK_sd_emmc_c_clk0                                          \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_C_CLK0, "sd_emmc_c_clk0", \
            "sd_emmc_c_clk0_div",       /* parent */                    \
            HHI_NAND_CLK_CNTL,          /* reg */                       \
            7)                          /* bit */

/* source as mpeg_clk */
#define G12_CLK_mpeg_sel                                                \
        MESON_CLK_MUX(MESONG12_CLOCK_MPEG_SEL, "mpeg_sel",              \
            PARENTS("xtal", NULL, "fclk_div7", "mpll1",                 \
            "mpll2", "fclk_div4", "fclk_div3", "fclk_div5"),            \
            HHI_MPEG_CLK_CNTL,          /* reg */                       \
            __BITS(14,12),              /* sel */                       \
            0)
#define G12_CLK_mpeg_clk_div                                            \
        MESON_CLK_DIV(MESONG12_CLOCK_MPEG_DIV, "mpeg_clk_div",          \
            "mpeg_sel",                 /* parent */                    \
            HHI_MPEG_CLK_CNTL,          /* reg */                       \
            __BITS(6,0),                /* div */                       \
            MESON_CLK_DIV_SET_RATE_PARENT)
#define G12_CLK_clk81                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_CLK81, "clk81",                   \
            "mpeg_clk_div",             /* parent */                    \
            HHI_MPEG_CLK_CNTL,          /* reg */                       \
            7)                          /* bit */
#define G12_CLK_ddr                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_DDR, "ddr",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            0)                          /* bit */
#define G12_CLK_dos                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_DOS, "dos",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            1)                          /* bit */
#define G12_CLK_audio_locker                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_AUDIO_LOCKER, "audio_locker",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            2)                          /* bit */
#define G12_CLK_mipi_dsi_host                                           \
        MESON_CLK_GATE(MESONG12_CLOCK_MIPI_DSI_HOST, "mipi_dsi_host",   \
           "clk81",                     /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            3)                          /* bit */
#define G12_CLK_eth_phy                                                 \
        MESON_CLK_GATE(MESONG12_CLOCK_ETH_PHY, "eth_phy",               \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            4)                          /* bit */
#define G12_CLK_isa                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_ISA, "isa",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            5)                          /* bit */
#define G12_CLK_pl301                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_PL301, "pl301",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            6)                          /* bit */
#define G12_CLK_periphs                                                 \
        MESON_CLK_GATE(MESONG12_CLOCK_PERIPHS, "periphs",               \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            7)                          /* bit */
#define G12_CLK_spicc0                                                  \
        MESON_CLK_GATE(MESONG12_CLOCK_SPICC0, "spicc0",                 \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            8)                          /* bit */
#define G12_CLK_i2c                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_I2C, "i2c",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            9)                          /* bit */
#define G12_CLK_sana                                                    \
        MESON_CLK_GATE(MESONG12_CLOCK_SANA, "sana",                     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            10)                         /* bit */
#define G12_CLK_sd                                                      \
        MESON_CLK_GATE(MESONG12_CLOCK_SD, "sd",                         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            11)                         /* bit */
#define G12_CLK_rng0                                                    \
        MESON_CLK_GATE(MESONG12_CLOCK_RNG0, "rng0",                     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            12)                         /* bit */
#define G12_CLK_uart0                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_UART0, "uart0",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            13)                         /* bit */
#define G12_CLK_spicc1                                                  \
        MESON_CLK_GATE(MESONG12_CLOCK_SPICC1, "spicc1",                 \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            14)                         /* bit */
#define G12_CLK_hiu_iface                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_HIU_IFACE, "hiu_iface",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            19)                         /* bit */
#define G12_CLK_mipi_dsi_phy                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_MIPI_DSI_PHY, "mipi_dsi_phy",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            20)                         /* bit */
#define G12_CLK_assist_misc                                             \
        MESON_CLK_GATE(MESONG12_CLOCK_ASSIST_MISC, "assist_misc",       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            23)                         /* bit */
#define G12_CLK_sd_emmc_a                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_A, "sd_emmc_a",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            4)                          /* bit */
#define G12_CLK_sd_emmc_b                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_B, "sd_emmc_b",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            25)                         /* bit */
#define G12_CLK_sd_emmc_c                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_SD_EMMC_C, "sd_emmc_c",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            26)                         /* bit */
#define G12_CLK_audio_codec                                             \
        MESON_CLK_GATE(MESONG12_CLOCK_AUDIO_CODEC, "audio_codec",       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG0,             /* reg */                       \
            28)                         /* bit */
#define G12_CLK_audio                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_AUDIO, "audio",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            0)                          /* bit */
#define G12_CLK_eth                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_ETH, "eth",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            3)                          /* bit */
#define G12_CLK_demux                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_DEMUX, "demux",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            4)                          /* bit */
#define G12_CLK_audio_ififo                                             \
        MESON_CLK_GATE(MESONG12_CLOCK_AUDIO_IFIFO, "audio_ififo",       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            11)                         /* bit */
#define G12_CLK_adc                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_ADC, "adc",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            13)                         /* bit */
#define G12_CLK_uart1                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_UART1, "uart1",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            16)                         /* bit */
#define G12_CLK_g2d                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_G2D, "g2d",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            20)                         /* bit */
#define G12_CLK_reset                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_RESET, "reset",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            23)                         /* bit */
#define G12_CLK_pcie_comb                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_PCIE_COMB, "pcie_comb",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            24)                         /* bit */
#define G12_CLK_parser                                                  \
        MESON_CLK_GATE(MESONG12_CLOCK_PARSER, "parser",                 \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            25)                         /* bit */
#define G12_CLK_usb                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_USB, "usb",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            26)                         /* bit */
#define G12_CLK_pcie_phy                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_PCIE_PHY, "pcie_phy",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            27)                         /* bit */
#define G12_CLK_ahb_arb0                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_AHB_ARB0, "ahb_arb0",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG1,             /* reg */                       \
            29)                         /* bit */
#define G12_CLK_ahb_data_bus                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_AHB_DATA_BUS, "ahb_data_bus",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            1)                          /* bit */
#define G12_CLK_ahb_ctrl_bus                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_AHB_CTRL_BUS, "ahb_ctrl_bus",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            2)                          /* bit */
#define G12_CLK_htx_hdcp22                                              \
        MESON_CLK_GATE(MESONG12_CLOCK_HTX_HDCP22, "htx_hdcp22",         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            3)                          /* bit */
#define G12_CLK_htx_pclk                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_HTX_PCLK, "htx_pclk",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            4)                          /* bit */
#define G12_CLK_bt656                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_BT656, "bt656",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            6)                          /* bit */
#define G12_CLK_usb1_ddr_bridge                                         \
        MESON_CLK_GATE(MESONG12_CLOCK_USB1_DDR_BRIDGE, "usb1_ddr_bridge", \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            8)                          /* bit */
#define G12_CLK_mmc_pclk                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_MMC_PCLK, "mmc_pclk",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            11)                         /* bit */
#define G12_CLK_uart2                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_UART2, "uart2",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            15)                         /* bit */
#define G12_CLK_vpu_intr                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_VPU_INTR, "vpu_intr",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            25)                         /* bit */
#define G12_CLK_gic                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_GIC, "gic",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_MPEG2,             /* reg */                       \
            30)                         /* bit */
#define G12_CLK_vclk2_venci0                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCI0, "vclk2_venci0",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            1)                          /* bit */
#define G12_CLK_vclk2_venci1                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCI1, "vclk2_venci1",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            2)                          /* bit */
#define G12_CLK_vclk2_vencp0                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCP0, "vclk2_vencp0",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            3)                          /* bit */
#define G12_CLK_vclk2_vencp1                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCP1, "vclk2_vencp1",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            4)                          /* bit */
#define G12_CLK_vclk2_venct0                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCT0, "vclk2_venct0",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            5)                          /* bit */
#define G12_CLK_vclk2_venct1                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCT1, "vclk2_venct1",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            6)                          /* bit */
#define G12_CLK_vclk2_other                                             \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_OTHER, "vclk2_other",       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            7)                          /* bit */
#define G12_CLK_vclk2_enci                                              \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_ENCI, "vclk2_enci",         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            8)                          /* bit */
#define G12_CLK_vclk2_encp                                              \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_ENCP, "vclk2_encp",         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            9)                          /* bit */
#define G12_CLK_dac_clk                                                 \
        MESON_CLK_GATE(MESONG12_CLOCK_DAC_CLK, "dac_clk",               \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            10)                         /* bit */
#define G12_CLK_aoclk                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_AOCLK, "aoclk",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            14)                         /* bit */
#define G12_CLK_iec958                                                  \
        MESON_CLK_GATE(MESONG12_CLOCK_IEC958, "iec958",                 \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            16)                         /* bit */
#define G12_CLK_enc480p                                                 \
        MESON_CLK_GATE(MESONG12_CLOCK_ENC480P, "enc480p",               \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            20)                         /* bit */
#define G12_CLK_rng1                                                    \
        MESON_CLK_GATE(MESONG12_CLOCK_RNG1, "rng1",                     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            21)                         /* bit */
#define G12_CLK_vclk2_enct                                              \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_ENCT, "vclk2_enct",         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            22)                         /* bit */
#define G12_CLK_vclk2_encl                                              \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_ENCL, "vclk2_encl",         \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            23)                         /* bit */
#define G12_CLK_vclk2_venclmmc                                          \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCLMMC, "vclk2_venclmmc", \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            24)                         /* bit */
#define G12_CLK_vclk2_vencl                                             \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_VENCL, "vclk2_vencl",       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            25)                         /* bit */
#define G12_CLK_vclk2_other1                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_VCLK2_OTHER1, "vclk2_other1",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER,             /* reg */                       \
            26)                         /* bit */
#define G12_CLK_dma                                                     \
        MESON_CLK_GATE(MESONG12_CLOCK_DMA, "dma",                       \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER2,            /* reg */                       \
            0)                          /* bit */
#define G12_CLK_efuse                                                   \
        MESON_CLK_GATE(MESONG12_CLOCK_EFUSE, "efuse",                   \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER2,            /* reg */                       \
            1)                          /* bit */
#define G12_CLK_rom_boot                                                \
        MESON_CLK_GATE(MESONG12_CLOCK_ROM_BOOT, "rom_boot",             \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER2,            /* reg */                       \
            2)                          /* bit */
#define G12_CLK_reset_sec                                               \
        MESON_CLK_GATE(MESONG12_CLOCK_RESET_SEC, "reset_sec",           \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER2,            /* reg */                       \
            3)                          /* bit */
#define G12_CLK_sec_ahb_apb3                                            \
        MESON_CLK_GATE(MESONG12_CLOCK_SEC_AHB_APB3, "sec_ahb_apb3",     \
            "clk81",                    /* parent */                    \
            HHI_GCLK_OTHER2,            /* reg */                       \
            4)                          /* bit */

/* little cpu cluster */
#define G12_CLK_cpu_clk_dyn0_sel                                        \
        MESON_CLK_MUX(MESONG12_CLOCK_CPU_CLK_DYN0_SEL, "cpu_clk_dyn0_sel", \
            PARENTS("fclk_div2", "fclk_div3", "xtal"),                  \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BITS(1,0),                /* sel */                       \
            0)
#define G12_CLK_cpu_clk_dyn1_sel                                        \
        MESON_CLK_MUX(MESONG12_CLOCK_CPU_CLK_DYN1_SEL, "cpu_clk_dyn1_sel", \
            PARENTS("fclk_div2", "fclk_div3", "xtal"),                  \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BITS(17,16),              /* sel */                       \
            0)
#define G12_CLK_cpu_clk_dyn0_div                                        \
        MESON_CLK_DIV(MESONG12_CLOCK_CPU_CLK_DYN0_DIV, "cpu_clk_dyn0_div", \
            "cpu_clk_dyn0_sel",         /* parent */                    \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(26),                  /* div */                       \
            0)
#define G12_CLK_cpu_clk_dyn1_div                                        \
        MESON_CLK_DIV(MESONG12_CLOCK_CPU_CLK_DYN1_DIV, "cpu_clk_dyn1_div", \
            "cpu_clk_dyn1_sel",         /* parent */                    \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BITS(25,20),              /* div */                       \
            0)
#define G12_CLK_cpu_clk_dyn0                                            \
        MESON_CLK_MUX(MESONG12_CLOCK_CPU_CLK_DYN0, "cpu_clk_dyn0",      \
            PARENTS("cpu_clk_dyn0_div", "cpu_clk_dyn0_sel"),            \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(2),                   /* sel */                       \
            0)
#define G12_CLK_cpu_clk_dyn1                                            \
        MESON_CLK_MUX(MESONG12_CLOCK_CPU_CLK_DYN1, "cpu_clk_dyn1",      \
            PARENTS("cpu_clk_dyn1_div", "cpu_clk_dyn1_sel"),            \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(18),                  /* sel */                       \
            0)
#define G12_CLK_cpu_clk_dyn                                             \
        MESON_CLK_MUX(MESONG12_CLOCK_CPU_CLK_DYN, "cpu_clk_dyn",        \
            PARENTS("cpu_clk_dyn0", "cpu_clk_dyn1"),                    \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(10),                  /* sel */                       \
            0)
#define G12A_CLK_cpu_clk                                                \
        MESON_CLK_MUX_RATE(MESONG12_CLOCK_CPU_CLK, "cpu_clk",           \
            PARENTS("cpu_clk_dyn", "sys_pll"),                          \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(11),                  /* sel */                       \
            mesong12_cpuclk_get_rate,                                   \
            mesong12_cpuclk_set_rate,                                   \
            0)
#define G12B_CLK_cpu_clk                                                \
        MESON_CLK_MUX_RATE(MESONG12_CLOCK_CPU_CLK, "cpu_clk",           \
            PARENTS("cpu_clk_dyn", "sys1_pll"),                         \
            HHI_SYS_CPU_CLK_CNTL0,      /* reg */                       \
            __BIT(11),                  /* sel */                       \
            mesong12_cpuclk_get_rate,                                   \
            mesong12_cpuclk_set_rate,                                   \
            0)

/* big cpu cluster */
#define G12_CLK_cpub_clk_dyn0_sel                                       \
        MESON_CLK_MUX(MESONG12_CLOCK_CPUB_CLK_DYN0_SEL, "cpub_clk_dyn0_sel", \
            PARENTS("fclk_div2", "fclk_div3", "xtal"),                  \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BITS(1,0),                /* sel */                       \
            0)
#define G12_CLK_cpub_clk_dyn0_div                                       \
        MESON_CLK_DIV(MESONG12_CLOCK_CPUB_CLK_DYN0_DIV, "cpub_clk_dyn0_div", \
            "cpub_clk_dyn0_sel",        /* parent */                    \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BITS(9,4),                /* div */                       \
            0)
#define G12_CLK_cpub_clk_dyn0                                           \
        MESON_CLK_MUX(MESONG12_CLOCK_CPUB_CLK_DYN0, "cpub_clk_dyn0",    \
            PARENTS("cpub_clk_dyn0_div", "cpub_clk_dyn0_sel"),          \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BIT(2),                   /* sel */                       \
            0)
#define G12_CLK_cpub_clk_dyn1_sel                                       \
        MESON_CLK_MUX(MESONG12_CLOCK_CPUB_CLK_DYN1_SEL, "cpub_clk_dyn1_sel", \
            PARENTS("fclk_div2", "fclk_div3", "xtal", "xtal"),          \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BITS(17,16),              /* sel */                       \
            0)
#define G12_CLK_cpub_clk_dyn1_div                                       \
        MESON_CLK_DIV(MESONG12_CLOCK_CPUB_CLK_DYN1_DIV, "cpub_clk_dyn1_div", \
            "cpub_clk_dyn1_sel",        /* parent */                    \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BITS(25,20),              /* div */                       \
            0)
#define G12_CLK_cpub_clk_dyn1                                           \
        MESON_CLK_MUX(MESONG12_CLOCK_CPUB_CLK_DYN1, "cpub_clk_dyn1",    \
            PARENTS("cpub_clk_dyn1_div", "cpub_clk_dyn1_sel"),          \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BIT(18),                  /* sel */                       \
            0)
#define G12_CLK_cpub_clk_dyn                                            \
        MESON_CLK_MUX(MESONG12_CLOCK_CPUB_CLK_DYN, "cpub_clk_dyn",      \
            PARENTS("cpub_clk_dyn0", "cpub_clk_dyn1"),                  \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BIT(10),                  /* sel */                       \
            0)
#define G12_CLK_cpub_clk                                                \
        MESON_CLK_MUX_RATE(MESONG12_CLOCK_CPUB_CLK, "cpub_clk",         \
            PARENTS("cpub_clk_dyn", "sys_pll"),                         \
            HHI_SYS_CPUB_CLK_CNTL,      /* reg */                       \
            __BIT(11),                  /* sel */                       \
            mesong12_cpuclk_get_rate,                                   \
            mesong12_cpuclk_set_rate,                                   \
            0)

/* ts */
#define G12_CLK_ts_div                                                  \
        MESON_CLK_DIV(MESONG12_CLOCK_TS_DIV, "ts_div",                  \
            "xtal",                     /* parent */                    \
            HHI_TS_CLK_CNTL,            /* reg */                       \
            __BITS(7,0),                /* div */                       \
            0)
#define G12_CLK_ts                                                      \
        MESON_CLK_GATE(MESONG12_CLOCK_TS, "ts",                         \
            "ts_div",                   /* parent */                    \
            HHI_TS_CLK_CNTL,            /* ret */                       \
            8)                          /* bit */

/* hdmi */
#define G12_CLK_hdmi_pll_dco                                            \
        MESON_CLK_PLL(MESONG12_CLOCK_HDMI_PLL_DCO, "hdmi_pll_dco",      \
            "xtal",                                             /* parent */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL0, __BIT(28)),   /* enable */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL0, __BITS(7,0)), /* m */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL0, __BITS(14,10)),/* n */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL1, __BITS(15,0)),/* frac */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL0, __BIT(30)),   /* l */ \
            MESON_CLK_PLL_REG(HHI_HDMI_PLL_CNTL0, __BIT(29)),   /* reset */ \
            0)
#define G12_CLK_hdmi_pll_od                                             \
        MESON_CLK_DIV(MESONG12_CLOCK_HDMI_PLL_OD, "hdmi_pll_od",        \
            "hdmi_pll_dco",             /* parent */                    \
            HHI_HDMI_PLL_CNTL0,         /* reg */                       \
            __BITS(17,16),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO)
#define G12_CLK_hdmi_pll_od2                                            \
        MESON_CLK_DIV(MESONG12_CLOCK_HDMI_PLL_OD2, "hdmi_pll_od2",      \
            "hdmi_pll_od",              /* parent */                    \
            HHI_HDMI_PLL_CNTL0,         /* reg */                       \
            __BITS(19,18),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO)
#define G12_CLK_hdmi_pll                                                \
        MESON_CLK_DIV(MESONG12_CLOCK_HDMI_PLL, "hdmi_pll",              \
            "hdmi_pll_od2",             /* parent */                    \
            HHI_HDMI_PLL_CNTL0,         /* reg */                       \
            __BITS(21,20),              /* div */                       \
            MESON_CLK_DIV_POWER_OF_TWO)

#define G12_CLK_vid_pll_div                                             \
        MESON_CLK_DIV(MESONG12_CLOCK_VID_PLL_DIV, "vid_pll_div",        \
            "hdmi_pll",                 /* parent */                    \
            HHI_FIX_PLL_CNTL0,          /* reg */                       \
            __BITS(17,16),              /* div */                       \
            0)
#define G12_CLK_vid_pll_sel                                             \
        MESON_CLK_MUX(MESONG12_CLOCK_VID_PLL_SEL, "vid_pll_sel",        \
            PARENTS("vid_pll_div", "hdmi_pll"),                         \
            HHI_VID_PLL_CLK_DIV,        /* reg */                       \
            __BIT(18),                  /* sel */                       \
            0)
#define G12_CLK_vid_pll                                                 \
        MESON_CLK_GATE(MESONG12_CLOCK_VID_PLL, "vid_pll",               \
            "vid_pll_sel",              /* parent */                    \
            HHI_VID_PLL_CLK_DIV,        /* reg */                       \
            19)                         /* bit */

/* USB3/PCIe */
#define G12_CLK_pcie_pll_dco                                            \
        MESON_CLK_PLL_RATE(MESONG12_CLOCK_PCIE_PLL_DCO, "pcie_pll_dco", \
            "xtal",                                             /* parent */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL0, __BIT(28)),   /* enable */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL0, __BITS(7,0)), /* m */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL0, __BITS(14,10)),/* n */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL1, __BITS(11,0)),/* frac */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL0, __BIT(31)),   /* l */ \
            MESON_CLK_PLL_REG(HHI_PCIE_PLL_CNTL0, __BIT(29)),   /* reset */ \
            mesong12_clk_pcie_pll_set_rate,                             \
            0)
#define G12_CLK_pcie_pll_dco_div2                                       \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_PCIE_PLL_DCO_DIV2,        \
            "pcie_pll_dco_div2",                                        \
            "pcie_pll_dco",             /* parent */                    \
            2,                          /* div */                       \
            1)                          /* mult */
#define G12_CLK_pcie_pll_od                                             \
        MESON_CLK_DIV(MESONG12_CLOCK_PCIE_PLL_OD, "pcie_pll_od",        \
            "pcie_pll_dco_div2",        /* parent */                    \
            HHI_PCIE_PLL_CNTL0,         /* reg */                       \
            __BITS(20,16),              /* div */                       \
            MESON_CLK_DIV_SET_RATE_PARENT)
#define G12_CLK_pcie_pll_pll                                            \
        MESON_CLK_FIXED_FACTOR(MESONG12_CLOCK_PCIE_PLL, "pcie_pll_pll", \
            "pcie_pll_od",              /* parent */                    \
            2,                          /* div */                       \
            1)                          /* mult */

/* not all clocks are defined */
static struct meson_clk_clk mesong12a_clkc_clks[] = {
        G12_CLK_fixed_pll_dco,
        G12_CLK_fixed_pll,
        G12_CLK_sys_pll_dco,
        G12_CLK_sys_pll,
        G12_CLK_fclk_div2_div,
        G12_CLK_fclk_div2,
        G12_CLK_fclk_div2p5_div,
        G12_CLK_fclk_div3_div,
        G12_CLK_fclk_div3,
        G12_CLK_fclk_div4_div,
        G12_CLK_fclk_div4,
        G12_CLK_fclk_div5_div,
        G12_CLK_fclk_div5,
        G12_CLK_fclk_div7_div,
        G12_CLK_fclk_div7,
        G12_CLK_mpll_prediv,
        G12_CLK_mpll0_div,
        G12_CLK_mpll1_div,
        G12_CLK_mpll2_div,
        G12_CLK_mpll0,
        G12_CLK_mpll1,
        G12_CLK_mpll2,
        G12_CLK_mpeg_sel,
        G12_CLK_mpeg_clk_div,
        G12_CLK_clk81,
        G12_CLK_mpll_50m_div,
        G12_CLK_mpll_50m,
        G12_CLK_sd_emmc_a_clk0_sel,
        G12_CLK_sd_emmc_b_clk0_sel,
        G12_CLK_sd_emmc_c_clk0_sel,
        G12_CLK_sd_emmc_a_clk0_div,
        G12_CLK_sd_emmc_b_clk0_div,
        G12_CLK_sd_emmc_c_clk0_div,
        G12_CLK_sd_emmc_a_clk0,
        G12_CLK_sd_emmc_b_clk0,
        G12_CLK_sd_emmc_c_clk0,
        G12_CLK_ddr,
        G12_CLK_dos,
        G12_CLK_audio_locker,
        G12_CLK_mipi_dsi_host,
        G12_CLK_eth_phy,
        G12_CLK_isa,
        G12_CLK_pl301,
        G12_CLK_periphs,
        G12_CLK_spicc0,
        G12_CLK_i2c,
        G12_CLK_sana,
        G12_CLK_sd,
        G12_CLK_rng0,
        G12_CLK_uart0,
        G12_CLK_spicc1,
        G12_CLK_hiu_iface,
        G12_CLK_mipi_dsi_phy,
        G12_CLK_assist_misc,
        G12_CLK_sd_emmc_a,
        G12_CLK_sd_emmc_b,
        G12_CLK_sd_emmc_c,
        G12_CLK_audio_codec,
        G12_CLK_audio,
        G12_CLK_eth,
        G12_CLK_demux,
        G12_CLK_audio_ififo,
        G12_CLK_adc,
        G12_CLK_uart1,
        G12_CLK_g2d,
        G12_CLK_reset,
        G12_CLK_pcie_comb,
        G12_CLK_parser,
        G12_CLK_usb,
        G12_CLK_pcie_phy,
        G12_CLK_ahb_arb0,
        G12_CLK_ahb_data_bus,
        G12_CLK_ahb_ctrl_bus,
        G12_CLK_htx_hdcp22,
        G12_CLK_htx_pclk,
        G12_CLK_bt656,
        G12_CLK_usb1_ddr_bridge,
        G12_CLK_mmc_pclk,
        G12_CLK_uart2,
        G12_CLK_vpu_intr,
        G12_CLK_gic,
        G12_CLK_vclk2_venci0,
        G12_CLK_vclk2_venci1,
        G12_CLK_vclk2_vencp0,
        G12_CLK_vclk2_vencp1,
        G12_CLK_vclk2_venct0,
        G12_CLK_vclk2_venct1,
        G12_CLK_vclk2_other,
        G12_CLK_vclk2_enci,
        G12_CLK_vclk2_encp,
        G12_CLK_dac_clk,
        G12_CLK_aoclk,
        G12_CLK_iec958,
        G12_CLK_enc480p,
        G12_CLK_rng1,
        G12_CLK_vclk2_enct,
        G12_CLK_vclk2_encl,
        G12_CLK_vclk2_venclmmc,
        G12_CLK_vclk2_vencl,
        G12_CLK_vclk2_other1,
        G12_CLK_dma,
        G12_CLK_efuse,
        G12_CLK_rom_boot,
        G12_CLK_reset_sec,
        G12_CLK_sec_ahb_apb3,
        G12_CLK_cpu_clk_dyn0_sel,
        G12_CLK_cpu_clk_dyn1_sel,
        G12_CLK_cpu_clk_dyn0_div,
        G12_CLK_cpu_clk_dyn1_div,
        G12_CLK_cpu_clk_dyn0,
        G12_CLK_cpu_clk_dyn1,
        G12_CLK_cpu_clk_dyn,
        G12A_CLK_cpu_clk,
        G12_CLK_ts_div,
        G12_CLK_ts,
        G12_CLK_hdmi_pll_dco,
        G12_CLK_hdmi_pll_od,
        G12_CLK_hdmi_pll_od2,
        G12_CLK_hdmi_pll,
        G12_CLK_vid_pll_div,
        G12_CLK_vid_pll_sel,
        G12_CLK_vid_pll,
        G12_CLK_pcie_pll_dco,
        G12_CLK_pcie_pll_dco_div2,
        G12_CLK_pcie_pll_od,
        G12_CLK_pcie_pll_pll
};

static struct meson_clk_clk mesong12b_clkc_clks[] = {
        G12_CLK_fixed_pll_dco,
        G12_CLK_fixed_pll,
        G12_CLK_sys_pll_dco,
        G12_CLK_sys_pll,
        G12B_CLK_sys1_pll_dco,
        G12B_CLK_sys1_pll,
        G12_CLK_fclk_div2_div,
        G12_CLK_fclk_div2,
        G12_CLK_fclk_div2p5_div,
        G12_CLK_fclk_div3_div,
        G12_CLK_fclk_div3,
        G12_CLK_fclk_div4_div,
        G12_CLK_fclk_div4,
        G12_CLK_fclk_div5_div,
        G12_CLK_fclk_div5,
        G12_CLK_fclk_div7_div,
        G12_CLK_fclk_div7,
        G12_CLK_mpll_prediv,
        G12_CLK_mpll0_div,
        G12_CLK_mpll1_div,
        G12_CLK_mpll2_div,
        G12_CLK_mpll0,
        G12_CLK_mpll1,
        G12_CLK_mpll2,
        G12_CLK_mpeg_sel,
        G12_CLK_mpeg_clk_div,
        G12_CLK_clk81,
        G12_CLK_mpll_50m_div,
        G12_CLK_mpll_50m,
        G12_CLK_sd_emmc_a_clk0_sel,
        G12_CLK_sd_emmc_b_clk0_sel,
        G12_CLK_sd_emmc_c_clk0_sel,
        G12_CLK_sd_emmc_a_clk0_div,
        G12_CLK_sd_emmc_b_clk0_div,
        G12_CLK_sd_emmc_c_clk0_div,
        G12_CLK_sd_emmc_a_clk0,
        G12_CLK_sd_emmc_b_clk0,
        G12_CLK_sd_emmc_c_clk0,
        G12_CLK_ddr,
        G12_CLK_dos,
        G12_CLK_audio_locker,
        G12_CLK_mipi_dsi_host,
        G12_CLK_eth_phy,
        G12_CLK_isa,
        G12_CLK_pl301,
        G12_CLK_periphs,
        G12_CLK_spicc0,
        G12_CLK_i2c,
        G12_CLK_sana,
        G12_CLK_sd,
        G12_CLK_rng0,
        G12_CLK_uart0,
        G12_CLK_spicc1,
        G12_CLK_hiu_iface,
        G12_CLK_mipi_dsi_phy,
        G12_CLK_assist_misc,
        G12_CLK_sd_emmc_a,
        G12_CLK_sd_emmc_b,
        G12_CLK_sd_emmc_c,
        G12_CLK_audio_codec,
        G12_CLK_audio,
        G12_CLK_eth,
        G12_CLK_demux,
        G12_CLK_audio_ififo,
        G12_CLK_adc,
        G12_CLK_uart1,
        G12_CLK_g2d,
        G12_CLK_reset,
        G12_CLK_pcie_comb,
        G12_CLK_parser,
        G12_CLK_usb,
        G12_CLK_pcie_phy,
        G12_CLK_ahb_arb0,
        G12_CLK_ahb_data_bus,
        G12_CLK_ahb_ctrl_bus,
        G12_CLK_htx_hdcp22,
        G12_CLK_htx_pclk,
        G12_CLK_bt656,
        G12_CLK_usb1_ddr_bridge,
        G12_CLK_mmc_pclk,
        G12_CLK_uart2,
        G12_CLK_vpu_intr,
        G12_CLK_gic,
        G12_CLK_vclk2_venci0,
        G12_CLK_vclk2_venci1,
        G12_CLK_vclk2_vencp0,
        G12_CLK_vclk2_vencp1,
        G12_CLK_vclk2_venct0,
        G12_CLK_vclk2_venct1,
        G12_CLK_vclk2_other,
        G12_CLK_vclk2_enci,
        G12_CLK_vclk2_encp,
        G12_CLK_dac_clk,
        G12_CLK_aoclk,
        G12_CLK_iec958,
        G12_CLK_enc480p,
        G12_CLK_rng1,
        G12_CLK_vclk2_enct,
        G12_CLK_vclk2_encl,
        G12_CLK_vclk2_venclmmc,
        G12_CLK_vclk2_vencl,
        G12_CLK_vclk2_other1,
        G12_CLK_dma,
        G12_CLK_efuse,
        G12_CLK_rom_boot,
        G12_CLK_reset_sec,
        G12_CLK_sec_ahb_apb3,
        G12_CLK_cpu_clk_dyn0_sel,
        G12_CLK_cpu_clk_dyn1_sel,
        G12_CLK_cpu_clk_dyn0_div,
        G12_CLK_cpu_clk_dyn1_div,
        G12_CLK_cpu_clk_dyn0,
        G12_CLK_cpu_clk_dyn1,
        G12_CLK_cpu_clk_dyn,
        G12B_CLK_cpu_clk,
        G12_CLK_cpub_clk_dyn0_sel,
        G12_CLK_cpub_clk_dyn0_div,
        G12_CLK_cpub_clk_dyn0,
        G12_CLK_cpub_clk_dyn1_sel,
        G12_CLK_cpub_clk_dyn1_div,
        G12_CLK_cpub_clk_dyn1,
        G12_CLK_cpub_clk_dyn,
        G12_CLK_cpub_clk,
        G12_CLK_ts_div,
        G12_CLK_ts,
        G12_CLK_hdmi_pll_dco,
        G12_CLK_hdmi_pll_od,
        G12_CLK_hdmi_pll_od2,
        G12_CLK_hdmi_pll,
        G12_CLK_vid_pll_div,
        G12_CLK_vid_pll_sel,
        G12_CLK_vid_pll,
        G12_CLK_pcie_pll_dco,
        G12_CLK_pcie_pll_dco_div2,
        G12_CLK_pcie_pll_od,
        G12_CLK_pcie_pll_pll
};

/*
 * XXX:
 * mesong12_cpuclk_get_rate() is needed because the source clock exceeds 32bit
 * and sys/dev/clk cannot handle it.
 * By modifying sys/dev/clk to be able to handle 64-bit clocks, this function
 * will no longer be needed.
 */
static u_int
mesong12_cpuclk_get_rate(struct meson_clk_softc *sc, struct meson_clk_clk *clk)
{
        bus_size_t reg_cntl0;
        uint64_t freq;
        uint32_t val, m, n, div_shift, div;
        uint64_t xtal_clock = clk_get_rate(fdtbus_clock_byname("xtal"));

        KASSERT(clk->type == MESON_CLK_MUX);
        if (sc->sc_clks == mesong12a_clkc_clks) {
                reg_cntl0 = HHI_SYS_PLL_CNTL0;
        } else {
                switch (clk->u.mux.reg) {
                case HHI_SYS_CPU_CLK_CNTL0:
                        reg_cntl0 = HHI_SYS1_PLL_CNTL0;
                        break;
                case HHI_SYS_CPUB_CLK_CNTL:
                        reg_cntl0 = HHI_SYS_PLL_CNTL0;
                        break;
                default:
                        panic("%s: illegal clk table\n", __func__);
                }
        }
        CLK_LOCK(sc);

        if ((CLK_READ(sc, clk->u.mux.reg) & __BIT(11)) == 0) {
                CLK_UNLOCK(sc);

                /* use dyn clock instead of sys1?_pll */
                struct clk *clkp;

                switch (clk->u.mux.reg) {
                case HHI_SYS_CPU_CLK_CNTL0:
                        clkp = (struct clk *)meson_clk_clock_find(sc,
                            "cpu_clk_dyn");
                        freq = clk_get_rate(clkp);
                        break;
                case HHI_SYS_CPUB_CLK_CNTL:
                        clkp = (struct clk *)meson_clk_clock_find(sc,
                            "cpub_clk_dyn");
                        freq = clk_get_rate(clkp);
                        break;
                default:
                        freq = 0;
                        break;
                }
                return freq;
        }
        val = CLK_READ(sc, reg_cntl0);
        m = __SHIFTOUT(val, __BITS(7,0));
        n = __SHIFTOUT(val, __BITS(14,10));
        div_shift = __SHIFTOUT(val, __BITS(18,16));
        div = 1 << div_shift;
        CLK_UNLOCK(sc);

        freq = xtal_clock * m / n / div;
        return freq;
}

static int
mesong12_cpuclk_set_rate(struct meson_clk_softc *sc, struct meson_clk_clk *clk,
    u_int rate)
{
        bus_size_t reg_cntl0;
        uint32_t val;
        uint64_t xtal_clock = clk_get_rate(fdtbus_clock_byname("xtal"));
        int new_m, new_n, new_div, i, error;

        KASSERT(clk->type == MESON_CLK_MUX);
        if (sc->sc_clks == mesong12a_clkc_clks) {
                reg_cntl0 = HHI_SYS_PLL_CNTL0;
        } else {
                switch (clk->u.mux.reg) {
                case HHI_SYS_CPU_CLK_CNTL0:
                        reg_cntl0 = HHI_SYS1_PLL_CNTL0;
                        break;
                case HHI_SYS_CPUB_CLK_CNTL:
                        reg_cntl0 = HHI_SYS_PLL_CNTL0;
                        break;
                default:
                        panic("%s: illegal clk table\n", __func__);
                }
        }

        new_div = 7;
        new_n = 1;
        new_m = (uint64_t)rate * (1 << new_div) / xtal_clock;
        while (new_m >= 250 && (new_div > 0)) {
                new_div--;
                new_m /= 2;
        }

        if (new_m >= 256)
                return EINVAL;

        CLK_LOCK(sc);

        /* use cpub?_clk_dyn temporary */
        val = CLK_READ(sc, clk->u.mux.reg);
        CLK_WRITE(sc, clk->u.mux.reg, val & ~__BIT(11));
        DELAY(100);

#define MESON_PLL_CNTL_REG_LOCK __BIT(31)
#define MESON_PLL_CNTL_REG_RST  __BIT(29)
#define MESON_PLL_CNTL_REG_EN   __BIT(28)
        /* disable */
        val = CLK_READ(sc, reg_cntl0);
        CLK_WRITE(sc, reg_cntl0, val | MESON_PLL_CNTL_REG_RST);
        val = CLK_READ(sc, reg_cntl0);
        CLK_WRITE(sc, reg_cntl0, val & ~MESON_PLL_CNTL_REG_EN);

        /* HHI_SYS{,1}_PLL_CNTL{1,2,3,4,5} */
        CLK_WRITE(sc, reg_cntl0 + CBUS_REG(1), 0x00000000);
        CLK_WRITE(sc, reg_cntl0 + CBUS_REG(2), 0x00000000);
        CLK_WRITE(sc, reg_cntl0 + CBUS_REG(3), 0x48681c00);
        CLK_WRITE(sc, reg_cntl0 + CBUS_REG(4), 0x88770290);
        CLK_WRITE(sc, reg_cntl0 + CBUS_REG(5), 0x39272000);
        DELAY(100);

        /* write new M, N, and DIV */
        val = CLK_READ(sc, reg_cntl0);
        val &= ~__BITS(7,0);
        val |= __SHIFTIN(new_m, __BITS(7,0));
        val &= ~__BITS(14,10);
        val |= __SHIFTIN(new_n, __BITS(14,10));
        val &= ~__BITS(18,16);
        val |= __SHIFTIN(new_div, __BITS(18,16));
        CLK_WRITE(sc, reg_cntl0, val);

        /* enable */
        val = CLK_READ(sc, reg_cntl0);
        CLK_WRITE(sc, reg_cntl0, val | MESON_PLL_CNTL_REG_RST);
        val = CLK_READ(sc, reg_cntl0);
        CLK_WRITE(sc, reg_cntl0, val | MESON_PLL_CNTL_REG_EN);
        DELAY(1000);
        val = CLK_READ(sc, reg_cntl0);
        CLK_WRITE(sc, reg_cntl0, val & ~MESON_PLL_CNTL_REG_RST);

        error = ETIMEDOUT;
        for (i = 24000000; i > 0; i--) {
                if ((CLK_READ(sc, reg_cntl0) & MESON_PLL_CNTL_REG_LOCK) != 0) {
                        error = 0;
                        break;
                }
        }

        /* XXX: always use sys1?_pll. cpub?_clk_dyn should be used for <1GHz */
        val = CLK_READ(sc, clk->u.mux.reg);
        CLK_WRITE(sc, clk->u.mux.reg, val | __BIT(11));
        DELAY(100);

        CLK_UNLOCK(sc);

        return error;
}

static int
mesong12_clk_pcie_pll_set_rate(struct meson_clk_softc *sc,
    struct meson_clk_clk *clk, u_int new_rate)
{
        struct meson_clk_pll *pll = &clk->u.pll;

        KASSERT(clk->type == MESON_CLK_PLL);

        /*
         * A strict register sequence is required to set the PLL to the
         * fine-tuned 100MHz for PCIe
         */
        if (new_rate == (100000000 * 2 * 2)) { /* "2*2" is fixed factor */
                uint32_t cntl0, cntl4, cntl3, cntl5;

                cntl0 = __SHIFTIN(9, HHI_PCIE_PLL_CNTL0_PCIE_APLL_OD) |
                    __SHIFTIN(1, HHI_PCIE_PLL_CNTL0_PCIE_APLL_PREDIV_SEL) |
                    __SHIFTIN(150, HHI_PCIE_PLL_CNTL0_PCIE_APLL_FBKDIV);
                cntl4 =  __SHIFTIN(1, HHI_PCIE_PLL_CNTL4_PCIE_APLL_LPF_CAPADJ) |
                    HHI_PCIE_PLL_CNTL4_PCIE_APLL_LOAD |
                    HHI_PCIE_PLL_CNTL4_PCIE_APLL_LOAD_EN;
                cntl3 = __SHIFTIN(1, HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_HOLD_T) |
                    __SHIFTIN(2, HHI_PCIE_PLL_CNTL3_PCIE_APLL_AFC_DIV) |
                    HHI_PCIE_PLL_CNTL3_PCIE_APLL_BIAS_LPF_EN |
                    __SHIFTIN(8, HHI_PCIE_PLL_CNTL3_PCIE_APLL_CP_ICAP) |
                    __SHIFTIN(14, HHI_PCIE_PLL_CNTL3_PCIE_APLL_CP_IRES);
                cntl5 = __SHIFTIN(6, HHI_PCIE_PLL_CNTL5_PCIE_HCSL_ADJ_LDO) |
                    HHI_PCIE_PLL_CNTL5_PCIE_HCSL_BGP_EN |
                    HHI_PCIE_PLL_CNTL5_PCIE_HCSL_CAL_EN |
                    HHI_PCIE_PLL_CNTL5_PCIE_HCSL_EN0;

                CLK_LOCK(sc);
                CLK_WRITE_BITS(sc, pll->reset.reg, pll->reset.mask, 1);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL0, cntl0 |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_RESET);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL0, cntl0 |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_RESET |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_EN);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL1, 0);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL2,
                    __SHIFTIN(0x1100, HHI_PCIE_PLL_CNTL2_PCIE_APLL_RESERVE));
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL3, cntl3);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL4, cntl4);
                delay(20);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL5, cntl5);
                delay(10);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL5, cntl5 |
                    HHI_PCIE_PLL_CNTL5_PCIE_HCSL_CAL_RSTN);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL4, cntl4 |
                    HHI_PCIE_PLL_CNTL4_PCIE_APLL_VCTRL_MON_EN);
                delay(10);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL0, cntl0 |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_RESET |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_EN |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_AFC_START);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL0, cntl0 |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_EN |
                    HHI_PCIE_PLL_CNTL0_PCIE_APLL_AFC_START);
                CLK_WRITE(sc, HHI_PCIE_PLL_CNTL2,
                    __SHIFTIN(0x1000, HHI_PCIE_PLL_CNTL2_PCIE_APLL_RESERVE));

                CLK_WRITE_BITS(sc, pll->reset.reg, pll->reset.mask, 0);
                /* XXX: pll_wait_lock() sometimes times out? but ignore it */
                meson_clk_pll_wait_lock(sc, pll);
                CLK_UNLOCK(sc);
                return 0;
        }

        return meson_clk_pll_set_rate(sc, clk, new_rate);
}

static const struct mesong12_clkc_config g12a_config = {
        .name = "Meson G12A",
        .clks = mesong12a_clkc_clks,
        .nclks = __arraycount(mesong12a_clkc_clks),
};

static const struct mesong12_clkc_config g12b_config = {
        .name = "Meson G12B",
        .clks = mesong12b_clkc_clks,
        .nclks = __arraycount(mesong12b_clkc_clks),
};

static const struct device_compatible_entry compat_data[] = {
        { .compat = "amlogic,g12a-clkc",        .data = &g12a_config },
        { .compat = "amlogic,g12b-clkc",        .data = &g12b_config },
        DEVICE_COMPAT_EOL
};

CFATTACH_DECL_NEW(mesong12_clkc, sizeof(struct meson_clk_softc),
    mesong12_clkc_match, mesong12_clkc_attach, NULL, NULL);

static int
mesong12_clkc_match(device_t parent, cfdata_t cf, void *aux)
{
        struct fdt_attach_args * const faa = aux;

        return of_compatible_match(faa->faa_phandle, compat_data);
}

static void
mesong12_clkc_attach(device_t parent, device_t self, void *aux)
{
        struct meson_clk_softc * const sc = device_private(self);
        struct fdt_attach_args * const faa = aux;
        const struct mesong12_clkc_config *conf;
        const int phandle = faa->faa_phandle;

        sc->sc_dev = self;
        sc->sc_phandle = faa->faa_phandle;
        sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(sc->sc_phandle));
        if (sc->sc_syscon == NULL) {
                aprint_error(": couldn't get syscon registers\n");
                return;
        }

        conf = of_compatible_lookup(phandle, compat_data)->data;
        sc->sc_clks = conf->clks;
        sc->sc_nclks = conf->nclks;

        aprint_naive("\n");
        aprint_normal(": %s clock controller\n", conf->name);

        meson_clk_attach(sc);
        meson_clk_print(sc);
}