From f5abfed8e916b9dd7a1b1187935e834acd5c9710 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Sun, 10 Feb 2019 14:54:30 +0100 Subject: clk: create meson directory and move related drivers In order to support the Amlogic G12A clock controller, re-architect the clock files into a meson directory. No functionnal changes. MAINTAINERS entry is also updated. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 2 +- drivers/clk/clk_meson.c | 918 ------------------------------------------ drivers/clk/clk_meson.h | 47 --- drivers/clk/clk_meson_axg.c | 316 --------------- drivers/clk/meson/Kconfig | 15 + drivers/clk/meson/Makefile | 8 + drivers/clk/meson/axg.c | 316 +++++++++++++++ drivers/clk/meson/clk_meson.h | 47 +++ drivers/clk/meson/gxbb.c | 918 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1306 insertions(+), 1282 deletions(-) delete mode 100644 drivers/clk/clk_meson.c delete mode 100644 drivers/clk/clk_meson.h delete mode 100644 drivers/clk/clk_meson_axg.c create mode 100644 drivers/clk/meson/Kconfig create mode 100644 drivers/clk/meson/Makefile create mode 100644 drivers/clk/meson/axg.c create mode 100644 drivers/clk/meson/clk_meson.h create mode 100644 drivers/clk/meson/gxbb.c (limited to 'drivers/clk') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ff60fc5..96969b9 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -101,6 +101,7 @@ config CLK_STM32MP1 source "drivers/clk/at91/Kconfig" source "drivers/clk/exynos/Kconfig" source "drivers/clk/imx/Kconfig" +source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/owl/Kconfig" source "drivers/clk/renesas/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1d9d725..719b9b8 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -12,7 +12,7 @@ obj-y += imx/ obj-y += tegra/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ -obj-$(CONFIG_ARCH_MESON) += clk_meson.o clk_meson_axg.o +obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_SOCFPGA) += altera/ obj-$(CONFIG_CLK_AT91) += at91/ diff --git a/drivers/clk/clk_meson.c b/drivers/clk/clk_meson.c deleted file mode 100644 index 2cb53fb..0000000 --- a/drivers/clk/clk_meson.c +++ /dev/null @@ -1,918 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2018 - Beniamino Galvani - * (C) Copyright 2018 - BayLibre, SAS - * Author: Neil Armstrong - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "clk_meson.h" - -/* This driver support only basic clock tree operations : - * - Can calculate clock frequency on a limited tree - * - Can Read muxes and basic dividers (0-based only) - * - Can enable/disable gates with limited propagation - * - Can reparent without propagation, only on muxes - * - Can set rates without reparenting - * This driver is adapted to what is actually supported by U-Boot - */ - -/* Only the clocks ids we don't want to expose, such as the internal muxes - * and dividers of composite clocks, will remain defined here. - */ -#define CLKID_MPEG_SEL 10 -#define CLKID_MPEG_DIV 11 -#define CLKID_SAR_ADC_DIV 99 -#define CLKID_MALI_0_DIV 101 -#define CLKID_MALI_1_DIV 104 -#define CLKID_CTS_AMCLK_SEL 108 -#define CLKID_CTS_AMCLK_DIV 109 -#define CLKID_CTS_MCLK_I958_SEL 111 -#define CLKID_CTS_MCLK_I958_DIV 112 -#define CLKID_32K_CLK_SEL 115 -#define CLKID_32K_CLK_DIV 116 -#define CLKID_SD_EMMC_A_CLK0_SEL 117 -#define CLKID_SD_EMMC_A_CLK0_DIV 118 -#define CLKID_SD_EMMC_B_CLK0_SEL 120 -#define CLKID_SD_EMMC_B_CLK0_DIV 121 -#define CLKID_SD_EMMC_C_CLK0_SEL 123 -#define CLKID_SD_EMMC_C_CLK0_DIV 124 -#define CLKID_VPU_0_DIV 127 -#define CLKID_VPU_1_DIV 130 -#define CLKID_VAPB_0_DIV 134 -#define CLKID_VAPB_1_DIV 137 -#define CLKID_HDMI_PLL_PRE_MULT 141 -#define CLKID_MPLL0_DIV 142 -#define CLKID_MPLL1_DIV 143 -#define CLKID_MPLL2_DIV 144 -#define CLKID_MPLL_PREDIV 145 -#define CLKID_FCLK_DIV2_DIV 146 -#define CLKID_FCLK_DIV3_DIV 147 -#define CLKID_FCLK_DIV4_DIV 148 -#define CLKID_FCLK_DIV5_DIV 149 -#define CLKID_FCLK_DIV7_DIV 150 -#define CLKID_VDEC_1_SEL 151 -#define CLKID_VDEC_1_DIV 152 -#define CLKID_VDEC_HEVC_SEL 154 -#define CLKID_VDEC_HEVC_DIV 155 - -#define XTAL_RATE 24000000 - -struct meson_clk { - struct regmap *map; -}; - -static ulong meson_div_get_rate(struct clk *clk, unsigned long id); -static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, - ulong current_rate); -static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, - unsigned long parent_id); -static ulong meson_mux_get_rate(struct clk *clk, unsigned long id); -static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, - ulong rate, ulong current_rate); -static ulong meson_mux_get_parent(struct clk *clk, unsigned long id); -static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); - -static struct meson_gate gates[] = { - /* Everything Else (EE) domain gates */ - MESON_GATE(CLKID_DDR, HHI_GCLK_MPEG0, 0), - MESON_GATE(CLKID_DOS, HHI_GCLK_MPEG0, 1), - MESON_GATE(CLKID_ISA, HHI_GCLK_MPEG0, 5), - MESON_GATE(CLKID_PL301, HHI_GCLK_MPEG0, 6), - MESON_GATE(CLKID_PERIPHS, HHI_GCLK_MPEG0, 7), - MESON_GATE(CLKID_SPICC, HHI_GCLK_MPEG0, 8), - MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), - MESON_GATE(CLKID_SAR_ADC, HHI_GCLK_MPEG0, 10), - MESON_GATE(CLKID_SMART_CARD, HHI_GCLK_MPEG0, 11), - MESON_GATE(CLKID_RNG0, HHI_GCLK_MPEG0, 12), - MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), - MESON_GATE(CLKID_SDHC, HHI_GCLK_MPEG0, 14), - MESON_GATE(CLKID_STREAM, HHI_GCLK_MPEG0, 15), - MESON_GATE(CLKID_ASYNC_FIFO, HHI_GCLK_MPEG0, 16), - MESON_GATE(CLKID_SDIO, HHI_GCLK_MPEG0, 17), - MESON_GATE(CLKID_ABUF, HHI_GCLK_MPEG0, 18), - MESON_GATE(CLKID_HIU_IFACE, HHI_GCLK_MPEG0, 19), - MESON_GATE(CLKID_ASSIST_MISC, HHI_GCLK_MPEG0, 23), - MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 24), - MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), - MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), - MESON_GATE(CLKID_SPI, HHI_GCLK_MPEG0, 30), - - MESON_GATE(CLKID_I2S_SPDIF, HHI_GCLK_MPEG1, 2), - MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), - MESON_GATE(CLKID_DEMUX, HHI_GCLK_MPEG1, 4), - MESON_GATE(CLKID_AIU_GLUE, HHI_GCLK_MPEG1, 6), - MESON_GATE(CLKID_IEC958, HHI_GCLK_MPEG1, 7), - MESON_GATE(CLKID_I2S_OUT, HHI_GCLK_MPEG1, 8), - MESON_GATE(CLKID_AMCLK, HHI_GCLK_MPEG1, 9), - MESON_GATE(CLKID_AIFIFO2, HHI_GCLK_MPEG1, 10), - MESON_GATE(CLKID_MIXER, HHI_GCLK_MPEG1, 11), - MESON_GATE(CLKID_MIXER_IFACE, HHI_GCLK_MPEG1, 12), - MESON_GATE(CLKID_ADC, HHI_GCLK_MPEG1, 13), - MESON_GATE(CLKID_BLKMV, HHI_GCLK_MPEG1, 14), - MESON_GATE(CLKID_AIU, HHI_GCLK_MPEG1, 15), - MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), - MESON_GATE(CLKID_G2D, HHI_GCLK_MPEG1, 20), - MESON_GATE(CLKID_USB0, HHI_GCLK_MPEG1, 21), - MESON_GATE(CLKID_USB1, HHI_GCLK_MPEG1, 22), - MESON_GATE(CLKID_RESET, HHI_GCLK_MPEG1, 23), - MESON_GATE(CLKID_NAND, HHI_GCLK_MPEG1, 24), - MESON_GATE(CLKID_DOS_PARSER, HHI_GCLK_MPEG1, 25), - MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 26), - MESON_GATE(CLKID_VDIN1, HHI_GCLK_MPEG1, 28), - MESON_GATE(CLKID_AHB_ARB0, HHI_GCLK_MPEG1, 29), - MESON_GATE(CLKID_EFUSE, HHI_GCLK_MPEG1, 30), - MESON_GATE(CLKID_BOOT_ROM, HHI_GCLK_MPEG1, 31), - - MESON_GATE(CLKID_AHB_DATA_BUS, HHI_GCLK_MPEG2, 1), - MESON_GATE(CLKID_AHB_CTRL_BUS, HHI_GCLK_MPEG2, 2), - MESON_GATE(CLKID_HDMI_INTR_SYNC, HHI_GCLK_MPEG2, 3), - MESON_GATE(CLKID_HDMI_PCLK, HHI_GCLK_MPEG2, 4), - MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8), - MESON_GATE(CLKID_USB0_DDR_BRIDGE, HHI_GCLK_MPEG2, 9), - MESON_GATE(CLKID_MMC_PCLK, HHI_GCLK_MPEG2, 11), - MESON_GATE(CLKID_DVIN, HHI_GCLK_MPEG2, 12), - MESON_GATE(CLKID_UART2, HHI_GCLK_MPEG2, 15), - MESON_GATE(CLKID_SANA, HHI_GCLK_MPEG2, 22), - MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25), - MESON_GATE(CLKID_SEC_AHB_AHB3_BRIDGE, HHI_GCLK_MPEG2, 26), - MESON_GATE(CLKID_CLK81_A53, HHI_GCLK_MPEG2, 29), - - MESON_GATE(CLKID_VCLK2_VENCI0, HHI_GCLK_OTHER, 1), - MESON_GATE(CLKID_VCLK2_VENCI1, HHI_GCLK_OTHER, 2), - MESON_GATE(CLKID_VCLK2_VENCP0, HHI_GCLK_OTHER, 3), - MESON_GATE(CLKID_VCLK2_VENCP1, HHI_GCLK_OTHER, 4), - MESON_GATE(CLKID_GCLK_VENCI_INT0, HHI_GCLK_OTHER, 8), - MESON_GATE(CLKID_DAC_CLK, HHI_GCLK_OTHER, 10), - MESON_GATE(CLKID_AOCLK_GATE, HHI_GCLK_OTHER, 14), - MESON_GATE(CLKID_IEC958_GATE, HHI_GCLK_OTHER, 16), - MESON_GATE(CLKID_ENC480P, HHI_GCLK_OTHER, 20), - MESON_GATE(CLKID_RNG1, HHI_GCLK_OTHER, 21), - MESON_GATE(CLKID_GCLK_VENCI_INT1, HHI_GCLK_OTHER, 22), - MESON_GATE(CLKID_VCLK2_VENCLMCC, HHI_GCLK_OTHER, 24), - MESON_GATE(CLKID_VCLK2_VENCL, HHI_GCLK_OTHER, 25), - MESON_GATE(CLKID_VCLK_OTHER, HHI_GCLK_OTHER, 26), - MESON_GATE(CLKID_EDP, HHI_GCLK_OTHER, 31), - - /* Always On (AO) domain gates */ - MESON_GATE(CLKID_AO_MEDIA_CPU, HHI_GCLK_AO, 0), - MESON_GATE(CLKID_AO_AHB_SRAM, HHI_GCLK_AO, 1), - MESON_GATE(CLKID_AO_AHB_BUS, HHI_GCLK_AO, 2), - MESON_GATE(CLKID_AO_IFACE, HHI_GCLK_AO, 3), - MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), - - /* PLL Gates */ - /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ - MESON_GATE(CLKID_FCLK_DIV3, HHI_MPLL_CNTL6, 28), - MESON_GATE(CLKID_FCLK_DIV4, HHI_MPLL_CNTL6, 29), - MESON_GATE(CLKID_FCLK_DIV5, HHI_MPLL_CNTL6, 30), - MESON_GATE(CLKID_FCLK_DIV7, HHI_MPLL_CNTL6, 31), - MESON_GATE(CLKID_MPLL0, HHI_MPLL_CNTL7, 14), - MESON_GATE(CLKID_MPLL1, HHI_MPLL_CNTL8, 14), - MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), - /* CLKID_CLK81 is critical for the system */ - - /* Peripheral Gates */ - MESON_GATE(CLKID_SAR_ADC_CLK, HHI_SAR_CLK_CNTL, 8), - MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7), - MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), - MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), - MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8), - MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24), - MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8), - MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24), - MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30), -}; - -static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct meson_gate *gate; - - debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id); - - /* Propagate through muxes */ - switch (id) { - case CLKID_VPU: - return meson_set_gate_by_id(clk, - meson_mux_get_parent(clk, CLKID_VPU), on); - case CLKID_VAPB_SEL: - return meson_set_gate_by_id(clk, - meson_mux_get_parent(clk, CLKID_VAPB_SEL), on); - } - - if (id >= ARRAY_SIZE(gates)) - return -ENOENT; - - gate = &gates[id]; - - if (gate->reg == 0) - return 0; - - debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id); - - regmap_update_bits(priv->map, gate->reg, - BIT(gate->bit), on ? BIT(gate->bit) : 0); - - /* Propagate to next gate(s) */ - switch (id) { - case CLKID_VAPB: - return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on); - } - - return 0; -} - -static int meson_clk_enable(struct clk *clk) -{ - return meson_set_gate_by_id(clk, clk->id, true); -} - -static int meson_clk_disable(struct clk *clk) -{ - return meson_set_gate_by_id(clk, clk->id, false); -} - -static struct parm meson_vpu_0_div_parm = { - HHI_VPU_CLK_CNTL, 0, 7, -}; - -int meson_vpu_0_div_parent = CLKID_VPU_0_SEL; - -static struct parm meson_vpu_1_div_parm = { - HHI_VPU_CLK_CNTL, 16, 7, -}; - -int meson_vpu_1_div_parent = CLKID_VPU_1_SEL; - -static struct parm meson_vapb_0_div_parm = { - HHI_VAPBCLK_CNTL, 0, 7, -}; - -int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL; - -static struct parm meson_vapb_1_div_parm = { - HHI_VAPBCLK_CNTL, 16, 7, -}; - -int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL; - -static ulong meson_div_get_rate(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - unsigned int rate, parent_rate; - struct parm *parm; - int parent; - uint reg; - - switch (id) { - case CLKID_VPU_0_DIV: - parm = &meson_vpu_0_div_parm; - parent = meson_vpu_0_div_parent; - break; - case CLKID_VPU_1_DIV: - parm = &meson_vpu_1_div_parm; - parent = meson_vpu_1_div_parent; - break; - case CLKID_VAPB_0_DIV: - parm = &meson_vapb_0_div_parm; - parent = meson_vapb_0_div_parent; - break; - case CLKID_VAPB_1_DIV: - parm = &meson_vapb_1_div_parm; - parent = meson_vapb_1_div_parent; - break; - default: - return -ENOENT; - } - - regmap_read(priv->map, parm->reg_off, ®); - reg = PARM_GET(parm->width, parm->shift, reg); - - debug("%s: div of %ld is %d\n", __func__, id, reg + 1); - - parent_rate = meson_clk_get_rate_by_id(clk, parent); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate); - - rate = parent_rate / (reg + 1); - - debug("%s: rate of %ld is %d\n", __func__, id, rate); - - return rate; -} - -static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, - ulong current_rate) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - unsigned int new_div = -EINVAL; - unsigned long parent_rate; - struct parm *parm; - int parent; - int ret; - - if (current_rate == rate) - return 0; - - debug("%s: setting rate of %ld from %ld to %ld\n", - __func__, id, current_rate, rate); - - switch (id) { - case CLKID_VPU_0_DIV: - parm = &meson_vpu_0_div_parm; - parent = meson_vpu_0_div_parent; - break; - case CLKID_VPU_1_DIV: - parm = &meson_vpu_1_div_parm; - parent = meson_vpu_1_div_parent; - break; - case CLKID_VAPB_0_DIV: - parm = &meson_vapb_0_div_parm; - parent = meson_vapb_0_div_parent; - break; - case CLKID_VAPB_1_DIV: - parm = &meson_vapb_1_div_parm; - parent = meson_vapb_1_div_parent; - break; - default: - return -ENOENT; - } - - parent_rate = meson_clk_get_rate_by_id(clk, parent); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate); - - /* If can't divide, set parent instead */ - if (!parent_rate || rate > parent_rate) - return meson_clk_set_rate_by_id(clk, parent, rate, - current_rate); - - new_div = DIV_ROUND_CLOSEST(parent_rate, rate); - - debug("%s: new div of %ld is %d\n", __func__, id, new_div); - - /* If overflow, try to set parent rate and retry */ - if (!new_div || new_div > (1 << parm->width)) { - ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate); - if (IS_ERR_VALUE(ret)) - return ret; - - parent_rate = meson_clk_get_rate_by_id(clk, parent); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - new_div = DIV_ROUND_CLOSEST(parent_rate, rate); - - debug("%s: new new div of %ld is %d\n", __func__, id, new_div); - - if (!new_div || new_div > (1 << parm->width)) - return -EINVAL; - } - - debug("%s: setting div of %ld to %d\n", __func__, id, new_div); - - regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), - (new_div - 1) << parm->shift); - - debug("%s: new rate of %ld is %ld\n", - __func__, id, meson_div_get_rate(clk, id)); - - return 0; -} - -static struct parm meson_vpu_mux_parm = { - HHI_VPU_CLK_CNTL, 31, 1, -}; - -int meson_vpu_mux_parents[] = { - CLKID_VPU_0, - CLKID_VPU_1, -}; - -static struct parm meson_vpu_0_mux_parm = { - HHI_VPU_CLK_CNTL, 9, 2, -}; - -static struct parm meson_vpu_1_mux_parm = { - HHI_VPU_CLK_CNTL, 25, 2, -}; - -static int meson_vpu_0_1_mux_parents[] = { - CLKID_FCLK_DIV4, - CLKID_FCLK_DIV3, - CLKID_FCLK_DIV5, - CLKID_FCLK_DIV7, -}; - -static struct parm meson_vapb_sel_mux_parm = { - HHI_VAPBCLK_CNTL, 31, 1, -}; - -int meson_vapb_sel_mux_parents[] = { - CLKID_VAPB_0, - CLKID_VAPB_1, -}; - -static struct parm meson_vapb_0_mux_parm = { - HHI_VAPBCLK_CNTL, 9, 2, -}; - -static struct parm meson_vapb_1_mux_parm = { - HHI_VAPBCLK_CNTL, 25, 2, -}; - -static int meson_vapb_0_1_mux_parents[] = { - CLKID_FCLK_DIV4, - CLKID_FCLK_DIV3, - CLKID_FCLK_DIV5, - CLKID_FCLK_DIV7, -}; - -static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct parm *parm; - int *parents; - uint reg; - - switch (id) { - case CLKID_VPU: - parm = &meson_vpu_mux_parm; - parents = meson_vpu_mux_parents; - break; - case CLKID_VPU_0_SEL: - parm = &meson_vpu_0_mux_parm; - parents = meson_vpu_0_1_mux_parents; - break; - case CLKID_VPU_1_SEL: - parm = &meson_vpu_1_mux_parm; - parents = meson_vpu_0_1_mux_parents; - break; - case CLKID_VAPB_SEL: - parm = &meson_vapb_sel_mux_parm; - parents = meson_vapb_sel_mux_parents; - break; - case CLKID_VAPB_0_SEL: - parm = &meson_vapb_0_mux_parm; - parents = meson_vapb_0_1_mux_parents; - break; - case CLKID_VAPB_1_SEL: - parm = &meson_vapb_1_mux_parm; - parents = meson_vapb_0_1_mux_parents; - break; - default: - return -ENOENT; - } - - regmap_read(priv->map, parm->reg_off, ®); - reg = PARM_GET(parm->width, parm->shift, reg); - - debug("%s: parent of %ld is %d (%d)\n", - __func__, id, parents[reg], reg); - - return parents[reg]; -} - -static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, - unsigned long parent_id) -{ - unsigned long cur_parent = meson_mux_get_parent(clk, id); - struct meson_clk *priv = dev_get_priv(clk->dev); - unsigned int new_index = -EINVAL; - struct parm *parm; - int *parents; - int i; - - if (IS_ERR_VALUE(cur_parent)) - return cur_parent; - - debug("%s: setting parent of %ld from %ld to %ld\n", - __func__, id, cur_parent, parent_id); - - if (cur_parent == parent_id) - return 0; - - switch (id) { - case CLKID_VPU: - parm = &meson_vpu_mux_parm; - parents = meson_vpu_mux_parents; - break; - case CLKID_VPU_0_SEL: - parm = &meson_vpu_0_mux_parm; - parents = meson_vpu_0_1_mux_parents; - break; - case CLKID_VPU_1_SEL: - parm = &meson_vpu_1_mux_parm; - parents = meson_vpu_0_1_mux_parents; - break; - case CLKID_VAPB_SEL: - parm = &meson_vapb_sel_mux_parm; - parents = meson_vapb_sel_mux_parents; - break; - case CLKID_VAPB_0_SEL: - parm = &meson_vapb_0_mux_parm; - parents = meson_vapb_0_1_mux_parents; - break; - case CLKID_VAPB_1_SEL: - parm = &meson_vapb_1_mux_parm; - parents = meson_vapb_0_1_mux_parents; - break; - default: - /* Not a mux */ - return -ENOENT; - } - - for (i = 0 ; i < (1 << parm->width) ; ++i) { - if (parents[i] == parent_id) - new_index = i; - } - - if (IS_ERR_VALUE(new_index)) - return new_index; - - debug("%s: new index of %ld is %d\n", __func__, id, new_index); - - regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), - new_index << parm->shift); - - debug("%s: new parent of %ld is %ld\n", - __func__, id, meson_mux_get_parent(clk, id)); - - return 0; -} - -static ulong meson_mux_get_rate(struct clk *clk, unsigned long id) -{ - int parent = meson_mux_get_parent(clk, id); - - if (IS_ERR_VALUE(parent)) - return parent; - - return meson_clk_get_rate_by_id(clk, parent); -} - -static unsigned long meson_clk81_get_rate(struct clk *clk) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - unsigned long parent_rate; - uint reg; - int parents[] = { - -1, - -1, - CLKID_FCLK_DIV7, - CLKID_MPLL1, - CLKID_MPLL2, - CLKID_FCLK_DIV4, - CLKID_FCLK_DIV3, - CLKID_FCLK_DIV5 - }; - - /* mux */ - regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); - reg = (reg >> 12) & 7; - - switch (reg) { - case 0: - parent_rate = XTAL_RATE; - break; - case 1: - return -ENOENT; - default: - parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); - } - - /* divider */ - regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); - reg = reg & ((1 << 7) - 1); - - /* clk81 divider is zero based */ - return parent_rate / (reg + 1); -} - -static long mpll_rate_from_params(unsigned long parent_rate, - unsigned long sdm, - unsigned long n2) -{ - unsigned long divisor = (SDM_DEN * n2) + sdm; - - if (n2 < N2_MIN) - return -EINVAL; - - return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); -} - -static struct parm meson_mpll0_parm[3] = { - {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ -}; - -static struct parm meson_mpll1_parm[3] = { - {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ -}; - -static struct parm meson_mpll2_parm[3] = { - {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ -}; - -/* - * MultiPhase Locked Loops are outputs from a PLL with additional frequency - * scaling capabilities. MPLL rates are calculated as: - * - * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) - */ -static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct parm *psdm, *pn2; - unsigned long sdm, n2; - unsigned long parent_rate; - uint reg; - - switch (id) { - case CLKID_MPLL0: - psdm = &meson_mpll0_parm[0]; - pn2 = &meson_mpll0_parm[1]; - break; - case CLKID_MPLL1: - psdm = &meson_mpll1_parm[0]; - pn2 = &meson_mpll1_parm[1]; - break; - case CLKID_MPLL2: - psdm = &meson_mpll2_parm[0]; - pn2 = &meson_mpll2_parm[1]; - break; - default: - return -ENOENT; - } - - parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - regmap_read(priv->map, psdm->reg_off, ®); - sdm = PARM_GET(psdm->width, psdm->shift, reg); - - regmap_read(priv->map, pn2->reg_off, ®); - n2 = PARM_GET(pn2->width, pn2->shift, reg); - - return mpll_rate_from_params(parent_rate, sdm, n2); -} - -static struct parm meson_fixed_pll_parm[3] = { - {HHI_MPLL_CNTL, 0, 9}, /* pm */ - {HHI_MPLL_CNTL, 9, 5}, /* pn */ - {HHI_MPLL_CNTL, 16, 2}, /* pod */ -}; - -static struct parm meson_sys_pll_parm[3] = { - {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ - {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ - {HHI_SYS_PLL_CNTL, 10, 2}, /* pod */ -}; - -static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct parm *pm, *pn, *pod; - unsigned long parent_rate_mhz = XTAL_RATE / 1000000; - u16 n, m, od; - uint reg; - - switch (id) { - case CLKID_FIXED_PLL: - pm = &meson_fixed_pll_parm[0]; - pn = &meson_fixed_pll_parm[1]; - pod = &meson_fixed_pll_parm[2]; - break; - case CLKID_SYS_PLL: - pm = &meson_sys_pll_parm[0]; - pn = &meson_sys_pll_parm[1]; - pod = &meson_sys_pll_parm[2]; - break; - default: - return -ENOENT; - } - - regmap_read(priv->map, pn->reg_off, ®); - n = PARM_GET(pn->width, pn->shift, reg); - - regmap_read(priv->map, pm->reg_off, ®); - m = PARM_GET(pm->width, pm->shift, reg); - - regmap_read(priv->map, pod->reg_off, ®); - od = PARM_GET(pod->width, pod->shift, reg); - - return ((parent_rate_mhz * m / n) >> od) * 1000000; -} - -static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) -{ - ulong rate; - - switch (id) { - case CLKID_FIXED_PLL: - case CLKID_SYS_PLL: - rate = meson_pll_get_rate(clk, id); - break; - case CLKID_FCLK_DIV2: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; - break; - case CLKID_FCLK_DIV3: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; - break; - case CLKID_FCLK_DIV4: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; - break; - case CLKID_FCLK_DIV5: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; - break; - case CLKID_FCLK_DIV7: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; - break; - case CLKID_MPLL0: - case CLKID_MPLL1: - case CLKID_MPLL2: - rate = meson_mpll_get_rate(clk, id); - break; - case CLKID_CLK81: - rate = meson_clk81_get_rate(clk); - break; - case CLKID_VPU_0: - rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV); - break; - case CLKID_VPU_1: - rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV); - break; - case CLKID_VAPB: - rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL); - break; - case CLKID_VAPB_0: - rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV); - break; - case CLKID_VAPB_1: - rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); - break; - case CLKID_VPU_0_DIV: - case CLKID_VPU_1_DIV: - case CLKID_VAPB_0_DIV: - case CLKID_VAPB_1_DIV: - rate = meson_div_get_rate(clk, id); - break; - case CLKID_VPU: - case CLKID_VPU_0_SEL: - case CLKID_VPU_1_SEL: - case CLKID_VAPB_SEL: - case CLKID_VAPB_0_SEL: - case CLKID_VAPB_1_SEL: - rate = meson_mux_get_rate(clk, id); - break; - default: - if (gates[id].reg != 0) { - /* a clock gate */ - rate = meson_clk81_get_rate(clk); - break; - } - return -ENOENT; - } - - debug("clock %lu has rate %lu\n", id, rate); - return rate; -} - -static ulong meson_clk_get_rate(struct clk *clk) -{ - return meson_clk_get_rate_by_id(clk, clk->id); -} - -static int meson_clk_set_parent(struct clk *clk, struct clk *parent) -{ - return meson_mux_set_parent(clk, clk->id, parent->id); -} - -static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, - ulong rate, ulong current_rate) -{ - if (current_rate == rate) - return 0; - - switch (id) { - /* Fixed clocks */ - case CLKID_FIXED_PLL: - case CLKID_SYS_PLL: - case CLKID_FCLK_DIV2: - case CLKID_FCLK_DIV3: - case CLKID_FCLK_DIV4: - case CLKID_FCLK_DIV5: - case CLKID_FCLK_DIV7: - case CLKID_MPLL0: - case CLKID_MPLL1: - case CLKID_MPLL2: - case CLKID_CLK81: - if (current_rate != rate) - return -EINVAL; - - return 0; - case CLKID_VPU: - return meson_clk_set_rate_by_id(clk, - meson_mux_get_parent(clk, CLKID_VPU), rate, - current_rate); - case CLKID_VAPB: - case CLKID_VAPB_SEL: - return meson_clk_set_rate_by_id(clk, - meson_mux_get_parent(clk, CLKID_VAPB_SEL), - rate, current_rate); - case CLKID_VPU_0: - return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate, - current_rate); - case CLKID_VPU_1: - return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate, - current_rate); - case CLKID_VAPB_0: - return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate, - current_rate); - case CLKID_VAPB_1: - return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate, - current_rate); - case CLKID_VPU_0_DIV: - case CLKID_VPU_1_DIV: - case CLKID_VAPB_0_DIV: - case CLKID_VAPB_1_DIV: - return meson_div_set_rate(clk, id, rate, current_rate); - default: - return -ENOENT; - } - - return -EINVAL; -} - -static ulong meson_clk_set_rate(struct clk *clk, ulong rate) -{ - ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id); - int ret; - - if (IS_ERR_VALUE(current_rate)) - return current_rate; - - debug("%s: setting rate of %ld from %ld to %ld\n", - __func__, clk->id, current_rate, rate); - - ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate); - if (IS_ERR_VALUE(ret)) - return ret; - - debug("clock %lu has new rate %lu\n", clk->id, - meson_clk_get_rate_by_id(clk, clk->id)); - - return 0; -} - -static int meson_clk_probe(struct udevice *dev) -{ - struct meson_clk *priv = dev_get_priv(dev); - - priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); - if (IS_ERR(priv->map)) - return PTR_ERR(priv->map); - - debug("meson-clk: probed\n"); - - return 0; -} - -static struct clk_ops meson_clk_ops = { - .disable = meson_clk_disable, - .enable = meson_clk_enable, - .get_rate = meson_clk_get_rate, - .set_parent = meson_clk_set_parent, - .set_rate = meson_clk_set_rate, -}; - -static const struct udevice_id meson_clk_ids[] = { - { .compatible = "amlogic,gxbb-clkc" }, - { .compatible = "amlogic,gxl-clkc" }, - { } -}; - -U_BOOT_DRIVER(meson_clk) = { - .name = "meson_clk", - .id = UCLASS_CLK, - .of_match = meson_clk_ids, - .priv_auto_alloc_size = sizeof(struct meson_clk), - .ops = &meson_clk_ops, - .probe = meson_clk_probe, -}; diff --git a/drivers/clk/clk_meson.h b/drivers/clk/clk_meson.h deleted file mode 100644 index 7adc55a..0000000 --- a/drivers/clk/clk_meson.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2018 - Beniamino Galvani - * (C) Copyright 2018 - BayLibre, SAS - * Author: Neil Armstrong - */ - -#ifndef CLK_MESON_H -#define CLK_MESON_H - -/* Gate Structure */ - -struct meson_gate { - unsigned int reg; - unsigned int bit; -}; - -#define MESON_GATE(id, _reg, _bit) \ - [id] = { \ - .reg = (_reg), \ - .bit = (_bit), \ - } - -/* PLL Parameters */ - -struct parm { - u16 reg_off; - u8 shift; - u8 width; -}; - -#define PMASK(width) GENMASK(width - 1, 0) -#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) -#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) - -#define PARM_GET(width, shift, reg) \ - (((reg) & SETPMASK(width, shift)) >> (shift)) -#define PARM_SET(width, shift, reg, val) \ - (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) - -/* MPLL Parameters */ - -#define SDM_DEN 16384 -#define N2_MIN 4 -#define N2_MAX 511 - -#endif diff --git a/drivers/clk/clk_meson_axg.c b/drivers/clk/clk_meson_axg.c deleted file mode 100644 index 32cbf75..0000000 --- a/drivers/clk/clk_meson_axg.c +++ /dev/null @@ -1,316 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2018 - Beniamino Galvani - * (C) Copyright 2018 - BayLibre, SAS - * Author: Neil Armstrong - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "clk_meson.h" - -#define XTAL_RATE 24000000 - -struct meson_clk { - struct regmap *map; -}; - -static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); - -static struct meson_gate gates[] = { - /* Everything Else (EE) domain gates */ - MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8), - MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), - MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), - MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 15), - MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), - MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), - MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), - MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), - - /* Always On (AO) domain gates */ - MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), - - /* PLL Gates */ - /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ - MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), - /* CLKID_CLK81 is critical for the system */ - - /* Peripheral Gates */ - MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), - MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), -}; - -static int meson_set_gate(struct clk *clk, bool on) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct meson_gate *gate; - - if (clk->id >= ARRAY_SIZE(gates)) - return -ENOENT; - - gate = &gates[clk->id]; - - if (gate->reg == 0) - return 0; - - regmap_update_bits(priv->map, gate->reg, - BIT(gate->bit), on ? BIT(gate->bit) : 0); - - return 0; -} - -static int meson_clk_enable(struct clk *clk) -{ - return meson_set_gate(clk, true); -} - -static int meson_clk_disable(struct clk *clk) -{ - return meson_set_gate(clk, false); -} - -static unsigned long meson_clk81_get_rate(struct clk *clk) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - unsigned long parent_rate; - uint reg; - int parents[] = { - -1, - -1, - CLKID_FCLK_DIV7, - CLKID_MPLL1, - CLKID_MPLL2, - CLKID_FCLK_DIV4, - CLKID_FCLK_DIV3, - CLKID_FCLK_DIV5 - }; - - /* mux */ - regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); - reg = (reg >> 12) & 7; - - switch (reg) { - case 0: - parent_rate = XTAL_RATE; - break; - case 1: - return -ENOENT; - default: - parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); - } - - /* divider */ - regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); - reg = reg & ((1 << 7) - 1); - - return parent_rate / reg; -} - -static long mpll_rate_from_params(unsigned long parent_rate, - unsigned long sdm, - unsigned long n2) -{ - unsigned long divisor = (SDM_DEN * n2) + sdm; - - if (n2 < N2_MIN) - return -EINVAL; - - return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); -} - -static struct parm meson_mpll0_parm[3] = { - {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ -}; - -static struct parm meson_mpll1_parm[3] = { - {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ -}; - -static struct parm meson_mpll2_parm[3] = { - {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ - {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ -}; - -/* - * MultiPhase Locked Loops are outputs from a PLL with additional frequency - * scaling capabilities. MPLL rates are calculated as: - * - * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) - */ -static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct parm *psdm, *pn2; - unsigned long sdm, n2; - unsigned long parent_rate; - uint reg; - - switch (id) { - case CLKID_MPLL0: - psdm = &meson_mpll0_parm[0]; - pn2 = &meson_mpll0_parm[1]; - break; - case CLKID_MPLL1: - psdm = &meson_mpll1_parm[0]; - pn2 = &meson_mpll1_parm[1]; - break; - case CLKID_MPLL2: - psdm = &meson_mpll2_parm[0]; - pn2 = &meson_mpll2_parm[1]; - break; - default: - return -ENOENT; - } - - parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - regmap_read(priv->map, psdm->reg_off, ®); - sdm = PARM_GET(psdm->width, psdm->shift, reg); - - regmap_read(priv->map, pn2->reg_off, ®); - n2 = PARM_GET(pn2->width, pn2->shift, reg); - - return mpll_rate_from_params(parent_rate, sdm, n2); -} - -static struct parm meson_fixed_pll_parm[3] = { - {HHI_MPLL_CNTL, 0, 9}, /* pm */ - {HHI_MPLL_CNTL, 9, 5}, /* pn */ - {HHI_MPLL_CNTL, 16, 2}, /* pod */ -}; - -static struct parm meson_sys_pll_parm[3] = { - {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ - {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ - {HHI_SYS_PLL_CNTL, 16, 2}, /* pod */ -}; - -static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) -{ - struct meson_clk *priv = dev_get_priv(clk->dev); - struct parm *pm, *pn, *pod; - unsigned long parent_rate_mhz = XTAL_RATE / 1000000; - u16 n, m, od; - uint reg; - - switch (id) { - case CLKID_FIXED_PLL: - pm = &meson_fixed_pll_parm[0]; - pn = &meson_fixed_pll_parm[1]; - pod = &meson_fixed_pll_parm[2]; - break; - case CLKID_SYS_PLL: - pm = &meson_sys_pll_parm[0]; - pn = &meson_sys_pll_parm[1]; - pod = &meson_sys_pll_parm[2]; - break; - default: - return -ENOENT; - } - - regmap_read(priv->map, pn->reg_off, ®); - n = PARM_GET(pn->width, pn->shift, reg); - - regmap_read(priv->map, pm->reg_off, ®); - m = PARM_GET(pm->width, pm->shift, reg); - - regmap_read(priv->map, pod->reg_off, ®); - od = PARM_GET(pod->width, pod->shift, reg); - - return ((parent_rate_mhz * m / n) >> od) * 1000000; -} - -static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) -{ - ulong rate; - - switch (id) { - case CLKID_FIXED_PLL: - case CLKID_SYS_PLL: - rate = meson_pll_get_rate(clk, id); - break; - case CLKID_FCLK_DIV2: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; - break; - case CLKID_FCLK_DIV3: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; - break; - case CLKID_FCLK_DIV4: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; - break; - case CLKID_FCLK_DIV5: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; - break; - case CLKID_FCLK_DIV7: - rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; - break; - case CLKID_MPLL0: - case CLKID_MPLL1: - case CLKID_MPLL2: - rate = meson_mpll_get_rate(clk, id); - break; - case CLKID_CLK81: - rate = meson_clk81_get_rate(clk); - break; - default: - if (gates[id].reg != 0) { - /* a clock gate */ - rate = meson_clk81_get_rate(clk); - break; - } - return -ENOENT; - } - - debug("clock %lu has rate %lu\n", id, rate); - return rate; -} - -static ulong meson_clk_get_rate(struct clk *clk) -{ - return meson_clk_get_rate_by_id(clk, clk->id); -} - -static int meson_clk_probe(struct udevice *dev) -{ - struct meson_clk *priv = dev_get_priv(dev); - - priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); - if (IS_ERR(priv->map)) - return PTR_ERR(priv->map); - - debug("meson-clk-axg: probed\n"); - - return 0; -} - -static struct clk_ops meson_clk_ops = { - .disable = meson_clk_disable, - .enable = meson_clk_enable, - .get_rate = meson_clk_get_rate, -}; - -static const struct udevice_id meson_clk_ids[] = { - { .compatible = "amlogic,axg-clkc" }, - { } -}; - -U_BOOT_DRIVER(meson_clk_axg) = { - .name = "meson_clk_axg", - .id = UCLASS_CLK, - .of_match = meson_clk_ids, - .priv_auto_alloc_size = sizeof(struct meson_clk), - .ops = &meson_clk_ops, - .probe = meson_clk_probe, -}; diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig new file mode 100644 index 0000000..2419a30 --- /dev/null +++ b/drivers/clk/meson/Kconfig @@ -0,0 +1,15 @@ +config CLK_MESON_GX + bool "Enable clock support for Amlogic GX" + depends on CLK && ARCH_MESON + default MESON_GX + help + Enable clock support for the Amlogic GX SoC family, such as + the S905, S905X/D and S912. + +config CLK_MESON_AXG + bool "Enable clock support for Amlogic AXG" + depends on CLK && ARCH_MESON + default MESON_AXG + help + Enable clock support for the Amlogic AXG SoC family, such as + the A113X/D diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile new file mode 100644 index 0000000..47a5ad5 --- /dev/null +++ b/drivers/clk/meson/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2019 Baylibre, SAS +# Jerome Brunet + +obj-$(CONFIG_CLK_MESON_GX) += gxbb.o +obj-$(CONFIG_CLK_MESON_AXG) += axg.o + diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c new file mode 100644 index 0000000..32cbf75 --- /dev/null +++ b/drivers/clk/meson/axg.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 - Beniamino Galvani + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk_meson.h" + +#define XTAL_RATE 24000000 + +struct meson_clk { + struct regmap *map; +}; + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); + +static struct meson_gate gates[] = { + /* Everything Else (EE) domain gates */ + MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8), + MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), + MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), + MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 15), + MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), + MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), + MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), + MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), + + /* Always On (AO) domain gates */ + MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), + + /* PLL Gates */ + /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ + MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), + /* CLKID_CLK81 is critical for the system */ + + /* Peripheral Gates */ + MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), + MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), +}; + +static int meson_set_gate(struct clk *clk, bool on) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct meson_gate *gate; + + if (clk->id >= ARRAY_SIZE(gates)) + return -ENOENT; + + gate = &gates[clk->id]; + + if (gate->reg == 0) + return 0; + + regmap_update_bits(priv->map, gate->reg, + BIT(gate->bit), on ? BIT(gate->bit) : 0); + + return 0; +} + +static int meson_clk_enable(struct clk *clk) +{ + return meson_set_gate(clk, true); +} + +static int meson_clk_disable(struct clk *clk) +{ + return meson_set_gate(clk, false); +} + +static unsigned long meson_clk81_get_rate(struct clk *clk) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned long parent_rate; + uint reg; + int parents[] = { + -1, + -1, + CLKID_FCLK_DIV7, + CLKID_MPLL1, + CLKID_MPLL2, + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5 + }; + + /* mux */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = (reg >> 12) & 7; + + switch (reg) { + case 0: + parent_rate = XTAL_RATE; + break; + case 1: + return -ENOENT; + default: + parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); + } + + /* divider */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = reg & ((1 << 7) - 1); + + return parent_rate / reg; +} + +static long mpll_rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + unsigned long divisor = (SDM_DEN * n2) + sdm; + + if (n2 < N2_MIN) + return -EINVAL; + + return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); +} + +static struct parm meson_mpll0_parm[3] = { + {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll1_parm[3] = { + {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll2_parm[3] = { + {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ +}; + +/* + * MultiPhase Locked Loops are outputs from a PLL with additional frequency + * scaling capabilities. MPLL rates are calculated as: + * + * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) + */ +static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *psdm, *pn2; + unsigned long sdm, n2; + unsigned long parent_rate; + uint reg; + + switch (id) { + case CLKID_MPLL0: + psdm = &meson_mpll0_parm[0]; + pn2 = &meson_mpll0_parm[1]; + break; + case CLKID_MPLL1: + psdm = &meson_mpll1_parm[0]; + pn2 = &meson_mpll1_parm[1]; + break; + case CLKID_MPLL2: + psdm = &meson_mpll2_parm[0]; + pn2 = &meson_mpll2_parm[1]; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + regmap_read(priv->map, psdm->reg_off, ®); + sdm = PARM_GET(psdm->width, psdm->shift, reg); + + regmap_read(priv->map, pn2->reg_off, ®); + n2 = PARM_GET(pn2->width, pn2->shift, reg); + + return mpll_rate_from_params(parent_rate, sdm, n2); +} + +static struct parm meson_fixed_pll_parm[3] = { + {HHI_MPLL_CNTL, 0, 9}, /* pm */ + {HHI_MPLL_CNTL, 9, 5}, /* pn */ + {HHI_MPLL_CNTL, 16, 2}, /* pod */ +}; + +static struct parm meson_sys_pll_parm[3] = { + {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ + {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ + {HHI_SYS_PLL_CNTL, 16, 2}, /* pod */ +}; + +static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *pm, *pn, *pod; + unsigned long parent_rate_mhz = XTAL_RATE / 1000000; + u16 n, m, od; + uint reg; + + switch (id) { + case CLKID_FIXED_PLL: + pm = &meson_fixed_pll_parm[0]; + pn = &meson_fixed_pll_parm[1]; + pod = &meson_fixed_pll_parm[2]; + break; + case CLKID_SYS_PLL: + pm = &meson_sys_pll_parm[0]; + pn = &meson_sys_pll_parm[1]; + pod = &meson_sys_pll_parm[2]; + break; + default: + return -ENOENT; + } + + regmap_read(priv->map, pn->reg_off, ®); + n = PARM_GET(pn->width, pn->shift, reg); + + regmap_read(priv->map, pm->reg_off, ®); + m = PARM_GET(pm->width, pm->shift, reg); + + regmap_read(priv->map, pod->reg_off, ®); + od = PARM_GET(pod->width, pod->shift, reg); + + return ((parent_rate_mhz * m / n) >> od) * 1000000; +} + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) +{ + ulong rate; + + switch (id) { + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + rate = meson_pll_get_rate(clk, id); + break; + case CLKID_FCLK_DIV2: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; + break; + case CLKID_FCLK_DIV3: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; + break; + case CLKID_FCLK_DIV4: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; + break; + case CLKID_FCLK_DIV5: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; + break; + case CLKID_FCLK_DIV7: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; + break; + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + rate = meson_mpll_get_rate(clk, id); + break; + case CLKID_CLK81: + rate = meson_clk81_get_rate(clk); + break; + default: + if (gates[id].reg != 0) { + /* a clock gate */ + rate = meson_clk81_get_rate(clk); + break; + } + return -ENOENT; + } + + debug("clock %lu has rate %lu\n", id, rate); + return rate; +} + +static ulong meson_clk_get_rate(struct clk *clk) +{ + return meson_clk_get_rate_by_id(clk, clk->id); +} + +static int meson_clk_probe(struct udevice *dev) +{ + struct meson_clk *priv = dev_get_priv(dev); + + priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); + + debug("meson-clk-axg: probed\n"); + + return 0; +} + +static struct clk_ops meson_clk_ops = { + .disable = meson_clk_disable, + .enable = meson_clk_enable, + .get_rate = meson_clk_get_rate, +}; + +static const struct udevice_id meson_clk_ids[] = { + { .compatible = "amlogic,axg-clkc" }, + { } +}; + +U_BOOT_DRIVER(meson_clk_axg) = { + .name = "meson_clk_axg", + .id = UCLASS_CLK, + .of_match = meson_clk_ids, + .priv_auto_alloc_size = sizeof(struct meson_clk), + .ops = &meson_clk_ops, + .probe = meson_clk_probe, +}; diff --git a/drivers/clk/meson/clk_meson.h b/drivers/clk/meson/clk_meson.h new file mode 100644 index 0000000..7adc55a --- /dev/null +++ b/drivers/clk/meson/clk_meson.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 - Beniamino Galvani + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef CLK_MESON_H +#define CLK_MESON_H + +/* Gate Structure */ + +struct meson_gate { + unsigned int reg; + unsigned int bit; +}; + +#define MESON_GATE(id, _reg, _bit) \ + [id] = { \ + .reg = (_reg), \ + .bit = (_bit), \ + } + +/* PLL Parameters */ + +struct parm { + u16 reg_off; + u8 shift; + u8 width; +}; + +#define PMASK(width) GENMASK(width - 1, 0) +#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) +#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) + +#define PARM_GET(width, shift, reg) \ + (((reg) & SETPMASK(width, shift)) >> (shift)) +#define PARM_SET(width, shift, reg, val) \ + (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) + +/* MPLL Parameters */ + +#define SDM_DEN 16384 +#define N2_MIN 4 +#define N2_MAX 511 + +#endif diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c new file mode 100644 index 0000000..2cb53fb --- /dev/null +++ b/drivers/clk/meson/gxbb.c @@ -0,0 +1,918 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 - Beniamino Galvani + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk_meson.h" + +/* This driver support only basic clock tree operations : + * - Can calculate clock frequency on a limited tree + * - Can Read muxes and basic dividers (0-based only) + * - Can enable/disable gates with limited propagation + * - Can reparent without propagation, only on muxes + * - Can set rates without reparenting + * This driver is adapted to what is actually supported by U-Boot + */ + +/* Only the clocks ids we don't want to expose, such as the internal muxes + * and dividers of composite clocks, will remain defined here. + */ +#define CLKID_MPEG_SEL 10 +#define CLKID_MPEG_DIV 11 +#define CLKID_SAR_ADC_DIV 99 +#define CLKID_MALI_0_DIV 101 +#define CLKID_MALI_1_DIV 104 +#define CLKID_CTS_AMCLK_SEL 108 +#define CLKID_CTS_AMCLK_DIV 109 +#define CLKID_CTS_MCLK_I958_SEL 111 +#define CLKID_CTS_MCLK_I958_DIV 112 +#define CLKID_32K_CLK_SEL 115 +#define CLKID_32K_CLK_DIV 116 +#define CLKID_SD_EMMC_A_CLK0_SEL 117 +#define CLKID_SD_EMMC_A_CLK0_DIV 118 +#define CLKID_SD_EMMC_B_CLK0_SEL 120 +#define CLKID_SD_EMMC_B_CLK0_DIV 121 +#define CLKID_SD_EMMC_C_CLK0_SEL 123 +#define CLKID_SD_EMMC_C_CLK0_DIV 124 +#define CLKID_VPU_0_DIV 127 +#define CLKID_VPU_1_DIV 130 +#define CLKID_VAPB_0_DIV 134 +#define CLKID_VAPB_1_DIV 137 +#define CLKID_HDMI_PLL_PRE_MULT 141 +#define CLKID_MPLL0_DIV 142 +#define CLKID_MPLL1_DIV 143 +#define CLKID_MPLL2_DIV 144 +#define CLKID_MPLL_PREDIV 145 +#define CLKID_FCLK_DIV2_DIV 146 +#define CLKID_FCLK_DIV3_DIV 147 +#define CLKID_FCLK_DIV4_DIV 148 +#define CLKID_FCLK_DIV5_DIV 149 +#define CLKID_FCLK_DIV7_DIV 150 +#define CLKID_VDEC_1_SEL 151 +#define CLKID_VDEC_1_DIV 152 +#define CLKID_VDEC_HEVC_SEL 154 +#define CLKID_VDEC_HEVC_DIV 155 + +#define XTAL_RATE 24000000 + +struct meson_clk { + struct regmap *map; +}; + +static ulong meson_div_get_rate(struct clk *clk, unsigned long id); +static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, + ulong current_rate); +static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, + unsigned long parent_id); +static ulong meson_mux_get_rate(struct clk *clk, unsigned long id); +static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, + ulong rate, ulong current_rate); +static ulong meson_mux_get_parent(struct clk *clk, unsigned long id); +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); + +static struct meson_gate gates[] = { + /* Everything Else (EE) domain gates */ + MESON_GATE(CLKID_DDR, HHI_GCLK_MPEG0, 0), + MESON_GATE(CLKID_DOS, HHI_GCLK_MPEG0, 1), + MESON_GATE(CLKID_ISA, HHI_GCLK_MPEG0, 5), + MESON_GATE(CLKID_PL301, HHI_GCLK_MPEG0, 6), + MESON_GATE(CLKID_PERIPHS, HHI_GCLK_MPEG0, 7), + MESON_GATE(CLKID_SPICC, HHI_GCLK_MPEG0, 8), + MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), + MESON_GATE(CLKID_SAR_ADC, HHI_GCLK_MPEG0, 10), + MESON_GATE(CLKID_SMART_CARD, HHI_GCLK_MPEG0, 11), + MESON_GATE(CLKID_RNG0, HHI_GCLK_MPEG0, 12), + MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), + MESON_GATE(CLKID_SDHC, HHI_GCLK_MPEG0, 14), + MESON_GATE(CLKID_STREAM, HHI_GCLK_MPEG0, 15), + MESON_GATE(CLKID_ASYNC_FIFO, HHI_GCLK_MPEG0, 16), + MESON_GATE(CLKID_SDIO, HHI_GCLK_MPEG0, 17), + MESON_GATE(CLKID_ABUF, HHI_GCLK_MPEG0, 18), + MESON_GATE(CLKID_HIU_IFACE, HHI_GCLK_MPEG0, 19), + MESON_GATE(CLKID_ASSIST_MISC, HHI_GCLK_MPEG0, 23), + MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 24), + MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), + MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), + MESON_GATE(CLKID_SPI, HHI_GCLK_MPEG0, 30), + + MESON_GATE(CLKID_I2S_SPDIF, HHI_GCLK_MPEG1, 2), + MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), + MESON_GATE(CLKID_DEMUX, HHI_GCLK_MPEG1, 4), + MESON_GATE(CLKID_AIU_GLUE, HHI_GCLK_MPEG1, 6), + MESON_GATE(CLKID_IEC958, HHI_GCLK_MPEG1, 7), + MESON_GATE(CLKID_I2S_OUT, HHI_GCLK_MPEG1, 8), + MESON_GATE(CLKID_AMCLK, HHI_GCLK_MPEG1, 9), + MESON_GATE(CLKID_AIFIFO2, HHI_GCLK_MPEG1, 10), + MESON_GATE(CLKID_MIXER, HHI_GCLK_MPEG1, 11), + MESON_GATE(CLKID_MIXER_IFACE, HHI_GCLK_MPEG1, 12), + MESON_GATE(CLKID_ADC, HHI_GCLK_MPEG1, 13), + MESON_GATE(CLKID_BLKMV, HHI_GCLK_MPEG1, 14), + MESON_GATE(CLKID_AIU, HHI_GCLK_MPEG1, 15), + MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), + MESON_GATE(CLKID_G2D, HHI_GCLK_MPEG1, 20), + MESON_GATE(CLKID_USB0, HHI_GCLK_MPEG1, 21), + MESON_GATE(CLKID_USB1, HHI_GCLK_MPEG1, 22), + MESON_GATE(CLKID_RESET, HHI_GCLK_MPEG1, 23), + MESON_GATE(CLKID_NAND, HHI_GCLK_MPEG1, 24), + MESON_GATE(CLKID_DOS_PARSER, HHI_GCLK_MPEG1, 25), + MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 26), + MESON_GATE(CLKID_VDIN1, HHI_GCLK_MPEG1, 28), + MESON_GATE(CLKID_AHB_ARB0, HHI_GCLK_MPEG1, 29), + MESON_GATE(CLKID_EFUSE, HHI_GCLK_MPEG1, 30), + MESON_GATE(CLKID_BOOT_ROM, HHI_GCLK_MPEG1, 31), + + MESON_GATE(CLKID_AHB_DATA_BUS, HHI_GCLK_MPEG2, 1), + MESON_GATE(CLKID_AHB_CTRL_BUS, HHI_GCLK_MPEG2, 2), + MESON_GATE(CLKID_HDMI_INTR_SYNC, HHI_GCLK_MPEG2, 3), + MESON_GATE(CLKID_HDMI_PCLK, HHI_GCLK_MPEG2, 4), + MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8), + MESON_GATE(CLKID_USB0_DDR_BRIDGE, HHI_GCLK_MPEG2, 9), + MESON_GATE(CLKID_MMC_PCLK, HHI_GCLK_MPEG2, 11), + MESON_GATE(CLKID_DVIN, HHI_GCLK_MPEG2, 12), + MESON_GATE(CLKID_UART2, HHI_GCLK_MPEG2, 15), + MESON_GATE(CLKID_SANA, HHI_GCLK_MPEG2, 22), + MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25), + MESON_GATE(CLKID_SEC_AHB_AHB3_BRIDGE, HHI_GCLK_MPEG2, 26), + MESON_GATE(CLKID_CLK81_A53, HHI_GCLK_MPEG2, 29), + + MESON_GATE(CLKID_VCLK2_VENCI0, HHI_GCLK_OTHER, 1), + MESON_GATE(CLKID_VCLK2_VENCI1, HHI_GCLK_OTHER, 2), + MESON_GATE(CLKID_VCLK2_VENCP0, HHI_GCLK_OTHER, 3), + MESON_GATE(CLKID_VCLK2_VENCP1, HHI_GCLK_OTHER, 4), + MESON_GATE(CLKID_GCLK_VENCI_INT0, HHI_GCLK_OTHER, 8), + MESON_GATE(CLKID_DAC_CLK, HHI_GCLK_OTHER, 10), + MESON_GATE(CLKID_AOCLK_GATE, HHI_GCLK_OTHER, 14), + MESON_GATE(CLKID_IEC958_GATE, HHI_GCLK_OTHER, 16), + MESON_GATE(CLKID_ENC480P, HHI_GCLK_OTHER, 20), + MESON_GATE(CLKID_RNG1, HHI_GCLK_OTHER, 21), + MESON_GATE(CLKID_GCLK_VENCI_INT1, HHI_GCLK_OTHER, 22), + MESON_GATE(CLKID_VCLK2_VENCLMCC, HHI_GCLK_OTHER, 24), + MESON_GATE(CLKID_VCLK2_VENCL, HHI_GCLK_OTHER, 25), + MESON_GATE(CLKID_VCLK_OTHER, HHI_GCLK_OTHER, 26), + MESON_GATE(CLKID_EDP, HHI_GCLK_OTHER, 31), + + /* Always On (AO) domain gates */ + MESON_GATE(CLKID_AO_MEDIA_CPU, HHI_GCLK_AO, 0), + MESON_GATE(CLKID_AO_AHB_SRAM, HHI_GCLK_AO, 1), + MESON_GATE(CLKID_AO_AHB_BUS, HHI_GCLK_AO, 2), + MESON_GATE(CLKID_AO_IFACE, HHI_GCLK_AO, 3), + MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), + + /* PLL Gates */ + /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ + MESON_GATE(CLKID_FCLK_DIV3, HHI_MPLL_CNTL6, 28), + MESON_GATE(CLKID_FCLK_DIV4, HHI_MPLL_CNTL6, 29), + MESON_GATE(CLKID_FCLK_DIV5, HHI_MPLL_CNTL6, 30), + MESON_GATE(CLKID_FCLK_DIV7, HHI_MPLL_CNTL6, 31), + MESON_GATE(CLKID_MPLL0, HHI_MPLL_CNTL7, 14), + MESON_GATE(CLKID_MPLL1, HHI_MPLL_CNTL8, 14), + MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), + /* CLKID_CLK81 is critical for the system */ + + /* Peripheral Gates */ + MESON_GATE(CLKID_SAR_ADC_CLK, HHI_SAR_CLK_CNTL, 8), + MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7), + MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), + MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), + MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8), + MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24), + MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8), + MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24), + MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30), +}; + +static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct meson_gate *gate; + + debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id); + + /* Propagate through muxes */ + switch (id) { + case CLKID_VPU: + return meson_set_gate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VPU), on); + case CLKID_VAPB_SEL: + return meson_set_gate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VAPB_SEL), on); + } + + if (id >= ARRAY_SIZE(gates)) + return -ENOENT; + + gate = &gates[id]; + + if (gate->reg == 0) + return 0; + + debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id); + + regmap_update_bits(priv->map, gate->reg, + BIT(gate->bit), on ? BIT(gate->bit) : 0); + + /* Propagate to next gate(s) */ + switch (id) { + case CLKID_VAPB: + return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on); + } + + return 0; +} + +static int meson_clk_enable(struct clk *clk) +{ + return meson_set_gate_by_id(clk, clk->id, true); +} + +static int meson_clk_disable(struct clk *clk) +{ + return meson_set_gate_by_id(clk, clk->id, false); +} + +static struct parm meson_vpu_0_div_parm = { + HHI_VPU_CLK_CNTL, 0, 7, +}; + +int meson_vpu_0_div_parent = CLKID_VPU_0_SEL; + +static struct parm meson_vpu_1_div_parm = { + HHI_VPU_CLK_CNTL, 16, 7, +}; + +int meson_vpu_1_div_parent = CLKID_VPU_1_SEL; + +static struct parm meson_vapb_0_div_parm = { + HHI_VAPBCLK_CNTL, 0, 7, +}; + +int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL; + +static struct parm meson_vapb_1_div_parm = { + HHI_VAPBCLK_CNTL, 16, 7, +}; + +int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL; + +static ulong meson_div_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int rate, parent_rate; + struct parm *parm; + int parent; + uint reg; + + switch (id) { + case CLKID_VPU_0_DIV: + parm = &meson_vpu_0_div_parm; + parent = meson_vpu_0_div_parent; + break; + case CLKID_VPU_1_DIV: + parm = &meson_vpu_1_div_parm; + parent = meson_vpu_1_div_parent; + break; + case CLKID_VAPB_0_DIV: + parm = &meson_vapb_0_div_parm; + parent = meson_vapb_0_div_parent; + break; + case CLKID_VAPB_1_DIV: + parm = &meson_vapb_1_div_parm; + parent = meson_vapb_1_div_parent; + break; + default: + return -ENOENT; + } + + regmap_read(priv->map, parm->reg_off, ®); + reg = PARM_GET(parm->width, parm->shift, reg); + + debug("%s: div of %ld is %d\n", __func__, id, reg + 1); + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate); + + rate = parent_rate / (reg + 1); + + debug("%s: rate of %ld is %d\n", __func__, id, rate); + + return rate; +} + +static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, + ulong current_rate) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int new_div = -EINVAL; + unsigned long parent_rate; + struct parm *parm; + int parent; + int ret; + + if (current_rate == rate) + return 0; + + debug("%s: setting rate of %ld from %ld to %ld\n", + __func__, id, current_rate, rate); + + switch (id) { + case CLKID_VPU_0_DIV: + parm = &meson_vpu_0_div_parm; + parent = meson_vpu_0_div_parent; + break; + case CLKID_VPU_1_DIV: + parm = &meson_vpu_1_div_parm; + parent = meson_vpu_1_div_parent; + break; + case CLKID_VAPB_0_DIV: + parm = &meson_vapb_0_div_parm; + parent = meson_vapb_0_div_parent; + break; + case CLKID_VAPB_1_DIV: + parm = &meson_vapb_1_div_parm; + parent = meson_vapb_1_div_parent; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate); + + /* If can't divide, set parent instead */ + if (!parent_rate || rate > parent_rate) + return meson_clk_set_rate_by_id(clk, parent, rate, + current_rate); + + new_div = DIV_ROUND_CLOSEST(parent_rate, rate); + + debug("%s: new div of %ld is %d\n", __func__, id, new_div); + + /* If overflow, try to set parent rate and retry */ + if (!new_div || new_div > (1 << parm->width)) { + ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate); + if (IS_ERR_VALUE(ret)) + return ret; + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + new_div = DIV_ROUND_CLOSEST(parent_rate, rate); + + debug("%s: new new div of %ld is %d\n", __func__, id, new_div); + + if (!new_div || new_div > (1 << parm->width)) + return -EINVAL; + } + + debug("%s: setting div of %ld to %d\n", __func__, id, new_div); + + regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), + (new_div - 1) << parm->shift); + + debug("%s: new rate of %ld is %ld\n", + __func__, id, meson_div_get_rate(clk, id)); + + return 0; +} + +static struct parm meson_vpu_mux_parm = { + HHI_VPU_CLK_CNTL, 31, 1, +}; + +int meson_vpu_mux_parents[] = { + CLKID_VPU_0, + CLKID_VPU_1, +}; + +static struct parm meson_vpu_0_mux_parm = { + HHI_VPU_CLK_CNTL, 9, 2, +}; + +static struct parm meson_vpu_1_mux_parm = { + HHI_VPU_CLK_CNTL, 25, 2, +}; + +static int meson_vpu_0_1_mux_parents[] = { + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5, + CLKID_FCLK_DIV7, +}; + +static struct parm meson_vapb_sel_mux_parm = { + HHI_VAPBCLK_CNTL, 31, 1, +}; + +int meson_vapb_sel_mux_parents[] = { + CLKID_VAPB_0, + CLKID_VAPB_1, +}; + +static struct parm meson_vapb_0_mux_parm = { + HHI_VAPBCLK_CNTL, 9, 2, +}; + +static struct parm meson_vapb_1_mux_parm = { + HHI_VAPBCLK_CNTL, 25, 2, +}; + +static int meson_vapb_0_1_mux_parents[] = { + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5, + CLKID_FCLK_DIV7, +}; + +static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *parm; + int *parents; + uint reg; + + switch (id) { + case CLKID_VPU: + parm = &meson_vpu_mux_parm; + parents = meson_vpu_mux_parents; + break; + case CLKID_VPU_0_SEL: + parm = &meson_vpu_0_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VPU_1_SEL: + parm = &meson_vpu_1_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VAPB_SEL: + parm = &meson_vapb_sel_mux_parm; + parents = meson_vapb_sel_mux_parents; + break; + case CLKID_VAPB_0_SEL: + parm = &meson_vapb_0_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + case CLKID_VAPB_1_SEL: + parm = &meson_vapb_1_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + default: + return -ENOENT; + } + + regmap_read(priv->map, parm->reg_off, ®); + reg = PARM_GET(parm->width, parm->shift, reg); + + debug("%s: parent of %ld is %d (%d)\n", + __func__, id, parents[reg], reg); + + return parents[reg]; +} + +static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, + unsigned long parent_id) +{ + unsigned long cur_parent = meson_mux_get_parent(clk, id); + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int new_index = -EINVAL; + struct parm *parm; + int *parents; + int i; + + if (IS_ERR_VALUE(cur_parent)) + return cur_parent; + + debug("%s: setting parent of %ld from %ld to %ld\n", + __func__, id, cur_parent, parent_id); + + if (cur_parent == parent_id) + return 0; + + switch (id) { + case CLKID_VPU: + parm = &meson_vpu_mux_parm; + parents = meson_vpu_mux_parents; + break; + case CLKID_VPU_0_SEL: + parm = &meson_vpu_0_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VPU_1_SEL: + parm = &meson_vpu_1_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VAPB_SEL: + parm = &meson_vapb_sel_mux_parm; + parents = meson_vapb_sel_mux_parents; + break; + case CLKID_VAPB_0_SEL: + parm = &meson_vapb_0_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + case CLKID_VAPB_1_SEL: + parm = &meson_vapb_1_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + default: + /* Not a mux */ + return -ENOENT; + } + + for (i = 0 ; i < (1 << parm->width) ; ++i) { + if (parents[i] == parent_id) + new_index = i; + } + + if (IS_ERR_VALUE(new_index)) + return new_index; + + debug("%s: new index of %ld is %d\n", __func__, id, new_index); + + regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), + new_index << parm->shift); + + debug("%s: new parent of %ld is %ld\n", + __func__, id, meson_mux_get_parent(clk, id)); + + return 0; +} + +static ulong meson_mux_get_rate(struct clk *clk, unsigned long id) +{ + int parent = meson_mux_get_parent(clk, id); + + if (IS_ERR_VALUE(parent)) + return parent; + + return meson_clk_get_rate_by_id(clk, parent); +} + +static unsigned long meson_clk81_get_rate(struct clk *clk) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned long parent_rate; + uint reg; + int parents[] = { + -1, + -1, + CLKID_FCLK_DIV7, + CLKID_MPLL1, + CLKID_MPLL2, + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5 + }; + + /* mux */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = (reg >> 12) & 7; + + switch (reg) { + case 0: + parent_rate = XTAL_RATE; + break; + case 1: + return -ENOENT; + default: + parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); + } + + /* divider */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = reg & ((1 << 7) - 1); + + /* clk81 divider is zero based */ + return parent_rate / (reg + 1); +} + +static long mpll_rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + unsigned long divisor = (SDM_DEN * n2) + sdm; + + if (n2 < N2_MIN) + return -EINVAL; + + return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); +} + +static struct parm meson_mpll0_parm[3] = { + {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll1_parm[3] = { + {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll2_parm[3] = { + {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ +}; + +/* + * MultiPhase Locked Loops are outputs from a PLL with additional frequency + * scaling capabilities. MPLL rates are calculated as: + * + * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) + */ +static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *psdm, *pn2; + unsigned long sdm, n2; + unsigned long parent_rate; + uint reg; + + switch (id) { + case CLKID_MPLL0: + psdm = &meson_mpll0_parm[0]; + pn2 = &meson_mpll0_parm[1]; + break; + case CLKID_MPLL1: + psdm = &meson_mpll1_parm[0]; + pn2 = &meson_mpll1_parm[1]; + break; + case CLKID_MPLL2: + psdm = &meson_mpll2_parm[0]; + pn2 = &meson_mpll2_parm[1]; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + regmap_read(priv->map, psdm->reg_off, ®); + sdm = PARM_GET(psdm->width, psdm->shift, reg); + + regmap_read(priv->map, pn2->reg_off, ®); + n2 = PARM_GET(pn2->width, pn2->shift, reg); + + return mpll_rate_from_params(parent_rate, sdm, n2); +} + +static struct parm meson_fixed_pll_parm[3] = { + {HHI_MPLL_CNTL, 0, 9}, /* pm */ + {HHI_MPLL_CNTL, 9, 5}, /* pn */ + {HHI_MPLL_CNTL, 16, 2}, /* pod */ +}; + +static struct parm meson_sys_pll_parm[3] = { + {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ + {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ + {HHI_SYS_PLL_CNTL, 10, 2}, /* pod */ +}; + +static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *pm, *pn, *pod; + unsigned long parent_rate_mhz = XTAL_RATE / 1000000; + u16 n, m, od; + uint reg; + + switch (id) { + case CLKID_FIXED_PLL: + pm = &meson_fixed_pll_parm[0]; + pn = &meson_fixed_pll_parm[1]; + pod = &meson_fixed_pll_parm[2]; + break; + case CLKID_SYS_PLL: + pm = &meson_sys_pll_parm[0]; + pn = &meson_sys_pll_parm[1]; + pod = &meson_sys_pll_parm[2]; + break; + default: + return -ENOENT; + } + + regmap_read(priv->map, pn->reg_off, ®); + n = PARM_GET(pn->width, pn->shift, reg); + + regmap_read(priv->map, pm->reg_off, ®); + m = PARM_GET(pm->width, pm->shift, reg); + + regmap_read(priv->map, pod->reg_off, ®); + od = PARM_GET(pod->width, pod->shift, reg); + + return ((parent_rate_mhz * m / n) >> od) * 1000000; +} + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) +{ + ulong rate; + + switch (id) { + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + rate = meson_pll_get_rate(clk, id); + break; + case CLKID_FCLK_DIV2: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; + break; + case CLKID_FCLK_DIV3: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; + break; + case CLKID_FCLK_DIV4: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; + break; + case CLKID_FCLK_DIV5: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; + break; + case CLKID_FCLK_DIV7: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; + break; + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + rate = meson_mpll_get_rate(clk, id); + break; + case CLKID_CLK81: + rate = meson_clk81_get_rate(clk); + break; + case CLKID_VPU_0: + rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV); + break; + case CLKID_VPU_1: + rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV); + break; + case CLKID_VAPB: + rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL); + break; + case CLKID_VAPB_0: + rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV); + break; + case CLKID_VAPB_1: + rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); + break; + case CLKID_VPU_0_DIV: + case CLKID_VPU_1_DIV: + case CLKID_VAPB_0_DIV: + case CLKID_VAPB_1_DIV: + rate = meson_div_get_rate(clk, id); + break; + case CLKID_VPU: + case CLKID_VPU_0_SEL: + case CLKID_VPU_1_SEL: + case CLKID_VAPB_SEL: + case CLKID_VAPB_0_SEL: + case CLKID_VAPB_1_SEL: + rate = meson_mux_get_rate(clk, id); + break; + default: + if (gates[id].reg != 0) { + /* a clock gate */ + rate = meson_clk81_get_rate(clk); + break; + } + return -ENOENT; + } + + debug("clock %lu has rate %lu\n", id, rate); + return rate; +} + +static ulong meson_clk_get_rate(struct clk *clk) +{ + return meson_clk_get_rate_by_id(clk, clk->id); +} + +static int meson_clk_set_parent(struct clk *clk, struct clk *parent) +{ + return meson_mux_set_parent(clk, clk->id, parent->id); +} + +static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, + ulong rate, ulong current_rate) +{ + if (current_rate == rate) + return 0; + + switch (id) { + /* Fixed clocks */ + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + case CLKID_FCLK_DIV2: + case CLKID_FCLK_DIV3: + case CLKID_FCLK_DIV4: + case CLKID_FCLK_DIV5: + case CLKID_FCLK_DIV7: + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + case CLKID_CLK81: + if (current_rate != rate) + return -EINVAL; + + return 0; + case CLKID_VPU: + return meson_clk_set_rate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VPU), rate, + current_rate); + case CLKID_VAPB: + case CLKID_VAPB_SEL: + return meson_clk_set_rate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VAPB_SEL), + rate, current_rate); + case CLKID_VPU_0: + return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate, + current_rate); + case CLKID_VPU_1: + return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate, + current_rate); + case CLKID_VAPB_0: + return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate, + current_rate); + case CLKID_VAPB_1: + return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate, + current_rate); + case CLKID_VPU_0_DIV: + case CLKID_VPU_1_DIV: + case CLKID_VAPB_0_DIV: + case CLKID_VAPB_1_DIV: + return meson_div_set_rate(clk, id, rate, current_rate); + default: + return -ENOENT; + } + + return -EINVAL; +} + +static ulong meson_clk_set_rate(struct clk *clk, ulong rate) +{ + ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id); + int ret; + + if (IS_ERR_VALUE(current_rate)) + return current_rate; + + debug("%s: setting rate of %ld from %ld to %ld\n", + __func__, clk->id, current_rate, rate); + + ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate); + if (IS_ERR_VALUE(ret)) + return ret; + + debug("clock %lu has new rate %lu\n", clk->id, + meson_clk_get_rate_by_id(clk, clk->id)); + + return 0; +} + +static int meson_clk_probe(struct udevice *dev) +{ + struct meson_clk *priv = dev_get_priv(dev); + + priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); + + debug("meson-clk: probed\n"); + + return 0; +} + +static struct clk_ops meson_clk_ops = { + .disable = meson_clk_disable, + .enable = meson_clk_enable, + .get_rate = meson_clk_get_rate, + .set_parent = meson_clk_set_parent, + .set_rate = meson_clk_set_rate, +}; + +static const struct udevice_id meson_clk_ids[] = { + { .compatible = "amlogic,gxbb-clkc" }, + { .compatible = "amlogic,gxl-clkc" }, + { } +}; + +U_BOOT_DRIVER(meson_clk) = { + .name = "meson_clk", + .id = UCLASS_CLK, + .of_match = meson_clk_ids, + .priv_auto_alloc_size = sizeof(struct meson_clk), + .ops = &meson_clk_ops, + .probe = meson_clk_probe, +}; -- cgit v1.1