From 224e893fbb7f5144381e77b7021f607f9906b227 Mon Sep 17 00:00:00 2001 From: Yun Cai Date: Thu, 6 Apr 2017 09:59:22 +0800 Subject: [PATCH] clk: m8b add clks for mpll/media/gpu/misc/store/test PD#141217: add mpll/media/gpu/misc/store/test clks for meson8b Change-Id: I95268d46395d78419d311f1b9a5add9c593da810 Signed-off-by: Yun Cai --- drivers/amlogic/clk/Makefile | 14 +- drivers/amlogic/clk/clk-mux.c | 4 + drivers/amlogic/clk/clk-pll.c | 4 + drivers/amlogic/clk/m8b/clk-cpu.c | 16 +- drivers/amlogic/clk/m8b/clk-mpll.c | 201 ++++++++++ drivers/amlogic/clk/m8b/clk_gpu.c | 188 +++++++++ drivers/amlogic/clk/m8b/clk_media.c | 637 +++++++++++++++++++++++++++++++ drivers/amlogic/clk/m8b/clk_misc.c | 348 +++++++++++++++++ drivers/amlogic/clk/m8b/clk_store.c | 101 +++++ drivers/amlogic/clk/m8b/clk_test.c | 180 +++++++++ drivers/amlogic/clk/m8b/clkc.h | 32 +- drivers/amlogic/clk/m8b/meson8b.c | 156 +++++++- drivers/amlogic/clk/m8b/meson8b.h | 50 ++- include/dt-bindings/clock/meson8b-clkc.h | 82 +++- 14 files changed, 1953 insertions(+), 60 deletions(-) create mode 100644 drivers/amlogic/clk/m8b/clk-mpll.c create mode 100644 drivers/amlogic/clk/m8b/clk_gpu.c create mode 100644 drivers/amlogic/clk/m8b/clk_media.c create mode 100644 drivers/amlogic/clk/m8b/clk_misc.c create mode 100644 drivers/amlogic/clk/m8b/clk_store.c create mode 100644 drivers/amlogic/clk/m8b/clk_test.c diff --git a/drivers/amlogic/clk/Makefile b/drivers/amlogic/clk/Makefile index a93fa9f..fafb5da 100644 --- a/drivers/amlogic/clk/Makefile +++ b/drivers/amlogic/clk/Makefile @@ -5,16 +5,16 @@ obj-$(CONFIG_AMLOGIC_COMMON_CLK_SCPI) += clk-scpi.o obj-$(CONFIG_AMLOGIC_RESET) += rstc.o -#obj-$(CONFIG_AMLOGIC_CLK) += clk-pll.o clk-cpu.o clk-mpll.o \ +#obj-$(CONFIG_AMLOGIC_CLK) += clk-pll.o clk-cpu.o \ # clk_measure.o \ # clk_sdemmc.o clk_gpu.o clk_media.o clk_misc.o\ # clk-mux.o -obj-$(CONFIG_AMLOGIC_CLK) += clk-pll.o +obj-$(CONFIG_AMLOGIC_CLK) += clk-pll.o clk-mux.o -obj-$(CONFIG_AMLOGIC_GX_CLK) += clk-cpu.o clk-mpll.o clk-mux.o\ - clk_measure.o clk_sdemmc.o clk_gpu.o clk_media.o clk_misc.o\ - gxl.o +obj-$(CONFIG_AMLOGIC_GX_CLK) += clk-cpu.o clk-mpll.o \ + clk_measure.o clk_sdemmc.o clk_gpu.o clk_media.o clk_misc.o \ + gxl.o clk_test.o -obj-$(CONFIG_AMLOGIC_M8B_CLK) += m8b/clk-cpu.o m8b/meson8b.o -#obj-$(CONFIG_AMLOGIC_CLK) += clk_test.o +obj-$(CONFIG_AMLOGIC_M8B_CLK) += m8b/clk-cpu.o m8b/meson8b.o m8b/clk_test.o \ + m8b/clk-mpll.o m8b/clk_gpu.o m8b/clk_media.o m8b/clk_store.o m8b/clk_misc.o diff --git a/drivers/amlogic/clk/clk-mux.c b/drivers/amlogic/clk/clk-mux.c index 1b7782c..efc288e 100644 --- a/drivers/amlogic/clk/clk-mux.c +++ b/drivers/amlogic/clk/clk-mux.c @@ -25,7 +25,11 @@ #include #include +#ifdef CONFIG_ARM64 #include "clkc.h" +#else +#include "m8b/clkc.h" +#endif #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) diff --git a/drivers/amlogic/clk/clk-pll.c b/drivers/amlogic/clk/clk-pll.c index 8ae0f69..f9097d7 100644 --- a/drivers/amlogic/clk/clk-pll.c +++ b/drivers/amlogic/clk/clk-pll.c @@ -40,7 +40,11 @@ #include #include +#ifdef CONFIG_ARM64 #include "clkc.h" +#else +#include "m8b/clkc.h" +#endif #define MESON_PLL_RESET BIT(29) #define MESON_PLL_ENABLE BIT(30) diff --git a/drivers/amlogic/clk/m8b/clk-cpu.c b/drivers/amlogic/clk/m8b/clk-cpu.c index f8b2b7e..5b366a7b 100644 --- a/drivers/amlogic/clk/m8b/clk-cpu.c +++ b/drivers/amlogic/clk/m8b/clk-cpu.c @@ -1,18 +1,18 @@ /* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione + * drivers/amlogic/clk/m8b/clk-cpu.c * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * - * This program is distributed in the hope it will be useful, but WITHOUT + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ /* diff --git a/drivers/amlogic/clk/m8b/clk-mpll.c b/drivers/amlogic/clk/m8b/clk-mpll.c new file mode 100644 index 0000000..98306d3 --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk-mpll.c @@ -0,0 +1,201 @@ +/* + * drivers/amlogic/clk/m8b/clk-mpll.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +/* + * 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) + */ + +#include +#include "clkc.h" + +#define SDM_DEN 16384 +#define SDM_MIN 1 +#define SDM_MAX 16383 +#define N2_MIN 4 +#define N2_MAX 511 + +#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) + +static unsigned long rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + return DIV_ROUND_UP_ULL(((uint64_t)parent_rate * SDM_DEN), + ((SDM_DEN * n2) + sdm)); +} + +static void params_from_rate(unsigned long requested_rate, + unsigned long parent_rate, + unsigned long *sdm, + unsigned long *n2) +{ + uint64_t div = parent_rate; + uint64_t rem = do_div(div, requested_rate); + + if (div < N2_MIN) { + *n2 = N2_MIN; + *sdm = SDM_MIN; + } else if (div > N2_MAX) { + *n2 = N2_MAX; + *sdm = SDM_MAX; + } else { + *n2 = div; + *sdm = DIV_ROUND_UP_ULL(rem * SDM_DEN, requested_rate); + if (*sdm < SDM_MIN) + *sdm = SDM_MIN; + else if (*sdm > SDM_MAX) + *sdm = SDM_MAX; + } +} + +static unsigned long mpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg, sdm, n2; + + p = &mpll->sdm; + reg = readl(mpll->base + p->reg_off); + sdm = PARM_GET(p->width, p->shift, reg); + + p = &mpll->n2; + reg = readl(mpll->base + p->reg_off); + n2 = PARM_GET(p->width, p->shift, reg); + + if ((!sdm) || (!n2)) + return 0; + else + return rate_from_params(parent_rate, sdm, n2); +} + +static long mpll_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long sdm, n2; + + params_from_rate(rate, *parent_rate, &sdm, &n2); + return rate_from_params(*parent_rate, sdm, n2); +} + +static int mpll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg, sdm, n2; + unsigned long flags = 0; + + params_from_rate(rate, parent_rate, &sdm, &n2); + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + else + __acquire(mpll->lock); + + p = &mpll->sdm; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, sdm); + writel(reg, mpll->base + p->reg_off); + + p = &mpll->sdm_en; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, 1); + writel(reg, mpll->base + p->reg_off); + + p = &mpll->n2; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, n2); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + else + __release(mpll->lock); + + return 0; +} + +static void mpll_enable_core(struct clk_hw *hw, int enable) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg; + unsigned long flags = 0; + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + else + __acquire(mpll->lock); + + p = &mpll->en; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + else + __release(mpll->lock); +} + + +static int mpll_enable(struct clk_hw *hw) +{ + mpll_enable_core(hw, 1); + + return 0; +} + +static void mpll_disable(struct clk_hw *hw) +{ + mpll_enable_core(hw, 0); +} + +static int mpll_is_enabled(struct clk_hw *hw) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg; + int en; + + p = &mpll->en; + reg = readl(mpll->base + p->reg_off); + en = PARM_GET(p->width, p->shift, reg); + + return en; +} + +const struct clk_ops meson_clk_mpll_ro_ops = { + .recalc_rate = mpll_recalc_rate, + .round_rate = mpll_round_rate, + .is_enabled = mpll_is_enabled, +}; + +const struct clk_ops meson_clk_mpll_ops = { + .recalc_rate = mpll_recalc_rate, + .round_rate = mpll_round_rate, + .set_rate = mpll_set_rate, + .enable = mpll_enable, + .disable = mpll_disable, + .is_enabled = mpll_is_enabled, +}; diff --git a/drivers/amlogic/clk/m8b/clk_gpu.c b/drivers/amlogic/clk/m8b/clk_gpu.c new file mode 100644 index 0000000..7021138 --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk_gpu.c @@ -0,0 +1,188 @@ +/* + * drivers/amlogic/clk/m8b/clk_gpu.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "meson8b.h" + +const char *gpu_parent_names[] = { "xtal", "NULL", "mpll2", "mpll1", + "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5"}; + +static struct clk_mux gpu_p0_mux = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gpu_p0_mux", + .ops = &clk_mux_ops, + .parent_names = gpu_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider gpu_p0_div = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gpu_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "gpu_p0_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate gpu_p0_gate = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "gpu_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "gpu_p0_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux gpu_p1_mux = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gpu_p1_mux", + .ops = &clk_mux_ops, + .parent_names = gpu_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider gpu_p1_div = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gpu_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "gpu_p1_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate gpu_p1_gate = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "gpu_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "gpu_p1_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux gpu_mux = { + .reg = (void *)HHI_MALI_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "gpu_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "gpu_p0_composite", + "gpu_p1_composite"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | + CLK_PARENT_ALTERNATE), + }, +}; + +static struct clk_hw *gpu_clk_hws[] = { + [CLKID_GPU_P0_MUX - CLKID_GPU_P0_MUX] = &gpu_p0_mux.hw, + [CLKID_GPU_P0_DIV - CLKID_GPU_P0_MUX] = &gpu_p0_div.hw, + [CLKID_GPU_P0_GATE - CLKID_GPU_P0_MUX] = &gpu_p0_gate.hw, + [CLKID_GPU_P1_MUX - CLKID_GPU_P0_MUX] = &gpu_p1_mux.hw, + [CLKID_GPU_P1_DIV - CLKID_GPU_P0_MUX] = &gpu_p1_div.hw, + [CLKID_GPU_P1_GATE - CLKID_GPU_P0_MUX] = &gpu_p1_gate.hw, + [CLKID_GPU_MUX - CLKID_GPU_P0_MUX] = &gpu_mux.hw, +}; + +void amlogic_init_gpu(void) +{ + gpu_p0_mux.reg = clk_base + (u32)(gpu_p0_mux.reg); + gpu_p0_div.reg = clk_base + (u32)(gpu_p0_div.reg); + gpu_p0_gate.reg = clk_base + (u32)(gpu_p0_gate.reg); + gpu_p1_mux.reg = clk_base + (u32)(gpu_p1_mux.reg); + gpu_p1_div.reg = clk_base + (u32)(gpu_p1_div.reg); + gpu_p1_gate.reg = clk_base + (u32)(gpu_p1_gate.reg); + gpu_mux.reg = clk_base + (u32)(gpu_mux.reg); + + clks[CLKID_GPU_P0_COMP] = clk_register_composite(NULL, + "gpu_p0_composite", + gpu_parent_names, 8, + gpu_clk_hws[CLKID_GPU_P0_MUX - CLKID_GPU_P0_MUX], + &clk_mux_ops, + gpu_clk_hws[CLKID_GPU_P0_DIV - CLKID_GPU_P0_MUX], + &clk_divider_ops, + gpu_clk_hws[CLKID_GPU_P0_GATE - CLKID_GPU_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_GPU_P0_COMP])) + pr_err("%s: %d clk_register_composite gpu_p0_composite error\n", + __func__, __LINE__); + + clks[CLKID_GPU_P1_COMP] = clk_register_composite(NULL, + "gpu_p1_composite", + gpu_parent_names, 8, + gpu_clk_hws[CLKID_GPU_P1_MUX - CLKID_GPU_P0_MUX], + &clk_mux_ops, + gpu_clk_hws[CLKID_GPU_P1_DIV - CLKID_GPU_P0_MUX], + &clk_divider_ops, + gpu_clk_hws[CLKID_GPU_P1_GATE - CLKID_GPU_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_GPU_P1_COMP])) + pr_err("%s: %d clk_register_composite gpu_p1_composite error\n", + __func__, __LINE__); + + clks[CLKID_GPU_MUX] = clk_register(NULL, + gpu_clk_hws[CLKID_GPU_MUX - CLKID_GPU_P0_MUX]); + WARN_ON(IS_ERR(clks[CLKID_GPU_MUX])); + + clk_set_parent(clks[CLKID_GPU_MUX], clks[CLKID_GPU_P0_COMP]); + clk_prepare_enable(clks[CLKID_GPU_P0_COMP]); + clk_prepare_enable(clks[CLKID_GPU_P1_COMP]); + clk_set_rate(clks[CLKID_GPU_MUX], 400000000); + + pr_info("%s: register meson gpu clk\n", __func__); +} + diff --git a/drivers/amlogic/clk/m8b/clk_media.c b/drivers/amlogic/clk/m8b/clk_media.c new file mode 100644 index 0000000..ea2c674 --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk_media.c @@ -0,0 +1,637 @@ +/* + * drivers/amlogic/clk/m8b/clk_media.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "meson8b.h" + +const char *dec_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", + "fclk_div7", "mpll1", "mpll2", "NULL", "xtal"}; + +/* cts_vdec_clk */ +static struct clk_mux vdec_p0_mux = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider vdec_p0_div = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vdec_p0_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate vdec_p0_gate = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdec_p0_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux vdec_p1_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider vdec_p1_div = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vdec_p1_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate vdec_p1_gate = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdec_p1_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux vdec_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 15, + .lock = &clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "vdec_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "vdec_p0_composite", + "vdec_p1_composite"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | + CLK_PARENT_ALTERNATE), + }, +}; + +static struct clk_hw *vdec_clk_hws[] = { + [CLKID_VDEC_P0_MUX - CLKID_VDEC_P0_MUX] = &vdec_p0_mux.hw, + [CLKID_VDEC_P0_DIV - CLKID_VDEC_P0_MUX] = &vdec_p0_div.hw, + [CLKID_VDEC_P0_GATE - CLKID_VDEC_P0_MUX] = &vdec_p0_gate.hw, + [CLKID_VDEC_P1_MUX - CLKID_VDEC_P0_MUX] = &vdec_p1_mux.hw, + [CLKID_VDEC_P1_DIV - CLKID_VDEC_P0_MUX] = &vdec_p1_div.hw, + [CLKID_VDEC_P1_GATE - CLKID_VDEC_P0_MUX] = &vdec_p1_gate.hw, + [CLKID_VDEC_MUX - CLKID_VDEC_P0_MUX] = &vdec_mux.hw, +}; + +/* cts_hcodec_clk */ +static struct clk_mux hcodec_p0_mux = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p0_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider hcodec_p0_div = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hcodec_p0_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate hcodec_p0_gate = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hcodec_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hcodec_p0_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux hcodec_p1_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p1_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider hcodec_p1_div = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hcodec_p1_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate hcodec_p1_gate = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hcodec_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hcodec_p1_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux hcodec_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "hcodec_p0_composite", + "hcodec_p1_composite"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | + CLK_PARENT_ALTERNATE), + }, +}; + +static struct clk_hw *hcodec_clk_hws[] = { + [CLKID_HCODEC_P0_MUX - CLKID_HCODEC_P0_MUX] = &hcodec_p0_mux.hw, + [CLKID_HCODEC_P0_DIV - CLKID_HCODEC_P0_MUX] = &hcodec_p0_div.hw, + [CLKID_HCODEC_P0_GATE - CLKID_HCODEC_P0_MUX] = &hcodec_p0_gate.hw, + [CLKID_HCODEC_P1_MUX - CLKID_HCODEC_P0_MUX] = &hcodec_p1_mux.hw, + [CLKID_HCODEC_P1_DIV - CLKID_HCODEC_P0_MUX] = &hcodec_p1_div.hw, + [CLKID_HCODEC_P1_GATE - CLKID_HCODEC_P0_MUX] = &hcodec_p1_gate.hw, + [CLKID_HCODEC_MUX - CLKID_HCODEC_P0_MUX] = &hcodec_mux.hw, +}; + +/* cts_hevc_clk */ +static struct clk_mux hevc_p0_mux = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p0_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider hevc_p0_div = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevc_p0_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate hevc_p0_gate = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevc_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevc_p0_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux hevc_p1_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p1_mux", + .ops = &clk_mux_ops, + .parent_names = dec_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider hevc_p1_div = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevc_p1_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate hevc_p1_gate = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevc_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevc_p1_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux hevc_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "hevc_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "hevc_p0_composite", + "hevc_p1_composite"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | + CLK_PARENT_ALTERNATE), + }, +}; + +static struct clk_hw *hevc_clk_hws[] = { + [CLKID_HEVC_P0_MUX - CLKID_HEVC_P0_MUX] = &hevc_p0_mux.hw, + [CLKID_HEVC_P0_DIV - CLKID_HEVC_P0_MUX] = &hevc_p0_div.hw, + [CLKID_HEVC_P0_GATE - CLKID_HEVC_P0_MUX] = &hevc_p0_gate.hw, + [CLKID_HEVC_P1_MUX - CLKID_HEVC_P0_MUX] = &hevc_p1_mux.hw, + [CLKID_HEVC_P1_DIV - CLKID_HEVC_P0_MUX] = &hevc_p1_div.hw, + [CLKID_HEVC_P1_GATE - CLKID_HEVC_P0_MUX] = &hevc_p1_gate.hw, + [CLKID_HEVC_MUX - CLKID_HEVC_P0_MUX] = &hevc_mux.hw, +}; + +const char *vpu_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", + "fclk_div7", "mpll1", "vid_pll_clk", "vid2_pll_clk", "xtal"}; + +/* cts_vpu_clk */ +static struct clk_mux vpu_p0_mux = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_p0_mux", + .ops = &clk_mux_ops, + .parent_names = vpu_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider vpu_p0_div = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vpu_p0_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate vpu_p0_gate = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vpu_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vpu_p0_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux vpu_p1_mux = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_p1_mux", + .ops = &clk_mux_ops, + .parent_names = vpu_parent_names, + .num_parents = 8, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider vpu_p1_div = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vpu_p1_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate vpu_p1_gate = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vpu_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vpu_p1_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_mux vpu_mux = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "vpu_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "vpu_p0_composite", + "vpu_p1_composite"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | + CLK_PARENT_ALTERNATE), + }, +}; + +static struct clk_hw *vpu_clk_hws[] = { + [CLKID_VPU_P0_MUX - CLKID_VPU_P0_MUX] = &vpu_p0_mux.hw, + [CLKID_VPU_P0_DIV - CLKID_VPU_P0_MUX] = &vpu_p0_div.hw, + [CLKID_VPU_P0_GATE - CLKID_VPU_P0_MUX] = &vpu_p0_gate.hw, + [CLKID_VPU_P1_MUX - CLKID_VPU_P0_MUX] = &vpu_p1_mux.hw, + [CLKID_VPU_P1_DIV - CLKID_VPU_P0_MUX] = &vpu_p1_div.hw, + [CLKID_VPU_P1_GATE - CLKID_VPU_P0_MUX] = &vpu_p1_gate.hw, + [CLKID_VPU_MUX - CLKID_VPU_P0_MUX] = &vpu_mux.hw, +}; + +void amlogic_init_media(void) +{ + /* cts_vdec_clk */ + vdec_p0_mux.reg = clk_base + (u32)(vdec_p0_mux.reg); + vdec_p0_div.reg = clk_base + (u32)(vdec_p0_div.reg); + vdec_p0_gate.reg = clk_base + (u32)(vdec_p0_gate.reg); + vdec_p1_mux.reg = clk_base + (u32)(vdec_p1_mux.reg); + vdec_p1_div.reg = clk_base + (u32)(vdec_p1_div.reg); + vdec_p1_gate.reg = clk_base + (u32)(vdec_p1_gate.reg); + vdec_mux.reg = clk_base + (u32)(vdec_mux.reg); + /* cts_hcodec_clk */ + hcodec_p0_mux.reg = clk_base + (u32)(hcodec_p0_mux.reg); + hcodec_p0_div.reg = clk_base + (u32)(hcodec_p0_div.reg); + hcodec_p0_gate.reg = clk_base + (u32)(hcodec_p0_gate.reg); + hcodec_p1_mux.reg = clk_base + (u32)(hcodec_p1_mux.reg); + hcodec_p1_div.reg = clk_base + (u32)(hcodec_p1_div.reg); + hcodec_p1_gate.reg = clk_base + (u32)(hcodec_p1_gate.reg); + hcodec_mux.reg = clk_base + (u32)(hcodec_mux.reg); + /* cts_hevc_clk */ + hevc_p0_mux.reg = clk_base + (u32)(hevc_p0_mux.reg); + hevc_p0_div.reg = clk_base + (u32)(hevc_p0_div.reg); + hevc_p0_gate.reg = clk_base + (u32)(hevc_p0_gate.reg); + hevc_p1_mux.reg = clk_base + (u32)(hevc_p1_mux.reg); + hevc_p1_div.reg = clk_base + (u32)(hevc_p1_div.reg); + hevc_p1_gate.reg = clk_base + (u32)(hevc_p1_gate.reg); + hevc_mux.reg = clk_base + (u32)(hevc_mux.reg); + /* cts_vpu_clk */ + vpu_p0_mux.reg = clk_base + (u32)(vpu_p0_mux.reg); + vpu_p0_div.reg = clk_base + (u32)(vpu_p0_div.reg); + vpu_p0_gate.reg = clk_base + (u32)(vpu_p0_gate.reg); + vpu_p1_mux.reg = clk_base + (u32)(vpu_p1_mux.reg); + vpu_p1_div.reg = clk_base + (u32)(vpu_p1_div.reg); + vpu_p1_gate.reg = clk_base + (u32)(vpu_p1_gate.reg); + vpu_mux.reg = clk_base + (u32)(vpu_mux.reg); + + /* cts_vdec_clk */ + clks[CLKID_VDEC_P0_COMP] = clk_register_composite(NULL, + "vdec_p0_composite", + dec_parent_names, 8, + vdec_clk_hws[CLKID_VDEC_P0_MUX - CLKID_VDEC_P0_MUX], + &clk_mux_ops, + vdec_clk_hws[CLKID_VDEC_P0_DIV - CLKID_VDEC_P0_MUX], + &clk_divider_ops, + vdec_clk_hws[CLKID_VDEC_P0_GATE - CLKID_VDEC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_VDEC_P0_COMP])) + pr_err("%s: %d clk_register_composite vdec_p0_composite error\n", + __func__, __LINE__); + + clks[CLKID_VDEC_P1_COMP] = clk_register_composite(NULL, + "vdec_p1_composite", + dec_parent_names, 8, + vdec_clk_hws[CLKID_VDEC_P1_MUX - CLKID_VDEC_P0_MUX], + &clk_mux_ops, + vdec_clk_hws[CLKID_VDEC_P1_DIV - CLKID_VDEC_P0_MUX], + &clk_divider_ops, + vdec_clk_hws[CLKID_VDEC_P1_GATE - CLKID_VDEC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_VDEC_P1_COMP])) + pr_err("%s: %d clk_register_composite vdec_p1_composite error\n", + __func__, __LINE__); + + clks[CLKID_VDEC_MUX] = clk_register(NULL, + vdec_clk_hws[CLKID_VDEC_MUX - CLKID_VDEC_P0_MUX]); + WARN_ON(IS_ERR(clks[CLKID_VDEC_MUX])); + + /* cts_hcodec_clk */ + clks[CLKID_HCODEC_P0_COMP] = clk_register_composite(NULL, + "hcodec_p0_composite", + dec_parent_names, 8, + hcodec_clk_hws[CLKID_HCODEC_P0_MUX - CLKID_HCODEC_P0_MUX], + &clk_mux_ops, + hcodec_clk_hws[CLKID_HCODEC_P0_DIV - CLKID_HCODEC_P0_MUX], + &clk_divider_ops, + hcodec_clk_hws[CLKID_HCODEC_P0_GATE - CLKID_HCODEC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_HCODEC_P0_COMP])) + pr_err("%s: %d clk_register_composite hcodec_p0_composite error\n", + __func__, __LINE__); + + clks[CLKID_HCODEC_P1_COMP] = clk_register_composite(NULL, + "hcodec_p1_composite", + dec_parent_names, 8, + hcodec_clk_hws[CLKID_HCODEC_P1_MUX - CLKID_HCODEC_P0_MUX], + &clk_mux_ops, + hcodec_clk_hws[CLKID_HCODEC_P1_DIV - CLKID_HCODEC_P0_MUX], + &clk_divider_ops, + hcodec_clk_hws[CLKID_HCODEC_P1_GATE - CLKID_HCODEC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_HCODEC_P1_COMP])) + pr_err("%s: %d clk_register_composite hcodec_p1_composite error\n", + __func__, __LINE__); + + clks[CLKID_HCODEC_MUX] = clk_register(NULL, + hcodec_clk_hws[CLKID_HCODEC_MUX - CLKID_HCODEC_P0_MUX]); + WARN_ON(IS_ERR(clks[CLKID_HCODEC_MUX])); + + /* cts_hevc_clk */ + clks[CLKID_HEVC_P0_COMP] = clk_register_composite(NULL, + "hevc_p0_composite", + dec_parent_names, 8, + hevc_clk_hws[CLKID_HEVC_P0_MUX - CLKID_HEVC_P0_MUX], + &clk_mux_ops, + hevc_clk_hws[CLKID_HEVC_P0_DIV - CLKID_HEVC_P0_MUX], + &clk_divider_ops, + hevc_clk_hws[CLKID_HEVC_P0_GATE - CLKID_HEVC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_HEVC_P0_COMP])) + pr_err("%s: %d clk_register_composite hevc_p0_composite error\n", + __func__, __LINE__); + + clks[CLKID_HEVC_P1_COMP] = clk_register_composite(NULL, + "hevc_p1_composite", + dec_parent_names, 8, + hevc_clk_hws[CLKID_HEVC_P1_MUX - CLKID_HEVC_P0_MUX], + &clk_mux_ops, + hevc_clk_hws[CLKID_HEVC_P1_DIV - CLKID_HEVC_P0_MUX], + &clk_divider_ops, + hevc_clk_hws[CLKID_HEVC_P1_GATE - CLKID_HEVC_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_HEVC_P1_COMP])) + pr_err("%s: %d clk_register_composite hevc_p1_composite error\n", + __func__, __LINE__); + + clks[CLKID_HEVC_MUX] = clk_register(NULL, + hevc_clk_hws[CLKID_HEVC_MUX - CLKID_HEVC_P0_MUX]); + WARN_ON(IS_ERR(clks[CLKID_HEVC_MUX])); + + /* cts_vpu_clk */ + clks[CLKID_VPU_P0_COMP] = clk_register_composite(NULL, + "vpu_p0_composite", + vpu_parent_names, 8, + vpu_clk_hws[CLKID_VPU_P0_MUX - CLKID_VPU_P0_MUX], + &clk_mux_ops, + vpu_clk_hws[CLKID_VPU_P0_DIV - CLKID_VPU_P0_MUX], + &clk_divider_ops, + vpu_clk_hws[CLKID_VPU_P0_GATE - CLKID_VPU_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_VPU_P0_COMP])) + pr_err("%s: %d clk_register_composite vpu_p0_composite error\n", + __func__, __LINE__); + + clks[CLKID_VPU_P1_COMP] = clk_register_composite(NULL, + "vpu_p1_composite", + vpu_parent_names, 8, + vpu_clk_hws[CLKID_VPU_P1_MUX - CLKID_VPU_P0_MUX], + &clk_mux_ops, + vpu_clk_hws[CLKID_VPU_P1_DIV - CLKID_VPU_P0_MUX], + &clk_divider_ops, + vpu_clk_hws[CLKID_VPU_P1_GATE - CLKID_VPU_P0_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_VPU_P1_COMP])) + pr_err("%s: %d clk_register_composite vpu_p1_composite error\n", + __func__, __LINE__); + + clks[CLKID_VPU_MUX] = clk_register(NULL, + vpu_clk_hws[CLKID_VPU_MUX - CLKID_VPU_P0_MUX]); + WARN_ON(IS_ERR(clks[CLKID_VPU_MUX])); + clk_prepare_enable(clks[CLKID_VPU_MUX]); + + pr_info("%s: register meson media clk\n", __func__); +} + diff --git a/drivers/amlogic/clk/m8b/clk_misc.c b/drivers/amlogic/clk/m8b/clk_misc.c new file mode 100644 index 0000000..309dcaa --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk_misc.c @@ -0,0 +1,348 @@ +/* + * drivers/amlogic/clk/m8b/clk_misc.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "meson8b.h" + +/* cts_vdin_meas_clk */ +const char *meas_parent_names[] = { "xtal", "fclk_div4", + "fclk_div3", "fclk_div5", "vid_pll_clk", "vid2_pll_clk"}; + +/* cts_vdin_meas_clk */ +static struct clk_mux vdin_meas_mux = { + .reg = (void *)HHI_VDIN_MEAS_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_mux", + .ops = &clk_mux_ops, + .parent_names = meas_parent_names, + .num_parents = 6, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider vdin_meas_div = { + .reg = (void *)HHI_VDIN_MEAS_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vdin_meas_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate vdin_meas_gate = { + .reg = (void *)HHI_VDIN_MEAS_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdin_meas_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw *vdin_meas_clk_hws[] = { +[CLKID_VDIN_MEAS_MUX - CLKID_VDIN_MEAS_MUX] = &vdin_meas_mux.hw, +[CLKID_VDIN_MEAS_DIV - CLKID_VDIN_MEAS_MUX] = &vdin_meas_div.hw, +[CLKID_VDIN_MEAS_GATE - CLKID_VDIN_MEAS_MUX] = &vdin_meas_gate.hw, +}; + +/* cts_amclk */ +const char *amclk_parent_names[] = { "ddr_pll_clk", "mpll0", "mpll1", "mpll2"}; + +static struct clk_mux amclk_mux = { + .reg = (void *)HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "amclk_mux", + .ops = &clk_mux_ops, + .parent_names = amclk_parent_names, + .num_parents = 4, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider amclk_div = { + .reg = (void *)HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "amclk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "amclk_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate amclk_gate = { + .reg = (void *)HHI_AUD_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "amclk_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "amclk_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw *amclk_hws[] = { +[CLKID_AMCLK_MUX - CLKID_AMCLK_MUX] = &amclk_mux.hw, +[CLKID_AMCLK_DIV - CLKID_AMCLK_MUX] = &amclk_div.hw, +[CLKID_AMCLK_GATE - CLKID_AMCLK_MUX] = &amclk_gate.hw, +}; + +/* cts_clk_i958 */ +const char *i958_parent_names[] = { "ddr_pll_clk", "mpll0", "mpll1", "mpll2"}; + +static struct clk_mux i958_mux = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "i958_mux", + .ops = &clk_mux_ops, + .parent_names = i958_parent_names, + .num_parents = 4, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider i958_div = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "i958_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "i958_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate i958_gate = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "i958_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "i958_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw *i958_hws[] = { +[CLKID_I958_MUX - CLKID_I958_MUX] = &i958_mux.hw, +[CLKID_I958_DIV - CLKID_I958_MUX] = &i958_div.hw, +[CLKID_I958_GATE - CLKID_I958_MUX] = &i958_gate.hw, +}; + +/* cts_pcm_mclk */ +const char *pcm_mclk_parent_names[] = { "mpll0", "fclk_div4", + "fclk_div3", "fclk_div5"}; + +static struct clk_mux pcm_mclk_mux = { + .reg = (void *)HHI_PCM_CLK_CNTL, + .mask = 0x3, + .shift = 10, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "pcm_mclk_mux", + .ops = &clk_mux_ops, + .parent_names = pcm_mclk_parent_names, + .num_parents = 4, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider pcm_mclk_div = { + .reg = (void *)HHI_PCM_CLK_CNTL, + .shift = 0, + .width = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "pcm_mclk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "pcm_mclk_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate pcm_mclk_gate = { + .reg = (void *)HHI_PCM_CLK_CNTL, + .bit_idx = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "pcm_mclk_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "pcm_mclk_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw *pcm_mclk_hws[] = { +[CLKID_PCM_MCLK_MUX - CLKID_PCM_MCLK_MUX] = &pcm_mclk_mux.hw, +[CLKID_PCM_MCLK_DIV - CLKID_PCM_MCLK_MUX] = &pcm_mclk_div.hw, +[CLKID_PCM_MCLK_GATE - CLKID_PCM_MCLK_MUX] = &pcm_mclk_gate.hw, +}; + +/* cts_pcm_sclk */ +static struct clk_divider pcm_sclk_div = { + .reg = (void *)HHI_PCM_CLK_CNTL, + .shift = 16, + .width = 5, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "pcm_sclk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "pcm_mclk_composite" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate pcm_sclk_gate = { + .reg = (void *)HHI_PCM_CLK_CNTL, + .bit_idx = 22, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "pcm_sclk_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "pcm_sclk_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +void amlogic_init_misc(void) +{ + /* cts_vdin_meas_clk */ + vdin_meas_mux.reg = clk_base + (u32)(vdin_meas_mux.reg); + vdin_meas_div.reg = clk_base + (u32)(vdin_meas_div.reg); + vdin_meas_gate.reg = clk_base + (u32)(vdin_meas_gate.reg); + + /* cts_amclk */ + amclk_mux.reg = clk_base + (u32)(amclk_mux.reg); + amclk_div.reg = clk_base + (u32)(amclk_div.reg); + amclk_gate.reg = clk_base + (u32)(amclk_gate.reg); + + /* cts_clk_i958 */ + i958_mux.reg = clk_base + (u32)(i958_mux.reg); + i958_div.reg = clk_base + (u32)(i958_div.reg); + i958_gate.reg = clk_base + (u32)(i958_gate.reg); + + /* cts_pclk_mclk */ + pcm_mclk_mux.reg = clk_base + (u32)(pcm_mclk_mux.reg); + pcm_mclk_div.reg = clk_base + (u32)(pcm_mclk_div.reg); + pcm_mclk_gate.reg = clk_base + (u32)(pcm_mclk_gate.reg); + + /* cts_pclk_sclk */ + pcm_sclk_div.reg = clk_base + (u32)(pcm_sclk_div.reg); + pcm_sclk_gate.reg = clk_base + (u32)(pcm_sclk_gate.reg); + + clks[CLKID_VDIN_MEAS_COMP] = clk_register_composite(NULL, + "vdin_meas_composite", + meas_parent_names, 6, + vdin_meas_clk_hws[CLKID_VDIN_MEAS_MUX - CLKID_VDIN_MEAS_MUX], + &clk_mux_ops, + vdin_meas_clk_hws[CLKID_VDIN_MEAS_DIV - CLKID_VDIN_MEAS_MUX], + &clk_divider_ops, + vdin_meas_clk_hws[CLKID_VDIN_MEAS_GATE - CLKID_VDIN_MEAS_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_VDIN_MEAS_COMP])) + pr_err("%s: %d clk_register_composite vdin_meas_composite error\n", + __func__, __LINE__); + + clks[CLKID_AMCLK_COMP] = clk_register_composite(NULL, + "amclk_composite", + amclk_parent_names, 4, + amclk_hws[CLKID_AMCLK_MUX - CLKID_AMCLK_MUX], + &clk_mux_ops, + amclk_hws[CLKID_AMCLK_DIV - CLKID_AMCLK_MUX], + &clk_divider_ops, + amclk_hws[CLKID_AMCLK_GATE - CLKID_AMCLK_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_AMCLK_COMP])) + pr_err("%s: %d clk_register_composite amclk_composite error\n", + __func__, __LINE__); + + clks[CLKID_I958_COMP] = clk_register_composite(NULL, + "i958_composite", + i958_parent_names, 4, + i958_hws[CLKID_I958_MUX - CLKID_I958_MUX], + &clk_mux_ops, + i958_hws[CLKID_I958_DIV - CLKID_I958_MUX], + &clk_divider_ops, + i958_hws[CLKID_I958_GATE - CLKID_I958_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_I958_COMP])) + pr_err("%s: %d clk_register_composite i958_composite error\n", + __func__, __LINE__); + /* special for m8baby cts_clk_i958, use 0x1064[27] set 1 */ + writel_relaxed(readl_relaxed(i958_mux.reg)|(1<<27), i958_mux.reg); + + clks[CLKID_PCM_MCLK_COMP] = clk_register_composite(NULL, + "pcm_mclk_composite", + pcm_mclk_parent_names, 4, + pcm_mclk_hws[CLKID_PCM_MCLK_MUX - CLKID_PCM_MCLK_MUX], + &clk_mux_ops, + pcm_mclk_hws[CLKID_PCM_MCLK_DIV - CLKID_PCM_MCLK_MUX], + &clk_divider_ops, + pcm_mclk_hws[CLKID_PCM_MCLK_GATE - CLKID_PCM_MCLK_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_PCM_MCLK_COMP])) + pr_err("%s: %d clk_register_composite pcm_mclk_composite error\n", + __func__, __LINE__); + + clks[CLKID_PCM_SCLK_DIV] = clk_register(NULL, &pcm_sclk_div.hw); + WARN_ON(IS_ERR(clks[CLKID_PCM_SCLK_DIV])); + + clks[CLKID_PCM_SCLK_GATE] = clk_register(NULL, &pcm_sclk_gate.hw); + WARN_ON(IS_ERR(clks[CLKID_PCM_SCLK_GATE])); + + pr_info("%s: register meson misc clk\n", __func__); +}; + diff --git a/drivers/amlogic/clk/m8b/clk_store.c b/drivers/amlogic/clk/m8b/clk_store.c new file mode 100644 index 0000000..0a0e4da --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk_store.c @@ -0,0 +1,101 @@ +/* + * drivers/amlogic/clk/m8b/clk_store.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "meson8b.h" + +/* cts_nand_core_clk */ +const char *nand_parent_names[] = { "fclk_div4", + "fclk_div3", "fclk_div5", "fclk_div7", "xtal", "mpll1"}; + +static struct clk_mux nand_core_mux = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "nand_core_mux", + .ops = &clk_mux_ops, + .parent_names = nand_parent_names, + .num_parents = 6, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider nand_core_div = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "nand_core_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "nand_core_mux" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_gate nand_core_gate = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "nand_core_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "nand_core_div" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw *nand_core_clk_hws[] = { +[CLKID_NAND_CORE_MUX - CLKID_NAND_CORE_MUX] = &nand_core_mux.hw, +[CLKID_NAND_CORE_DIV - CLKID_NAND_CORE_MUX] = &nand_core_div.hw, +[CLKID_NAND_CORE_GATE - CLKID_NAND_CORE_MUX] = &nand_core_gate.hw, +}; + +void amlogic_init_store(void) +{ + /* Populate base address for reg */ + nand_core_mux.reg = clk_base + (u32)(nand_core_mux.reg); + nand_core_div.reg = clk_base + (u32)(nand_core_div.reg); + nand_core_gate.reg = clk_base + (u32)(nand_core_gate.reg); + + clks[CLKID_NAND_CORE_COMP] = clk_register_composite(NULL, + "nand_core_comp", + nand_parent_names, 6, + nand_core_clk_hws[CLKID_NAND_CORE_MUX - CLKID_NAND_CORE_MUX], + &clk_mux_ops, + nand_core_clk_hws[CLKID_NAND_CORE_DIV - CLKID_NAND_CORE_MUX], + &clk_divider_ops, + nand_core_clk_hws[CLKID_NAND_CORE_GATE - CLKID_NAND_CORE_MUX], + &clk_gate_ops, 0); + if (IS_ERR(clks[CLKID_NAND_CORE_COMP])) + pr_err("%s: %d clk_register_composite nand_core_comp error\n", + __func__, __LINE__); + + pr_info("%s: register amlogic store clk\n", __func__); +} diff --git a/drivers/amlogic/clk/m8b/clk_test.c b/drivers/amlogic/clk/m8b/clk_test.c new file mode 100644 index 0000000..675d529 --- /dev/null +++ b/drivers/amlogic/clk/m8b/clk_test.c @@ -0,0 +1,180 @@ +/* + * drivers/amlogic/clk/m8b/clk_test.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "meson8b.h" + + +static struct dentry *debugfs_root; + +void usage(void) +{ + pr_info("\nclk_test:\n"); + pr_info(" echo get clk_name > /sys/kernel/debug/aml_clk/clk_test\n"); + pr_info(" -- get the clock rate of clk_name\n"); + pr_info(" echo set clk_name clkrate > /sys/kernel/debug/aml_clk/clk_test\n"); + pr_info(" -- set the clk_name's rate to clkrate\n"); +} + +struct clk *aml_get_clk_by_name(char *name) +{ + int idx; + struct clk *cur_clk; + + for (idx = 0; idx < NR_CLKS; idx++) { + if (!clks[idx]) { + pr_debug("no such clk clks[%d]\n", idx); + continue; + } + if (!strcmp(__clk_get_name(clks[idx]), name)) { + cur_clk = clks[idx]; + return cur_clk; + } + } + pr_debug("%s: can not find clk: %s\n", __func__, name); + return NULL; +} + +static ssize_t clk_test_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + usage(); + return 0; +} + +static ssize_t clk_test_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct clk *cur_clk; + unsigned long rate, old_rate, new_rate; + char get_set[4]; + char clk_name[32]; + char buf[80]; + int ret; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + + buf[count] = 0; + + ret = sscanf(buf, "%s %s %lu", get_set, clk_name, &rate); + switch (ret) { + case 1: + pr_err("%s error usage!\n", __func__); + usage(); + break; + case 2: + if (!strcmp(get_set, "get")) { + cur_clk = aml_get_clk_by_name(clk_name); + if (cur_clk != NULL) { + pr_info("try to get %s's rate", clk_name); + rate = clk_get_rate(cur_clk); + pr_info("%s: %lu\n", clk_name, rate); + } else + pr_err("Fail! Can not find this clk %s\n", + clk_name); + } else { + pr_err("%s error usage!\n", __func__); + usage(); + } + break; + case 3: + if (!strcmp(get_set, "set")) { + if (!rate) + return -EINVAL; + cur_clk = aml_get_clk_by_name(clk_name); + if (cur_clk != NULL) { + old_rate = clk_get_rate(cur_clk); + if (old_rate == rate) { + pr_info("cur rate is %lu, no need to set again!\n", + rate); + break; + } + pr_info("try to set %s's rate from %lu to %lu\n", + clk_name, old_rate, rate); + ret = clk_set_rate(cur_clk, rate); + new_rate = clk_get_rate(cur_clk); + if (ret) { + pr_err("Fail! Can not set %s to %lu, cur rate: %lu\n", + clk_name, rate, new_rate); + break; + } + if (new_rate == old_rate) + pr_err("Fail! Can not set %s to %lu, still rate: %lu\n", + clk_name, rate, new_rate); + else + pr_info("success! %s cur rate: %lu\n", + clk_name, new_rate); + } else + pr_err("Fail! Can not find this clk %s\n", + clk_name); + } else { + pr_err("%s error usage!\n", __func__); + usage(); + } + + break; + default: + return -EINVAL; + } + + return count; +} + +static const struct file_operations clk_test_file_ops = { + .open = simple_open, + .read = clk_test_read, + .write = clk_test_write, +}; + +static int __init clk_test_init(void) +{ + debugfs_root = debugfs_create_dir("aml_clk", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + pr_warn("failed to create debugfs directory\n"); + debugfs_root = NULL; + return -1; + } + + debugfs_create_file("clk_test", S_IFREG | 0444, + debugfs_root, NULL, &clk_test_file_ops); + return 0; +} + +static void __exit clk_test_exit(void) +{ +} + +module_init(clk_test_init); +module_exit(clk_test_exit); + +MODULE_DESCRIPTION("AMLOGIC clk test driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cai Yun "); diff --git a/drivers/amlogic/clk/m8b/clkc.h b/drivers/amlogic/clk/m8b/clkc.h index 9bb70e7..8ec0718 100644 --- a/drivers/amlogic/clk/m8b/clkc.h +++ b/drivers/amlogic/clk/m8b/clkc.h @@ -1,23 +1,24 @@ /* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione + * drivers/amlogic/clk/m8b/clkc.h * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * - * This program is distributed in the hope it will be useful, but WITHOUT + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #ifndef __CLKC_H #define __CLKC_H +#define CLK_PARENT_ALTERNATE BIT(5) #define PMASK(width) GENMASK(width - 1, 0) #define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) #define CLRPMASK(width, shift) (~SETPMASK(width, shift)) @@ -25,7 +26,7 @@ #define PARM_GET(width, shift, reg) \ (((reg) & SETPMASK(width, shift)) >> (shift)) #define PARM_SET(width, shift, reg, val) \ - (((reg) & CLRPMASK(width, shift)) | (val << (shift))) + (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) #define MESON_PARM_APPLICABLE(p) (!!((p)->width)) @@ -92,8 +93,9 @@ struct meson_clk_mpll { struct clk_hw hw; void __iomem *base; struct parm sdm; + struct parm sdm_en; struct parm n2; - /* FIXME ssen gate control? */ + struct parm en; spinlock_t *lock; }; @@ -116,5 +118,13 @@ extern const struct clk_ops meson_clk_pll_ro_ops; extern const struct clk_ops meson_clk_pll_ops; extern const struct clk_ops meson_clk_cpu_ops; extern const struct clk_ops meson_clk_mpll_ro_ops; - +extern const struct clk_ops meson_clk_mpll_ops; +extern const struct clk_ops meson_clk_mux_ops; +extern spinlock_t clk_lock; +extern void __iomem *clk_base; +extern struct clk **clks; +void amlogic_init_store(void); +void amlogic_init_gpu(void); +void amlogic_init_media(void); +void amlogic_init_misc(void); #endif /* __CLKC_H */ diff --git a/drivers/amlogic/clk/m8b/meson8b.c b/drivers/amlogic/clk/m8b/meson8b.c index 4019dec..8b98132 100644 --- a/drivers/amlogic/clk/m8b/meson8b.c +++ b/drivers/amlogic/clk/m8b/meson8b.c @@ -1,23 +1,18 @@ /* - * AmLogic S805 / Meson8b Clock Controller Driver + * drivers/amlogic/clk/m8b/meson8b.c * - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * - * Copyright (c) 2016 BayLibre, Inc. - * Michael Turquette + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #include @@ -31,8 +26,9 @@ #include "clkc.h" #include "meson8b.h" -static DEFINE_SPINLOCK(clk_lock); +DEFINE_SPINLOCK(clk_lock); struct clk **clks; +void __iomem *clk_base; static struct clk_onecell_data clk_data; static const struct pll_rate_table sys_pll_rate_table[] = { @@ -249,6 +245,96 @@ static struct clk_fixed_factor meson8b_fclk_div7 = { }, }; +static struct meson_clk_mpll meson8b_mpll0 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 14, + .width = 1, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll meson8b_mpll1 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 14, + .width = 1, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll meson8b_mpll2 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 14, + .width = 1, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + /* * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL * post-dividers and should be modeled with their respective PLLs via the @@ -494,6 +580,9 @@ static struct clk_hw *meson8b_clk_hws[] = { [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, }; static struct meson_clk_pll *const meson8b_clk_plls[] = { @@ -502,6 +591,11 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = { &meson8b_sys_pll, }; +static struct meson_clk_mpll *const meson8b_clk_mplls[] = { + &meson8b_mpll0, + &meson8b_mpll1, + &meson8b_mpll2, +}; static struct clk_gate *meson8b_clk_gates[] = { &meson8b_clk81, &meson8b_ddr, @@ -583,13 +677,19 @@ static struct clk_gate *meson8b_clk_gates[] = { &meson8b_ao_iface, }; +static struct clk_mux *const meson8b_clk_muxes[] = { + &meson8b_mpeg_clk_sel, +}; + +static struct clk_divider *const meson8b_clk_dividers[] = { + &meson8b_mpeg_clk_div, +}; + static void __init meson8b_clkc_init(struct device_node *np) { - void __iomem *clk_base; int ret, clkid, i; struct clk_hw *parent_hw; struct clk *parent_clk; - //struct device *dev = &pdev->dev; pr_info("%s\n", __func__); /* Generic clocks and PLLs */ @@ -604,19 +704,28 @@ static void __init meson8b_clkc_init(struct device_node *np) for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) meson8b_clk_plls[i]->base = clk_base; + /* Populate base address for MPLLs */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++) + meson8b_clk_mplls[i]->base = clk_base; + /* Populate the base address for CPU clk */ meson8b_cpu_clk.base = clk_base; - /* Populate the base address for the MPEG clks */ - meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg; - meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; - meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; - /* Populate base address for gates */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) meson8b_clk_gates[i]->reg = clk_base + (u32)meson8b_clk_gates[i]->reg; + /* Populate base address for muxes */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++) + meson8b_clk_muxes[i]->reg = clk_base + + (u32)meson8b_clk_muxes[i]->reg; + + /* Populate base address for dividers */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++) + meson8b_clk_dividers[i]->reg = clk_base + + (u32)meson8b_clk_dividers[i]->reg; + clks = kzalloc(NR_CLKS*sizeof(struct clk *), GFP_KERNEL); if (!clks) { /* pr_err("%s: alloc clks fail!", __func__); */ @@ -629,7 +738,7 @@ static void __init meson8b_clkc_init(struct device_node *np) * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 */ - for (clkid = CLKID_XTAL; clkid < NR_CLKS; clkid++) { + for (clkid = CLKID_XTAL; clkid < OTHER_BASE; clkid++) { /* array might be sparse */ if (!meson8b_clk_hws[clkid]) continue; @@ -639,6 +748,11 @@ static void __init meson8b_clkc_init(struct device_node *np) WARN_ON(IS_ERR(clks[clkid])); } + amlogic_init_store(); + amlogic_init_gpu(); + amlogic_init_media(); + amlogic_init_misc(); + pr_info("%s: register all clk ok!", __func__); /* * Register CPU clk notifier * diff --git a/drivers/amlogic/clk/m8b/meson8b.h b/drivers/amlogic/clk/m8b/meson8b.h index 0d089ca..6d9f5c0 100644 --- a/drivers/amlogic/clk/m8b/meson8b.h +++ b/drivers/amlogic/clk/m8b/meson8b.h @@ -1,21 +1,18 @@ /* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione + * drivers/amlogic/clk/m8b/meson8b.h * - * Copyright (c) 2016 BayLibre, Inc. - * Michael Turquette + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #ifndef __MESON8B_H @@ -37,10 +34,39 @@ #define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ -#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ + +#define HHI_AUD_CLK_CNTL 0x178 /* 0x5e offset in data sheet */ + +#define HHI_AUD_CLK_CNTL2 0x190 /* 0x64 offset in data sheet */ +#define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */ +#define HHI_VPU_CLK_CNTL 0x1bC /* 0x6f offset in data sheet */ + +#define HHI_VDEC_CLK_CNTL 0x1E0 /* 0x78 offset in data sheet */ +#define HHI_VDEC2_CLK_CNTL 0x1E4 /* 0x79 offset in data sheet */ +#define HHI_VDEC3_CLK_CNTL 0x1E8 /* 0x7a offset in data sheet */ +#define HHI_VDEC4_CLK_CNTL 0x1EC /* 0x7b offset in data sheet */ + +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 /* 0x94 offset in data sheet */ +#define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ +#define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ +#define HHI_SD_EMMC_CLK_CNTL 0x264 /* 0x99 offset in data sheet */ + /* + * MPLL register offeset taken from the S905 datasheet. Vendor kernel source + * confirm these are the same for the S805. + */ +#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ +#define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */ +#define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */ +#define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */ +#define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */ +#define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */ +#define HHI_MPLL_CNTL7 0x298 /* 0xa6 offset in data sheet */ +#define HHI_MPLL_CNTL8 0x29C /* 0xa7 offset in data sheet */ +#define HHI_MPLL_CNTL9 0x2A0 /* 0xa8 offset in data sheet */ +#define HHI_MPLL_CNTL10 0x2A4 /* 0xa9 offset in data sheet */ + #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ - /* include the CLKIDs that have been made part of the stable DT binding */ #include diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index 5a7d683..8d71d31 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -107,8 +107,88 @@ #define CLKID_AO_AHB_SRAM 90 #define CLKID_AO_AHB_BUS 91 #define CLKID_AO_IFACE 92 +#define CLKID_MPLL0 93 +#define CLKID_MPLL1 94 +#define CLKID_MPLL2 95 -#define NR_CLKS 93 +#define OTHER_BASE 96 /*96*/ + +#define CLKID_STORE_BASE OTHER_BASE +#define CLKID_NAND_CORE_MUX (CLKID_STORE_BASE + 0) +#define CLKID_NAND_CORE_DIV (CLKID_STORE_BASE + 1) +#define CLKID_NAND_CORE_GATE (CLKID_STORE_BASE + 2) +#define CLKID_NAND_CORE_COMP (CLKID_STORE_BASE + 3) + +#define CLKID_GPU_BASE (CLKID_STORE_BASE + 4) /*96+4*/ +#define CLKID_GPU_P0_MUX (CLKID_GPU_BASE + 0) +#define CLKID_GPU_P0_DIV (CLKID_GPU_BASE + 1) +#define CLKID_GPU_P0_GATE (CLKID_GPU_BASE + 2) +#define CLKID_GPU_P0_COMP (CLKID_GPU_BASE + 3) +#define CLKID_GPU_P1_MUX (CLKID_GPU_BASE + 4) +#define CLKID_GPU_P1_DIV (CLKID_GPU_BASE + 5) +#define CLKID_GPU_P1_GATE (CLKID_GPU_BASE + 6) +#define CLKID_GPU_P1_COMP (CLKID_GPU_BASE + 7) +#define CLKID_GPU_MUX (CLKID_GPU_BASE + 8) + +#define CLKID_MEDIA_BASE (CLKID_GPU_BASE + 9) /*96+4+9*/ +#define CLKID_VDEC_P0_MUX (CLKID_MEDIA_BASE + 0) +#define CLKID_VDEC_P0_DIV (CLKID_MEDIA_BASE + 1) +#define CLKID_VDEC_P0_GATE (CLKID_MEDIA_BASE + 2) +#define CLKID_VDEC_P0_COMP (CLKID_MEDIA_BASE + 3) +#define CLKID_VDEC_P1_MUX (CLKID_MEDIA_BASE + 4) +#define CLKID_VDEC_P1_DIV (CLKID_MEDIA_BASE + 5) +#define CLKID_VDEC_P1_GATE (CLKID_MEDIA_BASE + 6) +#define CLKID_VDEC_P1_COMP (CLKID_MEDIA_BASE + 7) +#define CLKID_VDEC_MUX (CLKID_MEDIA_BASE + 8) +#define CLKID_HCODEC_P0_MUX (CLKID_MEDIA_BASE + 9) +#define CLKID_HCODEC_P0_DIV (CLKID_MEDIA_BASE + 10) +#define CLKID_HCODEC_P0_GATE (CLKID_MEDIA_BASE + 11) +#define CLKID_HCODEC_P0_COMP (CLKID_MEDIA_BASE + 12) +#define CLKID_HCODEC_P1_MUX (CLKID_MEDIA_BASE + 13) +#define CLKID_HCODEC_P1_DIV (CLKID_MEDIA_BASE + 14) +#define CLKID_HCODEC_P1_GATE (CLKID_MEDIA_BASE + 15) +#define CLKID_HCODEC_P1_COMP (CLKID_MEDIA_BASE + 16) +#define CLKID_HCODEC_MUX (CLKID_MEDIA_BASE + 17) +#define CLKID_HEVC_P0_MUX (CLKID_MEDIA_BASE + 18) +#define CLKID_HEVC_P0_DIV (CLKID_MEDIA_BASE + 19) +#define CLKID_HEVC_P0_GATE (CLKID_MEDIA_BASE + 20) +#define CLKID_HEVC_P0_COMP (CLKID_MEDIA_BASE + 21) +#define CLKID_HEVC_P1_MUX (CLKID_MEDIA_BASE + 22) +#define CLKID_HEVC_P1_DIV (CLKID_MEDIA_BASE + 23) +#define CLKID_HEVC_P1_GATE (CLKID_MEDIA_BASE + 24) +#define CLKID_HEVC_P1_COMP (CLKID_MEDIA_BASE + 25) +#define CLKID_HEVC_MUX (CLKID_MEDIA_BASE + 26) +#define CLKID_VPU_P0_MUX (CLKID_MEDIA_BASE + 27) +#define CLKID_VPU_P0_DIV (CLKID_MEDIA_BASE + 28) +#define CLKID_VPU_P0_GATE (CLKID_MEDIA_BASE + 29) +#define CLKID_VPU_P0_COMP (CLKID_MEDIA_BASE + 30) +#define CLKID_VPU_P1_MUX (CLKID_MEDIA_BASE + 31) +#define CLKID_VPU_P1_DIV (CLKID_MEDIA_BASE + 32) +#define CLKID_VPU_P1_GATE (CLKID_MEDIA_BASE + 33) +#define CLKID_VPU_P1_COMP (CLKID_MEDIA_BASE + 34) +#define CLKID_VPU_MUX (CLKID_MEDIA_BASE + 35) + +#define CLKID_MISC_BASE (CLKID_MEDIA_BASE + 36) /*96+4+9+36*/ +#define CLKID_VDIN_MEAS_MUX (CLKID_MISC_BASE + 0) +#define CLKID_VDIN_MEAS_DIV (CLKID_MISC_BASE + 1) +#define CLKID_VDIN_MEAS_GATE (CLKID_MISC_BASE + 2) +#define CLKID_VDIN_MEAS_COMP (CLKID_MISC_BASE + 3) +#define CLKID_AMCLK_MUX (CLKID_MISC_BASE + 4) +#define CLKID_AMCLK_DIV (CLKID_MISC_BASE + 5) +#define CLKID_AMCLK_GATE (CLKID_MISC_BASE + 6) +#define CLKID_AMCLK_COMP (CLKID_MISC_BASE + 7) +#define CLKID_I958_MUX (CLKID_MISC_BASE + 8) +#define CLKID_I958_DIV (CLKID_MISC_BASE + 9) +#define CLKID_I958_GATE (CLKID_MISC_BASE + 10) +#define CLKID_I958_COMP (CLKID_MISC_BASE + 11) +#define CLKID_PCM_MCLK_MUX (CLKID_MISC_BASE + 12) +#define CLKID_PCM_MCLK_DIV (CLKID_MISC_BASE + 13) +#define CLKID_PCM_MCLK_GATE (CLKID_MISC_BASE + 14) +#define CLKID_PCM_MCLK_COMP (CLKID_MISC_BASE + 15) +#define CLKID_PCM_SCLK_DIV (CLKID_MISC_BASE + 16) +#define CLKID_PCM_SCLK_GATE (CLKID_MISC_BASE + 17) + +#define NR_CLKS 164 /*96+4+9+36+18*/ #endif /* __MESON8B_CLKC_H */ -- 2.7.4