Home | History | Annotate | Download | only in clk
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2016 Socionext Inc.
      4  *   Author: Masahiro Yamada <yamada.masahiro (at) socionext.com>
      5  */
      6 
      7 #include <linux/bitfield.h>
      8 #include <linux/bitops.h>
      9 #include <linux/delay.h>
     10 #include <linux/kernel.h>
     11 #include <linux/errno.h>
     12 #include <linux/io.h>
     13 #include <linux/sizes.h>
     14 
     15 #include "pll.h"
     16 
     17 /* PLL type: SSC */
     18 #define SC_PLLCTRL_SSC_DK_MASK		GENMASK(14, 0)
     19 #define SC_PLLCTRL_SSC_EN		BIT(31)
     20 #define SC_PLLCTRL2_NRSTDS		BIT(28)
     21 #define SC_PLLCTRL2_SSC_JK_MASK		GENMASK(26, 0)
     22 #define SC_PLLCTRL3_REGI_MASK		GENMASK(19, 16)
     23 
     24 /* PLL type: VPLL27 */
     25 #define SC_VPLL27CTRL_WP		BIT(0)
     26 #define SC_VPLL27CTRL3_K_LD		BIT(28)
     27 
     28 /* PLL type: DSPLL */
     29 #define SC_DSPLLCTRL2_K_LD		BIT(28)
     30 
     31 int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
     32 			      unsigned int ssc_rate, unsigned int divn)
     33 {
     34 	void __iomem *base;
     35 	u32 tmp;
     36 
     37 	base = ioremap(reg_base, SZ_16);
     38 	if (!base)
     39 		return -ENOMEM;
     40 
     41 	if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
     42 		tmp = readl(base);	/* SSCPLLCTRL */
     43 		tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
     44 		tmp |= FIELD_PREP(SC_PLLCTRL_SSC_DK_MASK,
     45 				  DIV_ROUND_CLOSEST(487UL * freq * ssc_rate,
     46 						    divn * 512));
     47 		writel(tmp, base);
     48 
     49 		tmp = readl(base + 4);
     50 		tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
     51 		tmp |= FIELD_PREP(SC_PLLCTRL2_SSC_JK_MASK,
     52 				  DIV_ROUND_CLOSEST(21431887UL * freq,
     53 						    divn * 512));
     54 		writel(tmp, base + 4);
     55 
     56 		udelay(50);
     57 	}
     58 
     59 	tmp = readl(base + 4);		/* SSCPLLCTRL2 */
     60 	tmp |= SC_PLLCTRL2_NRSTDS;
     61 	writel(tmp, base + 4);
     62 
     63 	iounmap(base);
     64 
     65 	return 0;
     66 }
     67 
     68 int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
     69 {
     70 	void __iomem *base;
     71 	u32 tmp;
     72 
     73 	base = ioremap(reg_base, SZ_16);
     74 	if (!base)
     75 		return -ENOMEM;
     76 
     77 	tmp = readl(base);	/* SSCPLLCTRL */
     78 	tmp |= SC_PLLCTRL_SSC_EN;
     79 	writel(tmp, base);
     80 
     81 	iounmap(base);
     82 
     83 	return 0;
     84 }
     85 
     86 int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi)
     87 {
     88 	void __iomem *base;
     89 	u32 tmp;
     90 
     91 	base = ioremap(reg_base, SZ_16);
     92 	if (!base)
     93 		return -ENOMEM;
     94 
     95 	tmp = readl(base + 8);	/* SSCPLLCTRL3 */
     96 	tmp &= ~SC_PLLCTRL3_REGI_MASK;
     97 	tmp |= FIELD_PREP(SC_PLLCTRL3_REGI_MASK, regi);
     98 	writel(tmp, base + 8);
     99 
    100 	iounmap(base);
    101 
    102 	return 0;
    103 }
    104 
    105 int uniphier_ld20_vpll27_init(unsigned long reg_base)
    106 {
    107 	void __iomem *base;
    108 	u32 tmp;
    109 
    110 	base = ioremap(reg_base, SZ_16);
    111 	if (!base)
    112 		return -ENOMEM;
    113 
    114 	tmp = readl(base);		/* VPLL27CTRL */
    115 	tmp |= SC_VPLL27CTRL_WP;	/* write protect off */
    116 	writel(tmp, base);
    117 
    118 	tmp = readl(base + 8);		/* VPLL27CTRL3 */
    119 	tmp |= SC_VPLL27CTRL3_K_LD;
    120 	writel(tmp, base + 8);
    121 
    122 	tmp = readl(base);		/* VPLL27CTRL */
    123 	tmp &= ~SC_VPLL27CTRL_WP;	/* write protect on */
    124 	writel(tmp, base);
    125 
    126 	iounmap(base);
    127 
    128 	return 0;
    129 }
    130 
    131 int uniphier_ld20_dspll_init(unsigned long reg_base)
    132 {
    133 	void __iomem *base;
    134 	u32 tmp;
    135 
    136 	base = ioremap(reg_base, SZ_16);
    137 	if (!base)
    138 		return -ENOMEM;
    139 
    140 	tmp = readl(base + 4);		/* DSPLLCTRL2 */
    141 	tmp |= SC_DSPLLCTRL2_K_LD;
    142 	writel(tmp, base + 4);
    143 
    144 	iounmap(base);
    145 
    146 	return 0;
    147 }
    148