ARM: uniphier: add PLL init code for LD20 SoC
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Fri, 16 Sep 2016 18:33:11 +0000 (03:33 +0900)
committerMasahiro Yamada <yamada.masahiro@socionext.com>
Sun, 18 Sep 2016 15:12:26 +0000 (00:12 +0900)
Initialize the DPLL (PLL for DRAM) in SPL, and others in U-Boot
proper.  Split the common code into pll-base-ld20.c for easier
re-use.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
arch/arm/mach-uniphier/board_init.c
arch/arm/mach-uniphier/clk/Makefile
arch/arm/mach-uniphier/clk/dpll-ld20.c [new file with mode: 0644]
arch/arm/mach-uniphier/clk/pll-base-ld20.c [new file with mode: 0644]
arch/arm/mach-uniphier/clk/pll-ld20.c [new file with mode: 0644]
arch/arm/mach-uniphier/clk/pll.h
arch/arm/mach-uniphier/init.h
arch/arm/mach-uniphier/init/init-ld20.c
arch/arm/mach-uniphier/sc64-regs.h

index a1c75414c3c3350bce691c03fce500121c469799..b57a33f299b0353072ebd9d14f99b132cf364ea8 100644 (file)
@@ -58,8 +58,14 @@ static void uniphier_nand_pin_init(bool cs2)
 
 int board_init(void)
 {
+       const struct uniphier_board_data *bd;
+
        led_puts("U0");
 
+       bd = uniphier_get_board_param();
+       if (!bd)
+               return -ENODEV;
+
        switch (uniphier_get_soc_type()) {
 #if defined(CONFIG_ARCH_UNIPHIER_SLD3)
        case SOC_UNIPHIER_SLD3:
@@ -133,6 +139,7 @@ int board_init(void)
                sg_set_pinsel(153, 14, 8, 4);   /* XIRQ4    -> XIRQ4 */
                sg_set_iectrl(153);
                led_puts("U1");
+               uniphier_ld20_pll_init(bd);
                uniphier_ld20_clk_init();
                cci500_init(2);
                break;
index 233e6591eeea816b5983efbec04660d6a0a3fded..c8d59eabe35b599d195c4c8b14d70697692857e5 100644 (file)
@@ -12,7 +12,7 @@ obj-$(CONFIG_ARCH_UNIPHIER_PRO5)      += early-clk-pro5.o
 obj-$(CONFIG_ARCH_UNIPHIER_PXS2)       += early-clk-pxs2.o
 obj-$(CONFIG_ARCH_UNIPHIER_LD6B)       += early-clk-pxs2.o
 obj-$(CONFIG_ARCH_UNIPHIER_LD11)       += early-clk-ld11.o
-obj-$(CONFIG_ARCH_UNIPHIER_LD20)       += early-clk-ld20.o
+obj-$(CONFIG_ARCH_UNIPHIER_LD20)       += early-clk-ld20.o dpll-ld20.o
 
 else
 
@@ -24,6 +24,8 @@ obj-$(CONFIG_ARCH_UNIPHIER_PRO5)      += clk-pro5.o
 obj-$(CONFIG_ARCH_UNIPHIER_PXS2)       += clk-pxs2.o
 obj-$(CONFIG_ARCH_UNIPHIER_LD6B)       += clk-pxs2.o
 obj-$(CONFIG_ARCH_UNIPHIER_LD11)       += clk-ld11.o
-obj-$(CONFIG_ARCH_UNIPHIER_LD20)       += clk-ld20.o
+obj-$(CONFIG_ARCH_UNIPHIER_LD20)       += clk-ld20.o pll-ld20.o
 
 endif
+
+obj-$(CONFIG_ARCH_UNIPHIER_LD20)       += pll-base-ld20.o
diff --git a/arch/arm/mach-uniphier/clk/dpll-ld20.c b/arch/arm/mach-uniphier/clk/dpll-ld20.c
new file mode 100644 (file)
index 0000000..1132313
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "../init.h"
+#include "../sc64-regs.h"
+#include "pll.h"
+
+int uniphier_ld20_dpll_init(const struct uniphier_board_data *bd)
+{
+       unsigned int dpll_ssc_rate = UNIPHIER_BD_DPLL_SSC_GET_RATE(bd->flags);
+       unsigned int dram_freq = bd->dram_freq;
+
+       uniphier_ld20_sscpll_init(SC_DPLL0CTRL, dram_freq, dpll_ssc_rate, 2);
+       uniphier_ld20_sscpll_init(SC_DPLL1CTRL, dram_freq, dpll_ssc_rate, 2);
+       uniphier_ld20_sscpll_init(SC_DPLL2CTRL, dram_freq, dpll_ssc_rate, 2);
+
+       return 0;
+}
diff --git a/arch/arm/mach-uniphier/clk/pll-base-ld20.c b/arch/arm/mach-uniphier/clk/pll-base-ld20.c
new file mode 100644 (file)
index 0000000..a5027d2
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+
+#include "pll.h"
+
+/* PLL type: SSC */
+#define SC_PLLCTRL_SSC_DK_MASK         GENMASK(14, 0)
+#define SC_PLLCTRL_SSC_EN              BIT(31)
+#define SC_PLLCTRL2_NRSTDS             BIT(28)
+#define SC_PLLCTRL2_SSC_JK_MASK                GENMASK(26, 0)
+
+/* PLL type: VPLL27 */
+#define SC_VPLL27CTRL_WP               BIT(0)
+#define SC_VPLL27CTRL3_K_LD            BIT(28)
+
+/* PLL type: DSPLL */
+#define SC_DSPLLCTRL2_K_LD             BIT(28)
+
+int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
+                             unsigned int ssc_rate, unsigned int divn)
+{
+       void __iomem *base;
+       u32 tmp;
+
+       base = ioremap(reg_base, SZ_16);
+       if (!base)
+               return -ENOMEM;
+
+       if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
+               tmp = readl(base);      /* SSCPLLCTRL */
+               tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
+               tmp |= (487 * freq * ssc_rate / divn / 512) &
+                                                       SC_PLLCTRL_SSC_DK_MASK;
+               writel(tmp, base);
+
+               tmp = readl(base + 4);
+               tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
+               tmp |= (41859 * freq / divn) & SC_PLLCTRL2_SSC_JK_MASK;
+
+               udelay(50);
+       }
+
+       tmp = readl(base + 4);          /* SSCPLLCTRL2 */
+       tmp |= SC_PLLCTRL2_NRSTDS;
+       writel(tmp, base + 4);
+
+       iounmap(base);
+
+       return 0;
+}
+
+int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
+{
+       void __iomem *base;
+       u32 tmp;
+
+       base = ioremap(reg_base, SZ_16);
+       if (!base)
+               return -ENOMEM;
+
+       mdelay(1);
+
+       tmp = readl(base);      /* SSCPLLCTRL */
+       tmp |= SC_PLLCTRL_SSC_EN;
+       writel(tmp, base);
+
+       iounmap(base);
+
+       return 0;
+}
+
+int uniphier_ld20_vpll27_init(unsigned long reg_base)
+{
+       void __iomem *base;
+       u32 tmp;
+
+       base = ioremap(reg_base, SZ_16);
+       if (!base)
+               return -ENOMEM;
+
+       tmp = readl(base);              /* VPLL27CTRL */
+       tmp |= SC_VPLL27CTRL_WP;        /* write protect off */
+       writel(tmp, base);
+
+       tmp = readl(base + 8);          /* VPLL27CTRL3 */
+       tmp |= SC_VPLL27CTRL3_K_LD;
+       writel(tmp, base + 8);
+
+       tmp = readl(base);              /* VPLL27CTRL */
+       tmp &= ~SC_VPLL27CTRL_WP;       /* write protect on */
+       writel(tmp, base);
+
+       iounmap(base);
+
+       return 0;
+}
+
+int uniphier_ld20_dspll_init(unsigned long reg_base)
+{
+       void __iomem *base;
+       u32 tmp;
+
+       base = ioremap(reg_base, SZ_16);
+       if (!base)
+               return -ENOMEM;
+
+       tmp = readl(base + 8);          /* DSPLLCTRL2 */
+       tmp |= SC_DSPLLCTRL2_K_LD;
+       writel(tmp, base + 8);
+
+       iounmap(base);
+
+       return 0;
+}
diff --git a/arch/arm/mach-uniphier/clk/pll-ld20.c b/arch/arm/mach-uniphier/clk/pll-ld20.c
new file mode 100644 (file)
index 0000000..5e545da
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+
+#include "../init.h"
+#include "../sc64-regs.h"
+#include "pll.h"
+
+int uniphier_ld20_pll_init(const struct uniphier_board_data *bd)
+{
+       unsigned int dpll_ssc_rate = UNIPHIER_BD_DPLL_SSC_GET_RATE(bd->flags);
+
+       uniphier_ld20_sscpll_init(SC_CPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
+       /* do nothing for SPLL */
+       uniphier_ld20_sscpll_init(SC_SPLL2CTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
+       uniphier_ld20_sscpll_init(SC_MPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
+       uniphier_ld20_sscpll_init(SC_VPPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
+       uniphier_ld20_sscpll_init(SC_GPPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
+
+       mdelay(1);
+
+       if (dpll_ssc_rate > 0) {
+               uniphier_ld20_sscpll_ssc_en(SC_DPLL0CTRL);
+               uniphier_ld20_sscpll_ssc_en(SC_DPLL1CTRL);
+               uniphier_ld20_sscpll_ssc_en(SC_DPLL2CTRL);
+       }
+
+       uniphier_ld20_vpll27_init(SC_VPLL27FCTRL);
+       uniphier_ld20_vpll27_init(SC_VPLL27ACTRL);
+
+       uniphier_ld20_dspll_init(SC_VPLL8KCTRL);
+       uniphier_ld20_dspll_init(SC_A2PLLCTRL);
+
+       return 0;
+}
index ef0f722d0a1c724000c0bd103abf2c7add3e19bd..d7e93037d66e50efed62f2320f4cec81a816cd1f 100644 (file)
@@ -8,6 +8,14 @@
 #ifndef MACH_PLL_H
 #define MACH_PLL_H
 
+#define UNIPHIER_PLL_FREQ_DEFAULT      (0)
+
 void uniphier_ld4_dpll_ssc_en(void);
 
+int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
+                             unsigned int ssc_rate, unsigned int divn);
+int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base);
+int uniphier_ld20_vpll27_init(unsigned long reg_base);
+int uniphier_ld20_dspll_init(unsigned long reg_base);
+
 #endif /* MACH_PLL_H */
index d8f5b493459f403afa7d763667d121e3b008bb87..5c7cd6b6a4b4cc6fe7e6b7414f424df6551d6ae8 100644 (file)
@@ -24,6 +24,9 @@ struct uniphier_board_data {
        struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH];
        unsigned int flags;
 
+#define UNIPHIER_BD_DPLL_SSC_GET_RATE(f)       (((f) >> 8) & 0x3)
+#define UNIPHIER_BD_DPLL_SSC_RATE(r)           (((r) & 0x3) << 8)
+
 #define UNIPHIER_BD_DDR3PLUS                   BIT(2)
 
 #define UNIPHIER_BD_BOARD_GET_TYPE(f)          ((f) & 0x3)
@@ -84,6 +87,7 @@ int uniphier_sld3_dpll_init(const struct uniphier_board_data *bd);
 int uniphier_ld4_dpll_init(const struct uniphier_board_data *bd);
 int uniphier_pro4_dpll_init(const struct uniphier_board_data *bd);
 int uniphier_sld8_dpll_init(const struct uniphier_board_data *bd);
+int uniphier_ld20_dpll_init(const struct uniphier_board_data *bd);
 
 int uniphier_ld4_early_clk_init(const struct uniphier_board_data *bd);
 int uniphier_pro5_early_clk_init(const struct uniphier_board_data *bd);
@@ -101,6 +105,7 @@ int uniphier_ld11_umc_init(const struct uniphier_board_data *bd);
 void uniphier_sld3_pll_init(void);
 void uniphier_ld4_pll_init(void);
 void uniphier_pro4_pll_init(void);
+int uniphier_ld20_pll_init(const struct uniphier_board_data *bd);
 
 void uniphier_ld4_clk_init(void);
 void uniphier_pro4_clk_init(void);
index a0760461ad2e9c189e9216a1df86281b4e2ed4b1..cb054212529918b9fc0fa6236efdcee22abb490d 100644 (file)
@@ -32,12 +32,14 @@ int uniphier_ld20_init(const struct uniphier_board_data *bd)
 
        led_puts("L2");
 
-       led_puts("L3");
-
 #ifdef CONFIG_SPL_SERIAL_SUPPORT
        preloader_console_init();
 #endif
 
+       led_puts("L3");
+
+       uniphier_ld20_dpll_init(bd);
+
        led_puts("L4");
 
        {
index ef02830a1ee0f165484166b6352cd270bb64f648..1e52bb1ef165654debc203668ac26f3fe30389fa 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * UniPhier SC (System Control) block registers for ARMv8 SoCs
  *
- * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #define SC_BASE_ADDR           0x61840000
 
+/* PLL type: SSC */
+#define SC_CPLLCTRL    (SC_BASE_ADDR | 0x1400) /* LD20: CPU/ARM */
+#define SC_SPLLCTRL    (SC_BASE_ADDR | 0x1410) /* LD20: misc */
+#define SC_SPLL2CTRL   (SC_BASE_ADDR | 0x1420) /* LD20: IPP */
+#define SC_MPLLCTRL    (SC_BASE_ADDR | 0x1430) /* LD20: Video codec */
+#define SC_VPPLLCTRL   (SC_BASE_ADDR | 0x1440) /* LD20: VPE etc. */
+#define SC_GPPLLCTRL   (SC_BASE_ADDR | 0x1450) /* LD20: GPU/Mali */
+#define SC_DPLL0CTRL   (SC_BASE_ADDR | 0x1460) /* LD20: DDR memory 0 */
+#define SC_DPLL1CTRL   (SC_BASE_ADDR | 0x1470) /* LD20: DDR memory 1 */
+#define SC_DPLL2CTRL   (SC_BASE_ADDR | 0x1480) /* LD20: DDR memory 2 */
+
+/* PLL type: VPLL27 */
+#define SC_VPLL27FCTRL (SC_BASE_ADDR | 0x1500)
+#define SC_VPLL27ACTRL (SC_BASE_ADDR | 0x1520)
+
+/* PLL type: DSPLL */
+#define SC_VPLL8KCTRL  (SC_BASE_ADDR | 0x1540)
+#define SC_A2PLLCTRL   (SC_BASE_ADDR | 0x15C0)
+
 #define SC_RSTCTRL             (SC_BASE_ADDR | 0x2000)
 #define SC_RSTCTRL3            (SC_BASE_ADDR | 0x2008)
 #define SC_RSTCTRL4            (SC_BASE_ADDR | 0x200c)