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/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_SHIFT 16 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 |= DIV_ROUND_CLOSEST(487UL * freq * ssc_rate, divn * 512) & 46 SC_PLLCTRL_SSC_DK_MASK; 47 writel(tmp, base); 48 49 tmp = readl(base + 4); 50 tmp &= ~SC_PLLCTRL2_SSC_JK_MASK; 51 tmp |= DIV_ROUND_CLOSEST(21431887UL * freq, divn * 512) & 52 SC_PLLCTRL2_SSC_JK_MASK; 53 writel(tmp, base + 4); 54 55 udelay(50); 56 } 57 58 tmp = readl(base + 4); /* SSCPLLCTRL2 */ 59 tmp |= SC_PLLCTRL2_NRSTDS; 60 writel(tmp, base + 4); 61 62 iounmap(base); 63 64 return 0; 65 } 66 67 int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base) 68 { 69 void __iomem *base; 70 u32 tmp; 71 72 base = ioremap(reg_base, SZ_16); 73 if (!base) 74 return -ENOMEM; 75 76 tmp = readl(base); /* SSCPLLCTRL */ 77 tmp |= SC_PLLCTRL_SSC_EN; 78 writel(tmp, base); 79 80 iounmap(base); 81 82 return 0; 83 } 84 85 int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi) 86 { 87 void __iomem *base; 88 u32 tmp; 89 90 base = ioremap(reg_base, SZ_16); 91 if (!base) 92 return -ENOMEM; 93 94 tmp = readl(base + 8); /* SSCPLLCTRL3 */ 95 tmp &= ~SC_PLLCTRL3_REGI_MASK; 96 tmp |= regi << SC_PLLCTRL3_REGI_SHIFT; 97 writel(tmp, base + 8); 98 99 iounmap(base); 100 101 return 0; 102 } 103 104 int uniphier_ld20_vpll27_init(unsigned long reg_base) 105 { 106 void __iomem *base; 107 u32 tmp; 108 109 base = ioremap(reg_base, SZ_16); 110 if (!base) 111 return -ENOMEM; 112 113 tmp = readl(base); /* VPLL27CTRL */ 114 tmp |= SC_VPLL27CTRL_WP; /* write protect off */ 115 writel(tmp, base); 116 117 tmp = readl(base + 8); /* VPLL27CTRL3 */ 118 tmp |= SC_VPLL27CTRL3_K_LD; 119 writel(tmp, base + 8); 120 121 tmp = readl(base); /* VPLL27CTRL */ 122 tmp &= ~SC_VPLL27CTRL_WP; /* write protect on */ 123 writel(tmp, base); 124 125 iounmap(base); 126 127 return 0; 128 } 129 130 int uniphier_ld20_dspll_init(unsigned long reg_base) 131 { 132 void __iomem *base; 133 u32 tmp; 134 135 base = ioremap(reg_base, SZ_16); 136 if (!base) 137 return -ENOMEM; 138 139 tmp = readl(base + 4); /* DSPLLCTRL2 */ 140 tmp |= SC_DSPLLCTRL2_K_LD; 141 writel(tmp, base + 4); 142 143 iounmap(base); 144 145 return 0; 146 } 147