[coreboot-gerrit] New patch to review for coreboot: mediatek/mt8173: Add PLL driver

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Tue Dec 1 19:57:23 CET 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/12588

-gerrit

commit 0eda85491ad206422b2a0b0047733d035cdf33a2
Author: James Liao <jamesjj.liao at mediatek.com>
Date:   Fri Jul 31 17:10:53 2015 +0800

    mediatek/mt8173: Add PLL driver
    
    Add PLL init code.
    
    BRANCH=none
    BUG=none
    TEST=none
    
    Change-Id: I2dcea8cdea1a3812bd8b84b7e8d961e7f8d4d953
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: e6e2eecb2fad30db018685b61912103f5e2cd524
    Original-Change-Id: Id67d8033f3b2a267a140d7d73daa5727bc032272
    Original-Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/292670
    Original-Commit-Ready: Yidi Lin <yidi.lin at mediatek.com>
    Original-Tested-by: Yidi Lin <yidi.lin at mediatek.com>
    Original-Reviewed-by: Julius Werner <jwerner at chromium.org>
---
 src/soc/mediatek/mt8173/Makefile.inc      |   1 +
 src/soc/mediatek/mt8173/bootblock.c       |   5 +
 src/soc/mediatek/mt8173/include/soc/pll.h | 291 +++++++++++++++++++
 src/soc/mediatek/mt8173/pll.c             | 460 ++++++++++++++++++++++++++++++
 4 files changed, 757 insertions(+)

diff --git a/src/soc/mediatek/mt8173/Makefile.inc b/src/soc/mediatek/mt8173/Makefile.inc
index 74a7618..0d7957e 100644
--- a/src/soc/mediatek/mt8173/Makefile.inc
+++ b/src/soc/mediatek/mt8173/Makefile.inc
@@ -21,6 +21,7 @@ ifeq ($(CONFIG_SOC_MEDIATEK_MT8173),y)
 
 bootblock-y += bootblock.c
 bootblock-y += cbfs.c
+bootblock-y += pll.c
 bootblock-y += timer.c
 
 ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y)
diff --git a/src/soc/mediatek/mt8173/bootblock.c b/src/soc/mediatek/mt8173/bootblock.c
index 232a655..aaa7f61 100644
--- a/src/soc/mediatek/mt8173/bootblock.c
+++ b/src/soc/mediatek/mt8173/bootblock.c
@@ -18,7 +18,12 @@
  */
 
 #include <bootblock_common.h>
+#include <soc/pll.h>
 
 void bootblock_soc_init(void)
 {
+	mt_pll_init();
+
+	/* post init pll */
+	mt_pll_post_init();
 }
