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