diff mbox series

[RFC,1/9] sunxi: clock: support H6/D1 video clocks

Message ID 20240420-d1_de2-v1-1-297efca674ba@jookia.org
State Under Review
Delegated to: Anatolij Gustschin
Headers show
Series sunxi: video: Support LCD and HDMI output on H6/D1 | expand

Commit Message

John Watts April 20, 2024, 12:02 a.m. UTC
This code adds support for clocking VIDEO0 and VIDEO1, as well as
registers used for the DE2.

This code deliberately uses a 12MHz step in clocking to align with
the DE2 code's expectation of double 6MHz steps.

Signed-off-by: John Watts <contact@jookia.org>
---
 arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h | 56 ++++++++++++++++++
 arch/arm/mach-sunxi/clock_sun50i_h6.c             | 71 +++++++++++++++++++++++
 2 files changed, 127 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
index a84a57e5b4..dfe8d9315f 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
@@ -236,6 +236,28 @@  struct sunxi_ccm_reg {
 #define CCM_PLL1_CTRL_P(p)		((p) << 16)
 #define CCM_PLL1_CTRL_N(n)		(((n) - 1) << 8)
 
+/* pll3 (video0) bit field */
+#define CCM_PLL3_CTRL_EN		BIT(31)
+#define CCM_PLL3_LDO_EN			BIT(30)
+#define CCM_PLL3_LOCK_EN		BIT(29)
+#define CCM_PLL3_LOCK			BIT(28)
+#define CCM_PLL3_OUT_EN			BIT(27)
+#define CCM_PLL3_INPUT_DIV2		BIT(1)
+#define CCM_PLL3_CTRL_N(n)		(((n) - 1) << 8)
+#define CCM_PLL3_CTRL_N_SHIFT		8
+#define CCM_PLL3_CTRL_N_MASK		(0xff << CCM_PLL3_CTRL_N_SHIFT)
+
+/* video1 bit field */
+#define CCM_VIDEO1_CTRL_EN		BIT(31)
+#define CCM_VIDEO1_LDO_EN		BIT(30)
+#define CCM_VIDEO1_LOCK_EN		BIT(29)
+#define CCM_VIDEO1_LOCK			BIT(28)
+#define CCM_VIDEO1_OUT_EN		BIT(27)
+#define CCM_VIDEO1_INPUT_DIV2		BIT(1)
+#define CCM_VIDEO1_CTRL_N(n)		(((n) - 1) << 8)
+#define CCM_VIDEO1_CTRL_N_SHIFT		8
+#define CCM_VIDEO1_CTRL_N_MASK		(0xff << CCM_VIDEO1_CTRL_N_SHIFT)
+
 /* pll5 bit field */
 #define CCM_PLL5_CTRL_EN		BIT(31)
 #define CCM_PLL5_LOCK_EN		BIT(29)
@@ -258,6 +280,16 @@  struct sunxi_ccm_reg {
 #define CCM_PLL6_CTRL_DIV2_SHIFT	1
 #define CCM_PLL6_CTRL_DIV2_MASK		(0x1 << CCM_PLL6_CTRL_DIV2_SHIFT)
 
+/* pll10 bit field */
+#define CCM_PLL10_CTRL_EN		BIT(31)
+#define CCM_PLL10_LOCK_EN		BIT(29)
+#define CCM_PLL10_LOCK			BIT(28)
+#define CCM_PLL10_OUT_EN		BIT(27)
+#define CCM_PLL10_INPUT_DIV2		BIT(1)
+#define CCM_PLL10_CTRL_N(n)		(((n) - 1) << 8)
+#define CCM_PLL10_CTRL_N_SHIFT		8
+#define CCM_PLL10_CTRL_N_MASK		(0xff << CCM_PLL10_CTRL_N_SHIFT)
+
 /* cpu_axi bit field*/
 #define CCM_CPU_AXI_MUX_MASK		(0x3 << 24)
 #define CCM_CPU_AXI_MUX_OSC24M		(0x0 << 24)
@@ -341,9 +373,33 @@  struct sunxi_ccm_reg {
 #define CCM_MMC_CTRL_OCLK_DLY(a)	((void) (a), 0)
 #define CCM_MMC_CTRL_SCLK_DLY(a)	((void) (a), 0)
 
+/* TCON0 clock bit field */
+#define CCM_TCON0_CTRL_ENABLE		(0x1 << 31)
+#define CCM_TCON0_CTRL_VIDEO0_4X	(0x1 << 24)
+#define CCM_TCON0_CTRL_M(m)		((((m) - 1) & 0xf) << 0)
+
+/* TCON1 clock bit field */
+#define CCM_TCON1_CTRL_ENABLE		(0x1 << 31)
+#define CCM_TCON1_CTRL_VIDEO0_4X	(0x1 << 24)
+#define CCM_TCON1_CTRL_M(m)		((((m) - 1) & 0xf) << 0)
+
+/* CCM bits common to all Display Engine 2.0 clock ctrl regs */
+#define CCM_DE2_CTRL_M(n)		((((n) - 1) & 0xf) << 0)
+#define CCM_DE2_CTRL_PLL_MASK		(3 << 24)
+#define CCM_DE2_CTRL_PLL10_H6		(0 << 24)
+#define CCM_DE2_CTRL_VIDEO1_4X_NCAT	(2 << 24)
+#define CCM_DE2_CTRL_GATE		(0x1 << 31)
+
 #ifndef __ASSEMBLY__
 void clock_set_pll1(unsigned int hz);
 unsigned int clock_get_pll6(void);
+
+#ifdef CONFIG_SUNXI_DE2
+void clock_set_pll3(unsigned int hz);
+void clock_set_video1(unsigned int hz);
+void clock_set_pll10(unsigned int hz);
+unsigned int clock_get_pll3(void);
+#endif
 #endif
 
 #endif /* _SUNXI_CLOCK_SUN50I_H6_H */
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
index dac3663e1b..11e303f801 100644
--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
@@ -160,3 +160,74 @@  int clock_twi_onoff(int port, int state)
 
 	return 0;
 }
+
+#ifdef CONFIG_SUNXI_DE2
+
+void clock_set_pll3(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (clk == 0) {
+		clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN);
+		return;
+	}
+
+	/* PLL3 rate = 24000000 * n / 2 */
+	writel(CCM_PLL3_CTRL_EN | CCM_PLL3_LOCK_EN | CCM_PLL3_OUT_EN | CCM_PLL3_LDO_EN |
+	       CCM_PLL3_INPUT_DIV2 | CCM_PLL3_CTRL_N(clk / 12000000),
+	       &ccm->pll3_cfg);
+
+	while (!(readl(&ccm->pll3_cfg) & CCM_PLL3_LOCK))
+		;
+}
+
+void clock_set_video1(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (clk == 0) {
+		clrbits_le32(&ccm->pll_video1_cfg, CCM_VIDEO1_CTRL_EN);
+		return;
+	}
+
+	/* VIDEO1 rate = 24000000 * n / 2 */
+	writel(CCM_VIDEO1_CTRL_EN | CCM_VIDEO1_LOCK_EN | CCM_VIDEO1_OUT_EN | CCM_VIDEO1_LDO_EN |
+	       CCM_VIDEO1_INPUT_DIV2 | CCM_VIDEO1_CTRL_N(clk / 12000000),
+	       &ccm->pll_video1_cfg);
+
+	while (!(readl(&ccm->pll_video1_cfg) & CCM_VIDEO1_LOCK))
+		;
+}
+
+void clock_set_pll10(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	if (clk == 0) {
+		clrbits_le32(&ccm->pll10_cfg, CCM_PLL10_CTRL_EN);
+		return;
+	}
+
+	/* PLL10 rate = 24000000 * n / 2 */
+	writel(CCM_PLL10_CTRL_EN | CCM_PLL10_LOCK_EN | CCM_PLL10_OUT_EN |
+	       CCM_PLL10_INPUT_DIV2 | CCM_PLL10_CTRL_N(clk / 12000000),
+	       &ccm->pll_video1_cfg);
+
+	while (!(readl(&ccm->pll_video1_cfg) & CCM_PLL10_LOCK))
+		;
+}
+
+unsigned int clock_get_pll3(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	u32 rval = readl(&ccm->pll3_cfg);
+	int n = ((rval & CCM_PLL3_CTRL_N_MASK) >> CCM_PLL3_CTRL_N_SHIFT) + 1;
+
+	return 12000 * n * 1000;
+}
+
+#endif