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