diff --git a/src/soc/mediatek/mt8173/include/soc/pll.h b/src/soc/mediatek/mt8173/include/soc/pll.h
new file mode 100644
index 0000000..b09ad41
--- /dev/null
+++ b/src/soc/mediatek/mt8173/include/soc/pll.h
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 MediaTek Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SOC_MEDIATEK_MT8173_PLL_H
+#define SOC_MEDIATEK_MT8173_PLL_H
+
+#include <soc/addressmap.h>
+
+struct mt8173_topckgen_regs {
+	u32 clk_mode;
+	u32 dcm_cfg;
+	u32 reserved1[6];
+	u32 tst_sel_0;		/* 0x020 */
+	u32 tst_sel_1;
+	u32 tst_sel_2;
+	u32 reserved2[5];
+	u32 clk_cfg_0;		/* 0x040 */
+	u32 clk_cfg_0_set;
+	u32 clk_cfg_0_clr;
+	u32 reserved3[1];
+	u32 clk_cfg_1;		/* 0x050 */
+	u32 clk_cfg_1_set;
+	u32 clk_cfg_1_clr;
+	u32 reserved4[1];
+	u32 clk_cfg_2;		/* 0x060 */
+	u32 clk_cfg_2_set;
+	u32 clk_cfg_2_clr;
+	u32 reserved5[1];
+	u32 clk_cfg_3;		/* 0x070 */
+	u32 clk_cfg_3_set;
+	u32 clk_cfg_3_clr;
+	u32 reserved6[1];
+	u32 clk_cfg_4;		/* 0x080 */
+	u32 clk_cfg_4_set;
+	u32 clk_cfg_4_clr;
+	u32 reserved7[1];
+	u32 clk_cfg_5;		/* 0x090 */
+	u32 clk_cfg_5_set;
+	u32 clk_cfg_5_clr;
+	u32 reserved8[1];
+	u32 clk_cfg_6;		/* 0x0a0 */
+	u32 clk_cfg_6_set;
+	u32 clk_cfg_6_clr;
+	u32 reserved9[1];
+	u32 clk_cfg_7;		/* 0x0b0 */
+	u32 clk_cfg_7_set;
+	u32 clk_cfg_7_clr;
+	u32 reserved10[1];
+	u32 clk_cfg_12;		/* 0x0c0 */
+	u32 clk_cfg_12_set;
+	u32 clk_cfg_12_clr;
+	u32 reserved11[1];
+	u32 clk_cfg_13;		/* 0x0d0 */
+	u32 clk_cfg_13_set;
+	u32 clk_cfg_13_clr;
+	u32 reserved12[9];
+	u32 clk_cfg_8;		/* 0x100 */
+	u32 clk_cfg_9;
+	u32 clk_cfg_10;
+	u32 clk_cfg_11;
+	u32 reserved13[4];
+	u32 clk_auddiv_0;	/* 0x120 */
+	u32 clk_auddiv_1;
+	u32 clk_auddiv_2;
+	u32 clk_auddiv_3;
+	u32 clk_mjcdiv_0;
+	u32 reserved14[51];
+	u32 clk_scp_cfg_0;	/* 0x200 */
+	u32 clk_scp_cfg_1;
+	u32 reserved15[2];
+	u32 clk_misc_cfg_0;	/* 0x210 */
+	u32 clk_misc_cfg_1;
+	u32 clk_misc_cfg_2;
+	u32 reserved16[1];
+	u32 clk26cali_0;	/* 0x220 */
+	u32 clk26cali_1;
+	u32 clk26cali_2;
+	u32 cksta_reg;
+	u32 test_mode_cfg;
+	u32 reserved17[53];
+	u32 mbist_cfg_0;	/* 0x308 */
+	u32 mbist_cfg_1;
+	u32 reset_deglitch_key;
+	u32 mbist_cfg_3;	/* 0x314 */
+};
+
+check_member(mt8173_topckgen_regs, clk_cfg_0, 0x40);
+check_member(mt8173_topckgen_regs, clk_cfg_8, 0x100);
+check_member(mt8173_topckgen_regs, clk_scp_cfg_0, 0x200);
+check_member(mt8173_topckgen_regs, mbist_cfg_3, 0x314);
+
+struct mt8173_apmixed_regs {
+	u32 ap_pll_con0;
+	u32 reserved1[1];
+	u32 ap_pll_con2;	/* 0x008 */
+	u32 ap_pll_con3;
+	u32 ap_pll_con4;
+	u32 ap_pll_con5;
+	u32 ap_pll_con6;
+	u32 ap_pll_con7;
+	u32 clksq_stb_con0;
+	u32 pll_pwr_con0;
+	u32 pll_pwr_con1;
+	u32 pll_iso_con0;
+	u32 pll_iso_con1;
+	u32 pll_stb_con0;
+	u32 div_stb_con0;
+	u32 pll_chg_con0;
+	u32 pll_test_con0;
+	u32 pll_test_con1;	/* 0x044 */
+	u32 reserved2[110];
+	u32 armca15pll_con0;	/* 0x200 */
+	u32 armca15pll_con1;
+	u32 armca15pll_con2;
+	u32 armca15pll_pwr_con0;
+	u32 armca7pll_con0;
+	u32 armca7pll_con1;
+	u32 armca7pll_con2;
+	u32 armca7pll_pwr_con0;
+	u32 mainpll_con0;
+	u32 mainpll_con1;
+	u32 mainpll_con2;
+	u32 mainpll_pwr_con0;
+	u32 univpll_con0;
+	u32 univpll_con1;
+	u32 univpll_con2;
+	u32 univpll_pwr_con0;
+	u32 mmpll_con0;
+	u32 mmpll_con1;
+	u32 mmpll_con2;
+	u32 mmpll_pwr_con0;
+	u32 msdcpll_con0;
+	u32 msdcpll_con1;
+	u32 msdcpll_con2;
+	u32 msdcpll_pwr_con0;
+	u32 vencpll_con0;
+	u32 vencpll_con1;
+	u32 vencpll_con2;
+	u32 vencpll_pwr_con0;
+	u32 tvdpll_con0;
+	u32 tvdpll_con1;
+	u32 tvdpll_con2;
+	u32 tvdpll_pwr_con0;
+	u32 mpll_con0;
+	u32 mpll_con1;
+	u32 mpll_con2;
+	u32 mpll_pwr_con0;
+	u32 vcodecpll_con0;
+	u32 vcodecpll_con1;
+	u32 vcodecpll_con2;
+	u32 vcodecpll_pwr_con0;
+	u32 apll1_con0;
+	u32 apll1_con1;
+	u32 apll1_con2;
+	u32 apll1_con3;
+	u32 apll1_pwr_con0;
+	u32 apll2_con0;
+	u32 apll2_con1;
+	u32 apll2_con2;
+	u32 apll2_con3;
+	u32 apll2_pwr_con0;
+	u32 reserved3[2];
+	u32 lvdspll_con0;	/* 0x2d0 */
+	u32 lvdspll_con1;
+	u32 lvdspll_con2;
+	u32 lvdspll_pwr_con0;
+	u32 lvdspll_ssc_con0;
+	u32 lvdspll_ssc_con1;
+	u32 lvdspll_ssc_con2;
+	u32 reserved4[1];
+	u32 msdcpll2_con0;	/* 0x2f0 */
+	u32 msdcpll2_con1;
+	u32 msdcpll2_con2;
+	u32 msdcpll2_pwr_con0;	/* 0x2fc */
+};
+
+check_member(mt8173_apmixed_regs, ap_pll_con2, 0x8);
+check_member(mt8173_apmixed_regs, armca15pll_con0, 0x200);
+check_member(mt8173_apmixed_regs, msdcpll2_pwr_con0, 0x2fc);
+
+static struct mt8173_topckgen_regs *const mt8173_topckgen = (void *)CKSYS_BASE;
+static struct mt8173_apmixed_regs *const mt8173_apmixed = (void *)APMIXED_BASE;
+
+/* PLL rate */
+enum {
+	ARMCA15PLL_HZ	= 851500 * KHz,
+	ARMCA7PLL_HZ	= 1105 * MHz,
+	MAINPLL_HZ	= 1092 * MHz,
+	UNIVPLL_HZ	= 1248 * MHz,
+	MMPLL_HZ	= 455 * MHz,
+	MSDCPLL_HZ	= 800 * MHz,
+	VENCPLL_HZ	= 660 * MHz,
+	TVDPLL_HZ	= 1782 * MHz,
+	MPLL_HZ		= 1456 * MHz,
+	VCODECPLL_HZ	= 1104 * MHz,
+	LVDSPLL_HZ	= 150 * MHz,
+	MSDCPLL2_HZ	= 800 * MHz,
+	APLL1_HZ	= 180633600,
+	APLL2_HZ	= 196608 * KHz,
+};
+
+/* top_div rate */
+enum {
+	AD_HDMITX_CLK_HZ	= TVDPLL_HZ / 12,
+	AD_LVDSPLL_CK_HZ	= LVDSPLL_HZ,
+	APLL1_CK_HZ		= APLL1_HZ,
+	APLL2_CK_HZ		= APLL2_HZ,
+	CLK26M_HZ		= 26 * MHz,
+	CLKRTC_EXT_HZ		= 32 * KHz,
+	MMPLL_CK_HZ		= MMPLL_HZ,
+	MSDCPLL_D4_HZ		= MSDCPLL_HZ / 4,
+	SYSPLL1_D2_HZ		= MAINPLL_HZ / 4,
+	SYSPLL1_D4_HZ		= MAINPLL_HZ / 8,
+	SYSPLL2_D2_HZ		= MAINPLL_HZ / 6,
+	SYSPLL3_D2_HZ		= MAINPLL_HZ / 10,
+	SYSPLL3_D4_HZ		= MAINPLL_HZ / 20,
+	SYSPLL_D2_HZ		= MAINPLL_HZ / 2,
+	TVDPLL_D2_HZ		= TVDPLL_HZ / 2,
+	UNIVPLL1_D2_HZ		= UNIVPLL_HZ / 4,
+	UNIVPLL1_D8_HZ		= UNIVPLL_HZ / 16,
+	UNIVPLL2_D2_HZ		= UNIVPLL_HZ / 6,
+	UNIVPLL2_D4_HZ		= UNIVPLL_HZ / 12,
+	UNIVPLL3_D2_HZ		= UNIVPLL_HZ / 10,
+	UNIVPLL_D52_HZ		= UNIVPLL_HZ / 52,
+	VCODECPLL_CK_HZ		= VCODECPLL_HZ / 3,
+	VENCPLL_D2_HZ		= VENCPLL_HZ / 2,
+};
+
+/* top_mux rate */
+enum {
+	AXI_HZ		= UNIVPLL2_D2_HZ,
+	MEM_HZ		= CLK26M_HZ,
+	DDRPHYCFG_HZ	= CLK26M_HZ,
+	MM_HZ		= VENCPLL_D2_HZ,
+	PWM_HZ		= CLK26M_HZ,
+	VDEC_HZ		= VCODECPLL_CK_HZ,
+	VENC_HZ		= VCODECPLL_CK_HZ,
+	MFG_HZ		= MMPLL_CK_HZ,
+	CAMTG_HZ	= CLK26M_HZ,
+	UART_HZ		= CLK26M_HZ,
+	SPI_HZ		= SYSPLL3_D2_HZ,
+	USB20_HZ	= UNIVPLL1_D8_HZ,
+	MSDC30_2_HZ	= MSDCPLL_D4_HZ,
+	MSDC30_3_HZ	= MSDCPLL_D4_HZ,
+	AUDIO_HZ	= CLK26M_HZ,
+	AUD_INTBUS_HZ	= SYSPLL1_D4_HZ,
+	PMICSPI_HZ	= CLK26M_HZ,
+	SCP_HZ		= SYSPLL1_D2_HZ,
+	ATB_HZ		= CLK26M_HZ,
+	VENC_LT_HZ	= UNIVPLL1_D2_HZ,
+	DPI0_HZ		= TVDPLL_D2_HZ,
+	IRDA_HZ		= UNIVPLL2_D4_HZ,
+	CCI400_HZ	= SYSPLL_D2_HZ,
+	AUD_1_HZ	= APLL1_CK_HZ,
+	AUD_2_HZ	= APLL2_CK_HZ,
+	MEM_MFG_IN_HZ	= MMPLL_CK_HZ,
+	AXI_MFG_IN_HZ	= AXI_HZ,
+	SCAM_HZ		= SYSPLL3_D2_HZ,
+	SPINFI_IFR_HZ	= CLK26M_HZ,
+	HDMI_HZ		= AD_HDMITX_CLK_HZ,
+	DPILVDS_HZ	= AD_LVDSPLL_CK_HZ,
+	MSDC50_2_H_HZ	= SYSPLL2_D2_HZ,
+	HDCP_HZ		= SYSPLL3_D4_HZ,
+	HDCP_24M_HZ	= UNIVPLL_D52_HZ,
+	RTC_HZ		= CLKRTC_EXT_HZ,
+	USB30_HZ	= UNIVPLL3_D2_HZ,
+	MSDC50_0_H_HZ	= SYSPLL2_D2_HZ,
+	MSDC50_0_HZ	= MSDCPLL_D4_HZ,
+	MSDC30_1_HZ	= MSDCPLL_D4_HZ,
+};
+
+void mt_pll_post_init(void);
+void mt_pll_init(void);
+
+#endif /* SOC_MEDIATEK_MT8173_PLL_H */
diff --git a/src/soc/mediatek/mt8173/pll.c b/src/soc/mediatek/mt8173/pll.c
new file mode 100644
index 0000000..f1ea9a9
--- /dev/null
+++ b/src/soc/mediatek/mt8173/pll.c
@@ -0,0 +1,460 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 MediaTek Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <assert.h>
+#include <console/console.h>
+#include <delay.h>
+#include <stddef.h>
+
+#include <soc/addressmap.h>
+#include <soc/infracfg.h>
+#include <soc/pll.h>
+
+#define GENMASK(h, l)	(((1U << ((h) - (l) + 1)) - 1) << (l))
+
+enum mux_id {
+	TOP_AXI_SEL,
+	TOP_MEM_SEL,
+	TOP_DDRPHYCFG_SEL,
+	TOP_MM_SEL,
+	TOP_PWM_SEL,
+	TOP_VDEC_SEL,
+	TOP_VENC_SEL,
+	TOP_MFG_SEL,
+	TOP_CAMTG_SEL,
+	TOP_UART_SEL,
+	TOP_SPI_SEL,
+	TOP_USB20_SEL,
+	TOP_USB30_SEL,
+	TOP_MSDC50_0_H_SEL,
+	TOP_MSDC50_0_SEL,
+	TOP_MSDC30_1_SEL,
+	TOP_MSDC30_2_SEL,
+	TOP_MSDC30_3_SEL,
+	TOP_AUDIO_SEL,
+	TOP_AUD_INTBUS_SEL,
+	TOP_PMICSPI_SEL,
+	TOP_SCP_SEL,
+	TOP_ATB_SEL,
+	TOP_VENC_LT_SEL,
+	TOP_DPI0_SEL,
+	TOP_IRDA_SEL,
+	TOP_CCI400_SEL,
+	TOP_AUD_1_SEL,
+	TOP_AUD_2_SEL,
+	TOP_MEM_MFG_IN_SEL,
+	TOP_AXI_MFG_IN_SEL,
+	TOP_SCAM_SEL,
+	TOP_SPINFI_IFR_SEL,
+	TOP_HDMI_SEL,
+	TOP_DPILVDS_SEL,
+	TOP_MSDC50_2_H_SEL,
+	TOP_HDCP_SEL,
+	TOP_HDCP_24M_SEL,
+	TOP_RTC_SEL,
+	TOP_NR_MUX
+};
+
+#define TOPCKGEN_REG(x)	(CKSYS_BASE + offsetof(struct mt8173_topckgen_regs, x))
+#define APMIXED_REG(x)	(APMIXED_BASE + offsetof(struct mt8173_apmixed_regs, x))
+
+struct mux {
+	void *reg;
+	u8 mux_shift;
+	u8 mux_width;
+};
+
+#define MUX(_id, _reg, _mux_shift, _mux_width)		\
+	[_id] = {					\
+		.reg = (void *)TOPCKGEN_REG(_reg),	\
+		.mux_shift = _mux_shift,		\
+		.mux_width = _mux_width,		\
+	}
+
+static const struct mux muxes[] = {
+	/* CLK_CFG_0 */
+	MUX(TOP_AXI_SEL, clk_cfg_0, 0, 3),
+	MUX(TOP_MEM_SEL, clk_cfg_0, 8, 1),
+	MUX(TOP_DDRPHYCFG_SEL, clk_cfg_0, 16, 1),
+	MUX(TOP_MM_SEL, clk_cfg_0, 24, 4),
+	/* CLK_CFG_1 */
+	MUX(TOP_PWM_SEL, clk_cfg_1, 0, 2),
+	MUX(TOP_VDEC_SEL, clk_cfg_1, 8, 4),
+	MUX(TOP_VENC_SEL, clk_cfg_1, 16, 4),
+	MUX(TOP_MFG_SEL, clk_cfg_1, 24, 4),
+	/* CLK_CFG_2 */
+	MUX(TOP_CAMTG_SEL, clk_cfg_2, 0, 3),
+	MUX(TOP_UART_SEL, clk_cfg_2, 8, 1),
+	MUX(TOP_SPI_SEL, clk_cfg_2, 16, 3),
+	MUX(TOP_USB20_SEL, clk_cfg_2, 24, 2),
+	/* CLK_CFG_3 */
+	MUX(TOP_USB30_SEL, clk_cfg_3, 0, 2),
+	MUX(TOP_MSDC50_0_H_SEL, clk_cfg_3, 8, 3),
+	MUX(TOP_MSDC50_0_SEL, clk_cfg_3, 16, 4),
+	MUX(TOP_MSDC30_1_SEL, clk_cfg_3, 24, 3),
+	/* CLK_CFG_4 */
+	MUX(TOP_MSDC30_2_SEL, clk_cfg_4, 0, 3),
+	MUX(TOP_MSDC30_3_SEL, clk_cfg_4, 8, 4),
+	MUX(TOP_AUDIO_SEL, clk_cfg_4, 16, 2),
+	MUX(TOP_AUD_INTBUS_SEL, clk_cfg_4, 24, 3),
+	/* CLK_CFG_5 */
+	MUX(TOP_PMICSPI_SEL, clk_cfg_5, 0, 3),
+	MUX(TOP_SCP_SEL, clk_cfg_5, 8, 3),
+	MUX(TOP_ATB_SEL, clk_cfg_5, 16, 2),
+	MUX(TOP_VENC_LT_SEL, clk_cfg_5, 24, 4),
+	/* CLK_CFG_6 */
+	MUX(TOP_DPI0_SEL, clk_cfg_6, 0, 3),
+	MUX(TOP_IRDA_SEL, clk_cfg_6, 8, 2),
+	MUX(TOP_CCI400_SEL, clk_cfg_6, 16, 3),
+	MUX(TOP_AUD_1_SEL, clk_cfg_6, 24, 2),
+	/* CLK_CFG_7 */
+	MUX(TOP_AUD_2_SEL, clk_cfg_7, 0, 2),
+	MUX(TOP_MEM_MFG_IN_SEL, clk_cfg_7, 8, 2),
+	MUX(TOP_AXI_MFG_IN_SEL, clk_cfg_7, 16, 2),
+	MUX(TOP_SCAM_SEL, clk_cfg_7, 24, 2),
+	/* CLK_CFG_12 */
+	MUX(TOP_SPINFI_IFR_SEL, clk_cfg_12, 0, 3),
+	MUX(TOP_HDMI_SEL, clk_cfg_12, 8, 2),
+	MUX(TOP_DPILVDS_SEL, clk_cfg_12, 24, 3),
+	/* CLK_CFG_13 */
+	MUX(TOP_MSDC50_2_H_SEL, clk_cfg_13, 0, 3),
+	MUX(TOP_HDCP_SEL, clk_cfg_13, 8, 2),
+	MUX(TOP_HDCP_24M_SEL, clk_cfg_13, 16, 2),
+	MUX(TOP_RTC_SEL, clk_cfg_13, 24, 2),
+};
+
+static void mux_set_sel(const struct mux *mux, u32 sel)
+{
+	u32 mask = GENMASK(mux->mux_width - 1, 0);
+	u32 val = read32(mux->reg);
+
+	val &= ~(mask << mux->mux_shift);
+	val |= (sel & mask) << mux->mux_shift;
+	write32(mux->reg, val);
+}
+
+#define PLL_PWR_ON		(1 << 0)
+#define PLL_EN			(1 << 0)
+#define PLL_ISO			(1 << 1)
+#define PLL_RSTB		(1 << 24)
+#define PLL_PCW_CHG		(1 << 31)
+#define PLL_POSTDIV_MASK	0x7
+#define PCW_INTEGER_BITS	7
+
+enum pll_id {
+	APMIXED_ARMCA15PLL,
+	APMIXED_ARMCA7PLL,
+	APMIXED_MAINPLL,
+	APMIXED_UNIVPLL,
+	APMIXED_MMPLL,
+	APMIXED_MSDCPLL,
+	APMIXED_VENCPLL,
+	APMIXED_TVDPLL,
+	APMIXED_MPLL,
+	APMIXED_VCODECPLL,
+	APMIXED_APLL1,
+	APMIXED_APLL2,
+	APMIXED_LVDSPLL,
+	APMIXED_MSDCPLL2,
+	APMIXED_NR_PLL
+};
+
+const u32 pll_div_rate[] = {
+	3UL * GHz,
+	1 * GHz,
+	500 * MHz,
+	250 * MHz,
+	125 * MHz,
+	0,
+};
+
+const u32 univpll_div_rate[] = {
+	3UL * GHz,
+	1500 * MHz,
+	750 * MHz,
+	375 * MHz,
+	187500 * KHz,
+	0,
+};
+
+const u32 mmpll_div_rate[] = {
+	3UL * GHz,
+	1 * GHz,
+	702 * MHz,
+	253500 * KHz,
+	126750 * KHz,
+	0,
+};
+
+struct pll {
+	void *reg;
+	void *pwr_reg;
+	u32 rstb;
+	u8 pcwbits;
+	void *div_reg;
+	u8 div_shift;
+	void *pcw_reg;
+	u8 pcw_shift;
+	const u32 *div_rate;
+};
+
+#define PLL(_id, _reg, _pwr_reg, _rstb, _pcwbits, _div_reg, _div_shift, \
+			_pcw_reg, _pcw_shift, _div_rate)		\
+	[_id] = {							\
+		.reg = (void *)APMIXED_REG(_reg),			\
+		.pwr_reg = (void *)APMIXED_REG(_pwr_reg),		\
+		.rstb = _rstb,						\
+		.pcwbits = _pcwbits,					\
+		.div_reg = (void *)APMIXED_REG(_div_reg),		\
+		.div_shift = _div_shift,				\
+		.pcw_reg = (void *)APMIXED_REG(_pcw_reg),		\
+		.pcw_shift = _pcw_shift,				\
+		.div_rate = _div_rate,					\
+	}
+
+static const struct pll plls[] = {
+	PLL(APMIXED_ARMCA15PLL, armca15pll_con0, armca15pll_pwr_con0, 0, 21,
+		armca15pll_con1, 24, armca15pll_con1, 0, pll_div_rate),
+	PLL(APMIXED_ARMCA7PLL, armca7pll_con0, armca7pll_pwr_con0, PLL_RSTB, 21,
+		armca7pll_con1, 24, armca7pll_con1, 0, pll_div_rate),
+	PLL(APMIXED_MAINPLL, mainpll_con0, mainpll_pwr_con0, PLL_RSTB, 21,
+		mainpll_con0, 4, mainpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_UNIVPLL, univpll_con0, univpll_pwr_con0, PLL_RSTB, 7,
+		univpll_con0, 4, univpll_con1, 14, univpll_div_rate),
+	PLL(APMIXED_MMPLL, mmpll_con0, mmpll_pwr_con0, 0, 21,
+		mmpll_con1, 24, mmpll_con1, 0, mmpll_div_rate),
+	PLL(APMIXED_MSDCPLL, msdcpll_con0, msdcpll_pwr_con0, 0, 21,
+		msdcpll_con0, 4, msdcpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_VENCPLL, vencpll_con0, vencpll_pwr_con0, 0, 21,
+		vencpll_con0, 4, vencpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_TVDPLL, tvdpll_con0, tvdpll_pwr_con0, 0, 21,
+		tvdpll_con0, 4, tvdpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_MPLL, mpll_con0, mpll_pwr_con0, 0, 21,
+		mpll_con0, 4, mpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_VCODECPLL, vcodecpll_con0, vcodecpll_pwr_con0, 0, 21,
+		vcodecpll_con0, 4, vcodecpll_con1, 0, pll_div_rate),
+	PLL(APMIXED_APLL1, apll1_con0, apll1_pwr_con0, 0, 31,
+		apll1_con0, 4, apll1_con1, 0, pll_div_rate),
+	PLL(APMIXED_APLL2, apll2_con0, apll2_pwr_con0, 0, 31,
+		apll2_con0, 4, apll2_con1, 0, pll_div_rate),
+	PLL(APMIXED_LVDSPLL, lvdspll_con0, lvdspll_pwr_con0, 0, 21,
+		lvdspll_con0, 4, lvdspll_con1, 0, pll_div_rate),
+	PLL(APMIXED_MSDCPLL2, msdcpll2_con0, msdcpll2_pwr_con0, 0, 21,
+		msdcpll2_con0, 4, msdcpll2_con1, 0, pll_div_rate),
+};
+
+static void pll_set_rate_regs(const struct pll *pll, u32 pcw, u32 postdiv)
+{
+	u32 val;
+
+	/* set postdiv */
+	val = read32(pll->div_reg);
+	val &= ~(PLL_POSTDIV_MASK << pll->div_shift);
+	val |= postdiv << pll->div_shift;
+
+	/* postdiv and pcw need to set at the same time if on same register */
+	if (pll->div_reg != pll->pcw_reg) {
+		write32(pll->div_reg, val);
+		val = read32(pll->pcw_reg);
+	}
+
+	/* set pcw */
+	val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift);
+	val |= pcw << pll->pcw_shift;
+	val |= PLL_PCW_CHG;
+	write32(pll->pcw_reg, val);
+}
+
+static void pll_calc_values(const struct pll *pll, u32 *pcw, u32 *postdiv,
+			    u32 freq)
+{
+	const u32 fin_hz = CLK26M_HZ;
+	const u32 *div_rate = pll->div_rate;
+	u32 val;
+
+	assert(freq <= div_rate[0]);
+	assert(freq >= 1 * GHz / 16);
+
+	for (val = 1; div_rate[val] != 0; val++) {
+		if (freq > div_rate[val])
+			break;
+	}
+	val--;
+	*postdiv = val;
+
+	/* _pcw = freq * 2^postdiv / fin * 2^pcwbits_fractional */
+	val += pll->pcwbits - PCW_INTEGER_BITS;
+
+	*pcw = ((u64)freq << val) / fin_hz;
+}
+
+static int pll_set_rate(const struct pll *pll, u32 rate)
+{
+	u32 pcw = 0;
+	u32 postdiv;
+
+	pll_calc_values(pll, &pcw, &postdiv, rate);
+	pll_set_rate_regs(pll, pcw, postdiv);
+
+	return 0;
+}
+
+void mt_pll_init(void)
+{
+	int i;
+
+	/* reduce CLKSQ disable time */
+	write32(&mt8173_apmixed->clksq_stb_con0, (0x05 << 8) | (0x01 << 0));
+	/* extend PWR/ISO control timing to 1us */
+	write32(&mt8173_apmixed->pll_iso_con0, (0x8 << 16) | (0x8 << 0));
+	write32(&mt8173_apmixed->ap_pll_con6, 0x00000000);
+
+	/*************
+	 * xPLL PWR ON
+	 **************/
+	for (i = 0; i < APMIXED_NR_PLL; i++)
+		setbits_le32(plls[i].pwr_reg, PLL_PWR_ON);
+
+	udelay(5); /* wait for xPLL_PWR_ON ready (min delay is 1us) */
+
+	/******************
+	 * xPLL ISO Disable
+	 *******************/
+	for (i = 0; i < APMIXED_NR_PLL; i++)
+		clrbits_le32(plls[i].pwr_reg, PLL_ISO);
+
+	/********************
+	 * xPLL Frequency Set
+	 *********************/
+
+	pll_set_rate(&plls[APMIXED_ARMCA15PLL], ARMCA15PLL_HZ);
+	pll_set_rate(&plls[APMIXED_ARMCA7PLL], ARMCA7PLL_HZ);
+	pll_set_rate(&plls[APMIXED_MAINPLL], MAINPLL_HZ);
+	pll_set_rate(&plls[APMIXED_UNIVPLL], UNIVPLL_HZ);
+	pll_set_rate(&plls[APMIXED_MMPLL], MMPLL_HZ);
+	pll_set_rate(&plls[APMIXED_MSDCPLL], MSDCPLL_HZ);
+	pll_set_rate(&plls[APMIXED_VENCPLL], VENCPLL_HZ);
+	pll_set_rate(&plls[APMIXED_TVDPLL], TVDPLL_HZ);
+	pll_set_rate(&plls[APMIXED_MPLL], MPLL_HZ);
+	pll_set_rate(&plls[APMIXED_VCODECPLL], VCODECPLL_HZ);
+	pll_set_rate(&plls[APMIXED_LVDSPLL], LVDSPLL_HZ);
+	pll_set_rate(&plls[APMIXED_MSDCPLL2], MSDCPLL2_HZ);
+	pll_set_rate(&plls[APMIXED_APLL1], APLL1_HZ);
+	pll_set_rate(&plls[APMIXED_APLL2], APLL2_HZ);
+
+	/***********************
+	 * xPLL Frequency Enable
+	 ************************/
+	for (i = 0; i < APMIXED_NR_PLL; i++)
+		setbits_le32(plls[i].reg, PLL_EN);
+
+	udelay(40); /* wait for PLL stable (min delay is 20us) */
+
+	/***************
+	 * xPLL DIV RSTB
+	 ****************/
+	for (i = 0; i < APMIXED_NR_PLL; i++) {
+		if (plls[i].rstb)
+			setbits_le32(plls[i].reg, plls[i].rstb);
+	}
+
+	/**************
+	 * INFRA CLKMUX
+	 ***************/
+
+	/* enable infrasys DCM */
+	setbits_le32(&mt8173_infracfg->top_dcmctl, 0x1);
+
+	write32(&mt8173_topckgen->clk_mode, 0x1);
+	write32(&mt8173_topckgen->clk_mode, 0x0); /* enable TOPCKGEN */
+
+	/************
+	 * TOP CLKMUX -- DO NOT CHANGE WITHOUT ADJUSTING <soc/pll.h> CONSTANTS!
+	 *************/
+
+	/* CLK_CFG_0 */
+	mux_set_sel(&muxes[TOP_AXI_SEL], 5);		/* 5: univpll2_d2 */
+	mux_set_sel(&muxes[TOP_MEM_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_DDRPHYCFG_SEL], 0);	/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_MM_SEL], 1);		/* 1: vencpll_d2 */
+	/* CLK_CFG_1 */
+	mux_set_sel(&muxes[TOP_PWM_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_VDEC_SEL], 1);		/* 1: vcodecpll_ck */
+	mux_set_sel(&muxes[TOP_VENC_SEL], 1);		/* 1: vcodecpll_ck */
+	mux_set_sel(&muxes[TOP_MFG_SEL], 1);		/* 1: mmpll_ck */
+	/* CLK_CFG_2 */
+	mux_set_sel(&muxes[TOP_CAMTG_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_UART_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_SPI_SEL], 1);		/* 1: syspll3_d2 */
+	mux_set_sel(&muxes[TOP_USB20_SEL], 1);		/* 1: univpll1_d8 */
+	/* CLK_CFG_4 */
+	mux_set_sel(&muxes[TOP_MSDC30_2_SEL], 2);	/* 2: msdcpll_d4 */
+	mux_set_sel(&muxes[TOP_MSDC30_3_SEL], 5);	/* 5: msdcpll_d4 */
+	mux_set_sel(&muxes[TOP_AUDIO_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_AUD_INTBUS_SEL], 1);	/* 1: syspll1_d4 */
+	/* CLK_CFG_5 */
+	mux_set_sel(&muxes[TOP_PMICSPI_SEL], 0);	/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_SCP_SEL], 1);		/* 1: syspll1_d2 */
+	mux_set_sel(&muxes[TOP_ATB_SEL], 0);		/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_VENC_LT_SEL], 6);	/* 6: univpll1_d2 */
+	/* CLK_CFG_6 */
+	mux_set_sel(&muxes[TOP_DPI0_SEL], 1);		/* 1: tvdpll_d2 */
+	mux_set_sel(&muxes[TOP_IRDA_SEL], 1);		/* 1: univpll2_d4 */
+	mux_set_sel(&muxes[TOP_CCI400_SEL], 5);		/* 5: syspll_d2 */
+	mux_set_sel(&muxes[TOP_AUD_1_SEL], 1);		/* 1: apll1_ck */
+	/* CLK_CFG_7 */
+	mux_set_sel(&muxes[TOP_AUD_2_SEL], 1);		/* 1: apll2_ck */
+	mux_set_sel(&muxes[TOP_MEM_MFG_IN_SEL], 1);	/* 1: mmpll_ck */
+	mux_set_sel(&muxes[TOP_AXI_MFG_IN_SEL], 1);	/* 1: hd_faxi_ck */
+	mux_set_sel(&muxes[TOP_SCAM_SEL], 1);		/* 1: syspll3_d2 */
+	/* CLK_CFG_12 */
+	mux_set_sel(&muxes[TOP_SPINFI_IFR_SEL], 0);	/* 0: clk26m */
+	mux_set_sel(&muxes[TOP_HDMI_SEL], 1);		/* 1: AD_HDMITX_CLK */
+	mux_set_sel(&muxes[TOP_DPILVDS_SEL], 1);	/* 1: AD_LVDSPLL_CK */
+	/* CLK_CFG_13 */
+	mux_set_sel(&muxes[TOP_MSDC50_2_H_SEL], 2);	/* 2: syspll2_d2 */
+	mux_set_sel(&muxes[TOP_HDCP_SEL], 2);		/* 2: syspll3_d4 */
+	mux_set_sel(&muxes[TOP_HDCP_24M_SEL], 2);	/* 2: univpll_d52 */
+	mux_set_sel(&muxes[TOP_RTC_SEL], 1);		/* 1: clkrtc_ext */
+	/* CLK_CFG_3 */
+	mux_set_sel(&muxes[TOP_USB30_SEL], 1);		/* 1: univpll3_d2 */
+	mux_set_sel(&muxes[TOP_MSDC50_0_H_SEL], 2);	/* 2: syspll2_d2 */
+	mux_set_sel(&muxes[TOP_MSDC50_0_SEL], 6);	/* 6: msdcpll_d4 */
+	mux_set_sel(&muxes[TOP_MSDC30_1_SEL], 2);	/* 2: msdcpll_d4 */
+
+	/* enable scpsys clock off control */
+	write32(&mt8173_topckgen->clk_scp_cfg_0,
+		(1 << 10) | (1 << 9) | (1 << 5) | (1 << 4) | (1 << 2) |
+		(1 << 1) | (1 << 0));
+	write32(&mt8173_topckgen->clk_scp_cfg_1,
+		(1 << 4) | (1 << 2) | (1 << 0));
+}
+
+/* after pmic_init */
+void mt_pll_post_init(void)
+{
+	/* CPU clock divide by 1 */
+	clrbits_le32(&mt8173_infracfg->top_ckdiv1, 0x3ff);
+
+	/* select ARMPLL */
+	/* TODO: possibly raise ARMPLL frequency here */
+	/* NOTICE: raise Vproc voltage before raise ARMPLL frequency */
+	write32(&mt8173_infracfg->top_ckmuxsel, (1 << 2) | 1);
+}



More information about the coreboot-gerrit mailing list