xref: /freebsd/sys/dev/clk/rockchip/rk_clk_pll.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
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, &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, &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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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