1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Socionext Inc. 4 * Author: Masahiro Yamada <yamada.masahiro@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