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