1/* $NetBSD: rk_cru_pll.c,v 1.6 2022/08/23 05:39:06 ryo Exp $ */ 2 3/*- 4 * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: rk_cru_pll.c,v 1.6 2022/08/23 05:39:06 ryo Exp $"); 31 32#include <sys/param.h> 33#include <sys/bus.h> 34 35#include <dev/clk/clk_backend.h> 36 37#include <arm/rockchip/rk_cru.h> 38 39#define PLL_CON0 0x00 40#define PLL_BYPASS __BIT(15) 41#define PLL_POSTDIV1 __BITS(14,12) 42#define PLL_FBDIV __BITS(11,0) 43 44#define PLL_CON1 0x04 45#define PLL_PDSEL __BIT(15) 46#define PLL_PD1 __BIT(14) 47#define PLL_PD0 __BIT(13) 48#define PLL_DSMPD __BIT(12) 49#define PLL_LOCK __BIT(10) 50#define PLL_POSTDIV2 __BITS(8,6) 51#define PLL_REFDIV __BITS(5,0) 52 53#define PLL_CON2 0x08 54#define PLL_FOUT4PHASEPD __BIT(27) 55#define PLL_FOUTVCOPD __BIT(26) 56#define PLL_FOUTPOSTDIVPD __BIT(25) 57#define PLL_DACPD __BIT(24) 58#define PLL_FRACDIV __BITS(23,0) 59 60#define PLL_CON3 0x0c 61#define PLL_CON6 0x18 62 63#define PLL_WRITE_MASK 0xffff0000 /* for CON0 and CON1 */ 64 65/* RK3288 CON0 */ 66#define RK3288_CLKR __BITS(13,8) 67#define RK3288_CLKOD __BITS(3,0) 68/* RK3288 CON1 */ 69#define RK3288_LOCK __BIT(31) 70#define RK3288_CLKF __BITS(12,0) 71/* RK3288 CON2 */ 72#define RK3288_BWADJ __BITS(11,0) 73/* RK3288 CON3 */ 74#define RK3288_BYPASS __BIT(0) 75 76#define RK3588_PLLCON0_M __BITS(9,0) 77#define RK3588_PLLCON1_P __BITS(5,0) 78#define RK3588_PLLCON1_S __BITS(8,6) 79#define RK3588_PLLCON2_K __BITS(15,0) 80#define RK3588_PLLCON1_PWRDOWN __BIT(13) 81#define RK3588_PLLCON6_LOCK __BIT(15) 82 83#define PLL_MODE_SLOW 0x0 84#define PLL_MODE_NORM 0x1 85 86u_int 87rk_cru_pll_get_rate(struct rk_cru_softc *sc, 88 struct rk_cru_clk *clk) 89{ 90 struct rk_cru_pll *pll = &clk->u.pll; 91 struct clk *clkp, *clkp_parent; 92 u_int foutvco, foutpostdiv; 93 94 KASSERT(clk->type == RK_CRU_PLL); 95 96 clkp = &clk->base; 97 clkp_parent = clk_get_parent(clkp); 98 if (clkp_parent == NULL) 99 return 0; 100 101 const u_int fref = clk_get_rate(clkp_parent); 102 if (fref == 0) 103 return 0; 104 105 const uint32_t con0 = CRU_READ(sc, pll->con_base + PLL_CON0); 106 const uint32_t con1 = CRU_READ(sc, pll->con_base + PLL_CON1); 107 const uint32_t con2 = CRU_READ(sc, pll->con_base + PLL_CON2); 108 const uint32_t con3 = CRU_READ(sc, pll->con_base + PLL_CON3); 109 110 if ((pll->flags & RK_PLL_RK3288) != 0) { 111 if ((con3 & RK3288_BYPASS) != 0) { 112 return fref; 113 } 114 115 const u_int nr = __SHIFTOUT(con0, RK3288_CLKR) + 1; 116 const u_int no = __SHIFTOUT(con0, RK3288_CLKOD) + 1; 117 const u_int nf = __SHIFTOUT(con1, RK3288_CLKF) + 1; 118 119 const uint64_t tmp = (uint64_t)fref * nf / nr / no; 120 121 return (u_int)tmp; 122 } else if ((pll->flags & RK_PLL_RK3588) != 0) { 123 const uint64_t m = __SHIFTOUT(con0, RK3588_PLLCON0_M); 124 const uint64_t p = __SHIFTOUT(con1, RK3588_PLLCON1_P); 125 const uint64_t s = __SHIFTOUT(con1, RK3588_PLLCON1_S); 126 const uint64_t k = __SHIFTOUT(con2, RK3588_PLLCON2_K); 127 128 uint64_t tmp = (uint64_t)fref * m; 129 if (p != 0) 130 tmp /= p; 131 if (k != 0 && p != 0) 132 tmp += ((uint64_t)fref * k) / (p * 65535); 133 tmp >>= s; 134 return (u_int)tmp; 135 } else { 136 const u_int postdiv1 = __SHIFTOUT(con0, PLL_POSTDIV1); 137 const u_int fbdiv = __SHIFTOUT(con0, PLL_FBDIV); 138 const u_int dsmpd = __SHIFTOUT(con1, PLL_DSMPD); 139 const u_int refdiv = __SHIFTOUT(con1, PLL_REFDIV); 140 const u_int postdiv2 = __SHIFTOUT(con1, PLL_POSTDIV2); 141 const u_int fracdiv = __SHIFTOUT(con2, PLL_FRACDIV); 142 143 if (dsmpd == 1) { 144 /* integer mode */ 145 foutvco = fref / refdiv * fbdiv; 146 } else { 147 /* fractional mode */ 148 foutvco = fref / refdiv * fbdiv + ((fref * fracdiv) >> 24); 149 } 150 foutpostdiv = foutvco / postdiv1 / postdiv2; 151 152 return foutpostdiv; 153 } 154} 155 156int 157rk_cru_pll_set_rate(struct rk_cru_softc *sc, 158 struct rk_cru_clk *clk, u_int rate) 159{ 160 struct rk_cru_pll *pll = &clk->u.pll; 161 const struct rk_cru_pll_rate *pll_rate = NULL; 162 uint32_t val; 163 int retry; 164 165 KASSERT(clk->type == RK_CRU_PLL); 166 167 if (pll->rates == NULL || rate == 0 || !HAS_GRF(sc)) 168 return EIO; 169 170 for (int i = 0; i < pll->nrates; i++) 171 if (pll->rates[i].rate == rate) { 172 pll_rate = &pll->rates[i]; 173 break; 174 } 175 if (pll_rate == NULL) 176 return EINVAL; 177 178 if ((pll->flags & RK_PLL_RK3288) != 0) { 179 /* XXX TODO */ 180 KASSERT(false); 181 } else if ((pll->flags & RK_PLL_RK3588) != 0) { 182 bool muxed = false; 183 184 /* into SLOW mode */ 185 if (__SHIFTOUT(CRU_READ(sc, pll->mode_reg), pll->mode_mask) == 186 PLL_MODE_NORM) { 187 CRU_WRITE(sc, pll->mode_reg, 188 pll->mode_mask << 16 | 189 __SHIFTIN(PLL_MODE_SLOW, pll->mode_mask)); 190 muxed = true; 191 } 192 193 /* power down */ 194 CRU_WRITE(sc, pll->con_base + PLL_CON1, 195 RK3588_PLLCON1_PWRDOWN << 16 | 196 __SHIFTIN(1, RK3588_PLLCON1_PWRDOWN)); 197 198 /* update m,p,s,k */ 199 CRU_WRITE(sc, pll->con_base + PLL_CON0, 200 RK3588_PLLCON0_M << 16 | 201 __SHIFTIN(pll_rate->m, RK3588_PLLCON0_M)); 202 CRU_WRITE(sc, pll->con_base + PLL_CON1, 203 RK3588_PLLCON1_P << 16 | 204 RK3588_PLLCON1_S << 16 | 205 __SHIFTIN(pll_rate->p, RK3588_PLLCON1_P) | 206 __SHIFTIN(pll_rate->s, RK3588_PLLCON1_S)); 207 CRU_WRITE(sc, pll->con_base + PLL_CON2, 208 RK3588_PLLCON2_K << 16 | 209 __SHIFTIN(pll_rate->k, RK3588_PLLCON2_K)); 210 211 /* power up */ 212 CRU_WRITE(sc, pll->con_base + PLL_CON1, 213 RK3588_PLLCON1_PWRDOWN << 16 | 214 __SHIFTIN(0, RK3588_PLLCON1_PWRDOWN)); 215 216 /* wait */ 217 for (retry = 1000; retry > 0; retry--) { 218 if (CRU_READ(sc, pll->con_base + PLL_CON6) & 219 pll->lock_mask) { 220 break; 221 } 222 delay(1); 223 } 224 if (retry == 0) 225 device_printf(sc->sc_dev, 226 "WARNING: %s failed to lock\n", clk->base.name); 227 228 /* into NORM mode */ 229 if (muxed) { 230 CRU_WRITE(sc, pll->mode_reg, 231 pll->mode_mask << 16 | 232 __SHIFTIN(PLL_MODE_NORM, pll->mode_mask)); 233 } 234 } else { 235 CRU_WRITE(sc, pll->con_base + PLL_CON0, 236 __SHIFTIN(pll_rate->postdiv1, PLL_POSTDIV1) | 237 __SHIFTIN(pll_rate->fbdiv, PLL_FBDIV) | 238 PLL_WRITE_MASK); 239 240 CRU_WRITE(sc, pll->con_base + PLL_CON1, 241 __SHIFTIN(pll_rate->dsmpd, PLL_DSMPD) | 242 __SHIFTIN(pll_rate->postdiv2, PLL_POSTDIV2) | 243 __SHIFTIN(pll_rate->refdiv, PLL_REFDIV) | 244 PLL_WRITE_MASK); 245 246 val = CRU_READ(sc, pll->con_base + PLL_CON2); 247 val &= ~PLL_FRACDIV; 248 val |= __SHIFTIN(pll_rate->fracdiv, PLL_FRACDIV); 249 CRU_WRITE(sc, pll->con_base + PLL_CON2, val); 250 251 /* Set PLL work mode to normal */ 252 const uint32_t write_mask = pll->mode_mask << 16; 253 const uint32_t write_val = pll->mode_mask; 254 CRU_WRITE(sc, pll->mode_reg, write_mask | write_val); 255 256 syscon_lock(sc->sc_grf); 257 for (retry = 1000; retry > 0; retry--) { 258 if (syscon_read_4(sc->sc_grf, 259 sc->sc_grf_soc_status) & pll->lock_mask) 260 break; 261 delay(1); 262 } 263 syscon_unlock(sc->sc_grf); 264 265 if (retry == 0) 266 device_printf(sc->sc_dev, 267 "WARNING: %s failed to lock\n", clk->base.name); 268 } 269 270 return 0; 271} 272 273const char * 274rk_cru_pll_get_parent(struct rk_cru_softc *sc, 275 struct rk_cru_clk *clk) 276{ 277 struct rk_cru_pll *pll = &clk->u.pll; 278 279 KASSERT(clk->type == RK_CRU_PLL); 280 281 return pll->parents[0]; 282} 283