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