Path: blob/main/sys/dev/clk/rockchip/rk_clk_pll.c
107001 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2018 Emmanuel Vadot <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR15* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES16* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.17* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,18* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,19* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;20* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED21* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,22* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/bus.h>3031#include <dev/clk/clk.h>3233#include <dev/clk/rockchip/rk_clk_pll.h>3435#include "clkdev_if.h"3637struct rk_clk_pll_sc {38uint32_t base_offset;3940uint32_t gate_offset;41uint32_t gate_shift;4243uint32_t mode_reg;44uint32_t mode_shift;4546uint32_t flags;4748struct rk_clk_pll_rate *rates;49struct rk_clk_pll_rate *frac_rates;50};5152#define WRITE4(_clk, off, val) \53CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)54#define READ4(_clk, off, val) \55CLKDEV_READ_4(clknode_get_device(_clk), off, val)56#define DEVICE_LOCK(_clk) \57CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))58#define DEVICE_UNLOCK(_clk) \59CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))6061#define RK_CLK_PLL_MASK_SHIFT 166263#if 064#define dprintf(format, arg...) \65printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)66#else67#define dprintf(format, arg...)68#endif6970static int71rk_clk_pll_set_gate(struct clknode *clk, bool enable)72{73struct rk_clk_pll_sc *sc;74uint32_t val = 0;7576sc = clknode_get_softc(clk);7778if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)79return (0);8081dprintf("%sabling gate\n", enable ? "En" : "Dis");82if (!enable)83val |= 1 << sc->gate_shift;84dprintf("sc->gate_shift: %x\n", sc->gate_shift);85val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;86dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);87DEVICE_LOCK(clk);88WRITE4(clk, sc->gate_offset, val);89DEVICE_UNLOCK(clk);9091return (0);92}9394/* CON0 */95#define RK3066_CLK_PLL_REFDIV_SHIFT 896#define RK3066_CLK_PLL_REFDIV_MASK 0x3F0097#define RK3066_CLK_PLL_POSTDIV_SHIFT 098#define RK3066_CLK_PLL_POSTDIV_MASK 0x000F99/* CON1 */100#define RK3066_CLK_PLL_LOCK_MASK (1U << 31)101#define RK3066_CLK_PLL_FBDIV_SHIFT 0102#define RK3066_CLK_PLL_FBDIV_MASK 0x0FFF103/* CON2 */104105/* CON3 */106#define RK3066_CLK_PLL_RESET (1 << 5)107#define RK3066_CLK_PLL_TEST (1 << 4)108#define RK3066_CLK_PLL_ENSAT (1 << 3)109#define RK3066_CLK_PLL_FASTEN (1 << 2)110#define RK3066_CLK_PLL_POWER_DOWN (1 << 1)111#define RK3066_CLK_PLL_BYPASS (1 << 0)112113#define RK3066_CLK_PLL_MODE_SLOW 0114#define RK3066_CLK_PLL_MODE_NORMAL 1115#define RK3066_CLK_PLL_MODE_DEEP_SLOW 2116#define RK3066_CLK_PLL_MODE_MASK 0x3117118static int119rk3066_clk_pll_init(struct clknode *clk, device_t dev)120{121struct rk_clk_pll_sc *sc;122uint32_t reg;123124sc = clknode_get_softc(clk);125126DEVICE_LOCK(clk);127READ4(clk, sc->mode_reg, ®);128DEVICE_UNLOCK(clk);129130reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;131clknode_init_parent_idx(clk, reg);132133return (0);134}135136static int137rk3066_clk_pll_set_mux(struct clknode *clk, int idx)138{139uint32_t reg;140struct rk_clk_pll_sc *sc;141142sc = clknode_get_softc(clk);143144reg = (idx & RK3066_CLK_PLL_MODE_MASK) << sc->mode_shift;145reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<146RK_CLK_PLL_MASK_SHIFT;147148DEVICE_LOCK(clk);149WRITE4(clk, sc->mode_reg, reg);150DEVICE_UNLOCK(clk);151return(0);152}153154static int155rk3066_clk_pll_recalc(struct clknode *clk, uint64_t *freq)156{157struct rk_clk_pll_sc *sc;158uint64_t rate;159uint32_t refdiv, fbdiv, postdiv;160uint32_t raw0, raw1, raw2, reg;161162sc = clknode_get_softc(clk);163164DEVICE_LOCK(clk);165166READ4(clk, sc->base_offset, &raw0);167READ4(clk, sc->base_offset + 4, &raw1);168READ4(clk, sc->base_offset + 8, &raw2);169READ4(clk, sc->mode_reg, ®);170171DEVICE_UNLOCK(clk);172173reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;174175if (reg != RK3066_CLK_PLL_MODE_NORMAL)176return (0);177178if (!(raw1 & RK3066_CLK_PLL_LOCK_MASK)) {179*freq = 0;180return (0);181}182183/* TODO MUX */184refdiv = (raw0 & RK3066_CLK_PLL_REFDIV_MASK) >>185RK3066_CLK_PLL_REFDIV_SHIFT;186refdiv += 1;187postdiv = (raw0 & RK3066_CLK_PLL_POSTDIV_MASK) >>188RK3066_CLK_PLL_POSTDIV_SHIFT;189postdiv += 1;190fbdiv = (raw1 & RK3066_CLK_PLL_FBDIV_MASK) >>191RK3066_CLK_PLL_FBDIV_SHIFT;192fbdiv += 1;193194rate = *freq * fbdiv;195rate /= refdiv;196*freq = rate / postdiv;197198return (0);199}200201static int202rk3066_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,203int flags, int *stop)204{205struct rk_clk_pll_rate *rates;206struct rk_clk_pll_sc *sc;207uint32_t reg;208int rv, timeout;209210sc = clknode_get_softc(clk);211212if (sc->rates == NULL)213return (EINVAL);214215for (rates = sc->rates; rates->freq; rates++) {216if (rates->freq == *fout)217break;218}219if (rates->freq == 0) {220*stop = 1;221return (EINVAL);222}223224DEVICE_LOCK(clk);225226/* Setting to slow mode during frequency change */227reg = (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<228RK_CLK_PLL_MASK_SHIFT;229dprintf("Set PLL_MODEREG to %x\n", reg);230WRITE4(clk, sc->mode_reg, reg);231232/* Reset PLL */233WRITE4(clk, sc->base_offset + 12, RK3066_CLK_PLL_RESET |234RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);235236/* Setting postdiv and refdiv */237reg = 0;238reg |= RK3066_CLK_PLL_POSTDIV_MASK << 16;239reg |= (rates->postdiv1 - 1) << RK3066_CLK_PLL_POSTDIV_SHIFT;240241reg |= RK3066_CLK_PLL_REFDIV_MASK << 16;242reg |= (rates->refdiv - 1)<< RK3066_CLK_PLL_REFDIV_SHIFT;243244dprintf("Set PLL_CON0 to %x\n", reg);245WRITE4(clk, sc->base_offset, reg);246247248/* Setting fbdiv (no write mask)*/249READ4(clk, sc->base_offset + 4, ®);250reg &= ~RK3066_CLK_PLL_FBDIV_MASK;251reg |= RK3066_CLK_PLL_FBDIV_MASK << 16;252reg = (rates->fbdiv - 1) << RK3066_CLK_PLL_FBDIV_SHIFT;253254dprintf("Set PLL_CON1 to %x\n", reg);255WRITE4(clk, sc->base_offset + 0x4, reg);256257/* PLL loop bandwidth adjust */258reg = rates->bwadj - 1;259dprintf("Set PLL_CON2 to %x (%x)\n", reg, rates->bwadj);260WRITE4(clk, sc->base_offset + 0x8, reg);261262/* Clear reset */263WRITE4(clk, sc->base_offset + 12,264RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);265DELAY(100000);266267/* Reading lock */268for (timeout = 1000; timeout >= 0; timeout--) {269READ4(clk, sc->base_offset + 0x4, ®);270if ((reg & RK3066_CLK_PLL_LOCK_MASK) != 0)271break;272DELAY(1);273}274275rv = 0;276if (timeout < 0) {277device_printf(clknode_get_device(clk),278"%s - Timedout while waiting for lock.\n",279clknode_get_name(clk));280dprintf("PLL_CON1: %x\n", reg);281rv = ETIMEDOUT;282}283284/* Set back to normal mode */285reg = (RK3066_CLK_PLL_MODE_NORMAL << sc->mode_shift);286reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<287RK_CLK_PLL_MASK_SHIFT;288dprintf("Set PLL_MODEREG to %x\n", reg);289WRITE4(clk, sc->mode_reg, reg);290291DEVICE_UNLOCK(clk);292*stop = 1;293rv = clknode_set_parent_by_idx(clk, 1);294return (rv);295}296297static clknode_method_t rk3066_clk_pll_clknode_methods[] = {298/* Device interface */299CLKNODEMETHOD(clknode_init, rk3066_clk_pll_init),300CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),301CLKNODEMETHOD(clknode_recalc_freq, rk3066_clk_pll_recalc),302CLKNODEMETHOD(clknode_set_freq, rk3066_clk_pll_set_freq),303CLKNODEMETHOD(clknode_set_mux, rk3066_clk_pll_set_mux),304CLKNODEMETHOD_END305};306307DEFINE_CLASS_1(rk3066_clk_pll_clknode, rk3066_clk_pll_clknode_class,308rk3066_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);309310int311rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)312{313struct clknode *clk;314struct rk_clk_pll_sc *sc;315316clk = clknode_create(clkdom, &rk3066_clk_pll_clknode_class,317&clkdef->clkdef);318if (clk == NULL)319return (1);320321sc = clknode_get_softc(clk);322323sc->base_offset = clkdef->base_offset;324sc->gate_offset = clkdef->gate_offset;325sc->gate_shift = clkdef->gate_shift;326sc->mode_reg = clkdef->mode_reg;327sc->mode_shift = clkdef->mode_shift;328sc->flags = clkdef->flags;329sc->rates = clkdef->rates;330sc->frac_rates = clkdef->frac_rates;331332clknode_register(clkdom, clk);333334return (0);335}336337#define RK3328_CLK_PLL_FBDIV_OFFSET 0338#define RK3328_CLK_PLL_FBDIV_SHIFT 0339#define RK3328_CLK_PLL_FBDIV_MASK 0xFFF340341#define RK3328_CLK_PLL_POSTDIV1_OFFSET 0342#define RK3328_CLK_PLL_POSTDIV1_SHIFT 12343#define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000344345#define RK3328_CLK_PLL_DSMPD_OFFSET 4346#define RK3328_CLK_PLL_DSMPD_SHIFT 12347#define RK3328_CLK_PLL_DSMPD_MASK 0x1000348349#define RK3328_CLK_PLL_REFDIV_OFFSET 4350#define RK3328_CLK_PLL_REFDIV_SHIFT 0351#define RK3328_CLK_PLL_REFDIV_MASK 0x3F352353#define RK3328_CLK_PLL_POSTDIV2_OFFSET 4354#define RK3328_CLK_PLL_POSTDIV2_SHIFT 6355#define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0356357#define RK3328_CLK_PLL_FRAC_OFFSET 8358#define RK3328_CLK_PLL_FRAC_SHIFT 0359#define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF360361#define RK3328_CLK_PLL_LOCK_MASK 0x400362363#define RK3328_CLK_PLL_MODE_SLOW 0364#define RK3328_CLK_PLL_MODE_NORMAL 1365#define RK3328_CLK_PLL_MODE_MASK 0x1366367static int368rk3328_clk_pll_init(struct clknode *clk, device_t dev)369{370clknode_init_parent_idx(clk, 0);371372return (0);373}374375static int376rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)377{378struct rk_clk_pll_sc *sc;379uint64_t rate;380uint32_t dsmpd, refdiv, fbdiv;381uint32_t postdiv1, postdiv2, frac;382uint32_t raw1, raw2, raw3;383384sc = clknode_get_softc(clk);385386DEVICE_LOCK(clk);387388READ4(clk, sc->base_offset, &raw1);389READ4(clk, sc->base_offset + 4, &raw2);390READ4(clk, sc->base_offset + 8, &raw3);391392fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;393postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;394395dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;396refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;397postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;398399frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;400401DEVICE_UNLOCK(clk);402403rate = *freq * fbdiv / refdiv;404if (dsmpd == 0) {405/* Fractional mode */406uint64_t frac_rate;407408frac_rate = *freq * frac / refdiv;409rate += frac_rate >> 24;410}411412*freq = rate / postdiv1 / postdiv2;413414if (*freq % 2)415*freq = *freq + 1;416417return (0);418}419420static int421rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,422int flags, int *stop)423{424struct rk_clk_pll_rate *rates;425struct rk_clk_pll_sc *sc;426uint32_t reg;427int timeout;428429sc = clknode_get_softc(clk);430431if (sc->rates)432rates = sc->rates;433else if (sc->frac_rates)434rates = sc->frac_rates;435else436return (EINVAL);437438for (; rates->freq; rates++) {439if (rates->freq == *fout)440break;441}442if (rates->freq == 0) {443*stop = 1;444return (EINVAL);445}446447DEVICE_LOCK(clk);448449/* Setting to slow mode during frequency change */450reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<451RK_CLK_PLL_MASK_SHIFT;452dprintf("Set PLL_MODEREG to %x\n", reg);453WRITE4(clk, sc->mode_reg, reg);454455/* Setting postdiv1 and fbdiv */456reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |457(rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);458reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;459dprintf("Set PLL_CON0 to %x\n", reg);460WRITE4(clk, sc->base_offset, reg);461462/* Setting dsmpd, postdiv2 and refdiv */463reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |464(rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |465(rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);466reg |= (RK3328_CLK_PLL_DSMPD_MASK |467RK3328_CLK_PLL_POSTDIV2_MASK |468RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;469dprintf("Set PLL_CON1 to %x\n", reg);470WRITE4(clk, sc->base_offset + 0x4, reg);471472/* Setting frac */473READ4(clk, sc->base_offset + 0x8, ®);474reg &= ~RK3328_CLK_PLL_FRAC_MASK;475reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;476dprintf("Set PLL_CON2 to %x\n", reg);477WRITE4(clk, sc->base_offset + 0x8, reg);478479/* Reading lock */480for (timeout = 1000; timeout; timeout--) {481READ4(clk, sc->base_offset + 0x4, ®);482if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)483break;484DELAY(1);485}486487/* Set back to normal mode */488reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);489reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<490RK_CLK_PLL_MASK_SHIFT;491dprintf("Set PLL_MODEREG to %x\n", reg);492WRITE4(clk, sc->mode_reg, reg);493494DEVICE_UNLOCK(clk);495496*stop = 1;497return (0);498}499500static clknode_method_t rk3328_clk_pll_clknode_methods[] = {501/* Device interface */502CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init),503CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),504CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc),505CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq),506CLKNODEMETHOD_END507};508509DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,510rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);511512int513rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)514{515struct clknode *clk;516struct rk_clk_pll_sc *sc;517518clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,519&clkdef->clkdef);520if (clk == NULL)521return (1);522523sc = clknode_get_softc(clk);524525sc->base_offset = clkdef->base_offset;526sc->gate_offset = clkdef->gate_offset;527sc->gate_shift = clkdef->gate_shift;528sc->mode_reg = clkdef->mode_reg;529sc->mode_shift = clkdef->mode_shift;530sc->flags = clkdef->flags;531sc->rates = clkdef->rates;532sc->frac_rates = clkdef->frac_rates;533534clknode_register(clkdom, clk);535536return (0);537}538539#define RK3399_CLK_PLL_FBDIV_OFFSET 0540#define RK3399_CLK_PLL_FBDIV_SHIFT 0541#define RK3399_CLK_PLL_FBDIV_MASK 0xFFF542543#define RK3399_CLK_PLL_POSTDIV2_OFFSET 4544#define RK3399_CLK_PLL_POSTDIV2_SHIFT 12545#define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000546547#define RK3399_CLK_PLL_POSTDIV1_OFFSET 4548#define RK3399_CLK_PLL_POSTDIV1_SHIFT 8549#define RK3399_CLK_PLL_POSTDIV1_MASK 0x700550551#define RK3399_CLK_PLL_REFDIV_OFFSET 4552#define RK3399_CLK_PLL_REFDIV_SHIFT 0553#define RK3399_CLK_PLL_REFDIV_MASK 0x3F554555#define RK3399_CLK_PLL_FRAC_OFFSET 8556#define RK3399_CLK_PLL_FRAC_SHIFT 0557#define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF558559#define RK3399_CLK_PLL_DSMPD_OFFSET 0xC560#define RK3399_CLK_PLL_DSMPD_SHIFT 3561#define RK3399_CLK_PLL_DSMPD_MASK 0x8562563#define RK3399_CLK_PLL_LOCK_OFFSET 8564#define RK3399_CLK_PLL_LOCK_MASK 0x400565566#define RK3399_CLK_PLL_MODE_OFFSET 0xC567#define RK3399_CLK_PLL_MODE_MASK 0x300568#define RK3399_CLK_PLL_MODE_SLOW 0569#define RK3399_CLK_PLL_MODE_NORMAL 1570#define RK3399_CLK_PLL_MODE_DEEPSLOW 2571#define RK3399_CLK_PLL_MODE_SHIFT 8572573#define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000574575static int576rk3399_clk_pll_init(struct clknode *clk, device_t dev)577{578clknode_init_parent_idx(clk, 0);579580return (0);581}582583static int584rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)585{586struct rk_clk_pll_sc *sc;587uint32_t dsmpd, refdiv, fbdiv;588uint32_t postdiv1, postdiv2, fracdiv;589uint32_t con1, con2, con3, con4;590uint64_t foutvco;591uint32_t mode;592sc = clknode_get_softc(clk);593594DEVICE_LOCK(clk);595READ4(clk, sc->base_offset, &con1);596READ4(clk, sc->base_offset + 4, &con2);597READ4(clk, sc->base_offset + 8, &con3);598READ4(clk, sc->base_offset + 0xC, &con4);599DEVICE_UNLOCK(clk);600601/*602* if we are in slow mode the output freq603* is the parent one, the 24Mhz external oscillator604* if we are in deep mode the output freq is 32.768khz605*/606mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;607if (mode == RK3399_CLK_PLL_MODE_SLOW) {608dprintf("pll in slow mode, con4=%x\n", con4);609return (0);610} else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {611dprintf("pll in deep slow, con4=%x\n", con4);612*freq = 32768;613return (0);614}615616dprintf("con0: %x\n", con1);617dprintf("con1: %x\n", con2);618dprintf("con2: %x\n", con3);619dprintf("con3: %x\n", con4);620621fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK)622>> RK3399_CLK_PLL_FBDIV_SHIFT;623624postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK)625>> RK3399_CLK_PLL_POSTDIV1_SHIFT;626postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK)627>> RK3399_CLK_PLL_POSTDIV2_SHIFT;628refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK)629>> RK3399_CLK_PLL_REFDIV_SHIFT;630631fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK)632>> RK3399_CLK_PLL_FRAC_SHIFT;633fracdiv >>= 24;634635dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;636637dprintf("fbdiv: %d\n", fbdiv);638dprintf("postdiv1: %d\n", postdiv1);639dprintf("postdiv2: %d\n", postdiv2);640dprintf("refdiv: %d\n", refdiv);641dprintf("fracdiv: %d\n", fracdiv);642dprintf("dsmpd: %d\n", dsmpd);643644dprintf("parent freq=%ju\n", *freq);645646if (dsmpd == 0) {647/* Fractional mode */648foutvco = *freq / refdiv * (fbdiv + fracdiv);649} else {650/* Integer mode */651foutvco = *freq / refdiv * fbdiv;652}653dprintf("foutvco: %ju\n", foutvco);654655*freq = foutvco / postdiv1 / postdiv2;656dprintf("freq: %ju\n", *freq);657658return (0);659}660661static int662rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,663int flags, int *stop)664{665struct rk_clk_pll_rate *rates;666struct rk_clk_pll_sc *sc;667uint32_t reg;668int timeout;669670sc = clknode_get_softc(clk);671672if (sc->rates)673rates = sc->rates;674else if (sc->frac_rates)675rates = sc->frac_rates;676else677return (EINVAL);678679for (; rates->freq; rates++) {680if (rates->freq == *fout)681break;682}683if (rates->freq == 0) {684*stop = 1;685return (EINVAL);686}687688DEVICE_LOCK(clk);689690/* Set to slow mode during frequency change */691reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;692reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;693WRITE4(clk, sc->base_offset + 0xC, reg);694695/* Setting fbdiv */696reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;697reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;698WRITE4(clk, sc->base_offset, reg);699700/* Setting postdiv1, postdiv2 and refdiv */701reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;702reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;703reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;704reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |705RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;706WRITE4(clk, sc->base_offset + 0x4, reg);707708/* Setting frac */709READ4(clk, sc->base_offset + 0x8, ®);710reg &= ~RK3399_CLK_PLL_FRAC_MASK;711reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;712WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);713714/* Set dsmpd */715reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;716reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;717WRITE4(clk, sc->base_offset + 0xC, reg);718719/* Reading lock */720for (timeout = 1000; timeout; timeout--) {721READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®);722if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)723break;724DELAY(1);725}726727/* Set back to normal mode */728reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;729reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;730WRITE4(clk, sc->base_offset + 0xC, reg);731732DEVICE_UNLOCK(clk);733734*stop = 1;735return (0);736}737738static clknode_method_t rk3399_clk_pll_clknode_methods[] = {739/* Device interface */740CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init),741CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),742CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc),743CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq),744CLKNODEMETHOD_END745};746747DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,748rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);749750int751rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)752{753struct clknode *clk;754struct rk_clk_pll_sc *sc;755756clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,757&clkdef->clkdef);758if (clk == NULL)759return (1);760761sc = clknode_get_softc(clk);762763sc->base_offset = clkdef->base_offset;764sc->gate_offset = clkdef->gate_offset;765sc->gate_shift = clkdef->gate_shift;766sc->flags = clkdef->flags;767sc->rates = clkdef->rates;768sc->frac_rates = clkdef->frac_rates;769770clknode_register(clkdom, clk);771772return (0);773}774775776