#define TL1_PLL_CNTL6 0x56540000
+#define TM2_PCIE_PLL_CNTL0_0 0x28060464
+#define TM2_PCIE_PLL_CNTL0_1 0x38060464
+#define TM2_PCIE_PLL_CNTL0_2 0x3c060464
+#define TM2_PCIE_PLL_CNTL0_3 0x1c060464
+#define TM2_PCIE_PLL_CNTL1 0x00000000
+#define TM2_PCIE_PLL_CNTL2 0x00001100
+#define TM2_PCIE_PLL_CNTL2_ 0x00001000
+#define TM2_PCIE_PLL_CNTL3 0x10058e00
+#define TM2_PCIE_PLL_CNTL4 0x000100c0
+#define TM2_PCIE_PLL_CNTL4_ 0x008100c0
+#define TM2_PCIE_PLL_CNTL5 0x68000048
+#define TM2_PCIE_PLL_CNTL5_ 0x68000068
+
#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,
writel(TL1_PLL_CNTL6,
cntlbase + (unsigned long)(6*4));
udelay(10);
+ } else if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) {
+ writel(TM2_PCIE_PLL_CNTL0_0,
+ cntlbase + (unsigned long)(0*4));
+ writel(TM2_PCIE_PLL_CNTL0_1,
+ cntlbase + (unsigned long)(0*4));
+ writel(TM2_PCIE_PLL_CNTL1,
+ cntlbase + (unsigned long)(1*4));
+ writel(TM2_PCIE_PLL_CNTL2,
+ cntlbase + (unsigned long)(7*4));
+ writel(TM2_PCIE_PLL_CNTL3,
+ cntlbase + (unsigned long)(8*4));
+ writel(TM2_PCIE_PLL_CNTL4,
+ cntlbase + (unsigned long)(53*4));
+ writel(TM2_PCIE_PLL_CNTL5,
+ cntlbase + (unsigned long)(54*4));
+ writel(TM2_PCIE_PLL_CNTL5_,
+ cntlbase + (unsigned long)(54*4));
+ udelay(20);
+ writel(TM2_PCIE_PLL_CNTL4_,
+ cntlbase + (unsigned long)(53*4));
+ udelay(10);
+ /*set pcie_apll_afc_start bit*/
+ writel(TM2_PCIE_PLL_CNTL0_2,
+ cntlbase + (unsigned long)(0*4));
+ writel(TM2_PCIE_PLL_CNTL0_3,
+ cntlbase + (unsigned long)(0*4));
+ udelay(10);
+ writel(TM2_PCIE_PLL_CNTL2_,
+ cntlbase + (unsigned long)(7*4));
} else {
pr_err("%s: %s pll not found!!!\n",
__func__, clk_hw_get_name(hw));
--- /dev/null
+/*
+ * drivers/amlogic/clk/tm2/tm2.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <dt-bindings/clock/amlogic,tl1-clkc.h>
+
+#include "../clkc.h"
+#include "../tl1/tl1.h"
+#include "tm2.h"
+
+static const struct pll_rate_table tm2_pcie_pll_rate_table[] = {
+ PLL_RATE(100000000, 100, 1, 6),
+ { /* sentinel */ },
+};
+
+static struct meson_clk_pll tm2_pcie_pll = {
+ .m = {
+ .reg_off = HHI_PCIE_PLL_CNTL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .n = {
+ .reg_off = HHI_PCIE_PLL_CNTL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .od = {
+ .reg_off = HHI_PCIE_PLL_CNTL0,
+ .shift = 16,
+ .width = 5,
+ },
+ .frac = {
+ .reg_off = HHI_PCIE_PLL_CNTL1,
+ .shift = 0,
+ .width = 12,
+ },
+ .rate_table = tm2_pcie_pll_rate_table,
+ .rate_count = ARRAY_SIZE(tm2_pcie_pll_rate_table),
+ .lock = &clk_lock,
+ .hw.init = &(struct clk_init_data){
+ .name = "pcie_pll",
+ .ops = &meson_tl1_pll_ops,
+ .parent_names = (const char *[]){ "xtal" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_gate tm2_pcie01_enable = {
+ .reg = (void *)HHI_PCIE_PLL_CNTL1,
+ .bit_idx = 29,
+ .lock = &clk_lock,
+ .hw.init = &(struct clk_init_data){
+ .name = "tm2_pcie01",
+ .ops = &clk_gate_ops,
+ .parent_names = (const char *[]){ "pcie_pll" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_gate tm2_pcie0_gate = {
+ .reg = (void *)HHI_PCIE_PLL_CNTL1,
+ .bit_idx = 28,
+ .lock = &clk_lock,
+ .hw.init = &(struct clk_init_data){
+ .name = "tm2_pcie0_gate",
+ .ops = &clk_gate_ops,
+ .parent_names = (const char *[]){ "tm2_pcie01" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_gate tm2_pcie1_gate = {
+ .reg = (void *)HHI_PCIE_PLL_CNTL5,
+ .bit_idx = 3,
+ .lock = &clk_lock,
+ .hw.init = &(struct clk_init_data){
+ .name = "tm2_pcie1_gate",
+ .ops = &clk_gate_ops,
+ .parent_names = (const char *[]){ "tm2_pcie01" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/* clk81 gate for tm2 */
+static MESON_GATE(tm2_vipnanoq, HHI_GCLK_MPEG1, 19);
+static MESON_GATE(tm2_pcie1, HHI_GCLK_MPEG1, 24);
+static MESON_GATE(tm2_pcie1phy, HHI_GCLK_MPEG1, 27);
+static MESON_GATE(tm2_parserl, HHI_GCLK_MPEG1, 28);
+static MESON_GATE(tm2_hdcp22_pclk, HHI_GCLK_MPEG2, 3);
+static MESON_GATE(tm2_hdmitx_pclk, HHI_GCLK_MPEG2, 4);
+static MESON_GATE(tm2_pcie0, HHI_GCLK_MPEG2, 6);
+static MESON_GATE(tm2_pcie0phy, HHI_GCLK_MPEG2, 7);
+static MESON_GATE(tm2_hdmirx_axi_pclk, HHI_GCLK_MPEG2, 12);
+static MESON_GATE(tm2_dspb, HHI_GCLK_MPEG2, 26);
+static MESON_GATE(tm2_dspa, HHI_GCLK_MPEG2, 27);
+
+PNAME(dsp_parent_names) = { "fclk_div2", "fclk_div3",
+ "fclk_div5", "fclk_div7", "xtal", "gp0_pll", "gp1_pll", "hifi_pll" };
+
+static MUX(dspa_clk_a_mux, HHI_DSP_CLK_CNTL, 0x7, 4,
+ dsp_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED);
+static DIV(dspa_clk_a_div, HHI_DSP_CLK_CNTL, 0, 4, "dspa_clk_a_mux",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+static GATE(dspa_clk_a_gate, HHI_DSP_CLK_CNTL, 7, "dspa_clk_a_div",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+
+static MUX(dspa_clk_b_mux, HHI_DSP_CLK_CNTL, 0x7, 12,
+ dsp_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED);
+static DIV(dspa_clk_b_div, HHI_DSP_CLK_CNTL, 8, 4, "dspa_clk_b_mux",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+static GATE(dspa_clk_b_gate, HHI_DSP_CLK_CNTL, 7, "dspa_clk_b_div",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+
+PNAME(dspa_parent_names) = { "dspa_clk_a_gate",
+ "dspa_clk_b_gate" };
+
+static MESON_MUX(dspa_clk_mux, HHI_DSP_CLK_CNTL, 0x1, 15,
+ dspa_parent_names, CLK_GET_RATE_NOCACHE);
+
+
+static MUX(dspb_clk_a_mux, HHI_DSP_CLK_CNTL, 0x7, 20,
+ dsp_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED);
+static DIV(dspb_clk_a_div, HHI_DSP_CLK_CNTL, 16, 4, "dspb_clk_a_mux",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+static GATE(dspb_clk_a_gate, HHI_SD_EMMC_CLK_CNTL, 23, "dspb_clk_a_div",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+
+static MUX(dspb_clk_b_mux, HHI_DSP_CLK_CNTL, 0x7, 28,
+ dsp_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED);
+static DIV(dspb_clk_b_div, HHI_DSP_CLK_CNTL, 24, 4, "dspb_clk_b_mux",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+static GATE(dspb_clk_b_gate, HHI_DSP_CLK_CNTL, 23, "dspb_clk_b_div",
+ CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT);
+
+PNAME(dspb_parent_names) = { "dspb_clk_a_gate",
+ "dspb_clk_b_gate" };
+
+static MESON_MUX(dspb_clk_mux, HHI_VPU_CLKC_CNTL, 0x1, 31,
+ dspb_parent_names, CLK_GET_RATE_NOCACHE);
+
+static struct clk_gate *tm2_clk_gates[] = {
+ &tm2_vipnanoq,
+ &tm2_pcie1,
+ &tm2_pcie1phy,
+ &tm2_parserl,
+ &tm2_hdcp22_pclk,
+ &tm2_hdmitx_pclk,
+ &tm2_pcie0phy,
+ &tm2_hdmirx_axi_pclk,
+ &tm2_dspb,
+ &tm2_dspa,
+ &dspa_clk_a_gate,
+ &dspa_clk_b_gate,
+ &dspb_clk_a_gate,
+ &dspb_clk_b_gate,
+ &tm2_pcie0_gate,
+ &tm2_pcie1_gate,
+ &tm2_pcie0,
+ &tm2_pcie01_enable,
+};
+
+static struct clk_mux *tm2_clk_mux[] = {
+ &dspa_clk_a_mux,
+ &dspa_clk_b_mux,
+ &dspb_clk_a_mux,
+ &dspb_clk_b_mux,
+ &dspa_clk_mux,
+ &dspb_clk_mux,
+};
+
+static struct clk_divider *tm2_clk_divs[] = {
+ &dspa_clk_a_div,
+ &dspa_clk_b_div,
+ &dspb_clk_a_div,
+ &dspb_clk_b_div,
+};
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw *tm2_clk_hws[] = {
+ [CLKID_PCIE_PLL] = &tm2_pcie_pll.hw,
+ [CLKID_VIPNANOQ] = &tm2_vipnanoq.hw,
+ [CLKID_PCIE0] = &tm2_pcie0.hw,
+ [CLKID_PCIE1] = &tm2_pcie1.hw,
+ [CLKID_PCIE1PHY] = &tm2_pcie1phy.hw,
+ [CLKID_PARSER1] = &tm2_parserl.hw,
+ [CLKID_HDCP22_PCLK] = &tm2_hdcp22_pclk.hw,
+ [CLKID_HDMITX_PCLK] = &tm2_hdmitx_pclk.hw,
+ [CLKID_PCIE0PHY] = &tm2_pcie0phy.hw,
+ [CLKID_HDMITX_AXI_PCLK] = &tm2_hdmirx_axi_pclk.hw,
+ [CLKID_DSPB] = &tm2_dspb.hw,
+ [CLKID_DSPA] = &tm2_dspa.hw,
+ [CLKID_DSPA_MUX_A] = &dspa_clk_a_mux.hw,
+ [CLKID_DSPA_DIV_A] = &dspa_clk_a_div.hw,
+ [CLKID_DSPA_GATE_A] = &dspa_clk_a_gate.hw,
+ [CLKID_DSPA_MUX_B] = &dspa_clk_b_mux.hw,
+ [CLKID_DSPA_DIV_B] = &dspa_clk_b_div.hw,
+ [CLKID_DSPA_GATE_B] = &dspa_clk_b_gate.hw,
+ [CLKID_DSPA_MUX] = &dspa_clk_mux.hw,
+ [CLKID_DSPB_MUX_A] = &dspb_clk_a_mux.hw,
+ [CLKID_DSPB_DIV_A] = &dspb_clk_a_div.hw,
+ [CLKID_DSPB_GATE_A] = &dspb_clk_a_gate.hw,
+ [CLKID_DSPB_MUX_B] = &dspb_clk_b_mux.hw,
+ [CLKID_DSPB_DIV_B] = &dspb_clk_b_div.hw,
+ [CLKID_DSPB_GATE_B] = &dspb_clk_b_gate.hw,
+ [CLKID_DSPB_MUX] = &dspb_clk_mux.hw,
+ [CLKID_PCIE01_ENABLE] = &tm2_pcie01_enable.hw,
+ [CLKID_PCIE0_GATE] = &tm2_pcie0_gate.hw,
+ [CLKID_PCIE1_GATE] = &tm2_pcie1_gate.hw,
+};
+
+static void __init tm2_clkc_init(struct device_node *np)
+{
+ int clkid, i;
+
+ if (!clk_base) {
+ pr_err("tm2 clock basic clock driver not prepare\n");
+ WARN_ON(IS_ERR(clk_base));
+ return;
+ }
+
+ /* Populate base address for pcie pll */
+ tm2_pcie_pll.base = clk_base;
+
+ /* Populate base address for media muxes */
+ for (i = 0; i < ARRAY_SIZE(tm2_clk_mux); i++)
+ tm2_clk_mux[i]->reg = clk_base +
+ (unsigned long)tm2_clk_mux[i]->reg;
+
+ /* Populate base address for media divs */
+ for (i = 0; i < ARRAY_SIZE(tm2_clk_divs); i++)
+ tm2_clk_divs[i]->reg = clk_base +
+ (unsigned long)tm2_clk_divs[i]->reg;
+
+ /* Populate base address for gates */
+ for (i = 0; i < ARRAY_SIZE(tm2_clk_gates); i++)
+ tm2_clk_gates[i]->reg = clk_base +
+ (unsigned long)tm2_clk_gates[i]->reg;
+
+ /* register tm2 clks, pcie pll is the first clock index */
+ for (clkid = CLKID_PCIE_PLL; clkid < GATE_BASE0; clkid++) {
+ if (tm2_clk_hws[clkid]) {
+ clks[clkid] = clk_register(NULL, tm2_clk_hws[clkid]);
+ WARN_ON(IS_ERR(clks[clkid]));
+ }
+ }
+}
+
+CLK_OF_DECLARE(tm2, "amlogic,tm2-clkc", tm2_clkc_init);