xref: /freebsd/sys/arm/mv/clk/a37x0_tbg_pll.c (revision be82b3a0)
1127e4d95SHubert Mazur /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3127e4d95SHubert Mazur  *
4127e4d95SHubert Mazur  * Copyright (c) 2021 Semihalf.
5127e4d95SHubert Mazur  *
6127e4d95SHubert Mazur  * Redistribution and use in source and binary forms, with or without
7127e4d95SHubert Mazur  * modification, are permitted provided that the following conditions
8127e4d95SHubert Mazur  * are met:
9127e4d95SHubert Mazur  * 1. Redistributions of source code must retain the above copyright
10127e4d95SHubert Mazur  *    notice, this list of conditions and the following disclaimer.
11127e4d95SHubert Mazur  * 2. Redistributions in binary form must reproduce the above copyright
12127e4d95SHubert Mazur  *    notice, this list of conditions and the following disclaimer in the
13127e4d95SHubert Mazur  *    documentation and/or other materials provided with the distribution.
14127e4d95SHubert Mazur  *
15127e4d95SHubert Mazur  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16127e4d95SHubert Mazur  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17127e4d95SHubert Mazur  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18127e4d95SHubert Mazur  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19127e4d95SHubert Mazur  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20127e4d95SHubert Mazur  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21127e4d95SHubert Mazur  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22127e4d95SHubert Mazur  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23127e4d95SHubert Mazur  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24127e4d95SHubert Mazur  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25127e4d95SHubert Mazur  * SUCH DAMAGE.
26127e4d95SHubert Mazur  */
27127e4d95SHubert Mazur 
28127e4d95SHubert Mazur #include <sys/param.h>
29127e4d95SHubert Mazur #include <sys/bus.h>
30127e4d95SHubert Mazur #include <sys/rman.h>
31127e4d95SHubert Mazur #include <machine/bus.h>
32127e4d95SHubert Mazur 
33*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
34127e4d95SHubert Mazur 
35127e4d95SHubert Mazur #include <dev/ofw/ofw_bus.h>
36127e4d95SHubert Mazur #include <dev/ofw/ofw_bus_subr.h>
37127e4d95SHubert Mazur 
38127e4d95SHubert Mazur #include "clkdev_if.h"
39127e4d95SHubert Mazur 
40127e4d95SHubert Mazur #include "a37x0_tbg_pll.h"
41127e4d95SHubert Mazur 
42127e4d95SHubert Mazur #define RD4(_clk, offset, val)			\
43127e4d95SHubert Mazur 	CLKDEV_READ_4(clknode_get_device(_clk), offset, val)
44127e4d95SHubert Mazur 
45127e4d95SHubert Mazur struct a37x0_tbg_pll_softc {
46127e4d95SHubert Mazur 	struct a37x0_tbg_pll_reg_def		vcodiv;
47127e4d95SHubert Mazur 	struct a37x0_tbg_pll_reg_def		refdiv;
48127e4d95SHubert Mazur 	struct a37x0_tbg_pll_reg_def		fbdiv;
49127e4d95SHubert Mazur 	struct a37x0_tbg_pll_reg_def		tbg_bypass;
50127e4d95SHubert Mazur };
51127e4d95SHubert Mazur 
52127e4d95SHubert Mazur static int
a37x0_tbg_pll_recalc_freq(struct clknode * clk,uint64_t * freq)53127e4d95SHubert Mazur a37x0_tbg_pll_recalc_freq(struct clknode *clk, uint64_t *freq)
54127e4d95SHubert Mazur {
55127e4d95SHubert Mazur 	struct a37x0_tbg_pll_softc *sc;
56127e4d95SHubert Mazur 	uint32_t vcodiv, fbdiv, refdiv;
57127e4d95SHubert Mazur 	unsigned int val;
58127e4d95SHubert Mazur 
59127e4d95SHubert Mazur 	sc = clknode_get_softc(clk);
60127e4d95SHubert Mazur 
61127e4d95SHubert Mazur 	RD4(clk, sc->tbg_bypass.offset, &val);
62127e4d95SHubert Mazur 	if ((val >> sc->tbg_bypass.shift) & sc->tbg_bypass.mask)
63127e4d95SHubert Mazur 		return 0;
64127e4d95SHubert Mazur 
65127e4d95SHubert Mazur 	RD4(clk, sc->vcodiv.offset, &val);
66127e4d95SHubert Mazur 	vcodiv = 1 << ((val >> sc->vcodiv.shift) & sc->vcodiv.mask);
67127e4d95SHubert Mazur 
68127e4d95SHubert Mazur 	RD4(clk, sc->refdiv.offset, &val);
69127e4d95SHubert Mazur 	refdiv = (val >> sc->refdiv.shift) & sc->refdiv.mask;
70127e4d95SHubert Mazur 
71127e4d95SHubert Mazur 	RD4(clk, sc->fbdiv.offset, &val);
72127e4d95SHubert Mazur 	fbdiv = (val >> sc->fbdiv.shift) & sc->fbdiv.mask;
73127e4d95SHubert Mazur 
74127e4d95SHubert Mazur 	if (refdiv == 0)
75127e4d95SHubert Mazur 		refdiv = 1;
76127e4d95SHubert Mazur 
77127e4d95SHubert Mazur 	*freq = *freq * (fbdiv / refdiv) * 4;
78127e4d95SHubert Mazur 	*freq /= vcodiv;
79127e4d95SHubert Mazur 
80127e4d95SHubert Mazur 	return (0);
81127e4d95SHubert Mazur }
82127e4d95SHubert Mazur 
83127e4d95SHubert Mazur static int
a37x0_tbg_pll_init(struct clknode * clk,device_t dev)84127e4d95SHubert Mazur a37x0_tbg_pll_init(struct clknode *clk, device_t dev)
85127e4d95SHubert Mazur {
86127e4d95SHubert Mazur 
87127e4d95SHubert Mazur 	clknode_init_parent_idx(clk, 0);
88127e4d95SHubert Mazur 
89127e4d95SHubert Mazur 	return (0);
90127e4d95SHubert Mazur }
91127e4d95SHubert Mazur 
92127e4d95SHubert Mazur static clknode_method_t a37x0_tbg_pll_clknode_methods[] = {
93127e4d95SHubert Mazur 	CLKNODEMETHOD(clknode_recalc_freq,	a37x0_tbg_pll_recalc_freq),
94127e4d95SHubert Mazur 	CLKNODEMETHOD(clknode_init,		a37x0_tbg_pll_init),
95127e4d95SHubert Mazur 
96127e4d95SHubert Mazur 	CLKNODEMETHOD_END
97127e4d95SHubert Mazur };
98127e4d95SHubert Mazur 
99127e4d95SHubert Mazur DEFINE_CLASS_1(a37x0_tbg_pll__clknode, a37x0_tbg_pll_clknode_class,
100127e4d95SHubert Mazur     a37x0_tbg_pll_clknode_methods, sizeof(struct a37x0_tbg_pll_softc),
101127e4d95SHubert Mazur     clknode_class);
102127e4d95SHubert Mazur 
103127e4d95SHubert Mazur int
a37x0_tbg_pll_clk_register(struct clkdom * clkdom,const struct a37x0_tbg_pll_clk_def * clkdef)104127e4d95SHubert Mazur a37x0_tbg_pll_clk_register(struct clkdom *clkdom,
105127e4d95SHubert Mazur     const struct a37x0_tbg_pll_clk_def *clkdef)
106127e4d95SHubert Mazur {
107127e4d95SHubert Mazur 	struct a37x0_tbg_pll_softc *sc;
108127e4d95SHubert Mazur 	struct clknode *clk;
109127e4d95SHubert Mazur 
110127e4d95SHubert Mazur 	clk = clknode_create(clkdom, &a37x0_tbg_pll_clknode_class,
111127e4d95SHubert Mazur 	    &clkdef->clkdef);
112127e4d95SHubert Mazur 
113127e4d95SHubert Mazur 	if (clk == NULL)
114127e4d95SHubert Mazur 		return (1);
115127e4d95SHubert Mazur 
116127e4d95SHubert Mazur 	sc = clknode_get_softc(clk);
117127e4d95SHubert Mazur 
118127e4d95SHubert Mazur 	sc->vcodiv = clkdef->vcodiv;
119127e4d95SHubert Mazur 	sc->refdiv = clkdef->refdiv;
120127e4d95SHubert Mazur 	sc->fbdiv = clkdef->fbdiv;
121127e4d95SHubert Mazur 	sc->tbg_bypass = clkdef->tbg_bypass;
122127e4d95SHubert Mazur 
123127e4d95SHubert Mazur 	if (clknode_register(clkdom, clk) == NULL)
124127e4d95SHubert Mazur 		return (1);
125127e4d95SHubert Mazur 
126127e4d95SHubert Mazur 	return (0);
127127e4d95SHubert Mazur }
128