177f22241SEmmanuel Vadot /*-
277f22241SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause
377f22241SEmmanuel Vadot *
477f22241SEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
577f22241SEmmanuel Vadot *
677f22241SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
777f22241SEmmanuel Vadot * modification, are permitted provided that the following conditions
877f22241SEmmanuel Vadot * are met:
977f22241SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
1077f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
1177f22241SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
1277f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
1377f22241SEmmanuel Vadot * documentation and/or other materials provided with the distribution.
1477f22241SEmmanuel Vadot *
1577f22241SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1677f22241SEmmanuel Vadot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1777f22241SEmmanuel Vadot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1877f22241SEmmanuel Vadot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1977f22241SEmmanuel Vadot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2077f22241SEmmanuel Vadot * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2177f22241SEmmanuel Vadot * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2277f22241SEmmanuel Vadot * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2377f22241SEmmanuel Vadot * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477f22241SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577f22241SEmmanuel Vadot * SUCH DAMAGE.
2677f22241SEmmanuel Vadot */
2777f22241SEmmanuel Vadot
2877f22241SEmmanuel Vadot #include <sys/param.h>
2977f22241SEmmanuel Vadot #include <sys/systm.h>
3077f22241SEmmanuel Vadot #include <sys/bus.h>
3177f22241SEmmanuel Vadot
32*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
3377f22241SEmmanuel Vadot
3477f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_pll.h>
3577f22241SEmmanuel Vadot
3677f22241SEmmanuel Vadot #include "clkdev_if.h"
3777f22241SEmmanuel Vadot
3877f22241SEmmanuel Vadot struct rk_clk_pll_sc {
3977f22241SEmmanuel Vadot uint32_t base_offset;
4077f22241SEmmanuel Vadot
4177f22241SEmmanuel Vadot uint32_t gate_offset;
4277f22241SEmmanuel Vadot uint32_t gate_shift;
4377f22241SEmmanuel Vadot
4477f22241SEmmanuel Vadot uint32_t mode_reg;
4577f22241SEmmanuel Vadot uint32_t mode_shift;
4677f22241SEmmanuel Vadot
4777f22241SEmmanuel Vadot uint32_t flags;
4877f22241SEmmanuel Vadot
4977f22241SEmmanuel Vadot struct rk_clk_pll_rate *rates;
5077f22241SEmmanuel Vadot struct rk_clk_pll_rate *frac_rates;
5177f22241SEmmanuel Vadot };
5277f22241SEmmanuel Vadot
5377f22241SEmmanuel Vadot #define WRITE4(_clk, off, val) \
5477f22241SEmmanuel Vadot CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
5577f22241SEmmanuel Vadot #define READ4(_clk, off, val) \
5677f22241SEmmanuel Vadot CLKDEV_READ_4(clknode_get_device(_clk), off, val)
5777f22241SEmmanuel Vadot #define DEVICE_LOCK(_clk) \
5877f22241SEmmanuel Vadot CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
5977f22241SEmmanuel Vadot #define DEVICE_UNLOCK(_clk) \
6077f22241SEmmanuel Vadot CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
6177f22241SEmmanuel Vadot
6277f22241SEmmanuel Vadot #define RK_CLK_PLL_MASK_SHIFT 16
6377f22241SEmmanuel Vadot
6477f22241SEmmanuel Vadot #if 0
6577f22241SEmmanuel Vadot #define dprintf(format, arg...) \
6677f22241SEmmanuel Vadot printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
6777f22241SEmmanuel Vadot #else
6877f22241SEmmanuel Vadot #define dprintf(format, arg...)
6977f22241SEmmanuel Vadot #endif
7077f22241SEmmanuel Vadot
7177f22241SEmmanuel Vadot static int
rk_clk_pll_set_gate(struct clknode * clk,bool enable)7277f22241SEmmanuel Vadot rk_clk_pll_set_gate(struct clknode *clk, bool enable)
7377f22241SEmmanuel Vadot {
7477f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
7577f22241SEmmanuel Vadot uint32_t val = 0;
7677f22241SEmmanuel Vadot
7777f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
7877f22241SEmmanuel Vadot
7977f22241SEmmanuel Vadot if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
8077f22241SEmmanuel Vadot return (0);
8177f22241SEmmanuel Vadot
8277f22241SEmmanuel Vadot dprintf("%sabling gate\n", enable ? "En" : "Dis");
8377f22241SEmmanuel Vadot if (!enable)
8477f22241SEmmanuel Vadot val |= 1 << sc->gate_shift;
8577f22241SEmmanuel Vadot dprintf("sc->gate_shift: %x\n", sc->gate_shift);
8677f22241SEmmanuel Vadot val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;
8777f22241SEmmanuel Vadot dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);
8877f22241SEmmanuel Vadot DEVICE_LOCK(clk);
8977f22241SEmmanuel Vadot WRITE4(clk, sc->gate_offset, val);
9077f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
9177f22241SEmmanuel Vadot
9277f22241SEmmanuel Vadot return (0);
9377f22241SEmmanuel Vadot }
9477f22241SEmmanuel Vadot
9577f22241SEmmanuel Vadot /* CON0 */
9677f22241SEmmanuel Vadot #define RK3066_CLK_PLL_REFDIV_SHIFT 8
9777f22241SEmmanuel Vadot #define RK3066_CLK_PLL_REFDIV_MASK 0x3F00
9877f22241SEmmanuel Vadot #define RK3066_CLK_PLL_POSTDIV_SHIFT 0
9977f22241SEmmanuel Vadot #define RK3066_CLK_PLL_POSTDIV_MASK 0x000F
10077f22241SEmmanuel Vadot /* CON1 */
10177f22241SEmmanuel Vadot #define RK3066_CLK_PLL_LOCK_MASK (1U << 31)
10277f22241SEmmanuel Vadot #define RK3066_CLK_PLL_FBDIV_SHIFT 0
10377f22241SEmmanuel Vadot #define RK3066_CLK_PLL_FBDIV_MASK 0x0FFF
10477f22241SEmmanuel Vadot /* CON2 */
10577f22241SEmmanuel Vadot
10677f22241SEmmanuel Vadot /* CON3 */
10777f22241SEmmanuel Vadot #define RK3066_CLK_PLL_RESET (1 << 5)
10877f22241SEmmanuel Vadot #define RK3066_CLK_PLL_TEST (1 << 4)
10977f22241SEmmanuel Vadot #define RK3066_CLK_PLL_ENSAT (1 << 3)
11077f22241SEmmanuel Vadot #define RK3066_CLK_PLL_FASTEN (1 << 2)
11177f22241SEmmanuel Vadot #define RK3066_CLK_PLL_POWER_DOWN (1 << 1)
11277f22241SEmmanuel Vadot #define RK3066_CLK_PLL_BYPASS (1 << 0)
11377f22241SEmmanuel Vadot
11477f22241SEmmanuel Vadot #define RK3066_CLK_PLL_MODE_SLOW 0
11577f22241SEmmanuel Vadot #define RK3066_CLK_PLL_MODE_NORMAL 1
11677f22241SEmmanuel Vadot #define RK3066_CLK_PLL_MODE_DEEP_SLOW 2
11777f22241SEmmanuel Vadot #define RK3066_CLK_PLL_MODE_MASK 0x3
11877f22241SEmmanuel Vadot
11977f22241SEmmanuel Vadot static int
rk3066_clk_pll_init(struct clknode * clk,device_t dev)12077f22241SEmmanuel Vadot rk3066_clk_pll_init(struct clknode *clk, device_t dev)
12177f22241SEmmanuel Vadot {
12277f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
12377f22241SEmmanuel Vadot uint32_t reg;
12477f22241SEmmanuel Vadot
12577f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
12677f22241SEmmanuel Vadot
12777f22241SEmmanuel Vadot DEVICE_LOCK(clk);
12877f22241SEmmanuel Vadot READ4(clk, sc->mode_reg, ®);
12977f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
13077f22241SEmmanuel Vadot
13177f22241SEmmanuel Vadot reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
13277f22241SEmmanuel Vadot clknode_init_parent_idx(clk, reg);
13377f22241SEmmanuel Vadot
13477f22241SEmmanuel Vadot return (0);
13577f22241SEmmanuel Vadot }
13677f22241SEmmanuel Vadot
13777f22241SEmmanuel Vadot static int
rk3066_clk_pll_set_mux(struct clknode * clk,int idx)13877f22241SEmmanuel Vadot rk3066_clk_pll_set_mux(struct clknode *clk, int idx)
13977f22241SEmmanuel Vadot {
14077f22241SEmmanuel Vadot uint32_t reg;
14177f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
14277f22241SEmmanuel Vadot
14377f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
14477f22241SEmmanuel Vadot
14577f22241SEmmanuel Vadot reg = (idx & RK3066_CLK_PLL_MODE_MASK) << sc->mode_shift;
14677f22241SEmmanuel Vadot reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
14777f22241SEmmanuel Vadot RK_CLK_PLL_MASK_SHIFT;
14877f22241SEmmanuel Vadot
14977f22241SEmmanuel Vadot DEVICE_LOCK(clk);
15077f22241SEmmanuel Vadot WRITE4(clk, sc->mode_reg, reg);
15177f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
15277f22241SEmmanuel Vadot return(0);
15377f22241SEmmanuel Vadot }
15477f22241SEmmanuel Vadot
15577f22241SEmmanuel Vadot static int
rk3066_clk_pll_recalc(struct clknode * clk,uint64_t * freq)15677f22241SEmmanuel Vadot rk3066_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
15777f22241SEmmanuel Vadot {
15877f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
15977f22241SEmmanuel Vadot uint64_t rate;
16077f22241SEmmanuel Vadot uint32_t refdiv, fbdiv, postdiv;
16177f22241SEmmanuel Vadot uint32_t raw0, raw1, raw2, reg;
16277f22241SEmmanuel Vadot
16377f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
16477f22241SEmmanuel Vadot
16577f22241SEmmanuel Vadot DEVICE_LOCK(clk);
16677f22241SEmmanuel Vadot
16777f22241SEmmanuel Vadot READ4(clk, sc->base_offset, &raw0);
16877f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 4, &raw1);
16977f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 8, &raw2);
17077f22241SEmmanuel Vadot READ4(clk, sc->mode_reg, ®);
17177f22241SEmmanuel Vadot
17277f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
17377f22241SEmmanuel Vadot
17477f22241SEmmanuel Vadot reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
17577f22241SEmmanuel Vadot
17677f22241SEmmanuel Vadot if (reg != RK3066_CLK_PLL_MODE_NORMAL)
17777f22241SEmmanuel Vadot return (0);
17877f22241SEmmanuel Vadot
17977f22241SEmmanuel Vadot if (!(raw1 & RK3066_CLK_PLL_LOCK_MASK)) {
18077f22241SEmmanuel Vadot *freq = 0;
18177f22241SEmmanuel Vadot return (0);
18277f22241SEmmanuel Vadot }
18377f22241SEmmanuel Vadot
18477f22241SEmmanuel Vadot /* TODO MUX */
18577f22241SEmmanuel Vadot refdiv = (raw0 & RK3066_CLK_PLL_REFDIV_MASK) >>
18677f22241SEmmanuel Vadot RK3066_CLK_PLL_REFDIV_SHIFT;
18777f22241SEmmanuel Vadot refdiv += 1;
18877f22241SEmmanuel Vadot postdiv = (raw0 & RK3066_CLK_PLL_POSTDIV_MASK) >>
18977f22241SEmmanuel Vadot RK3066_CLK_PLL_POSTDIV_SHIFT;
19077f22241SEmmanuel Vadot postdiv += 1;
19177f22241SEmmanuel Vadot fbdiv = (raw1 & RK3066_CLK_PLL_FBDIV_MASK) >>
19277f22241SEmmanuel Vadot RK3066_CLK_PLL_FBDIV_SHIFT;
19377f22241SEmmanuel Vadot fbdiv += 1;
19477f22241SEmmanuel Vadot
19577f22241SEmmanuel Vadot rate = *freq * fbdiv;
19677f22241SEmmanuel Vadot rate /= refdiv;
19777f22241SEmmanuel Vadot *freq = rate / postdiv;
19877f22241SEmmanuel Vadot
19977f22241SEmmanuel Vadot return (0);
20077f22241SEmmanuel Vadot }
20177f22241SEmmanuel Vadot
20277f22241SEmmanuel Vadot static int
rk3066_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)20377f22241SEmmanuel Vadot rk3066_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
20477f22241SEmmanuel Vadot int flags, int *stop)
20577f22241SEmmanuel Vadot {
20677f22241SEmmanuel Vadot struct rk_clk_pll_rate *rates;
20777f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
20877f22241SEmmanuel Vadot uint32_t reg;
20977f22241SEmmanuel Vadot int rv, timeout;
21077f22241SEmmanuel Vadot
21177f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
21277f22241SEmmanuel Vadot
21377f22241SEmmanuel Vadot if (sc->rates == NULL)
21477f22241SEmmanuel Vadot return (EINVAL);
21577f22241SEmmanuel Vadot
21677f22241SEmmanuel Vadot for (rates = sc->rates; rates->freq; rates++) {
21777f22241SEmmanuel Vadot if (rates->freq == *fout)
21877f22241SEmmanuel Vadot break;
21977f22241SEmmanuel Vadot }
22077f22241SEmmanuel Vadot if (rates->freq == 0) {
22177f22241SEmmanuel Vadot *stop = 1;
22277f22241SEmmanuel Vadot return (EINVAL);
22377f22241SEmmanuel Vadot }
22477f22241SEmmanuel Vadot
22577f22241SEmmanuel Vadot DEVICE_LOCK(clk);
22677f22241SEmmanuel Vadot
22777f22241SEmmanuel Vadot /* Setting to slow mode during frequency change */
22877f22241SEmmanuel Vadot reg = (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
22977f22241SEmmanuel Vadot RK_CLK_PLL_MASK_SHIFT;
23077f22241SEmmanuel Vadot dprintf("Set PLL_MODEREG to %x\n", reg);
23177f22241SEmmanuel Vadot WRITE4(clk, sc->mode_reg, reg);
23277f22241SEmmanuel Vadot
23377f22241SEmmanuel Vadot /* Reset PLL */
23477f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 12, RK3066_CLK_PLL_RESET |
23577f22241SEmmanuel Vadot RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
23677f22241SEmmanuel Vadot
23777f22241SEmmanuel Vadot /* Setting postdiv and refdiv */
23877f22241SEmmanuel Vadot reg = 0;
23977f22241SEmmanuel Vadot reg |= RK3066_CLK_PLL_POSTDIV_MASK << 16;
24077f22241SEmmanuel Vadot reg |= (rates->postdiv1 - 1) << RK3066_CLK_PLL_POSTDIV_SHIFT;
24177f22241SEmmanuel Vadot
24277f22241SEmmanuel Vadot reg |= RK3066_CLK_PLL_REFDIV_MASK << 16;
24377f22241SEmmanuel Vadot reg |= (rates->refdiv - 1)<< RK3066_CLK_PLL_REFDIV_SHIFT;
24477f22241SEmmanuel Vadot
24577f22241SEmmanuel Vadot dprintf("Set PLL_CON0 to %x\n", reg);
24677f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset, reg);
24777f22241SEmmanuel Vadot
24877f22241SEmmanuel Vadot
24977f22241SEmmanuel Vadot /* Setting fbdiv (no write mask)*/
25077f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 4, ®);
25177f22241SEmmanuel Vadot reg &= ~RK3066_CLK_PLL_FBDIV_MASK;
25277f22241SEmmanuel Vadot reg |= RK3066_CLK_PLL_FBDIV_MASK << 16;
25377f22241SEmmanuel Vadot reg = (rates->fbdiv - 1) << RK3066_CLK_PLL_FBDIV_SHIFT;
25477f22241SEmmanuel Vadot
25577f22241SEmmanuel Vadot dprintf("Set PLL_CON1 to %x\n", reg);
25677f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x4, reg);
25777f22241SEmmanuel Vadot
25877f22241SEmmanuel Vadot /* PLL loop bandwidth adjust */
25977f22241SEmmanuel Vadot reg = rates->bwadj - 1;
26077f22241SEmmanuel Vadot dprintf("Set PLL_CON2 to %x (%x)\n", reg, rates->bwadj);
26177f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x8, reg);
26277f22241SEmmanuel Vadot
26377f22241SEmmanuel Vadot /* Clear reset */
26477f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 12,
26577f22241SEmmanuel Vadot RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
26677f22241SEmmanuel Vadot DELAY(100000);
26777f22241SEmmanuel Vadot
26877f22241SEmmanuel Vadot /* Reading lock */
26977f22241SEmmanuel Vadot for (timeout = 1000; timeout >= 0; timeout--) {
27077f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 0x4, ®);
27177f22241SEmmanuel Vadot if ((reg & RK3066_CLK_PLL_LOCK_MASK) != 0)
27277f22241SEmmanuel Vadot break;
27377f22241SEmmanuel Vadot DELAY(1);
27477f22241SEmmanuel Vadot }
27577f22241SEmmanuel Vadot
27677f22241SEmmanuel Vadot rv = 0;
27777f22241SEmmanuel Vadot if (timeout < 0) {
27877f22241SEmmanuel Vadot device_printf(clknode_get_device(clk),
27977f22241SEmmanuel Vadot "%s - Timedout while waiting for lock.\n",
28077f22241SEmmanuel Vadot clknode_get_name(clk));
28177f22241SEmmanuel Vadot dprintf("PLL_CON1: %x\n", reg);
28277f22241SEmmanuel Vadot rv = ETIMEDOUT;
28377f22241SEmmanuel Vadot }
28477f22241SEmmanuel Vadot
28577f22241SEmmanuel Vadot /* Set back to normal mode */
28677f22241SEmmanuel Vadot reg = (RK3066_CLK_PLL_MODE_NORMAL << sc->mode_shift);
28777f22241SEmmanuel Vadot reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
28877f22241SEmmanuel Vadot RK_CLK_PLL_MASK_SHIFT;
28977f22241SEmmanuel Vadot dprintf("Set PLL_MODEREG to %x\n", reg);
29077f22241SEmmanuel Vadot WRITE4(clk, sc->mode_reg, reg);
29177f22241SEmmanuel Vadot
29277f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
29377f22241SEmmanuel Vadot *stop = 1;
29477f22241SEmmanuel Vadot rv = clknode_set_parent_by_idx(clk, 1);
29577f22241SEmmanuel Vadot return (rv);
29677f22241SEmmanuel Vadot }
29777f22241SEmmanuel Vadot
29877f22241SEmmanuel Vadot static clknode_method_t rk3066_clk_pll_clknode_methods[] = {
29977f22241SEmmanuel Vadot /* Device interface */
30077f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_init, rk3066_clk_pll_init),
30177f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
30277f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_recalc_freq, rk3066_clk_pll_recalc),
30377f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_freq, rk3066_clk_pll_set_freq),
30477f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_mux, rk3066_clk_pll_set_mux),
30577f22241SEmmanuel Vadot CLKNODEMETHOD_END
30677f22241SEmmanuel Vadot };
30777f22241SEmmanuel Vadot
30877f22241SEmmanuel Vadot DEFINE_CLASS_1(rk3066_clk_pll_clknode, rk3066_clk_pll_clknode_class,
30977f22241SEmmanuel Vadot rk3066_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
31077f22241SEmmanuel Vadot
31177f22241SEmmanuel Vadot int
rk3066_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)31277f22241SEmmanuel Vadot rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
31377f22241SEmmanuel Vadot {
31477f22241SEmmanuel Vadot struct clknode *clk;
31577f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
31677f22241SEmmanuel Vadot
31777f22241SEmmanuel Vadot clk = clknode_create(clkdom, &rk3066_clk_pll_clknode_class,
31877f22241SEmmanuel Vadot &clkdef->clkdef);
31977f22241SEmmanuel Vadot if (clk == NULL)
32077f22241SEmmanuel Vadot return (1);
32177f22241SEmmanuel Vadot
32277f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
32377f22241SEmmanuel Vadot
32477f22241SEmmanuel Vadot sc->base_offset = clkdef->base_offset;
32577f22241SEmmanuel Vadot sc->gate_offset = clkdef->gate_offset;
32677f22241SEmmanuel Vadot sc->gate_shift = clkdef->gate_shift;
32777f22241SEmmanuel Vadot sc->mode_reg = clkdef->mode_reg;
32877f22241SEmmanuel Vadot sc->mode_shift = clkdef->mode_shift;
32977f22241SEmmanuel Vadot sc->flags = clkdef->flags;
33077f22241SEmmanuel Vadot sc->rates = clkdef->rates;
33177f22241SEmmanuel Vadot sc->frac_rates = clkdef->frac_rates;
33277f22241SEmmanuel Vadot
33377f22241SEmmanuel Vadot clknode_register(clkdom, clk);
33477f22241SEmmanuel Vadot
33577f22241SEmmanuel Vadot return (0);
33677f22241SEmmanuel Vadot }
33777f22241SEmmanuel Vadot
33877f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FBDIV_OFFSET 0
33977f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FBDIV_SHIFT 0
34077f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF
34177f22241SEmmanuel Vadot
34277f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0
34377f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12
34477f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000
34577f22241SEmmanuel Vadot
34677f22241SEmmanuel Vadot #define RK3328_CLK_PLL_DSMPD_OFFSET 4
34777f22241SEmmanuel Vadot #define RK3328_CLK_PLL_DSMPD_SHIFT 12
34877f22241SEmmanuel Vadot #define RK3328_CLK_PLL_DSMPD_MASK 0x1000
34977f22241SEmmanuel Vadot
35077f22241SEmmanuel Vadot #define RK3328_CLK_PLL_REFDIV_OFFSET 4
35177f22241SEmmanuel Vadot #define RK3328_CLK_PLL_REFDIV_SHIFT 0
35277f22241SEmmanuel Vadot #define RK3328_CLK_PLL_REFDIV_MASK 0x3F
35377f22241SEmmanuel Vadot
35477f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4
35577f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6
35677f22241SEmmanuel Vadot #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0
35777f22241SEmmanuel Vadot
35877f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FRAC_OFFSET 8
35977f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FRAC_SHIFT 0
36077f22241SEmmanuel Vadot #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF
36177f22241SEmmanuel Vadot
36277f22241SEmmanuel Vadot #define RK3328_CLK_PLL_LOCK_MASK 0x400
36377f22241SEmmanuel Vadot
36477f22241SEmmanuel Vadot #define RK3328_CLK_PLL_MODE_SLOW 0
36577f22241SEmmanuel Vadot #define RK3328_CLK_PLL_MODE_NORMAL 1
36677f22241SEmmanuel Vadot #define RK3328_CLK_PLL_MODE_MASK 0x1
36777f22241SEmmanuel Vadot
36877f22241SEmmanuel Vadot static int
rk3328_clk_pll_init(struct clknode * clk,device_t dev)36977f22241SEmmanuel Vadot rk3328_clk_pll_init(struct clknode *clk, device_t dev)
37077f22241SEmmanuel Vadot {
37177f22241SEmmanuel Vadot clknode_init_parent_idx(clk, 0);
37277f22241SEmmanuel Vadot
37377f22241SEmmanuel Vadot return (0);
37477f22241SEmmanuel Vadot }
37577f22241SEmmanuel Vadot
37677f22241SEmmanuel Vadot static int
rk3328_clk_pll_recalc(struct clknode * clk,uint64_t * freq)37777f22241SEmmanuel Vadot rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
37877f22241SEmmanuel Vadot {
37977f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
38077f22241SEmmanuel Vadot uint64_t rate;
38177f22241SEmmanuel Vadot uint32_t dsmpd, refdiv, fbdiv;
38277f22241SEmmanuel Vadot uint32_t postdiv1, postdiv2, frac;
38377f22241SEmmanuel Vadot uint32_t raw1, raw2, raw3;
38477f22241SEmmanuel Vadot
38577f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
38677f22241SEmmanuel Vadot
38777f22241SEmmanuel Vadot DEVICE_LOCK(clk);
38877f22241SEmmanuel Vadot
38977f22241SEmmanuel Vadot READ4(clk, sc->base_offset, &raw1);
39077f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 4, &raw2);
39177f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 8, &raw3);
39277f22241SEmmanuel Vadot
39377f22241SEmmanuel Vadot fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
39477f22241SEmmanuel Vadot postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
39577f22241SEmmanuel Vadot
39677f22241SEmmanuel Vadot dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
39777f22241SEmmanuel Vadot refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
39877f22241SEmmanuel Vadot postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
39977f22241SEmmanuel Vadot
40077f22241SEmmanuel Vadot frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
40177f22241SEmmanuel Vadot
40277f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
40377f22241SEmmanuel Vadot
40477f22241SEmmanuel Vadot rate = *freq * fbdiv / refdiv;
40577f22241SEmmanuel Vadot if (dsmpd == 0) {
40677f22241SEmmanuel Vadot /* Fractional mode */
40777f22241SEmmanuel Vadot uint64_t frac_rate;
40877f22241SEmmanuel Vadot
40977f22241SEmmanuel Vadot frac_rate = *freq * frac / refdiv;
41077f22241SEmmanuel Vadot rate += frac_rate >> 24;
41177f22241SEmmanuel Vadot }
41277f22241SEmmanuel Vadot
41377f22241SEmmanuel Vadot *freq = rate / postdiv1 / postdiv2;
41477f22241SEmmanuel Vadot
41577f22241SEmmanuel Vadot if (*freq % 2)
41677f22241SEmmanuel Vadot *freq = *freq + 1;
41777f22241SEmmanuel Vadot
41877f22241SEmmanuel Vadot return (0);
41977f22241SEmmanuel Vadot }
42077f22241SEmmanuel Vadot
42177f22241SEmmanuel Vadot static int
rk3328_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)42277f22241SEmmanuel Vadot rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
42377f22241SEmmanuel Vadot int flags, int *stop)
42477f22241SEmmanuel Vadot {
42577f22241SEmmanuel Vadot struct rk_clk_pll_rate *rates;
42677f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
42777f22241SEmmanuel Vadot uint32_t reg;
42877f22241SEmmanuel Vadot int timeout;
42977f22241SEmmanuel Vadot
43077f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
43177f22241SEmmanuel Vadot
43277f22241SEmmanuel Vadot if (sc->rates)
43377f22241SEmmanuel Vadot rates = sc->rates;
43477f22241SEmmanuel Vadot else if (sc->frac_rates)
43577f22241SEmmanuel Vadot rates = sc->frac_rates;
43677f22241SEmmanuel Vadot else
43777f22241SEmmanuel Vadot return (EINVAL);
43877f22241SEmmanuel Vadot
43977f22241SEmmanuel Vadot for (; rates->freq; rates++) {
44077f22241SEmmanuel Vadot if (rates->freq == *fout)
44177f22241SEmmanuel Vadot break;
44277f22241SEmmanuel Vadot }
44377f22241SEmmanuel Vadot if (rates->freq == 0) {
44477f22241SEmmanuel Vadot *stop = 1;
44577f22241SEmmanuel Vadot return (EINVAL);
44677f22241SEmmanuel Vadot }
44777f22241SEmmanuel Vadot
44877f22241SEmmanuel Vadot DEVICE_LOCK(clk);
44977f22241SEmmanuel Vadot
45077f22241SEmmanuel Vadot /* Setting to slow mode during frequency change */
45177f22241SEmmanuel Vadot reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
45277f22241SEmmanuel Vadot RK_CLK_PLL_MASK_SHIFT;
45377f22241SEmmanuel Vadot dprintf("Set PLL_MODEREG to %x\n", reg);
45477f22241SEmmanuel Vadot WRITE4(clk, sc->mode_reg, reg);
45577f22241SEmmanuel Vadot
45677f22241SEmmanuel Vadot /* Setting postdiv1 and fbdiv */
45777f22241SEmmanuel Vadot reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
45877f22241SEmmanuel Vadot (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
45977f22241SEmmanuel Vadot reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
46077f22241SEmmanuel Vadot dprintf("Set PLL_CON0 to %x\n", reg);
46177f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset, reg);
46277f22241SEmmanuel Vadot
46377f22241SEmmanuel Vadot /* Setting dsmpd, postdiv2 and refdiv */
46477f22241SEmmanuel Vadot reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
46577f22241SEmmanuel Vadot (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
46677f22241SEmmanuel Vadot (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
46777f22241SEmmanuel Vadot reg |= (RK3328_CLK_PLL_DSMPD_MASK |
46877f22241SEmmanuel Vadot RK3328_CLK_PLL_POSTDIV2_MASK |
46977f22241SEmmanuel Vadot RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
47077f22241SEmmanuel Vadot dprintf("Set PLL_CON1 to %x\n", reg);
47177f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x4, reg);
47277f22241SEmmanuel Vadot
47377f22241SEmmanuel Vadot /* Setting frac */
47477f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 0x8, ®);
47577f22241SEmmanuel Vadot reg &= ~RK3328_CLK_PLL_FRAC_MASK;
47677f22241SEmmanuel Vadot reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
47777f22241SEmmanuel Vadot dprintf("Set PLL_CON2 to %x\n", reg);
47877f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x8, reg);
47977f22241SEmmanuel Vadot
48077f22241SEmmanuel Vadot /* Reading lock */
48177f22241SEmmanuel Vadot for (timeout = 1000; timeout; timeout--) {
48277f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 0x4, ®);
48377f22241SEmmanuel Vadot if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
48477f22241SEmmanuel Vadot break;
48577f22241SEmmanuel Vadot DELAY(1);
48677f22241SEmmanuel Vadot }
48777f22241SEmmanuel Vadot
48877f22241SEmmanuel Vadot /* Set back to normal mode */
48977f22241SEmmanuel Vadot reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
49077f22241SEmmanuel Vadot reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
49177f22241SEmmanuel Vadot RK_CLK_PLL_MASK_SHIFT;
49277f22241SEmmanuel Vadot dprintf("Set PLL_MODEREG to %x\n", reg);
49377f22241SEmmanuel Vadot WRITE4(clk, sc->mode_reg, reg);
49477f22241SEmmanuel Vadot
49577f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
49677f22241SEmmanuel Vadot
49777f22241SEmmanuel Vadot *stop = 1;
49877f22241SEmmanuel Vadot return (0);
49977f22241SEmmanuel Vadot }
50077f22241SEmmanuel Vadot
50177f22241SEmmanuel Vadot static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
50277f22241SEmmanuel Vadot /* Device interface */
50377f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init),
50477f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
50577f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc),
50677f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq),
50777f22241SEmmanuel Vadot CLKNODEMETHOD_END
50877f22241SEmmanuel Vadot };
50977f22241SEmmanuel Vadot
51077f22241SEmmanuel Vadot DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
51177f22241SEmmanuel Vadot rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
51277f22241SEmmanuel Vadot
51377f22241SEmmanuel Vadot int
rk3328_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)51477f22241SEmmanuel Vadot rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
51577f22241SEmmanuel Vadot {
51677f22241SEmmanuel Vadot struct clknode *clk;
51777f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
51877f22241SEmmanuel Vadot
51977f22241SEmmanuel Vadot clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
52077f22241SEmmanuel Vadot &clkdef->clkdef);
52177f22241SEmmanuel Vadot if (clk == NULL)
52277f22241SEmmanuel Vadot return (1);
52377f22241SEmmanuel Vadot
52477f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
52577f22241SEmmanuel Vadot
52677f22241SEmmanuel Vadot sc->base_offset = clkdef->base_offset;
52777f22241SEmmanuel Vadot sc->gate_offset = clkdef->gate_offset;
52877f22241SEmmanuel Vadot sc->gate_shift = clkdef->gate_shift;
52977f22241SEmmanuel Vadot sc->mode_reg = clkdef->mode_reg;
53077f22241SEmmanuel Vadot sc->mode_shift = clkdef->mode_shift;
53177f22241SEmmanuel Vadot sc->flags = clkdef->flags;
53277f22241SEmmanuel Vadot sc->rates = clkdef->rates;
53377f22241SEmmanuel Vadot sc->frac_rates = clkdef->frac_rates;
53477f22241SEmmanuel Vadot
53577f22241SEmmanuel Vadot clknode_register(clkdom, clk);
53677f22241SEmmanuel Vadot
53777f22241SEmmanuel Vadot return (0);
53877f22241SEmmanuel Vadot }
53977f22241SEmmanuel Vadot
54077f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FBDIV_OFFSET 0
54177f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FBDIV_SHIFT 0
54277f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF
54377f22241SEmmanuel Vadot
54477f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4
54577f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12
54677f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000
54777f22241SEmmanuel Vadot
54877f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4
54977f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8
55077f22241SEmmanuel Vadot #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700
55177f22241SEmmanuel Vadot
55277f22241SEmmanuel Vadot #define RK3399_CLK_PLL_REFDIV_OFFSET 4
55377f22241SEmmanuel Vadot #define RK3399_CLK_PLL_REFDIV_SHIFT 0
55477f22241SEmmanuel Vadot #define RK3399_CLK_PLL_REFDIV_MASK 0x3F
55577f22241SEmmanuel Vadot
55677f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FRAC_OFFSET 8
55777f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FRAC_SHIFT 0
55877f22241SEmmanuel Vadot #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF
55977f22241SEmmanuel Vadot
56077f22241SEmmanuel Vadot #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC
56177f22241SEmmanuel Vadot #define RK3399_CLK_PLL_DSMPD_SHIFT 3
56277f22241SEmmanuel Vadot #define RK3399_CLK_PLL_DSMPD_MASK 0x8
56377f22241SEmmanuel Vadot
56477f22241SEmmanuel Vadot #define RK3399_CLK_PLL_LOCK_OFFSET 8
56577f22241SEmmanuel Vadot #define RK3399_CLK_PLL_LOCK_MASK 0x400
56677f22241SEmmanuel Vadot
56777f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_OFFSET 0xC
56877f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_MASK 0x300
56977f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_SLOW 0
57077f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_NORMAL 1
57177f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_DEEPSLOW 2
57277f22241SEmmanuel Vadot #define RK3399_CLK_PLL_MODE_SHIFT 8
57377f22241SEmmanuel Vadot
57477f22241SEmmanuel Vadot #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000
57577f22241SEmmanuel Vadot
57677f22241SEmmanuel Vadot static int
rk3399_clk_pll_init(struct clknode * clk,device_t dev)57777f22241SEmmanuel Vadot rk3399_clk_pll_init(struct clknode *clk, device_t dev)
57877f22241SEmmanuel Vadot {
57977f22241SEmmanuel Vadot clknode_init_parent_idx(clk, 0);
58077f22241SEmmanuel Vadot
58177f22241SEmmanuel Vadot return (0);
58277f22241SEmmanuel Vadot }
58377f22241SEmmanuel Vadot
58477f22241SEmmanuel Vadot static int
rk3399_clk_pll_recalc(struct clknode * clk,uint64_t * freq)58577f22241SEmmanuel Vadot rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
58677f22241SEmmanuel Vadot {
58777f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
58877f22241SEmmanuel Vadot uint32_t dsmpd, refdiv, fbdiv;
58977f22241SEmmanuel Vadot uint32_t postdiv1, postdiv2, fracdiv;
59077f22241SEmmanuel Vadot uint32_t con1, con2, con3, con4;
59177f22241SEmmanuel Vadot uint64_t foutvco;
59277f22241SEmmanuel Vadot uint32_t mode;
59377f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
59477f22241SEmmanuel Vadot
59577f22241SEmmanuel Vadot DEVICE_LOCK(clk);
59677f22241SEmmanuel Vadot READ4(clk, sc->base_offset, &con1);
59777f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 4, &con2);
59877f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 8, &con3);
59977f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 0xC, &con4);
60077f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
60177f22241SEmmanuel Vadot
60277f22241SEmmanuel Vadot /*
60377f22241SEmmanuel Vadot * if we are in slow mode the output freq
60477f22241SEmmanuel Vadot * is the parent one, the 24Mhz external oscillator
60577f22241SEmmanuel Vadot * if we are in deep mode the output freq is 32.768khz
60677f22241SEmmanuel Vadot */
60777f22241SEmmanuel Vadot mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;
60877f22241SEmmanuel Vadot if (mode == RK3399_CLK_PLL_MODE_SLOW) {
60977f22241SEmmanuel Vadot dprintf("pll in slow mode, con4=%x\n", con4);
61077f22241SEmmanuel Vadot return (0);
61177f22241SEmmanuel Vadot } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
61277f22241SEmmanuel Vadot dprintf("pll in deep slow, con4=%x\n", con4);
61377f22241SEmmanuel Vadot *freq = 32768;
61477f22241SEmmanuel Vadot return (0);
61577f22241SEmmanuel Vadot }
61677f22241SEmmanuel Vadot
61777f22241SEmmanuel Vadot dprintf("con0: %x\n", con1);
61877f22241SEmmanuel Vadot dprintf("con1: %x\n", con2);
61977f22241SEmmanuel Vadot dprintf("con2: %x\n", con3);
62077f22241SEmmanuel Vadot dprintf("con3: %x\n", con4);
62177f22241SEmmanuel Vadot
62277f22241SEmmanuel Vadot fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK)
62377f22241SEmmanuel Vadot >> RK3399_CLK_PLL_FBDIV_SHIFT;
62477f22241SEmmanuel Vadot
62577f22241SEmmanuel Vadot postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK)
62677f22241SEmmanuel Vadot >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
62777f22241SEmmanuel Vadot postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK)
62877f22241SEmmanuel Vadot >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
62977f22241SEmmanuel Vadot refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK)
63077f22241SEmmanuel Vadot >> RK3399_CLK_PLL_REFDIV_SHIFT;
63177f22241SEmmanuel Vadot
63277f22241SEmmanuel Vadot fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK)
63377f22241SEmmanuel Vadot >> RK3399_CLK_PLL_FRAC_SHIFT;
63477f22241SEmmanuel Vadot fracdiv >>= 24;
63577f22241SEmmanuel Vadot
63677f22241SEmmanuel Vadot dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
63777f22241SEmmanuel Vadot
63877f22241SEmmanuel Vadot dprintf("fbdiv: %d\n", fbdiv);
63977f22241SEmmanuel Vadot dprintf("postdiv1: %d\n", postdiv1);
64077f22241SEmmanuel Vadot dprintf("postdiv2: %d\n", postdiv2);
64177f22241SEmmanuel Vadot dprintf("refdiv: %d\n", refdiv);
64277f22241SEmmanuel Vadot dprintf("fracdiv: %d\n", fracdiv);
64377f22241SEmmanuel Vadot dprintf("dsmpd: %d\n", dsmpd);
64477f22241SEmmanuel Vadot
64577f22241SEmmanuel Vadot dprintf("parent freq=%ju\n", *freq);
64677f22241SEmmanuel Vadot
64777f22241SEmmanuel Vadot if (dsmpd == 0) {
64877f22241SEmmanuel Vadot /* Fractional mode */
64977f22241SEmmanuel Vadot foutvco = *freq / refdiv * (fbdiv + fracdiv);
65077f22241SEmmanuel Vadot } else {
65177f22241SEmmanuel Vadot /* Integer mode */
65277f22241SEmmanuel Vadot foutvco = *freq / refdiv * fbdiv;
65377f22241SEmmanuel Vadot }
65477f22241SEmmanuel Vadot dprintf("foutvco: %ju\n", foutvco);
65577f22241SEmmanuel Vadot
65677f22241SEmmanuel Vadot *freq = foutvco / postdiv1 / postdiv2;
65777f22241SEmmanuel Vadot dprintf("freq: %ju\n", *freq);
65877f22241SEmmanuel Vadot
65977f22241SEmmanuel Vadot return (0);
66077f22241SEmmanuel Vadot }
66177f22241SEmmanuel Vadot
66277f22241SEmmanuel Vadot static int
rk3399_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)66377f22241SEmmanuel Vadot rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
66477f22241SEmmanuel Vadot int flags, int *stop)
66577f22241SEmmanuel Vadot {
66677f22241SEmmanuel Vadot struct rk_clk_pll_rate *rates;
66777f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
66877f22241SEmmanuel Vadot uint32_t reg;
66977f22241SEmmanuel Vadot int timeout;
67077f22241SEmmanuel Vadot
67177f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
67277f22241SEmmanuel Vadot
67377f22241SEmmanuel Vadot if (sc->rates)
67477f22241SEmmanuel Vadot rates = sc->rates;
67577f22241SEmmanuel Vadot else if (sc->frac_rates)
67677f22241SEmmanuel Vadot rates = sc->frac_rates;
67777f22241SEmmanuel Vadot else
67877f22241SEmmanuel Vadot return (EINVAL);
67977f22241SEmmanuel Vadot
68077f22241SEmmanuel Vadot for (; rates->freq; rates++) {
68177f22241SEmmanuel Vadot if (rates->freq == *fout)
68277f22241SEmmanuel Vadot break;
68377f22241SEmmanuel Vadot }
68477f22241SEmmanuel Vadot if (rates->freq == 0) {
68577f22241SEmmanuel Vadot *stop = 1;
68677f22241SEmmanuel Vadot return (EINVAL);
68777f22241SEmmanuel Vadot }
68877f22241SEmmanuel Vadot
68977f22241SEmmanuel Vadot DEVICE_LOCK(clk);
69077f22241SEmmanuel Vadot
69177f22241SEmmanuel Vadot /* Set to slow mode during frequency change */
69277f22241SEmmanuel Vadot reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
69377f22241SEmmanuel Vadot reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
69477f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0xC, reg);
69577f22241SEmmanuel Vadot
69677f22241SEmmanuel Vadot /* Setting fbdiv */
69777f22241SEmmanuel Vadot reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
69877f22241SEmmanuel Vadot reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
69977f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset, reg);
70077f22241SEmmanuel Vadot
70177f22241SEmmanuel Vadot /* Setting postdiv1, postdiv2 and refdiv */
70277f22241SEmmanuel Vadot reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
70377f22241SEmmanuel Vadot reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
70477f22241SEmmanuel Vadot reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
70577f22241SEmmanuel Vadot reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
70677f22241SEmmanuel Vadot RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
70777f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x4, reg);
70877f22241SEmmanuel Vadot
70977f22241SEmmanuel Vadot /* Setting frac */
71077f22241SEmmanuel Vadot READ4(clk, sc->base_offset + 0x8, ®);
71177f22241SEmmanuel Vadot reg &= ~RK3399_CLK_PLL_FRAC_MASK;
71277f22241SEmmanuel Vadot reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
71377f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
71477f22241SEmmanuel Vadot
71577f22241SEmmanuel Vadot /* Set dsmpd */
71677f22241SEmmanuel Vadot reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
71777f22241SEmmanuel Vadot reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
71877f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0xC, reg);
71977f22241SEmmanuel Vadot
72077f22241SEmmanuel Vadot /* Reading lock */
72177f22241SEmmanuel Vadot for (timeout = 1000; timeout; timeout--) {
72277f22241SEmmanuel Vadot READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®);
72377f22241SEmmanuel Vadot if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
72477f22241SEmmanuel Vadot break;
72577f22241SEmmanuel Vadot DELAY(1);
72677f22241SEmmanuel Vadot }
72777f22241SEmmanuel Vadot
72877f22241SEmmanuel Vadot /* Set back to normal mode */
72977f22241SEmmanuel Vadot reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
73077f22241SEmmanuel Vadot reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
73177f22241SEmmanuel Vadot WRITE4(clk, sc->base_offset + 0xC, reg);
73277f22241SEmmanuel Vadot
73377f22241SEmmanuel Vadot DEVICE_UNLOCK(clk);
73477f22241SEmmanuel Vadot
73577f22241SEmmanuel Vadot *stop = 1;
73677f22241SEmmanuel Vadot return (0);
73777f22241SEmmanuel Vadot }
73877f22241SEmmanuel Vadot
73977f22241SEmmanuel Vadot static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
74077f22241SEmmanuel Vadot /* Device interface */
74177f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init),
74277f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
74377f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc),
74477f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq),
74577f22241SEmmanuel Vadot CLKNODEMETHOD_END
74677f22241SEmmanuel Vadot };
74777f22241SEmmanuel Vadot
74877f22241SEmmanuel Vadot DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
74977f22241SEmmanuel Vadot rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
75077f22241SEmmanuel Vadot
75177f22241SEmmanuel Vadot int
rk3399_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)75277f22241SEmmanuel Vadot rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
75377f22241SEmmanuel Vadot {
75477f22241SEmmanuel Vadot struct clknode *clk;
75577f22241SEmmanuel Vadot struct rk_clk_pll_sc *sc;
75677f22241SEmmanuel Vadot
75777f22241SEmmanuel Vadot clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
75877f22241SEmmanuel Vadot &clkdef->clkdef);
75977f22241SEmmanuel Vadot if (clk == NULL)
76077f22241SEmmanuel Vadot return (1);
76177f22241SEmmanuel Vadot
76277f22241SEmmanuel Vadot sc = clknode_get_softc(clk);
76377f22241SEmmanuel Vadot
76477f22241SEmmanuel Vadot sc->base_offset = clkdef->base_offset;
76577f22241SEmmanuel Vadot sc->gate_offset = clkdef->gate_offset;
76677f22241SEmmanuel Vadot sc->gate_shift = clkdef->gate_shift;
76777f22241SEmmanuel Vadot sc->flags = clkdef->flags;
76877f22241SEmmanuel Vadot sc->rates = clkdef->rates;
76977f22241SEmmanuel Vadot sc->frac_rates = clkdef->frac_rates;
77077f22241SEmmanuel Vadot
77177f22241SEmmanuel Vadot clknode_register(clkdom, clk);
77277f22241SEmmanuel Vadot
77377f22241SEmmanuel Vadot return (0);
77477f22241SEmmanuel Vadot }
775