From b8a2f778b1ea4e047bad8265f4cad129adfc7a36 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Tue, 11 Sep 2018 12:22:40 +0800 Subject: [PATCH] clock: tl1: initial add tl1 clock driver PD#172587: clock: tl1: initial add tl1 clock driver Initial add tl1 clock driver refered to txlx clock driver. Change-Id: I2f25c465ae7f3f4e65e842a9d0c35f0e0e75662f Signed-off-by: Jian Hu --- .../bindings/clock/amlogic,meson-clkc.txt | 2 + MAINTAINERS | 6 + drivers/amlogic/clk/Makefile | 1 + drivers/amlogic/clk/clkc.h | 12 + drivers/amlogic/clk/tl1/Makefile | 11 + drivers/amlogic/clk/tl1/tl1.c | 905 +++++++++++++++++++++ drivers/amlogic/clk/tl1/tl1.h | 229 ++++++ drivers/amlogic/clk/tl1/tl1_ao.c | 199 +++++ drivers/amlogic/clk/tl1/tl1_clk-mpll.c | 177 ++++ drivers/amlogic/clk/tl1/tl1_clk-pll.c | 420 ++++++++++ drivers/amlogic/clk/tl1/tl1_clk_gpu.c | 108 +++ drivers/amlogic/clk/tl1/tl1_clk_media.c | 650 +++++++++++++++ drivers/amlogic/clk/tl1/tl1_clk_misc.c | 185 +++++ drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c | 81 ++ 14 files changed, 2986 insertions(+) create mode 100644 drivers/amlogic/clk/tl1/Makefile create mode 100644 drivers/amlogic/clk/tl1/tl1.c create mode 100644 drivers/amlogic/clk/tl1/tl1.h create mode 100644 drivers/amlogic/clk/tl1/tl1_ao.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk-mpll.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk-pll.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk_gpu.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk_media.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk_misc.c create mode 100644 drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson-clkc.txt index 7f42f88..a0588e4 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,meson-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,meson-clkc.txt @@ -19,6 +19,8 @@ Required Properties: "amlogic,g12b-clkc-1" - for g12b ee part1 clock "amlogic,g12b-clkc-2" - for g12b ee part2 clock "amlogic,g12b-aoclkc" - for g12b ao clock + "amlogic,tl1-clkc" - for tl1 ee clock + "amlogic,tl1-aoclkc" - for tl1 ao clock - reg: physical base address of the clock controller and length of memory mapped region. diff --git a/MAINTAINERS b/MAINTAINERS index e126940..179435a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14626,3 +14626,9 @@ F: drivers/amlogic/input/sensor/cy8c4014.c F: Documentation/devicetree/bindings/amlogic/input/pca9557_keypad.txt F: drivers/amlogic/input/keyboard/pca9557_keypad.c F: Documentation/devicetree/bindings/is31fl3236a.txt + +AMLOGIC TL1 CLOCK DRIVERS +M: Jian Hu +F: include/dt-bindings/clock/amlogic,tl1-clkc.h +F: drivers/amlogic/clk/tl1/* + diff --git a/drivers/amlogic/clk/Makefile b/drivers/amlogic/clk/Makefile index f7090d4..77fdb66 100644 --- a/drivers/amlogic/clk/Makefile +++ b/drivers/amlogic/clk/Makefile @@ -17,5 +17,6 @@ obj-$(CONFIG_AMLOGIC_GX_CLK) += txlx/ obj-$(CONFIG_AMLOGIC_GX_CLK) += txl/ obj-$(CONFIG_AMLOGIC_GX_CLK) += g12a/ obj-$(CONFIG_AMLOGIC_GX_CLK) += g12b/ +obj-$(CONFIG_AMLOGIC_GX_CLK) += tl1/ obj-$(CONFIG_AMLOGIC_M8B_CLK) += m8b/ diff --git a/drivers/amlogic/clk/clkc.h b/drivers/amlogic/clk/clkc.h index 4fae6a2..7deac3e 100644 --- a/drivers/amlogic/clk/clkc.h +++ b/drivers/amlogic/clk/clkc.h @@ -258,6 +258,12 @@ extern const struct clk_ops meson_g12a_pcie_pll_ops; extern const struct clk_ops meson_g12a_mpll_ro_ops; extern const struct clk_ops meson_g12a_mpll_ops; +extern const struct clk_ops meson_tl1_pll_ro_ops; +extern const struct clk_ops meson_tl1_pll_ops; +extern const struct clk_ops meson_tl1_mpll_ro_ops; +extern const struct clk_ops meson_tl1_mpll_ops; + + extern void meson_clk_register_composite(struct clk **soc_clks, struct meson_composite *composite, unsigned int length); @@ -291,5 +297,11 @@ void meson_g12a_media_init(void); void meson_g12a_gpu_init(void); void meson_g12a_misc_init(void); +/*tl1*/ +void meson_tl1_sdemmc_init(void); +void meson_tl1_media_init(void); +void meson_tl1_gpu_init(void); +void meson_tl1_misc_init(void); + extern int clk_numbers; #endif /* __CLKC_H */ diff --git a/drivers/amlogic/clk/tl1/Makefile b/drivers/amlogic/clk/tl1/Makefile new file mode 100644 index 0000000..cdc82ae9 --- /dev/null +++ b/drivers/amlogic/clk/tl1/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for Meson TL1 clk +# + +obj-$(CONFIG_AMLOGIC_GX_CLK) += tl1.o tl1_ao.o \ + tl1_clk_sdemmc.o \ + tl1_clk_media.o \ + tl1_clk_misc.o \ + tl1_clk_gpu.o \ + tl1_clk-pll.o \ + tl1_clk-mpll.o \ diff --git a/drivers/amlogic/clk/tl1/tl1.c b/drivers/amlogic/clk/tl1/tl1.c new file mode 100644 index 0000000..efe6814a --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1.c @@ -0,0 +1,905 @@ +/* + * drivers/amlogic/clk/tl1/tl1.c + * + * Copyright (C) 2018 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 "tl1.h" + +#define MESON_GATE_TL1(_name, _reg, _bit) \ +struct clk_gate _name = { \ + .reg = (void __iomem *) _reg, \ + .bit_idx = (_bit), \ + .lock = &clk_lock, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_gate_ops, \ + .parent_names = (const char *[]){ "clk81" }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +} + + +static struct clk_onecell_data clk_data; + +static struct meson_clk_pll tl1_sys_pll = { + .m = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 16, + .width = 2, + }, + .rate_table = tl1_pll_rate_table, + .rate_count = ARRAY_SIZE(tl1_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &meson_tl1_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct meson_clk_pll tl1_gp0_pll = { + .m = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 16, + .width = 2, + }, + .rate_table = tl1_pll_rate_table, + .rate_count = ARRAY_SIZE(tl1_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &meson_tl1_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct meson_clk_pll tl1_gp1_pll = { + .m = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 16, + .width = 2, + }, + .rate_table = tl1_pll_rate_table, + .rate_count = ARRAY_SIZE(tl1_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll", + .ops = &meson_tl1_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct meson_clk_pll tl1_hifi_pll = { + .m = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .od = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 16, + .width = 2, + }, + .rate_table = tl1_pll_rate_table, + .rate_count = ARRAY_SIZE(tl1_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &meson_tl1_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +#if 0 +static struct meson_clk_pll tl1_adc_pll = { + .m = { + .reg_off = HHI_ADC_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_ADC_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_ADC_PLL_CNTL, + .shift = 14, + .width = 2, + }, + .rate_table = sys_pll_rate_table, + .rate_count = ARRAY_SIZE(sys_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; +#endif + +static struct meson_clk_pll tl1_fixed_pll = { + .m = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .od = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_FIX_PLL_CNTL1, + .shift = 0, + .width = 19, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &meson_tl1_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +/*tl1 fixed multiplier and divider clock*/ +static struct clk_fixed_factor tl1_fclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor tl1_fclk_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor tl1_fclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor tl1_fclk_div5 = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor tl1_fclk_div7 = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor tl1_fclk_div2p5 = { + .mult = 2, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll tl1_mpll0 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 0, + .width = 14, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 20, + .width = 9, + }, + .sdm_en = 30, + .en_dds = 31, + .mpll_cntl0_reg = HHI_MPLL_CNTL0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &meson_tl1_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll tl1_mpll1 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 0, + .width = 14, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 20, + .width = 9, + }, + .sdm_en = 30, + .en_dds = 31, + .mpll_cntl0_reg = HHI_MPLL_CNTL0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &meson_tl1_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll tl1_mpll2 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 0, + .width = 14, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 20, + .width = 9, + }, + .sdm_en = 30, + .en_dds = 31, + .mpll_cntl0_reg = HHI_MPLL_CNTL0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &meson_tl1_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll tl1_mpll3 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 20, + .width = 9, + }, + .sdm_en = 30, + .en_dds = 31, + .mpll_cntl0_reg = HHI_MPLL_CNTL0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &meson_tl1_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; +/* + *static struct meson_clk_pll tl1_hdmi_pll = { + * .m = { + * .reg_off = HHI_HDMI_PLL_CNTL, + * .shift = 0, + * .width = 9, + * }, + * .n = { + * .reg_off = HHI_HDMI_PLL_CNTL, + * .shift = 9, + * .width = 5, + * }, + * .lock = &clk_lock, + * .hw.init = &(struct clk_init_data){ + * .name = "hdmi_pll", + * .ops = &meson_clk_pll_ro_ops, + * .parent_names = (const char *[]){ "xtal" }, + * .num_parents = 1, + * .flags = CLK_GET_RATE_NOCACHE, + * }, + * }; + */ + +/* + * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL + * post-dividers and should be modelled with their respective PLLs via the + * forthcoming coordinated clock rates feature + */ +static u32 mux_table_cpu_p[] = { 0, 1, 2 }; +static u32 mux_table_cpu_px[] = { 0, 1 }; +static struct meson_cpu_mux_divider tl1_cpu_fclk_p = { + .reg = (void *)HHI_SYS_CPU_CLK_CNTL0, + .cpu_fclk_p00 = { + .mask = 0x3, + .shift = 0, + .width = 2, + }, + .cpu_fclk_p0 = { + .mask = 0x1, + .shift = 2, + .width = 1, + }, + .cpu_fclk_p10 = { + .mask = 0x3, + .shift = 16, + .width = 2, + }, + .cpu_fclk_p1 = { + .mask = 0x1, + .shift = 18, + .width = 1, + }, + .cpu_fclk_p = { + .mask = 0x1, + .shift = 10, + .width = 1, + }, + .cpu_fclk_p01 = { + .shift = 4, + .width = 6, + }, + .cpu_fclk_p11 = { + .shift = 20, + .width = 6, + }, + .table = mux_table_cpu_p, + .rate_table = fclk_pll_rate_table, + .rate_count = ARRAY_SIZE(fclk_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cpu_fixedpll_p", + .ops = &meson_fclk_cpu_ops, + .parent_names = (const char *[]){ "xtal", "fclk_div2", + "fclk_div3"}, + .num_parents = 3, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + +static struct meson_clk_cpu tl1_cpu_clk = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, + .mux.reg = (void *)HHI_SYS_CPU_CLK_CNTL0, + .mux.shift = 11, + .mux.mask = 0x1, + .mux.lock = &clk_lock, + .mux.table = mux_table_cpu_px, + .mux.hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &meson_clk_cpu_ops, + .parent_names = (const char *[]){ "cpu_fixedpll_p", "sys_pll"}, + .num_parents = 2, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static u32 mux_table_clk81[] = { 6, 5, 7 }; + +static struct clk_mux tl1_mpeg_clk_sel = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_READ_ONLY, + .table = mux_table_clk81, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_mux_ro_ops, + /* + * FIXME bits 14:12 selects from 8 possible parents: + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", + "fclk_div5" }, + .num_parents = 3, + .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_divider tl1_mpeg_clk_div = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +/* the mother of dragons^W gates */ +static struct clk_gate tl1_clk81 = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "mpeg_clk_div" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +/* Everything Else (EE) domain gates */ +/* HHI_GCLK_MPEG0 26 bits valid */ +static MESON_GATE_TL1(tl1_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE_TL1(tl1_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE_TL1(tl1_eth_phy, HHI_GCLK_MPEG0, 4); +static MESON_GATE_TL1(tl1_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE_TL1(tl1_pl310, HHI_GCLK_MPEG0, 6); +static MESON_GATE_TL1(tl1_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE_TL1(tl1_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE_TL1(tl1_sana, HHI_GCLK_MPEG0, 10); +static MESON_GATE_TL1(tl1_smart_card, HHI_GCLK_MPEG0, 11); +static MESON_GATE_TL1(tl1_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE_TL1(tl1_stream, HHI_GCLK_MPEG0, 15); +static MESON_GATE_TL1(tl1_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON_GATE_TL1(tl1_tvfe, HHI_GCLK_MPEG0, 18); +static MESON_GATE_TL1(tl1_hiu_reg, HHI_GCLK_MPEG0, 19); +static MESON_GATE_TL1(tl1_hdmirx_pclk, HHI_GCLK_MPEG0, 21); +static MESON_GATE_TL1(tl1_atv_demod, HHI_GCLK_MPEG0, 22); +static MESON_GATE_TL1(tl1_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE_TL1(tl1_emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE_TL1(tl1_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE_TL1(tl1_adec, HHI_GCLK_MPEG0, 27); +static MESON_GATE_TL1(tl1_acodec, HHI_GCLK_MPEG0, 28); +static MESON_GATE_TL1(tl1_tcon, HHI_GCLK_MPEG0, 29); +static MESON_GATE_TL1(tl1_spi, HHI_GCLK_MPEG0, 30); +static MESON_GATE_TL1(tl1_dsp, HHI_GCLK_MPEG0, 31); +/* HHI_GCLK_MPEG1 11 bits valid */ +static MESON_GATE_TL1(tl1_audio, HHI_GCLK_MPEG1, 0); +static MESON_GATE_TL1(tl1_eth_core, HHI_GCLK_MPEG1, 3); +static MESON_GATE_TL1(tl1_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE_TL1(tl1_aififo, HHI_GCLK_MPEG1, 11); +static MESON_GATE_TL1(tl1_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE_TL1(tl1_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE_TL1(tl1_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE_TL1(tl1_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE_TL1(tl1_u_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE_TL1(tl1_usb_general, HHI_GCLK_MPEG1, 26); +static MESON_GATE_TL1(tl1_ahb_arb0, HHI_GCLK_MPEG1, 29); +/* HHI_GCLK_MPEG2 11 bits valid */ +static MESON_GATE_TL1(tl1_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE_TL1(tl1_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE_TL1(tl1_bt656, HHI_GCLK_MPEG2, 6); +static MESON_GATE_TL1(tl1_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static MESON_GATE_TL1(tl1_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE_TL1(tl1_hdcp22_pclk, HHI_GCLK_MPEG2, 13); +static MESON_GATE_TL1(tl1_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE_TL1(tl1_ts, HHI_GCLK_MPEG2, 22); +static MESON_GATE_TL1(tl1_demod_comb, HHI_GCLK_MPEG2, 25); +static MESON_GATE_TL1(tl1_vpu_intr, HHI_GCLK_MPEG2, 28); +static MESON_GATE_TL1(tl1_gic, HHI_GCLK_MPEG2, 30); +/* HHI_GCLK_OTHER 17bits valid */ +static MESON_GATE_TL1(tl1_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE_TL1(tl1_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE_TL1(tl1_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE_TL1(tl1_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE_TL1(tl1_vclk2_venct0, HHI_GCLK_OTHER, 5); +static MESON_GATE_TL1(tl1_vclk2_venct1, HHI_GCLK_OTHER, 6); +static MESON_GATE_TL1(tl1_vclk2_other, HHI_GCLK_OTHER, 7); +static MESON_GATE_TL1(tl1_vclk2_enci, HHI_GCLK_OTHER, 8); +static MESON_GATE_TL1(tl1_vclk2_encp, HHI_GCLK_OTHER, 9); +static MESON_GATE_TL1(tl1_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE_TL1(tl1_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE_TL1(tl1_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE_TL1(tl1_vclk2_enct, HHI_GCLK_OTHER, 22); +static MESON_GATE_TL1(tl1_vclk2_encl, HHI_GCLK_OTHER, 23); +static MESON_GATE_TL1(tl1_vclk2_venclmmc, HHI_GCLK_OTHER, 24); +static MESON_GATE_TL1(tl1_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE_TL1(tl1_vclk2_other1, HHI_GCLK_OTHER, 26); +/* end Everything Else (EE) domain gates */ +/* Always On (AO) domain gates */ +static MESON_GATE(tl1_dma, HHI_GCLK_AO, 0); +static MESON_GATE(tl1_efuse, HHI_GCLK_AO, 1); +static MESON_GATE(tl1_rom_boot, HHI_GCLK_AO, 2); +static MESON_GATE(tl1_reset_sec, HHI_GCLK_AO, 3); +static MESON_GATE(tl1_sec_ahb_apb3, HHI_GCLK_AO, 4); + +static struct clk_gate tl1_spicc_0 = { + .reg = (void *)HHI_GCLK_MPEG0, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "tl1_spicc_0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "clk81" }, + .num_parents = 1, + .flags = 0, + }, +}; + +static struct clk_gate tl1_spicc_1 = { + .reg = (void *)HHI_GCLK_MPEG0, + .bit_idx = 14, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "tl1_spicc_1", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "clk81" }, + .num_parents = 1, + .flags = 0, + }, +}; + +/* Array of all clocks provided by this provider */ +static struct clk_hw *tl1_clk_hws[] = { + [CLKID_SYS_PLL] = &tl1_sys_pll.hw, + [CLKID_FIXED_PLL] = &tl1_fixed_pll.hw, + [CLKID_GP0_PLL] = &tl1_gp0_pll.hw, + [CLKID_GP1_PLL] = &tl1_gp1_pll.hw, + [CLKID_HIFI_PLL] = &tl1_hifi_pll.hw, + /*[CLKID_ADC_PLL] = &tl1_adc_pll.hw,*/ + [CLKID_FCLK_DIV2] = &tl1_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &tl1_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &tl1_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &tl1_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &tl1_fclk_div7.hw, + [CLKID_FCLK_DIV2P5] = &tl1_fclk_div2p5.hw, + [CLKID_MPEG_SEL] = &tl1_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &tl1_mpeg_clk_div.hw, + [CLKID_CLK81] = &tl1_clk81.hw, + [CLKID_MPLL0] = &tl1_mpll0.hw, + [CLKID_MPLL1] = &tl1_mpll1.hw, + [CLKID_MPLL2] = &tl1_mpll2.hw, + [CLKID_MPLL3] = &tl1_mpll3.hw, + [CLKID_DDR] = &tl1_ddr.hw, /*MPEG0 0*/ + [CLKID_DOS] = &tl1_dos.hw, /*MPEG0 1*/ + [CLKID_ETH_PHY] = &tl1_eth_phy.hw, /*MPEG0 4*/ + [CLKID_ISA] = &tl1_isa.hw, /*MPEG0 5*/ + [CLKID_PL310] = &tl1_pl310.hw, /*MPEG0 6*/ + [CLKID_PERIPHS] = &tl1_periphs.hw, /*MPEG0 7*/ + [CLKID_SPICC0] = &tl1_spicc_0.hw, /*MPEG0 8*/ + [CLKID_I2C] = &tl1_i2c.hw, /*MPEG0 9*/ + [CLKID_SANA] = &tl1_sana.hw, /*MPEG0 10*/ + [CLKID_SMART_CARD] = &tl1_smart_card.hw, /*MPEG0 11*/ + [CLKID_UART0] = &tl1_uart0.hw, /*MPEG0 13*/ + [CLKID_SPICC1] = &tl1_spicc_1.hw, /*MPEG0 14*/ + [CLKID_STREAM] = &tl1_stream.hw, /*MPEG0 15*/ + [CLKID_ASYNC_FIFO] = &tl1_async_fifo.hw,/*MPEG0 16*/ + [CLKID_TVFE] = &tl1_tvfe.hw, /*MPEG0 18*/ + [CLKID_HIU_REG] = &tl1_hiu_reg.hw, /*MPEG0 19*/ + [CLKID_HDMIRX_PCLK] = &tl1_hdmirx_pclk.hw, /*MPEG0 21*/ + [CLKID_ATV_DEMOD] = &tl1_atv_demod.hw, /*MPEG0 22*/ + [CLKID_ASSIST_MISC] = &tl1_assist_misc.hw, /*MPEG0 23*/ + [CLKID_SD_EMMC_B] = &tl1_emmc_b.hw, /*MPEG0 25*/ + [CLKID_SD_EMMC_C] = &tl1_emmc_c.hw, /*MPEG0 26*/ + [CLKID_ADEC] = &tl1_adec.hw, /*MPEG0 27*/ + [CLKID_ACODEC] = &tl1_acodec.hw, /*MPEG0 28*/ + [CLKID_TCON] = &tl1_tcon.hw, /*MPEG0 29*/ + [CLKID_SPI] = &tl1_spi.hw, /*MPEG0 30*/ + [CLKID_DSP] = &tl1_dsp.hw, /*MPEG0 31*/ + [CLKID_AUDIO] = &tl1_audio.hw, /*MPEG1 0*/ + [CLKID_ETH_CORE] = &tl1_eth_core.hw, /*MPEG1 3*/ + [CLKID_DEMUX] = &tl1_demux.hw, /*MPEG1 4*/ + [CLKID_AIFIFO] = &tl1_aififo.hw,/*MPEG1 11*/ + [CLKID_ADC] = &tl1_adc.hw, /*MPEG1 13*/ + [CLKID_UART1] = &tl1_uart1.hw, /*MPEG1 16*/ + [CLKID_G2D] = &tl1_g2d.hw, /*MPEG1 20*/ + [CLKID_RESET] = &tl1_reset.hw, /*MPEG1 23*/ + [CLKID_U_PARSER] = &tl1_u_parser.hw, /*MPEG1 25*/ + [CLKID_USB_GENERAL] = &tl1_usb_general.hw, /*MPEG1 26*/ + [CLKID_AHB_ARB0] = &tl1_ahb_arb0.hw, /*MPEG1 29*/ + [CLKID_AHB_DATA_BUS] = &tl1_ahb_data_bus.hw, /*MPEG2 1*/ + [CLKID_AHB_CTRL_BUS] = &tl1_ahb_ctrl_bus.hw, /*MPEG2 2*/ + [CLKID_BT656] = &tl1_bt656.hw, /*MPEG2 6*/ + [CLKID_USB1_TO_DDR] = &tl1_usb1_to_ddr.hw, /*MPEG2 8*/ + [CLKID_MMC_PCLK] = &tl1_mmc_pclk.hw, /*MPEG2 11*/ + [CLKID_HDCP22_PCLK] = &tl1_hdcp22_pclk.hw, /*MPEG2 13*/ + [CLKID_UART2] = &tl1_uart2.hw, /*MPEG2 15*/ + [CLKID_TS] = &tl1_ts.hw, /*MPEG2 22*/ + [CLKID_VPU_INTR] = &tl1_vpu_intr.hw, /*MPEG2 25*/ + [CLKID_DEMOD_COMB] = &tl1_demod_comb.hw, /*MPEG2 28*/ + [CLKID_GIC] = &tl1_gic.hw, /*MPEG2 30*/ + [CLKID_VCLK2_VENCI0] = &tl1_vclk2_venci0.hw, /*OTHER 1*/ + [CLKID_VCLK2_VENCI1] = &tl1_vclk2_venci1.hw, /*OTHER 2*/ + [CLKID_VCLK2_VENCP0] = &tl1_vclk2_vencp0.hw, /*OTHER 3*/ + [CLKID_VCLK2_VENCP1] = &tl1_vclk2_vencp1.hw, /*OTHER 4*/ + [CLKID_VCLK2_VENCT0] = &tl1_vclk2_venct0.hw, /*OTHER 5*/ + [CLKID_VCLK2_VENCT1] = &tl1_vclk2_venct1.hw, /*OTHER 6*/ + [CLKID_VCLK2_OTHER] = &tl1_vclk2_other.hw, /*OTHER 7*/ + [CLKID_VCLK2_ENCI] = &tl1_vclk2_enci.hw, /*OTHER 8*/ + [CLKID_VCLK2_ENCP] = &tl1_vclk2_encp.hw, /*OTHER 9*/ + [CLKID_DAC_CLK] = &tl1_dac_clk.hw, /*OTHER 10*/ + [CLKID_ENC480P] = &tl1_enc480p.hw, /*OTHER 20*/ + [CLKID_RNG1] = &tl1_rng1.hw, /*OTHER 21*/ + [CLKID_VCLK2_ENCT] = &tl1_vclk2_enct.hw, /*OTHER 22*/ + [CLKID_VCLK2_ENCL] = &tl1_vclk2_encl.hw, /*OTHER 23*/ + [CLKID_VCLK2_VENCLMMC] = &tl1_vclk2_venclmmc.hw, /*OTHER 24*/ + [CLKID_VCLK2_VENCL] = &tl1_vclk2_vencl.hw, /*OTHER 25*/ + [CLKID_VCLK2_OTHER1] = &tl1_vclk2_other1.hw, /*OTHER 26*/ + [CLKID_DMA] = &tl1_dma.hw, /*AO 0*/ + [CLKID_EFUSE] = &tl1_efuse.hw, /*AO 1*/ + [CLKID_ROM_BOOT] = &tl1_rom_boot.hw, /*AO 2*/ + [CLKID_RESET_SEC] = &tl1_reset_sec.hw, /*AO 3*/ + [CLKID_SEC_AHB_APB3] = &tl1_sec_ahb_apb3.hw, /*AO 4*/ + + [CLKID_CPU_FCLK_P] = &tl1_cpu_fclk_p.hw, + [CLKID_CPU_CLK] = &tl1_cpu_clk.mux.hw, +}; +/* Convenience tables to populate base addresses in .probe */ + +static struct meson_clk_pll *const tl1_clk_plls[] = { + &tl1_fixed_pll, + &tl1_sys_pll, + &tl1_gp0_pll, + &tl1_gp1_pll, + &tl1_hifi_pll, + /*&tl1_adc_pll,*/ + /*&tl1_hdmi_pll,*/ +}; + +static struct meson_clk_mpll *const tl1_clk_mplls[] = { + &tl1_mpll0, + &tl1_mpll1, + &tl1_mpll2, + &tl1_mpll3, +}; + +static struct clk_gate *tl1_clk_gates[] = { + &tl1_clk81, + &tl1_ddr, + &tl1_dos, + &tl1_eth_phy, + &tl1_isa, + &tl1_pl310, + &tl1_periphs, + &tl1_spicc_0, + &tl1_i2c, + &tl1_sana, + &tl1_smart_card, + &tl1_uart0, + &tl1_spicc_1, + &tl1_stream, + &tl1_async_fifo, + &tl1_tvfe, + &tl1_hiu_reg, + &tl1_hdmirx_pclk, + &tl1_atv_demod, + &tl1_assist_misc, + &tl1_emmc_b, + &tl1_emmc_c, + &tl1_adec, + &tl1_acodec, + &tl1_tcon, + &tl1_spi, + &tl1_dsp,/*gate0 end*/ + &tl1_audio, + &tl1_eth_core, + &tl1_demux, + &tl1_aififo, + &tl1_adc, + &tl1_uart1, + &tl1_g2d, + &tl1_reset, + &tl1_u_parser, + &tl1_usb_general, + &tl1_ahb_arb0, /*gate1 end*/ + &tl1_ahb_data_bus, + &tl1_ahb_ctrl_bus, + &tl1_bt656, + &tl1_usb1_to_ddr, + &tl1_mmc_pclk, + &tl1_hdcp22_pclk, + &tl1_uart2, + &tl1_ts, + &tl1_vpu_intr, + &tl1_demod_comb, + &tl1_gic,/*gate2 end*/ + &tl1_vclk2_venci0, + &tl1_vclk2_venci1, + &tl1_vclk2_vencp0, + &tl1_vclk2_vencp1, + &tl1_vclk2_venct0, + &tl1_vclk2_venct1, + &tl1_vclk2_other, + &tl1_vclk2_enci, + &tl1_vclk2_encp, + &tl1_dac_clk, + &tl1_enc480p, + &tl1_rng1, + &tl1_vclk2_enct, + &tl1_vclk2_encl, + &tl1_vclk2_venclmmc, + &tl1_vclk2_vencl, + &tl1_vclk2_other1,/* other end */ + &tl1_dma, + &tl1_efuse, + &tl1_rom_boot, + &tl1_reset_sec, + &tl1_sec_ahb_apb3, +}; + +static void __init tl1_clkc_init(struct device_node *np) +{ + int clkid, i; + int ret = 0; + struct clk_hw *parent_hw; + struct clk *parent_clk; + + /* Generic clocks and PLLs */ + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return; + } + + /* Populate base address for PLLs */ + for (i = 0; i < ARRAY_SIZE(tl1_clk_plls); i++) + tl1_clk_plls[i]->base = clk_base; + + /* Populate base address for MPLLs */ + for (i = 0; i < ARRAY_SIZE(tl1_clk_mplls); i++) + tl1_clk_mplls[i]->base = clk_base; + + /* Populate the base address for the MPEG clks */ + tl1_mpeg_clk_sel.reg = clk_base + + (unsigned long)tl1_mpeg_clk_sel.reg; + tl1_mpeg_clk_div.reg = clk_base + + (unsigned long)tl1_mpeg_clk_div.reg; + + /* Populate the base address for CPU clk */ + tl1_cpu_fclk_p.reg = clk_base + + (unsigned long)tl1_cpu_fclk_p.reg; + tl1_cpu_clk.base = clk_base; + tl1_cpu_clk.mux.reg = clk_base + + (unsigned long)tl1_cpu_clk.mux.reg; + + /* Populate base address for gates */ + for (i = 0; i < ARRAY_SIZE(tl1_clk_gates); i++) + tl1_clk_gates[i]->reg = clk_base + + (unsigned long)tl1_clk_gates[i]->reg; + + if (!clks) { + clks = kzalloc(NR_CLKS*sizeof(struct clk *), GFP_KERNEL); + if (!clks) { + pr_err("%s: alloc clks fail!", __func__); + return; + } + } else { + pr_err("%s: error: not kzalloc clks in eeclk!", __func__); + return; + } + clk_numbers = NR_CLKS; + clk_data.clks = clks; + clk_data.clk_num = NR_CLKS; + + /*register all clks*/ + for (clkid = 0; clkid < CLOCK_GATE; clkid++) { + if (tl1_clk_hws[clkid]) { + clks[clkid] = clk_register(NULL, tl1_clk_hws[clkid]); + WARN_ON(IS_ERR(clks[clkid])); + } + } + + meson_tl1_sdemmc_init(); + meson_tl1_media_init(); + meson_tl1_gpu_init(); + meson_tl1_misc_init(); + + parent_hw = clk_hw_get_parent(&tl1_cpu_clk.mux.hw); + parent_clk = parent_hw->clk; + ret = clk_notifier_register(parent_clk, &tl1_cpu_clk.clk_nb); + if (ret) { + pr_err("%s: failed to register clock notifier for cpu_clk\n", + __func__); + goto iounmap; + } + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, + &clk_data); + if (ret < 0) { + pr_err("%s fail ret: %d\n", __func__, ret); + return; + } + + return; + +iounmap: + iounmap(clk_base); + pr_err("%s iomap failed ret: %d\n", __func__, ret); +} + +CLK_OF_DECLARE(tl1, "amlogic,tl1-clkc", tl1_clkc_init); diff --git a/drivers/amlogic/clk/tl1/tl1.h b/drivers/amlogic/clk/tl1/tl1.h new file mode 100644 index 0000000..92d8996 --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1.h @@ -0,0 +1,229 @@ +/* + * drivers/amlogic/clk/tl1/tl1.h + * + * Copyright (C) 2018 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. + * + */ + +#ifndef __TL1_H +#define __TL1_H + +/* + * Clock controller register offsets + * + * Register offsets from the data sheet are listed in comment blocks below. + * Those offsets must be multiplied by 4 before adding them to the base address + * to get the right value + */ +#define HHI_GP0_PLL_CNTL0 0x40 /* 0x10 offset in datasheet very*/ +#define HHI_GP0_PLL_CNTL1 0x44 /* 0x11 offset in datasheet */ +#define HHI_GP0_PLL_CNTL2 0x48 /* 0x12 offset in datasheet */ +#define HHI_GP0_PLL_CNTL3 0x4c /* 0x13 offset in datasheet */ +#define HHI_GP0_PLL_CNTL4 0x50 /* 0x14 offset in datasheet */ +#define HHI_GP0_PLL_CNTL5 0x54 /* 0x15 offset in datasheet */ +#define HHI_GP0_PLL_CNTL6 0x58 /* 0x16 offset in datasheet */ +#define HHI_GP0_PLL_STS 0x5c /* 0x17 offset in datasheet */ +#define HHI_GP1_PLL_CNTL0 0x60 /* 0x18 offset in datasheet */ +#define HHI_GP1_PLL_CNTL1 0x64 /* 0x19 offset in datasheet */ +#define HHI_GP1_PLL_CNTL2 0x68 /* 0x1a offset in datasheet */ +#define HHI_GP1_PLL_CNTL3 0x6c /* 0x1b offset in datasheet */ +#define HHI_GP1_PLL_CNTL4 0x70 /* 0x1c offset in datasheet */ +#define HHI_GP1_PLL_CNTL5 0x74 /* 0x1d offset in datasheet */ +#define HHI_GP1_PLL_CNTL6 0x78 /* 0x1e offset in datasheet */ +#define HHI_GP1_PLL_STS 0x7c /* 0x1f offset in datasheet very*/ + +#define HHI_HIFI_PLL_CNTL0 0xd8 /* 0x36 offset in datasheet very*/ +#define HHI_HIFI_PLL_CNTL1 0xdc /* 0x37 offset in datasheet */ +#define HHI_HIFI_PLL_CNTL2 0xe0 /* 0x38 offset in datasheet */ +#define HHI_HIFI_PLL_CNTL4 0xe4 /* 0x39 offset in datasheet */ +#define HHI_HIFI_PLL_CNTL5 0xe8 /* 0x3a offset in datasheet */ +#define HHI_HIFI_PLL_CNTL6 0xec /* 0x3b offset in datasheet */ +#define HHI_HIFI_PLL_STS 0xf0 /* 0x3c offset in datasheet very*/ + +#define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in datasheet */ +#define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in datasheet */ +#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in datasheet */ +#define HHI_GCLK_OTHER 0x150 /* 0x54 offset in datasheet */ + +#define HHI_GCLK_AO 0x154 /* 0x55 offset in datasheet */ + +#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in datasheet */ +#define HHI_SPICC_HCLK_CNTL 0x168 /* 0x5a offset in datasheet */ + +#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in datasheet */ +#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in datasheet */ +#define HHI_TS_CLK_CNTL 0x190 /* 0x64 offset in datasheet1 */ +#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in datasheet */ +#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in datasheet */ +#define HHI_AUD_CLK_CNTL3 0x1A4 /* 0x69 offset in datasheet */ +#define HHI_AUD_CLK_CNTL4 0x1A8 /* 0x6a offset in datasheet */ +#define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in datasheet */ +#define HHI_VPU_CLKC_CNTL 0x1b4 /* 0x6d offset in datasheet1 */ +#define HHI_VPU_CLK_CNTL 0x1bC /* 0x6f offset in datasheet1 */ +#define HHI_AUDPLL_CLK_OUT_CNTL 0x1E0 /* 0x74 offset in datasheet1 */ +#define HHI_VDEC_CLK_CNTL 0x1E0 /* 0x78 offset in datasheet1 */ +#define HHI_VDEC2_CLK_CNTL 0x1E4 /* 0x79 offset in datasheet1 */ +#define HHI_VDEC3_CLK_CNTL 0x1E8 /* 0x7a offset in datasheet1 */ +#define HHI_VDEC4_CLK_CNTL 0x1EC /* 0x7b offset in datasheet1 */ +#define HHI_HDCP22_CLK_CNTL 0x1F0 /* 0x7c offset in datasheet1 */ +#define HHI_VAPBCLK_CNTL 0x1F4 /* 0x7d offset in datasheet1 */ +#define HHI_HDMIRX_CLK_CNTL 0x200 /* 0x80 offset in datasheet1 */ +#define HHI_HDMIRX_AUD_CLK_CNTL 0x204 /* 0x81 offset in datasheet1 */ +#define HHI_VPU_CLKB_CNTL 0x20C /* 0x83 offset in datasheet1 */ + +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 /* 0x94 offset in datasheet1 */ +#define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in datasheet1*/ +#define HHI_SD_EMMC_CLK_CNTL 0x264 /* 0x99 offset in datasheet1*/ +#define HHI_TCON_CLK_CNTL 0x270 /* 0x9c offset in datasheet1*/ + +#define HHI_MPLL_CNTL0 0x278 /* 0x9e offset in datasheet very*/ +#define HHI_MPLL_CNTL1 0x27c /* 0x9f offset in datasheet */ +#define HHI_MPLL_CNTL2 0x280 /* 0xa0 offset in datasheet */ +#define HHI_MPLL_CNTL3 0x284 /* 0xa1 offset in datasheet */ +#define HHI_MPLL_CNTL4 0x288 /* 0xa2 offset in datasheet */ +#define HHI_MPLL_CNTL5 0x28c /* 0xa3 offset in datasheet */ +#define HHI_MPLL_CNTL6 0x290 /* 0xa4 offset in datasheet */ +#define HHI_MPLL_CNTL7 0x294 /* 0xa5 offset in datasheet */ +#define HHI_MPLL_CNTL8 0x298 /* 0xa6 offset in datasheet */ +#define HHI_MPLL_STS 0x29c /* 0xa7 offset in datasheet very*/ + +#define HHI_FIX_PLL_CNTL0 0x2a0 /* 0xa8 offset in datasheet very*/ +#define HHI_FIX_PLL_CNTL1 0x2a4 /* 0xa9 offset in datasheet */ +#define HHI_FIX_PLL_CNTL2 0x2a8 /* 0xaa offset in datasheet */ +#define HHI_FIX_PLL_CNTL3 0x2ac /* 0xab offset in datasheet */ +#define HHI_FIX_PLL_CNTL4 0x2b0 /* 0xac offset in datasheet */ +#define HHI_FIX_PLL_CNTL5 0x2b4 /* 0xad offset in datasheet */ +#define HHI_FIX_PLL_CNTL6 0x2b8 /* 0xae offset in datasheet */ +#define HHI_FIX_PLL_STS 0x2bc /* 0xaf offset in datasheet very*/ + +#define HHI_MPLL3_CNTL0 0x2E0 /* 0xb8 offset in datasheet */ +#define HHI_MPLL3_CNTL1 0x2E4 /* 0xb9 offset in datasheet */ +#define HHI_PLL_TOP_MISC 0x2E8 /* 0xba offset in datasheet */ + +#define HHI_ADC_PLL_CNTL 0x2A8 /* 0xaa offset in datasheet */ +#define HHI_ADC_PLL_CNTL2 0x2AC /* 0xab offset in datasheet */ +#define HHI_ADC_PLL_CNTL3 0x2B0 /* 0xac offset in datasheet */ +#define HHI_ADC_PLL_CNTL4 0x2B4 /* 0xad offset in datasheet */ + +#define HHI_SYS_PLL_CNTL0 0x2f4 /* 0xbd offset in datasheet */ +#define HHI_SYS_PLL_CNTL1 0x2f8 /* 0xbe offset in datasheet */ +#define HHI_SYS_PLL_CNTL2 0x2fc /* 0xbf offset in datasheet */ +#define HHI_SYS_PLL_CNTL3 0x300 /* 0xc0 offset in datasheet */ +#define HHI_SYS_PLL_CNTL4 0x304 /* 0xc1 offset in datasheet */ +#define HHI_SYS_PLL_CNTL5 0x308 /* 0xc2 offset in datasheet */ +#define HHI_SYS_PLL_CNTL6 0x30c /* 0xc3 offset in datasheet */ + +#define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in datasheet */ +#define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in datasheet */ +#define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in datasheet */ +#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in datasheet */ +#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in datasheet */ +#define HHI_VID_LOCK_CLK_CNTL 0x3c8 /* 0xf2 offset in datasheet1 */ +#define HHI_BT656_CLK_CNTL 0x3d4 /* 0xf5 offset in datasheet1 */ +#define HHI_SPICC_CLK_CNTL 0x3dc /* 0xf7 offset in datasheet1 */ + +/* AO registers*/ +#define AO_RTI_PWR_CNTL_REG0 0x10 /* 0x4 offset in datasheet1*/ +#define AO_CLK_GATE0 0x4c /* 0x13 offset in datasheet1 */ +#define AO_CLK_GATE0_SP 0x50 /* 0x14 offset in datasheet1 */ +#define AO_SAR_CLK 0x90 /* 0x24 offset in datasheet1 */ + +/*tl1: pll: FDCO: 3G~6G FDCO = 24*(M+frac)/N + *N: recommend is 1 + *clk_out = FDCO >> OD + */ +static const struct pll_rate_table tl1_pll_rate_table[] = { + PLL_RATE(24000000ULL, 128, 1, 7), /*DCO=3072M*/ + PLL_RATE(48000000ULL, 128, 1, 6), /*DCO=3072M*/ + PLL_RATE(96000000ULL, 128, 1, 5), /*DCO=3072M*/ + PLL_RATE(192000000ULL, 128, 1, 4), /*DCO=3072M*/ + PLL_RATE(312000000ULL, 208, 1, 4), /*DCO=4992M*/ + PLL_RATE(408000000ULL, 136, 1, 3), /*DCO=3264M*/ + PLL_RATE(600000000ULL, 200, 1, 3), /*DCO=4800M*/ + PLL_RATE(696000000ULL, 232, 1, 3), /*DCO=5568M*/ + PLL_RATE(792000000ULL, 132, 1, 2), /*DCO=3168M*/ + PLL_RATE(846000000ULL, 141, 1, 2), /*DCO=3384M*/ + PLL_RATE(912000000ULL, 152, 1, 2), /*DCO=3648M*/ + PLL_RATE(1008000000ULL, 168, 1, 2), /*DCO=4032M*/ + PLL_RATE(1104000000ULL, 184, 1, 2), /*DCO=4416M*/ + PLL_RATE(1200000000ULL, 200, 1, 2), /*DCO=4800M*/ + PLL_RATE(1296000000ULL, 216, 1, 2), /*DCO=5184M*/ + PLL_RATE(1398000000ULL, 233, 1, 2), /*DCO=5592M*/ + PLL_RATE(1494000000ULL, 249, 1, 2), /*DCO=5976M*/ + PLL_RATE(1512000000ULL, 126, 1, 1), /*DCO=3024M*/ + PLL_RATE(1608000000ULL, 134, 1, 1), /*DCO=3216M*/ + PLL_RATE(1704000000ULL, 142, 1, 1), /*DCO=3408M*/ + PLL_RATE(1800000000ULL, 150, 1, 1), /*DCO=3600M*/ + PLL_RATE(1896000000ULL, 158, 1, 1), /*DCO=3792M*/ + PLL_RATE(1908000000ULL, 159, 1, 1), /*DCO=3816M*/ + PLL_RATE(1920000000ULL, 160, 1, 1), /*DCO=3840M*/ + PLL_RATE(2016000000ULL, 168, 1, 1), /*DCO=4032M*/ + PLL_RATE(2100000000ULL, 175, 1, 1), /*DCO=4200M*/ + PLL_RATE(2196000000ULL, 183, 1, 1), /*DCO=4392M*/ + PLL_RATE(2292000000ULL, 191, 1, 1), /*DCO=4584M*/ + PLL_RATE(2400000000ULL, 200, 1, 1), /*DCO=4800M*/ + PLL_RATE(2496000000ULL, 208, 1, 1), /*DCO=4992M*/ + PLL_RATE(2592000000ULL, 216, 1, 1), /*DCO=5184M*/ + PLL_RATE(2700000000ULL, 225, 1, 1), /*DCO=5400M*/ + PLL_RATE(2796000000ULL, 233, 1, 1), /*DCO=5592M*/ + PLL_RATE(2892000000ULL, 241, 1, 1), /*DCO=5784M*/ + PLL_RATE(3000000000ULL, 125, 1, 0), /*DCO=3000M*/ + PLL_RATE(3096000000ULL, 129, 1, 0), /*DCO=3096M*/ + PLL_RATE(3192000000ULL, 133, 1, 0), /*DCO=3192M*/ + PLL_RATE(3288000000ULL, 137, 1, 0), /*DCO=3288M*/ + PLL_RATE(3408000000ULL, 142, 1, 0), /*DCO=3408M*/ + PLL_RATE(3504000000ULL, 146, 1, 0), /*DCO=3504M*/ + PLL_RATE(3600000000ULL, 150, 1, 0), /*DCO=3600M*/ + PLL_RATE(3696000000ULL, 154, 1, 0), /*DCO=3696M*/ + PLL_RATE(3792000000ULL, 158, 1, 0), /*DCO=3792M*/ + PLL_RATE(3888000000ULL, 162, 1, 0), /*DCO=3888M*/ + PLL_RATE(4008000000ULL, 167, 1, 0), /*DCO=4008M*/ + PLL_RATE(4104000000ULL, 171, 1, 0), /*DCO=4104M*/ + PLL_RATE(4200000000ULL, 175, 1, 0), /*DCO=4200M*/ + PLL_RATE(4296000000ULL, 179, 1, 0), /*DCO=4296M*/ + PLL_RATE(4392000000ULL, 183, 1, 0), /*DCO=4392M*/ + PLL_RATE(4488000000ULL, 187, 1, 0), /*DCO=4488M*/ + PLL_RATE(4608000000ULL, 192, 1, 0), /*DCO=4608M*/ + PLL_RATE(4704000000ULL, 196, 1, 0), /*DCO=4704M*/ + PLL_RATE(4800000000ULL, 200, 1, 0), /*DCO=4800M*/ + PLL_RATE(4896000000ULL, 204, 1, 0), /*DCO=4896M*/ + PLL_RATE(4992000000ULL, 208, 1, 0), /*DCO=4992M*/ + PLL_RATE(5088000000ULL, 212, 1, 0), /*DCO=5088M*/ + PLL_RATE(5208000000ULL, 217, 1, 0), /*DCO=5208M*/ + PLL_RATE(5304000000ULL, 221, 1, 0), /*DCO=5304M*/ + PLL_RATE(5400000000ULL, 225, 1, 0), /*DCO=5400M*/ + PLL_RATE(5496000000ULL, 229, 1, 0), /*DCO=5496M*/ + PLL_RATE(5592000000ULL, 233, 1, 0), /*DCO=5592M*/ + PLL_RATE(5688000000ULL, 237, 1, 0), /*DCO=5688M*/ + PLL_RATE(5808000000ULL, 242, 1, 0), /*DCO=5808M*/ + PLL_RATE(5904000000ULL, 246, 1, 0), /*DCO=5904M*/ + PLL_RATE(6000000000ULL, 250, 1, 0), /*DCO=6000M*/ + + { /* sentinel */ }, + +}; + +/*fix pll rate table*/ +static const struct fclk_rate_table fclk_pll_rate_table[] = { + FCLK_PLL_RATE(50000000, 1, 1, 19), + FCLK_PLL_RATE(100000000, 1, 1, 9), + FCLK_PLL_RATE(167000000, 2, 1, 3), + FCLK_PLL_RATE(200000000, 1, 1, 4), + FCLK_PLL_RATE(250000000, 1, 1, 3), + FCLK_PLL_RATE(333000000, 2, 1, 1), + FCLK_PLL_RATE(500000000, 1, 1, 1), + FCLK_PLL_RATE(667000000, 2, 0, 0), + FCLK_PLL_RATE(1000000000, 1, 0, 0), +}; + +#endif /* __TL1_H */ diff --git a/drivers/amlogic/clk/tl1/tl1_ao.c b/drivers/amlogic/clk/tl1/tl1_ao.c new file mode 100644 index 0000000..b3c099c --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_ao.c @@ -0,0 +1,199 @@ +/* + * drivers/amlogic/clk/tl1/tl1_ao.c + * + * Copyright (C) 2018 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 "tl1.h" + +#define MESON_AO_GATE_TL1(_name, _reg, _bit) \ +struct clk_gate _name = { \ + .reg = (void __iomem *) _reg, \ + .bit_idx = (_bit), \ + .lock = &clk_lock, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_gate_ops, \ + .parent_names = (const char *[]){ "clk81" }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +} + +/* tl1 ao clock gates */ +MESON_AO_GATE_TL1(tl1_ao_ahb_bus, AO_CLK_GATE0, 0); +MESON_AO_GATE_TL1(tl1_ao_ir, AO_CLK_GATE0, 1); +MESON_AO_GATE_TL1(tl1_ao_i2c_master, AO_CLK_GATE0, 2); +MESON_AO_GATE_TL1(tl1_ao_i2c_slave, AO_CLK_GATE0, 3); +MESON_AO_GATE_TL1(tl1_ao_uart1, AO_CLK_GATE0, 4); +MESON_AO_GATE_TL1(tl1_ao_prod_i2c, AO_CLK_GATE0, 5); +MESON_AO_GATE_TL1(tl1_ao_uart2, AO_CLK_GATE0, 6); +MESON_AO_GATE_TL1(tl1_ao_ir_blaster, AO_CLK_GATE0, 7); +MESON_AO_GATE_TL1(tl1_ao_sar_adc, AO_CLK_GATE0, 8); +/* FIXME for AO_CLK_GATE0_SP clocks */ + +static struct clk_mux aoclk81 = { + .reg = (void *)AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 8, + .flags = CLK_MUX_READ_ONLY, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "aoclk81", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "clk81", "ao_slow_clk" }, + .num_parents = 2, + .flags = (CLK_SET_RATE_NO_REPARENT), + }, +}; + +/* sar_adc_clk */ +static struct clk_mux tl1_saradc_mux = { + .reg = (void *)AO_SAR_CLK, + .mask = 0x3, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "tl1_saradc_mux", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "xtal", "aoclk81"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE), + }, +}; + +static struct clk_divider tl1_saradc_div = { + .reg = (void *)AO_SAR_CLK, + .shift = 0, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "tl1_saradc_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "tl1_saradc_mux" }, + .num_parents = 1, + .flags = (CLK_DIVIDER_ROUND_CLOSEST), + }, +}; + +static struct clk_gate tl1_saradc_gate = { + .reg = (void *)AO_SAR_CLK, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "tl1_saradc_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "tl1_saradc_div" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + }, +}; + +/* Array of all clocks provided by this provider */ +static struct clk_hw *tl1_ao_clk_hws[] = { + [CLKID_AO_CLK81 - CLKID_AO_CLK81] + = &aoclk81.hw, + [CLKID_SARADC_MUX - CLKID_AO_CLK81] + = &tl1_saradc_mux.hw, + [CLKID_SARADC_DIV - CLKID_AO_CLK81] + = &tl1_saradc_div.hw, + [CLKID_SARADC_GATE - CLKID_AO_CLK81] + = &tl1_saradc_gate.hw, + [CLKID_AO_AHB_BUS - CLKID_AO_CLK81] + = &tl1_ao_ahb_bus.hw, + [CLKID_AO_IR - CLKID_AO_CLK81] + = &tl1_ao_ir.hw, + [CLKID_AO_I2C_MASTER - CLKID_AO_CLK81] + = &tl1_ao_i2c_master.hw, + [CLKID_AO_I2C_SLAVE - CLKID_AO_CLK81] + = &tl1_ao_i2c_slave.hw, + [CLKID_AO_UART1 - CLKID_AO_CLK81] + = &tl1_ao_uart1.hw, + [CLKID_AO_PROD_I2C - CLKID_AO_CLK81] + = &tl1_ao_prod_i2c.hw, + [CLKID_AO_UART2 - CLKID_AO_CLK81] + = &tl1_ao_uart2.hw, + [CLKID_AO_IR_BLASTER - CLKID_AO_CLK81] + = &tl1_ao_ir_blaster.hw, + [CLKID_AO_SAR_ADC - CLKID_AO_CLK81] + = &tl1_ao_sar_adc.hw, +}; + +static struct clk_gate *tl1_ao_clk_gates[] = { + &tl1_ao_ahb_bus, + &tl1_ao_i2c_master, + &tl1_ao_i2c_slave, + &tl1_ao_uart1, + &tl1_ao_prod_i2c, + &tl1_ao_uart2, + &tl1_ao_ir_blaster, + &tl1_ao_sar_adc, +}; + +static int tl1_aoclkc_probe(struct platform_device *pdev) +{ + void __iomem *aoclk_base; + int clkid, i; + struct device *dev = &pdev->dev; + + /* Generic clocks and PLLs */ + aoclk_base = of_iomap(dev->of_node, 0); + if (!aoclk_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + /* Populate the base address for ao clk */ + for (i = 0; i < ARRAY_SIZE(tl1_ao_clk_gates); i++) + tl1_ao_clk_gates[i]->reg = aoclk_base + + (unsigned long)tl1_ao_clk_gates[i]->reg; + + aoclk81.reg = aoclk_base + (unsigned long)aoclk81.reg; + tl1_saradc_mux.reg = aoclk_base + (unsigned long)tl1_saradc_mux.reg; + tl1_saradc_div.reg = aoclk_base + (unsigned long)tl1_saradc_div.reg; + tl1_saradc_gate.reg = aoclk_base + (unsigned long)tl1_saradc_gate.reg; + + for (clkid = CLKID_AO_BASE; clkid < NR_CLKS; clkid++) { + if (tl1_ao_clk_hws[clkid-CLKID_AO_BASE]) { + clks[clkid] = clk_register(NULL, + tl1_ao_clk_hws[clkid-CLKID_AO_BASE]); + WARN_ON(IS_ERR(clks[clkid])); + } + } + + return 0; +} + +static const struct of_device_id tl1_aoclkc_match_table[] = { + { .compatible = "amlogic,tl1-aoclkc" }, + { }, +}; + +static struct platform_driver tl1_aoclk_driver = { + .probe = tl1_aoclkc_probe, + .driver = { + .name = "tl1-aoclkc", + .of_match_table = tl1_aoclkc_match_table, + }, +}; + +builtin_platform_driver(tl1_aoclk_driver); diff --git a/drivers/amlogic/clk/tl1/tl1_clk-mpll.c b/drivers/amlogic/clk/tl1/tl1_clk-mpll.c new file mode 100644 index 0000000..81e9dfe --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk-mpll.c @@ -0,0 +1,177 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk-mpll.c + * + * Copyright (C) 2018 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 + +#include "../clkc.h" +/* #undef pr_debug */ +/* #define pr_debug pr_info */ +#define SDM_MAX 16384 +#define MAX_RATE 500000000 +#define MIN_RATE 3920000 + +#define TL1_MPLL_CNTL0 0x00000543 +#define TL1_MPLL_CNTL2 0x40000033 + + +#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) + +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 rate = 0; + unsigned long reg, sdm, n2; + u64 rate64 = parent_rate; + + 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 (n2 == 0 && sdm == 0) { + rate = 0; + } else { + rate64 = rate64 * SDM_MAX; + do_div(rate64, ((SDM_MAX * n2) + sdm)); + rate = rate64; + } + + return rate; +} + +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rate_val = rate; + + if (rate_val < MIN_RATE) + rate = MIN_RATE; + if (rate_val > MAX_RATE) + rate = MAX_RATE; + + return rate_val; +} + + +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; + + if ((rate > MAX_RATE) || (rate < MIN_RATE)) { + pr_err("Err: can not set rate to %lu!\n", rate); + pr_err("Range[3920000 - 500000000]\n"); + return -1; + } + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + + /* calculate new n2 and sdm */ + n2 = parent_rate / rate; + sdm = DIV_ROUND_UP((parent_rate - n2 * rate) * SDM_MAX, rate); + if (sdm >= SDM_MAX) + sdm = SDM_MAX - 1; + + pr_debug("%s: sdm: %lu n2: %lu rate: %lu parent_rate: %lu\n", + __func__, sdm, n2, rate, parent_rate); + + writel(TL1_MPLL_CNTL0, mpll->base + mpll->mpll_cntl0_reg); + + p = &mpll->sdm; + writel(TL1_MPLL_CNTL2, mpll->base + p->reg_off + (unsigned long)(1*4)); + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, sdm); + p = &mpll->n2; + reg = PARM_SET(p->width, p->shift, reg, n2); + reg = PARM_SET(1, mpll->sdm_en, reg, 1); + reg = PARM_SET(1, mpll->en_dds, reg, 1); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + + return 0; +} + +static int mpll_enable(struct clk_hw *hw) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p = &mpll->sdm; + unsigned long reg; + unsigned long flags = 0; + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(1, mpll->sdm_en, reg, 1); + reg = PARM_SET(1, mpll->en_dds, reg, 1); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + + return 0; +} + +static void mpll_disable(struct clk_hw *hw) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p = &mpll->sdm; + unsigned long reg; + unsigned long flags = 0; + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(1, mpll->sdm_en, reg, 0); + reg = PARM_SET(1, mpll->en_dds, reg, 0); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); +} + +const struct clk_ops meson_tl1_mpll_ops = { + .recalc_rate = mpll_recalc_rate, + .round_rate = meson_clk_pll_round_rate, + .set_rate = mpll_set_rate, + .enable = mpll_enable, + .disable = mpll_disable, +}; + +const struct clk_ops meson_tl1_mpll_ro_ops = { + .recalc_rate = mpll_recalc_rate, +}; diff --git a/drivers/amlogic/clk/tl1/tl1_clk-pll.c b/drivers/amlogic/clk/tl1/tl1_clk-pll.c new file mode 100644 index 0000000..8a9f42f --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk-pll.c @@ -0,0 +1,420 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk-pll.c + * + * Copyright (C) 2018 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. + * + */ + +/* + * In the most basic form, a Meson PLL is composed as follows: + * + * PLL + * +------------------------------+ + * | | + * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out + * | ^ ^ | + * +------------------------------+ + * | | + * FREF VCO + * + * out = (in * M / N) >> OD + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../clkc.h" + +#define MESON_PLL_RESET BIT(29) +#define MESON_PLL_ENABLE BIT(28) +#define MESON_PLL_LOCK BIT(31) + +/* tl1 */ +#define TL1_SYS_PLL_CNTL1 0x00000000 +#define TL1_SYS_PLL_CNTL2 0x00000000 +#define TL1_SYS_PLL_CNTL3 0x48681c00 +#define TL1_SYS_PLL_CNTL4 0x88770290 +#define TL1_SYS_PLL_CNTL5 0x39272000 + + +#define TL1_GP0_PLL_CNTL1 0x00000000 +#define TL1_GP0_PLL_CNTL2 0x00000000 +#define TL1_GP0_PLL_CNTL3 0x48681c00 +#define TL1_GP0_PLL_CNTL4 0x33771290 +#define TL1_GP0_PLL_CNTL5 0x39272000 + +#define TL1_HIFI_PLL_CNTL1 0x00000000 +#define TL1_HIFI_PLL_CNTL2 0x00000000 +#define TL1_HIFI_PLL_CNTL3 0x6a285c00 +#define TL1_HIFI_PLL_CNTL4 0x65771290 +#define TL1_HIFI_PLL_CNTL5 0x39272000 + +#define TL1_PLL_CNTL6 0x56540000 + +#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) + +static unsigned long meson_tl1_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p; + u64 parent_rate_mhz = parent_rate; + unsigned long rate_mhz; + u16 n, m, od, od2 = 0; + u32 reg, frac = 0; + u64 tmp64; + + p = &pll->n; + reg = readl(pll->base + p->reg_off); + n = PARM_GET(p->width, p->shift, reg); + + p = &pll->m; + reg = readl(pll->base + p->reg_off); + m = PARM_GET(p->width, p->shift, reg); + + p = &pll->od; + reg = readl(pll->base + p->reg_off); + od = PARM_GET(p->width, p->shift, reg); + + p = &pll->od2; + if (p->width) { + reg = readl(pll->base + p->reg_off); + od2 = PARM_GET(p->width, p->shift, reg); + } + + p = &pll->frac; + + if (p->width >= 2) { + reg = readl(pll->base + p->reg_off); + frac = PARM_GET(p->width - 1, p->shift, reg); + + if (reg & (1 << (p->width - 1))) { + tmp64 = (parent_rate_mhz * m - + ((parent_rate_mhz * frac) + >> (p->width - 2))); + do_div(tmp64, n); + rate_mhz = (unsigned long)tmp64; + } else { + tmp64 = (parent_rate_mhz * m + + ((parent_rate_mhz * frac) + >> (p->width - 2))); + do_div(tmp64, n); + rate_mhz = (unsigned long)tmp64; + } + + if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) + rate_mhz = rate_mhz/4/od; + else + rate_mhz = rate_mhz >> od; + } else { + if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) { + tmp64 = parent_rate_mhz * m; + do_div(tmp64, n * 4 * od); + rate_mhz = (unsigned long)tmp64; + } else { + tmp64 = parent_rate_mhz * m; + do_div(tmp64, n); + rate_mhz = tmp64 >> od >> od2; + } + } + + return rate_mhz; +} + +static long meson_tl1_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + const struct pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) { + if (rate <= rate_table[i].rate) + return rate_table[i].rate; + } + + /* else return the smallest value */ + return rate_table[0].rate; +} + +static const struct pll_rate_table *meson_tl1_get_pll_settings + (struct meson_clk_pll *pll, unsigned long rate) +{ + const struct pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) { + if (rate == rate_table[i].rate) + return &rate_table[i]; + } + return NULL; +} + +static int meson_tl1_pll_wait_lock(struct meson_clk_pll *pll, + struct parm *p_n) +{ + int delay = 24000000; + u32 reg; + + while (delay > 0) { + reg = readl(pll->base + p_n->reg_off); + + if (reg & MESON_PLL_LOCK) + return 0; + delay--; + } + return -ETIMEDOUT; +} + +static int meson_tl1_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p; + const struct pll_rate_table *rate_set; + unsigned long old_rate; + int ret = 0; + u32 reg; + unsigned long flags = 0; + void *cntlbase; + + if (parent_rate == 0 || rate == 0) + return -EINVAL; + + old_rate = rate; + + rate_set = meson_tl1_get_pll_settings(pll, rate); + if (!rate_set) + return -EINVAL; + + p = &pll->n; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + if (readl(pll->base + p->reg_off) & MESON_PLL_ENABLE) { + old_rate = meson_tl1_pll_recalc_rate(hw, parent_rate); + old_rate = meson_tl1_pll_round_rate(hw, old_rate, NULL); + + if (old_rate == rate) { + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + return ret; + } + } + + cntlbase = pll->base + p->reg_off; + + + if (!strcmp(clk_hw_get_name(hw), "sys_pll")) { + writel((readl(cntlbase) | MESON_PLL_RESET) + & (~MESON_PLL_ENABLE), cntlbase); + writel(TL1_SYS_PLL_CNTL1, + cntlbase + (unsigned long)(1*4)); + writel(TL1_SYS_PLL_CNTL2, + cntlbase + (unsigned long)(2*4)); + writel(TL1_SYS_PLL_CNTL3, + cntlbase + (unsigned long)(3*4)); + writel(TL1_SYS_PLL_CNTL4, + cntlbase + (unsigned long)(4*4)); + writel(TL1_SYS_PLL_CNTL5, + cntlbase + (unsigned long)(5*4)); + writel(TL1_PLL_CNTL6, + cntlbase + (unsigned long)(6*4)); + udelay(10); + } else if (!strcmp(clk_hw_get_name(hw), "gp0_pll")) { + writel((readl(cntlbase) | MESON_PLL_RESET) + & (~MESON_PLL_ENABLE), cntlbase); + writel(TL1_GP0_PLL_CNTL1, + cntlbase + (unsigned long)(1*4)); + writel(TL1_GP0_PLL_CNTL2, + cntlbase + (unsigned long)(2*4)); + writel(TL1_GP0_PLL_CNTL3, + cntlbase + (unsigned long)(3*4)); + writel(TL1_GP0_PLL_CNTL4, + cntlbase + (unsigned long)(4*4)); + writel(TL1_GP0_PLL_CNTL5, + cntlbase + (unsigned long)(5*4)); + writel(TL1_PLL_CNTL6, + cntlbase + (unsigned long)(6*4)); + udelay(10); + } else if (!strcmp(clk_hw_get_name(hw), "hifi_pll")) { + writel((readl(cntlbase) | MESON_PLL_RESET) + & (~MESON_PLL_ENABLE), cntlbase); + writel(TL1_GP0_PLL_CNTL1, + cntlbase + (unsigned long)(1*4)); + writel(TL1_GP0_PLL_CNTL2, + cntlbase + (unsigned long)(2*4)); + writel(TL1_GP0_PLL_CNTL3, + cntlbase + (unsigned long)(3*4)); + writel(TL1_GP0_PLL_CNTL4, + cntlbase + (unsigned long)(4*4)); + writel(TL1_GP0_PLL_CNTL5, + cntlbase + (unsigned long)(5*4)); + writel(TL1_PLL_CNTL6, + cntlbase + (unsigned long)(6*4)); + udelay(10); + } else { + pr_err("%s: %s pll not found!!!\n", + __func__, clk_hw_get_name(hw)); + return -EINVAL; + } + + reg = readl(pll->base + p->reg_off); + + reg = PARM_SET(p->width, p->shift, reg, rate_set->n); + writel(reg, pll->base + p->reg_off); + + p = &pll->m; + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->m); + writel(reg, pll->base + p->reg_off); + + p = &pll->od; + /*check OD width*/ + if (rate_set->od >> p->width) { + ret = -EINVAL; + pr_warn("%s: OD width is wrong at rate %lu !!\n", + __func__, rate); + goto OUT; + } + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->od); + writel(reg, pll->base + p->reg_off); + + p = &pll->od2; + if (p->width) { + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); + writel(reg, pll->base + p->reg_off); + } + + p = &pll->frac; + if (p->width) { + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); + writel(reg, pll->base + p->reg_off); + } + + p = &pll->n; + + /* PLL reset */ + writel(readl(pll->base + p->reg_off) | MESON_PLL_ENABLE, + pll->base + p->reg_off); + udelay(50); + writel(readl(pll->base + p->reg_off) & (~MESON_PLL_RESET), + pll->base + p->reg_off); + ret = meson_tl1_pll_wait_lock(pll, p); + +OUT: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + if (ret) { + pr_warn("%s: pll did not lock, trying to lock rate %lu again\n", + __func__, rate); + meson_tl1_pll_set_rate(hw, rate, parent_rate); + } + + return ret; +} + +static int meson_tl1_pll_enable(struct clk_hw *hw) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p; + int ret = 0; + unsigned long flags = 0; + unsigned long first_set = 1; + struct clk_hw *parent; + unsigned long rate; + + p = &pll->n; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + if (readl(pll->base + p->reg_off) & MESON_PLL_ENABLE) { + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + return ret; + } + + if (!strcmp(clk_hw_get_name(hw), "gp0_pll") + || !strcmp(clk_hw_get_name(hw), "hifi_pll") + || !strcmp(clk_hw_get_name(hw), "sys_pll")) { + void *cntlbase = pll->base + p->reg_off; + + if (readl(cntlbase + (unsigned long)(6*4)) + == TL1_PLL_CNTL6) + first_set = 0; + + } + + parent = clk_hw_get_parent(hw); + + /*First init, just set minimal rate.*/ + if (first_set) + rate = pll->rate_table[0].rate; + else { + rate = meson_tl1_pll_recalc_rate(hw, clk_hw_get_rate(parent)); + rate = meson_tl1_pll_round_rate(hw, rate, NULL); + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + ret = meson_tl1_pll_set_rate(hw, rate, clk_hw_get_rate(parent)); + + return ret; +} + +static void meson_tl1_pll_disable(struct clk_hw *hw) +{ + struct meson_clk_pll *pll = to_meson_clk_pll(hw); + struct parm *p = &pll->n; + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + writel(readl(pll->base + p->reg_off) | (MESON_PLL_RESET), + pll->base + p->reg_off); + writel(readl(pll->base + p->reg_off) & (~MESON_PLL_ENABLE), + pll->base + p->reg_off); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +const struct clk_ops meson_tl1_pll_ops = { + .recalc_rate = meson_tl1_pll_recalc_rate, + .round_rate = meson_tl1_pll_round_rate, + .set_rate = meson_tl1_pll_set_rate, + .enable = meson_tl1_pll_enable, + .disable = meson_tl1_pll_disable, +}; + +const struct clk_ops meson_tl1_pll_ro_ops = { + .recalc_rate = meson_tl1_pll_recalc_rate, +}; + diff --git a/drivers/amlogic/clk/tl1/tl1_clk_gpu.c b/drivers/amlogic/clk/tl1/tl1_clk_gpu.c new file mode 100644 index 0000000..ab8c3ce --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk_gpu.c @@ -0,0 +1,108 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk_gpu.c + * + * Copyright (C) 2018 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 "tl1.h" + +PNAME(gpus_parent_names) = { "xtal", "gp0_pll", "hifi_pll", + "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7"}; + +PNAME(gpumux_parent_names) = { "gpu_p0_composite", "gpu_p1_composite"}; + +/* gpu p0 */ +static MUX(gpu_p0_mux, HHI_MALI_CLK_CNTL, 0x7, 9, gpus_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(gpu_p0_div, HHI_MALI_CLK_CNTL, 0, 7, "gpu_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(gpu_p0_gate, HHI_MALI_CLK_CNTL, 8, "gpu_p0_div", + CLK_GET_RATE_NOCACHE); +/* gpu p1 */ +static MUX(gpu_p1_mux, HHI_MALI_CLK_CNTL, 0x7, 25, gpus_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(gpu_p1_div, HHI_MALI_CLK_CNTL, 16, 7, "gpu_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(gpu_p1_gate, HHI_MALI_CLK_CNTL, 24, "gpu_p1_div", + CLK_GET_RATE_NOCACHE); + +static MESON_MUX(gpu_mux, HHI_MALI_CLK_CNTL, 0x1, 31, +gpumux_parent_names, CLK_GET_RATE_NOCACHE); + +/* for init mux/div/gate clocks reg base*/ +static struct clk_mux *tl1_gpu_clk_muxes[] = { + &gpu_p0_mux, + &gpu_p1_mux, + &gpu_mux, +}; + +static struct clk_divider *tl1_gpu_clk_divs[] = { + &gpu_p0_div, + &gpu_p1_div, +}; + +static struct clk_gate *tl1_gpu_clk_gates[] = { + &gpu_p0_gate, + &gpu_p1_gate, +}; + +static struct meson_composite gpu_composite[] = { + {CLKID_GPU_P0_COMP, "gpu_p0_composite", + gpus_parent_names, ARRAY_SIZE(gpus_parent_names), + &gpu_p0_mux.hw, &gpu_p0_div.hw, + &gpu_p0_gate.hw, 0 + },/*gpu_p0*/ + + {CLKID_GPU_P1_COMP, "gpu_p1_composite", + gpus_parent_names, ARRAY_SIZE(gpus_parent_names), + &gpu_p1_mux.hw, &gpu_p1_div.hw, &gpu_p1_gate.hw, 0 + },/*gpu_p1*/ + + {}, +}; +void meson_tl1_gpu_init(void) +{ + int i, length; + + length = ARRAY_SIZE(gpu_composite); + /* Populate base address for gpu muxes, divs,gates */ + for (i = 0; i < ARRAY_SIZE(tl1_gpu_clk_muxes); i++) + tl1_gpu_clk_muxes[i]->reg = clk_base + + (unsigned long)tl1_gpu_clk_muxes[i]->reg; + for (i = 0; i < ARRAY_SIZE(tl1_gpu_clk_divs); i++) + tl1_gpu_clk_divs[i]->reg = clk_base + + (unsigned long)tl1_gpu_clk_divs[i]->reg; + for (i = 0; i < ARRAY_SIZE(tl1_gpu_clk_gates); i++) + tl1_gpu_clk_gates[i]->reg = clk_base + + (unsigned long)tl1_gpu_clk_gates[i]->reg; + + meson_clk_register_composite(clks, gpu_composite, length - 1); + + clks[CLKID_GPU_MUX] = clk_register(NULL, &gpu_mux.hw); + 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); +} diff --git a/drivers/amlogic/clk/tl1/tl1_clk_media.c b/drivers/amlogic/clk/tl1/tl1_clk_media.c new file mode 100644 index 0000000..6be0ef2 --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk_media.c @@ -0,0 +1,650 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk_media.c + * + * Copyright (C) 2018 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 "tl1.h" + +/* cts_vdin_meas_clk */ +PNAME(meas_parent_names) = { "xtal", "fclk_div4", +"fclk_div3", "fclk_div5", "vid_pll", "null", "null", "null" }; +static MUX(vdin_meas_mux, HHI_VDIN_MEAS_CLK_CNTL, 0x7, 9, meas_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vdin_meas_div, HHI_VDIN_MEAS_CLK_CNTL, 0, 7, "vdin_meas_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vdin_meas_gate, HHI_VDIN_MEAS_CLK_CNTL, 8, "vdin_meas_div", + CLK_GET_RATE_NOCACHE); + +/* cts_vpu_p0_clk */ +PNAME(vpu_parent_names) = { "fclk_div3", "fclk_div4", "fclk_div5", +"fclk_div7", "mpll1", "vid_pll", "hifi_pll", "gp0_pll"}; +static MUX(vpu_p0_mux, HHI_VPU_CLK_CNTL, 0x7, 9, vpu_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vpu_p0_div, HHI_VPU_CLK_CNTL, 0, 7, "vpu_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_p0_gate, HHI_VPU_CLK_CNTL, 8, "vpu_p0_div", + CLK_GET_RATE_NOCACHE); + +/* cts_vpu_p1_clk */ +static MUX(vpu_p1_mux, HHI_VPU_CLK_CNTL, 0x7, 25, vpu_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vpu_p1_div, HHI_VPU_CLK_CNTL, 16, 7, "vpu_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_p1_gate, HHI_VPU_CLK_CNTL, 24, "vpu_p1_div", + CLK_GET_RATE_NOCACHE); +/* vpu mux clk */ +PNAME(vpu_mux_parent_names) = { "vpu_p0_composite", "vpu_p1_composite" }; +static MESON_MUX(vpu_mux, HHI_VPU_CLK_CNTL, 0x1, 31, + vpu_mux_parent_names, CLK_GET_RATE_NOCACHE); + +/* vpu_clkb_tmp */ +PNAME(vpu_clkb_parent_names) = { "vpu_mux", + "fclk_div4", "fclk_div5", "fclk_div7" }; +static MUX(vpu_clkb_tmp_mux, HHI_VPU_CLKB_CNTL, 0x3, 20, +vpu_clkb_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(vpu_clkb_tmp_div, HHI_VPU_CLKB_CNTL, 16, 4, "vpu_clkb_tmp_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_clkb_tmp_gate, HHI_VPU_CLKB_CNTL, 24, "vpu_clkb_tmp_div", + CLK_GET_RATE_NOCACHE); + +/* vpu_clkb */ +PNAME(vpu_clkb_nomux_parent_names) = { "vpu_clkb_tmp_composite" }; +static DIV(vpu_clkb_div, HHI_VPU_CLKB_CNTL, 0, 8, "vpu_clkb_tmp_composite", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_clkb_gate, HHI_VPU_CLKB_CNTL, 8, "vpu_clkb_div", + CLK_GET_RATE_NOCACHE); + +/* vpu_clkc*/ +PNAME(vpu_clkc_parent_names) = { "fclk_div4", "fclk_div3", "fclk_div5", +"fclk_div7", "mpll1", "vid_pll", "mpll2", "gp0_pll"}; +static MUX(vpu_clkc_p0_mux, HHI_VPU_CLKC_CNTL, 0x7, 9, vpu_clkc_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vpu_clkc_p0_div, HHI_VPU_CLKC_CNTL, 0, 7, "vpu_clkc_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_clkc_p0_gate, HHI_VPU_CLKC_CNTL, 8, "vpu_clkc_p0_div", + CLK_GET_RATE_NOCACHE); + +static MUX(vpu_clkc_p1_mux, HHI_VPU_CLKC_CNTL, 0x7, 25, vpu_clkc_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vpu_clkc_p1_div, HHI_VPU_CLKC_CNTL, 16, 7, "vpu_clkc_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vpu_clkc_p1_gate, HHI_VPU_CLKC_CNTL, 24, "vpu_clkc_p1_div", + CLK_GET_RATE_NOCACHE); + +/* vpu_clkc mux clk */ +PNAME(vpu_clkc_mux_parent_names) = { "vpu_clkc_p0_composite", + "vpu_clkc_p1_composite" }; +static MESON_MUX(vpu_clkc_mux, HHI_VPU_CLKC_CNTL, 0x1, 31, + vpu_clkc_mux_parent_names, CLK_GET_RATE_NOCACHE); + +/* cts_bt656_clk0 */ +PNAME(bt656_clk0_parent_names) = { "fclk_div2", "fclk_div3", "fclk_div5", + "fclk_div7" }; +static MUX(bt656_clk0_mux, HHI_BT656_CLK_CNTL, 0x3, 9, bt656_clk0_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(bt656_clk0_div, HHI_BT656_CLK_CNTL, 0, 7, "bt656_clk0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(bt656_clk0_gate, HHI_BT656_CLK_CNTL, 7, "bt656_clk0_div", + CLK_GET_RATE_NOCACHE); + +/* cts_tcon_pll_clk */ +PNAME(tcon_pll_parent_names) = { "xtal", "fclk_div5", "fclk_div4", +"fclk_div3", "mpll2", "mpll3", "vid_pll", "gp0" }; +static MUX(tcon_pll_mux, HHI_TCON_CLK_CNTL, 0x3, 7, tcon_pll_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(tcon_pll_div, HHI_TCON_CLK_CNTL, 0, 6, "tcon_pll_mux", + CLK_GET_RATE_NOCACHE); +static GATE(tcon_pll_gate, HHI_TCON_CLK_CNTL, 6, "tcon_pll_div", + CLK_GET_RATE_NOCACHE); + +/* cts_vapb p0 clk */ +PNAME(vapb_parent_names) = { "fclk_div4", "fclk_div3", "fclk_div5", +"fclk_div7", "mpll1", "vid_pll", "mpll2", "fclk_div2p5"}; +static MUX(vapb_p0_mux, HHI_VAPBCLK_CNTL, 0x7, 9, vapb_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vapb_p0_div, HHI_VAPBCLK_CNTL, 0, 7, "vapb_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vapb_p0_gate, HHI_VAPBCLK_CNTL, 8, "vapb_p0_div", + CLK_GET_RATE_NOCACHE); +/* cts_vapb p1 clk */ +static MUX(vapb_p1_mux, HHI_VAPBCLK_CNTL, 0x7, 25, vapb_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vapb_p1_div, HHI_VAPBCLK_CNTL, 16, 7, "vapb_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vapb_p1_gate, HHI_VAPBCLK_CNTL, 24, "vapb_p1_div", + CLK_GET_RATE_NOCACHE); + +/* cts_vapb mux clk */ +PNAME(vapb_mux_parent_names) = { "vapb_p0_composite", "vapb_p1_composite" }; +static MESON_MUX(vapb_mux, HHI_VAPBCLK_CNTL, 0x1, 31, +vapb_mux_parent_names, CLK_GET_RATE_NOCACHE); +static GATE(ge2d_gate, HHI_VAPBCLK_CNTL, 30, "vapb_mux", + CLK_GET_RATE_NOCACHE); + +/*hdmirx cfg clock*/ +PNAME(hdmirx_parent_names) = { "xtal", "fclk_div4", "fclk_div3", "fclk_div5" }; +static MUX(hdmirx_cfg_mux, HHI_HDMIRX_CLK_CNTL, 0x3, 9, hdmirx_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hdmirx_cfg_div, HHI_HDMIRX_CLK_CNTL, 0, 7, "hdmirx_cfg_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hdmirx_cfg_gate, HHI_HDMIRX_CLK_CNTL, 8, "hdmirx_cfg_div", + CLK_GET_RATE_NOCACHE); +/*hdmirx modet clock*/ +static MUX(hdmirx_modet_mux, HHI_HDMIRX_CLK_CNTL, 0x3, 25, hdmirx_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hdmirx_modet_div, HHI_HDMIRX_CLK_CNTL, 16, 7, "hdmirx_modet_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hdmirx_modet_gate, HHI_HDMIRX_CLK_CNTL, 24, "hdmirx_modet_div", + CLK_GET_RATE_NOCACHE); + +/*hdmirx audmeas clock*/ +PNAME(hdmirx_ref_parent_names) = { "fclk_div4", +"fclk_div3", "fclk_div5", "fclk_div7" }; +static MUX(hdmirx_audmeas_mux, HHI_HDMIRX_AUD_CLK_CNTL, 0x3, 9, +hdmirx_ref_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(hdmirx_audmeas_div, HHI_HDMIRX_AUD_CLK_CNTL, 0, 7, +"hdmirx_audmeas_mux", CLK_GET_RATE_NOCACHE); +static GATE(hdmirx_audmeas_gate, HHI_HDMIRX_AUD_CLK_CNTL, 8, +"hdmirx_audmeas_div", CLK_GET_RATE_NOCACHE); +/* hdmirx acr clock*/ +static MUX(hdmirx_acr_mux, HHI_HDMIRX_AUD_CLK_CNTL, 0x3, 25, +hdmirx_ref_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(hdmirx_acr_div, HHI_HDMIRX_AUD_CLK_CNTL, 16, 7, "hdmirx_acr_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hdmirx_acr_gate, HHI_HDMIRX_AUD_CLK_CNTL, 24, "hdmirx_acr_div", + CLK_GET_RATE_NOCACHE); +/* hdcp22 skpclk*/ + +PNAME(hdcp22_skp_parent_names) = { "xtal", +"fclk_div4", "fclk_div3", "fclk_div5" }; +static MUX(hdcp22_skp_mux, HHI_HDCP22_CLK_CNTL, 0x3, 25, + hdcp22_skp_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(hdcp22_skp_div, HHI_HDCP22_CLK_CNTL, 16, 7, "hdcp22_skp_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hdcp22_skp_gate, HHI_HDCP22_CLK_CNTL, 24, "hdcp22_skp_div", + CLK_GET_RATE_NOCACHE); +/* hdcp22 esm clock */ +PNAME(hdcp22_esm_parent_names) = { "fclk_div7", +"fclk_div4", "fclk_div3", "fclk_div5" }; +static MUX(hdcp22_esm_mux, HHI_HDCP22_CLK_CNTL, 0x3, 9, +hdcp22_esm_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static DIV(hdcp22_esm_div, HHI_HDCP22_CLK_CNTL, 0, 7, "hdcp22_esm_mux", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static GATE(hdcp22_esm_gate, HHI_HDCP22_CLK_CNTL, 8, "hdcp22_esm_div", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); + +/*vdec clock*/ +/* cts_vdec_clk */ +PNAME(dec_parent_names) = { "fclk_div2p5", "fclk_div3", +"fclk_div4", "fclk_div5", "fclk_div7", "hifi", "gp0_pll", "xtal" }; +static MUX(vdec_p0_mux, HHI_VDEC_CLK_CNTL, 0x7, 9, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vdec_p0_div, HHI_VDEC_CLK_CNTL, 0, 7, "vdec_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vdec_p0_gate, HHI_VDEC_CLK_CNTL, 8, "vdec_p0_div", + CLK_GET_RATE_NOCACHE); +static MUX(vdec_p1_mux, HHI_VDEC3_CLK_CNTL, 0x7, 9, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vdec_p1_div, HHI_VDEC3_CLK_CNTL, 0, 7, "vdec_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vdec_p1_gate, HHI_VDEC3_CLK_CNTL, 8, "vdec_p1_div", + CLK_GET_RATE_NOCACHE); + +/* vdec_mux clk */ +PNAME(vdec_mux_parent_names) = { "vdec_p0_composite", "vdec_p1_composite" }; +static MESON_MUX(vdec_mux, HHI_VDEC3_CLK_CNTL, 0x1, 15, +vdec_mux_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); + +/* hcodev clock*/ +static MUX(hcodec_p0_mux, HHI_VDEC_CLK_CNTL, 0x7, 25, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hcodec_p0_div, HHI_VDEC_CLK_CNTL, 16, 7, "hcodec_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hcodec_p0_gate, HHI_VDEC_CLK_CNTL, 24, "hcodec_p0_div", + CLK_GET_RATE_NOCACHE); +static MUX(hcodec_p1_mux, HHI_VDEC3_CLK_CNTL, 0x7, 25, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hcodec_p1_div, HHI_VDEC3_CLK_CNTL, 16, 7, "hcodec_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hcodec_p1_gate, HHI_VDEC3_CLK_CNTL, 24, "hcodec_p1_div", + CLK_GET_RATE_NOCACHE); + +/* hcodec_mux clk */ +PNAME(hcodec_mux_parent_names) = { +"hcodec_p0_composite", "hcodec_p1_composite" }; +static MESON_MUX(hcodec_mux, HHI_VDEC3_CLK_CNTL, 0x1, 31, +hcodec_mux_parent_names, CLK_GET_RATE_NOCACHE); + + +/* hevc clock */ +static MUX(hevc_p0_mux, HHI_VDEC2_CLK_CNTL, 0x7, 25, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hevc_p0_div, HHI_VDEC2_CLK_CNTL, 16, 7, "hevc_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hevc_p0_gate, HHI_VDEC2_CLK_CNTL, 24, "hevc_p0_div", + CLK_GET_RATE_NOCACHE); +static MUX(hevc_p1_mux, HHI_VDEC4_CLK_CNTL, 0x7, 25, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hevc_p1_div, HHI_VDEC4_CLK_CNTL, 16, 7, "hevc_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hevc_p1_gate, HHI_VDEC4_CLK_CNTL, 24, "hevc_p1_div", + CLK_GET_RATE_NOCACHE); + +/* hevc_mux clk */ +PNAME(hevc_mux_parent_names) = { "hevc_p0_composite", "hevc_p1_composite" }; +static MESON_MUX(hevc_mux, HHI_VDEC4_CLK_CNTL, 0x1, 31, +hevc_mux_parent_names, CLK_GET_RATE_NOCACHE); + +/* hevcf clock */ +static MUX(hevcf_p0_mux, HHI_VDEC2_CLK_CNTL, 0x7, 9, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hevcf_p0_div, HHI_VDEC2_CLK_CNTL, 0, 7, "hevcf_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hevcf_p0_gate, HHI_VDEC2_CLK_CNTL, 8, "hevcf_p0_div", + CLK_GET_RATE_NOCACHE); +static MUX(hevcf_p1_mux, HHI_VDEC4_CLK_CNTL, 0x7, 9, dec_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(hevcf_p1_div, HHI_VDEC4_CLK_CNTL, 0, 7, "hevcf_p1_mux", + CLK_GET_RATE_NOCACHE); +static GATE(hevcf_p1_gate, HHI_VDEC4_CLK_CNTL, 8, "hevcf_p1_div", + CLK_GET_RATE_NOCACHE); + +/* hevcf_mux clk */ +PNAME(hevcf_mux_parent_names) = { "hevcf_p0_composite", "hevcf_p1_composite" }; +static MESON_MUX(hevcf_mux, HHI_VDEC4_CLK_CNTL, 0x1, 15, +hevcf_mux_parent_names, CLK_GET_RATE_NOCACHE); + +/* cts_vid_lock_clk */ +PNAME(vid_lock_parent_names) = { "xtal", "cts_encl_clk", +"cts_enci_clk", "cts_encp_clk" }; +static MUX(vid_lock_mux, HHI_VID_LOCK_CLK_CNTL, 0x3, 9, vid_lock_parent_names, + CLK_GET_RATE_NOCACHE); +static DIV(vid_lock_div, HHI_VID_LOCK_CLK_CNTL, 0, 7, "vdec_p0_mux", + CLK_GET_RATE_NOCACHE); +static GATE(vid_lock_gate, HHI_VID_LOCK_CLK_CNTL, 7, "vdec_p0_div", + CLK_GET_RATE_NOCACHE); + +/* cts demod core clock */ +PNAME(cts_demod_parent_names) = { "xtal", +"fclk_div4", "fclk_div3", "adc_dpll_int"}; +static MUX(cts_demod_mux, HHI_AUDPLL_CLK_OUT_CNTL, 0x3, 9, +cts_demod_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(cts_demod_div, HHI_AUDPLL_CLK_OUT_CNTL, 0, 7, "cts_demod_mux", + CLK_GET_RATE_NOCACHE); +static GATE(cts_demod_gate, HHI_AUDPLL_CLK_OUT_CNTL, 8, "cts_demod_div", + CLK_GET_RATE_NOCACHE); + +/* adc extclk in clock */ +PNAME(adc_extclk_in_parent_names) = { "xtal", "fclk_div4", "fclk_div3", +"fclk_div5", "fclk_div7", "mpll2", "gp0_pll", "gp1_pll" }; +static MUX(adc_extclk_in_mux, HHI_AUDPLL_CLK_OUT_CNTL, 0x7, 25, +adc_extclk_in_parent_names, CLK_GET_RATE_NOCACHE); +static DIV(adc_extclk_in_div, HHI_AUDPLL_CLK_OUT_CNTL, 16, 7, +"adc_extclk_in_mux", CLK_GET_RATE_NOCACHE); +static GATE(adc_extclk_in_gate, HHI_AUDPLL_CLK_OUT_CNTL, 24, +"adc_extclk_in_div", CLK_GET_RATE_NOCACHE); + +#if 0 +static struct clk_hw *media_vhec_mux[] = { + [CLKID_VDEC_MUX - CLKID_VDEC_MUX] = &vdec_mux.hw, + [CLKID_HCODEC_MUX - CLKID_VDEC_MUX] = &hcodec_mux.hw, + [CLKID_HEVC_MUX - CLKID_VDEC_MUX] = &hevc_mux.hw, +}; +#endif + +/* for init mux clocks reg base*/ +static struct clk_mux *tl1_media_clk_muxes[] = { + &vdin_meas_mux, + &vpu_p0_mux, + &vpu_p1_mux, + &vpu_mux, + &vapb_p0_mux, + &vapb_p1_mux, + &vapb_mux, + &vpu_clkb_tmp_mux, + &hdmirx_cfg_mux, + &hdmirx_modet_mux, + &hdmirx_audmeas_mux, + &hdmirx_acr_mux, + &hdcp22_skp_mux, + &hdcp22_esm_mux, + &vdec_p0_mux, + &vdec_p1_mux, + &vdec_mux, + &hcodec_p0_mux, + &hcodec_p1_mux, + &hcodec_mux, + &hevc_p0_mux, + &hevc_p1_mux, + &hevc_mux, + &hevcf_p0_mux, + &hevcf_p1_mux, + &hevcf_mux, + &vpu_clkc_p0_mux, + &vpu_clkc_p1_mux, + &vpu_clkc_mux, + &vid_lock_mux, + &bt656_clk0_mux, + &tcon_pll_mux, + &cts_demod_mux, + &adc_extclk_in_mux, +}; + +/* for init div clocks reg base*/ +static struct clk_divider *tl1_media_clk_divs[] = { + &vdin_meas_div, + &vpu_p0_div, + &vpu_p1_div, + &vapb_p0_div, + &vapb_p1_div, + &vpu_clkb_tmp_div, + &vpu_clkb_div, + &hdmirx_cfg_div, + &hdmirx_modet_div, + &hdmirx_audmeas_div, + &hdmirx_acr_div, + &hdcp22_skp_div, + &hdcp22_esm_div, + &vdec_p0_div, + &vdec_p1_div, + &hcodec_p0_div, + &hcodec_p1_div, + &hevc_p0_div, + &hevc_p1_div, + &hevcf_p0_div, + &hevcf_p1_div, + &vpu_clkc_p0_div, + &vpu_clkc_p1_div, + &vid_lock_div, + &bt656_clk0_div, + &tcon_pll_div, + &cts_demod_div, + &adc_extclk_in_div, +}; + +/* for init gate clocks reg base*/ +static struct clk_gate *tl1_media_clk_gates[] = { + &vdin_meas_gate, + &vpu_p0_gate, + &vpu_p1_gate, + &vapb_p0_gate, + &vapb_p1_gate, + &ge2d_gate, + &vpu_clkb_tmp_gate, + &vpu_clkb_gate, + &hdmirx_cfg_gate, + &hdmirx_modet_gate, + &hdmirx_audmeas_gate, + &hdmirx_acr_gate, + &hdcp22_skp_gate, + &hdcp22_esm_gate, + &vdec_p0_gate, + &vdec_p1_gate, + &hcodec_p0_gate, + &hcodec_p1_gate, + &hevc_p0_gate, + &hevc_p1_gate, + &hevcf_p0_gate, + &hevcf_p1_gate, + &vpu_clkc_p0_gate, + &vpu_clkc_p1_gate, + &vid_lock_gate, + &bt656_clk0_gate, + &tcon_pll_gate, + &cts_demod_gate, + &adc_extclk_in_gate, +}; + +static struct meson_composite m_composite[] = { + {CLKID_VPU_CLKB_TMP_COMP, "vpu_clkb_tmp_composite", + vpu_clkb_parent_names, ARRAY_SIZE(vpu_clkb_parent_names), + &vpu_clkb_tmp_mux.hw, &vpu_clkb_tmp_div.hw, + &vpu_clkb_tmp_gate.hw, 0 + },/*vpu_clkb_tmp*/ + + {CLKID_VPU_CLKB_COMP, "vpu_clkb_composite", + vpu_clkb_nomux_parent_names, ARRAY_SIZE(vpu_clkb_nomux_parent_names), + NULL, &vpu_clkb_div.hw, &vpu_clkb_gate.hw, 0 + },/*vpu_clkb*/ + + {CLKID_VDIN_MEAS_COMP, "vdin_meas_composite", + meas_parent_names, ARRAY_SIZE(meas_parent_names), + &vdin_meas_mux.hw, &vdin_meas_div.hw, + &vdin_meas_gate.hw, 0 + },/*vdin_meas*/ + + {CLKID_VPU_P0_COMP, "vpu_p0_composite", + vpu_parent_names, ARRAY_SIZE(vpu_parent_names), + &vpu_p0_mux.hw, &vpu_p0_div.hw, + &vpu_p0_gate.hw, 0 + },/* cts_vpu_clk p0*/ + + {CLKID_VPU_P1_COMP, "vpu_p1_composite", + vpu_parent_names, ARRAY_SIZE(vpu_parent_names), + &vpu_p1_mux.hw, &vpu_p1_div.hw, + &vpu_p1_gate.hw, 0 + }, + + {CLKID_VAPB_P0_COMP, "vapb_p0_composite", + vpu_parent_names, ARRAY_SIZE(vpu_parent_names), + &vapb_p0_mux.hw, &vapb_p0_div.hw, + &vapb_p0_gate.hw, 0 + }, + + {CLKID_VAPB_P1_COMP, "vapb_p1_composite", + vpu_parent_names, ARRAY_SIZE(vpu_parent_names), + &vapb_p1_mux.hw, &vapb_p1_div.hw, + &vapb_p1_gate.hw, 0 + }, + + {CLKID_HDMIRX_CFG_COMP, "hdmirx_cfg_composite", + hdmirx_parent_names, ARRAY_SIZE(hdmirx_parent_names), + &hdmirx_cfg_mux.hw, &hdmirx_cfg_div.hw, + &hdmirx_cfg_gate.hw, 0 + }, + + {CLKID_HDMIRX_MODET_COMP, "hdmirx_modet_composite", + hdmirx_parent_names, ARRAY_SIZE(hdmirx_parent_names), + &hdmirx_modet_mux.hw, &hdmirx_modet_div.hw, + &hdmirx_modet_gate.hw, 0 + }, + + {CLKID_HDMIRX_AUDMEAS_COMP, "hdmirx_audmeas_composite", + hdmirx_ref_parent_names, ARRAY_SIZE(hdmirx_ref_parent_names), + &hdmirx_audmeas_mux.hw, &hdmirx_audmeas_div.hw, + &hdmirx_audmeas_gate.hw, 0 + }, + + {CLKID_HDMIRX_ACR_COMP, "hdmirx_acr_composite", + hdmirx_ref_parent_names, ARRAY_SIZE(hdmirx_ref_parent_names), + &hdmirx_acr_mux.hw, &hdmirx_acr_div.hw, + &hdmirx_acr_gate.hw, 0 + }, + + {CLKID_HDCP22_SKP_COMP, "hdcp22_skp_composite", + hdcp22_skp_parent_names, ARRAY_SIZE(hdcp22_skp_parent_names), + &hdcp22_skp_mux.hw, &hdcp22_skp_div.hw, + &hdcp22_skp_gate.hw, 0 + }, + + {CLKID_HDCP22_ESM_COMP, "hdcp22_esm_composite", + hdcp22_esm_parent_names, ARRAY_SIZE(hdcp22_esm_parent_names), + &hdcp22_esm_mux.hw, &hdcp22_esm_div.hw, + &hdcp22_esm_gate.hw, 0 + }, + + {CLKID_VDEC_P0_COMP, "vdec_p0_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &vdec_p0_mux.hw, &vdec_p0_div.hw, + &vdec_p0_gate.hw, 0 + }, + + {CLKID_VDEC_P1_COMP, "vdec_p1_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &vdec_p1_mux.hw, &vdec_p1_div.hw, + &vdec_p1_gate.hw, 0 + }, + + {CLKID_HCODEC_P0_COMP, "hcodec_p0_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hcodec_p0_mux.hw, &hcodec_p0_div.hw, + &hcodec_p0_gate.hw, 0 + }, + + {CLKID_HCODEC_P1_COMP, "hcodec_p1_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hcodec_p1_mux.hw, &hcodec_p1_div.hw, + &hcodec_p1_gate.hw, 0 + }, + + {CLKID_HEVC_P0_COMP, "hevc_p0_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hevc_p0_mux.hw, &hevc_p0_div.hw, + &hevc_p0_gate.hw, 0 + }, + + {CLKID_HEVC_P1_COMP, "hevc_p1_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hevc_p1_mux.hw, &hevc_p1_div.hw, + &hevc_p1_gate.hw, 0 + }, + + {CLKID_HEVCF_P0_COMP, "hevcf_p0_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hevcf_p0_mux.hw, &hevcf_p0_div.hw, + &hevcf_p0_gate.hw, 0 + }, + + {CLKID_HEVCF_P1_COMP, "hevcf_p1_composite", + dec_parent_names, ARRAY_SIZE(dec_parent_names), + &hevcf_p1_mux.hw, &hevcf_p1_div.hw, + &hevcf_p1_gate.hw, 0 + }, + + {CLKID_VID_LOCK_COMP, "vid_lock_composite", + vid_lock_parent_names, ARRAY_SIZE(vid_lock_parent_names), + &vid_lock_mux.hw, &vid_lock_div.hw, + &vid_lock_gate.hw, 0 + }, + + {CLKID_BT656_CLK0_COMP, "bt656_clk0_composite", + bt656_clk0_parent_names, ARRAY_SIZE(bt656_clk0_parent_names), + &bt656_clk0_mux.hw, &bt656_clk0_div.hw, + &bt656_clk0_gate.hw, 0 + }, + + {CLKID_TCON_PLL_COMP, "tcon_pll_composite", + tcon_pll_parent_names, ARRAY_SIZE(tcon_pll_parent_names), + &tcon_pll_mux.hw, &tcon_pll_div.hw, + &tcon_pll_gate.hw, 0 + }, + + {CLKID_DEMOD_COMP, "demod_composite", + cts_demod_parent_names, ARRAY_SIZE(cts_demod_parent_names), + &cts_demod_mux.hw, &cts_demod_div.hw, + &cts_demod_gate.hw, 0 + }, + + {CLKID_ADC_EXTCLK_COMP, "adc_extclk_composite", + adc_extclk_in_parent_names, ARRAY_SIZE(adc_extclk_in_parent_names), + &adc_extclk_in_mux.hw, &adc_extclk_in_div.hw, + &adc_extclk_in_gate.hw, 0 + }, + + {CLKID_VPU_CLKC_P0_COMP, "vpu_clkc_p0_composite", + vpu_clkc_parent_names, ARRAY_SIZE(vpu_clkc_parent_names), + &vpu_clkc_p0_mux.hw, &vpu_clkc_p0_div.hw, + &vpu_clkc_p0_gate.hw, 0 + }, + + {CLKID_VPU_CLKC_P1_COMP, "vpu_clkc_p1_composite", + vpu_clkc_parent_names, ARRAY_SIZE(vpu_clkc_parent_names), + &vpu_clkc_p1_mux.hw, &vpu_clkc_p1_div.hw, + &vpu_clkc_p1_gate.hw, 0 + }, + + {}, +}; + +/* array for single hw*/ +static struct meson_hw m_hw[] = { + {CLKID_VDEC_MUX, &vdec_mux.hw}, + {CLKID_HCODEC_MUX, &hcodec_mux.hw}, + {CLKID_HEVC_MUX, &hevc_mux.hw}, +}; +void meson_tl1_media_init(void) +{ + int i; + int length, lengthhw; + + length = ARRAY_SIZE(m_composite); + lengthhw = ARRAY_SIZE(m_hw); + + /* Populate base address for media muxes */ + for (i = 0; i < ARRAY_SIZE(tl1_media_clk_muxes); i++) + tl1_media_clk_muxes[i]->reg = clk_base + + (unsigned long)tl1_media_clk_muxes[i]->reg; + + /* Populate base address for media divs */ + for (i = 0; i < ARRAY_SIZE(tl1_media_clk_divs); i++) + tl1_media_clk_divs[i]->reg = clk_base + + (unsigned long)tl1_media_clk_divs[i]->reg; + + /* Populate base address for media gates */ + for (i = 0; i < ARRAY_SIZE(tl1_media_clk_gates); i++) + tl1_media_clk_gates[i]->reg = clk_base + + (unsigned long)tl1_media_clk_gates[i]->reg; + + meson_clk_register_composite(clks, m_composite, length - 1); + + clks[CLKID_VPU_MUX] = clk_register(NULL, &vpu_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_VPU_MUX])); + clk_prepare_enable(clks[CLKID_VPU_MUX]); + + clks[CLKID_VAPB_MUX] = clk_register(NULL, &vapb_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_VAPB_MUX])); + clk_prepare_enable(clks[CLKID_VAPB_MUX]); + + clks[CLKID_GE2D_GATE] = clk_register(NULL, &ge2d_gate.hw); + WARN_ON(IS_ERR(clks[CLKID_GE2D_GATE])); + + /*mux*/ + clks[CLKID_VDEC_MUX] = clk_register(NULL, &vdec_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_VDEC_MUX])); + + clks[CLKID_HCODEC_MUX] = clk_register(NULL, &hcodec_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_HCODEC_MUX])); + + clks[CLKID_HEVC_MUX] = clk_register(NULL, &hevc_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_HEVC_MUX])); + + clks[CLKID_HEVCF_MUX] = clk_register(NULL, &hevcf_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_HEVCF_MUX])); + + clks[CLKID_VPU_CLKC_MUX] = clk_register(NULL, &vpu_clkc_mux.hw); + WARN_ON(IS_ERR(clks[CLKID_VPU_CLKC_MUX])); + + /* todo: set default div4 parent for tmp clkb */ + clk_set_parent(clks[CLKID_VPU_CLKB_TMP_COMP], clks[CLKID_FCLK_DIV4]); +} diff --git a/drivers/amlogic/clk/tl1/tl1_clk_misc.c b/drivers/amlogic/clk/tl1/tl1_clk_misc.c new file mode 100644 index 0000000..1d264aa --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk_misc.c @@ -0,0 +1,185 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk_misc.c + * + * Copyright (C) 2018 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 "tl1.h" + +/*ts clock */ +PNAME(ts_parent_names) = { "xtal" }; +static DIV(tl1_ts_div, HHI_TS_CLK_CNTL, 0, 7, "xtal", + CLK_GET_RATE_NOCACHE); +static GATE(tl1_ts_gate, HHI_TS_CLK_CNTL, 8, "tl1_ts_clk_div", + CLK_GET_RATE_NOCACHE); + +/* spicc0 and spicc1 clocks */ +static const char * const spicc_parent_names[] = { "xtal", + "clk81", "fclk_div4", "fclk_div3", "fclk_div2", "fclk_div5", + "fclk_div7", "gpo_pll"}; + +static struct clk_mux tl1_spicc0_mux = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .mask = 0x7, + .shift = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_mux", + .ops = &clk_mux_ops, + .parent_names = spicc_parent_names, + .num_parents = ARRAY_SIZE(spicc_parent_names), + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider tl1_spicc0_div = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .shift = 0, + .width = 6, + .lock = &clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "spicc0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate tl1_spicc0_gate = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .bit_idx = 6, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "spicc0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "spicc0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux tl1_spicc1_mux = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .mask = 0x7, + .shift = 23, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_mux", + .ops = &clk_mux_ops, + .parent_names = spicc_parent_names, + .num_parents = ARRAY_SIZE(spicc_parent_names), + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider tl1_spicc1_div = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .shift = 16, + .width = 6, + .lock = &clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data){ + .name = "spicc_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "spicc_p1_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate tl1_spicc1_gate = { + .reg = (void *)HHI_SPICC_CLK_CNTL, + .bit_idx = 22, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "spicc_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "spicc_p1_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux *tl1_misc_clk_muxes[] = { + &tl1_spicc0_mux, + &tl1_spicc1_mux, +}; + +static struct clk_divider *tl1_misc_clk_divs[] = { + &tl1_spicc0_div, + &tl1_spicc1_div, + &tl1_ts_div, +}; + +static struct clk_gate *tl1_media_clk_gates[] = { + &tl1_spicc0_gate, + &tl1_spicc1_gate, + &tl1_ts_gate, +}; + +static struct meson_composite misc_composite[] = { + {CLKID_TS_CLK_COMP, "ts_clk_composite", + ts_parent_names, ARRAY_SIZE(ts_parent_names), + NULL, &tl1_ts_div.hw, + &tl1_ts_gate.hw, 0 + },/* ts_clk */ + + {CLKID_SPICC0_COMP, "spicc0_composite", + spicc_parent_names, ARRAY_SIZE(spicc_parent_names), + &tl1_spicc0_mux.hw, &tl1_spicc0_div.hw, + &tl1_spicc0_gate.hw, 0 + },/* spicc0 */ + + {CLKID_SPICC1_COMP, "spicc1_composite", + spicc_parent_names, ARRAY_SIZE(spicc_parent_names), + &tl1_spicc1_mux.hw, &tl1_spicc1_div.hw, + &tl1_spicc1_gate.hw, 0 + },/* spicc1 */ + + {}, +}; +void meson_tl1_misc_init(void) +{ + int i, length; + + /* Populate base address for misc muxes */ + for (i = 0; i < ARRAY_SIZE(tl1_misc_clk_muxes); i++) + tl1_misc_clk_muxes[i]->reg = clk_base + + (unsigned long)tl1_misc_clk_muxes[i]->reg; + + /* Populate base address for misc divs */ + for (i = 0; i < ARRAY_SIZE(tl1_misc_clk_divs); i++) + tl1_misc_clk_divs[i]->reg = clk_base + + (unsigned long)tl1_misc_clk_divs[i]->reg; + + /* Populate base address for misc gates */ + for (i = 0; i < ARRAY_SIZE(tl1_media_clk_gates); i++) + tl1_media_clk_gates[i]->reg = clk_base + + (unsigned long)tl1_media_clk_gates[i]->reg; + + length = ARRAY_SIZE(misc_composite); + + meson_clk_register_composite(clks, misc_composite, length - 1); +} diff --git a/drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c b/drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c new file mode 100644 index 0000000..37c3740 --- /dev/null +++ b/drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c @@ -0,0 +1,81 @@ +/* + * drivers/amlogic/clk/tl1/tl1_clk_sdemmc.c + * + * Copyright (C) 2018 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 "tl1.h" + +PNAME(sd_emmc_parent_names) = { "xtal", "fclk_div2", + "fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll3", "gp0" }; +/*sd_emmc B*/ +static MUX(sd_emmc_p0_mux_B, HHI_SD_EMMC_CLK_CNTL, 0x7, 25, +sd_emmc_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static DIV(sd_emmc_p0_div_B, HHI_SD_EMMC_CLK_CNTL, 16, 7, "sd_emmc_p0_mux_B", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static GATE(sd_emmc_p0_gate_B, HHI_SD_EMMC_CLK_CNTL, 23, "sd_emmc_p0_div_B", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +/*sd_emmc C*/ +static MUX(sd_emmc_p0_mux_C, HHI_NAND_CLK_CNTL, 0x7, 9, +sd_emmc_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static DIV(sd_emmc_p0_div_C, HHI_NAND_CLK_CNTL, 0, 7, "sd_emmc_p0_mux_C", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); +static GATE(sd_emmc_p0_gate_C, HHI_NAND_CLK_CNTL, 7, "sd_emmc_p0_div_C", + CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED); + +static struct meson_composite sdemmc_comp[] = { + {CLKID_SD_EMMC_B_P0_COMP, "sd_emmc_p0_B_comp", + sd_emmc_parent_names, ARRAY_SIZE(sd_emmc_parent_names), + &sd_emmc_p0_mux_B.hw, &sd_emmc_p0_div_B.hw, + &sd_emmc_p0_gate_B.hw, 0 + },/* sd_emmc_B */ + + {CLKID_SD_EMMC_C_P0_COMP, "sd_emmc_p0_C_comp", + sd_emmc_parent_names, ARRAY_SIZE(sd_emmc_parent_names), + &sd_emmc_p0_mux_C.hw, &sd_emmc_p0_div_C.hw, + &sd_emmc_p0_gate_C.hw, 0 + },/* sd_emmc_C */ + + {}, +}; + +void meson_tl1_sdemmc_init(void) +{ + int length = ARRAY_SIZE(sdemmc_comp); + + /* Populate base address for reg */ + sd_emmc_p0_mux_B.reg = clk_base + + (unsigned long)(sd_emmc_p0_mux_B.reg); + sd_emmc_p0_div_B.reg = clk_base + + (unsigned long)(sd_emmc_p0_div_B.reg); + sd_emmc_p0_gate_B.reg = clk_base + + (unsigned long)(sd_emmc_p0_gate_B.reg); + sd_emmc_p0_mux_C.reg = clk_base + + (unsigned long)(sd_emmc_p0_mux_C.reg); + sd_emmc_p0_div_C.reg = clk_base + + (unsigned long)(sd_emmc_p0_div_C.reg); + sd_emmc_p0_gate_C.reg = clk_base + + (unsigned long)(sd_emmc_p0_gate_C.reg); + + meson_clk_register_composite(clks, sdemmc_comp, length - 1); +} -- 2.7.4