Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/clk/xilinx/zynqmp_clk_pll.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/cdefs.h>
29
30
#include <sys/param.h>
31
#include <sys/systm.h>
32
#include <sys/bus.h>
33
34
#include <dev/clk/clk.h>
35
36
#include <dev/clk/xilinx/zynqmp_clk_pll.h>
37
38
#include "clkdev_if.h"
39
#include "zynqmp_firmware_if.h"
40
41
struct zynqmp_clk_pll_softc {
42
device_t firmware;
43
uint32_t id;
44
};
45
46
enum pll_mode {
47
PLL_MODE_INT = 0,
48
PLL_MODE_FRAC,
49
PLL_MODE_ERROR,
50
};
51
52
static int
53
zynqmp_clk_pll_init(struct clknode *clk, device_t dev)
54
{
55
56
clknode_init_parent_idx(clk, 0);
57
return (0);
58
}
59
60
static int
61
zynqmp_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
62
{
63
struct zynqmp_clk_pll_softc *sc;
64
uint64_t pll_freq, pll_frac;
65
uint32_t div, mode, frac;
66
int rv;
67
68
sc = clknode_get_softc(clk);
69
rv = ZYNQMP_FIRMWARE_CLOCK_GETDIVIDER(sc->firmware, sc->id, &div);
70
if (rv != 0) {
71
printf("%s: Error while getting divider for %s\n",
72
__func__,
73
clknode_get_name(clk));
74
}
75
rv = ZYNQMP_FIRMWARE_PLL_GET_MODE(sc->firmware, sc->id, &mode);
76
if (rv != 0) {
77
printf("%s: Error while getting mode for %s\n",
78
__func__,
79
clknode_get_name(clk));
80
}
81
if (mode == PLL_MODE_ERROR)
82
return (0);
83
84
pll_freq = *freq * div;
85
if (mode == PLL_MODE_FRAC) {
86
ZYNQMP_FIRMWARE_PLL_GET_FRAC_DATA(sc->firmware, sc->id, &frac);
87
pll_frac = (*freq * frac) / (1 << 16);
88
pll_freq += pll_frac;
89
}
90
91
*freq = pll_freq;
92
return (0);
93
}
94
95
static int
96
zynqmp_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
97
int flags, int *stop)
98
{
99
100
/* TODO probably at one point */
101
return (ENOTSUP);
102
}
103
104
static clknode_method_t zynqmp_clk_pll_clknode_methods[] = {
105
/* Device interface */
106
CLKNODEMETHOD(clknode_init, zynqmp_clk_pll_init),
107
CLKNODEMETHOD(clknode_recalc_freq, zynqmp_clk_pll_recalc),
108
CLKNODEMETHOD(clknode_set_freq, zynqmp_clk_pll_set_freq),
109
CLKNODEMETHOD_END
110
};
111
112
DEFINE_CLASS_1(zynqmp_clk_pll_clknode, zynqmp_clk_pll_clknode_class,
113
zynqmp_clk_pll_clknode_methods, sizeof(struct zynqmp_clk_pll_softc), clknode_class);
114
115
int
116
zynqmp_clk_pll_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)
117
{
118
struct clknode *clk;
119
struct zynqmp_clk_pll_softc *sc;
120
uint32_t fw_clk_id;
121
122
fw_clk_id = clkdef->id - 1;
123
clkdef->id = 0;
124
clk = clknode_create(clkdom, &zynqmp_clk_pll_clknode_class, clkdef);
125
if (clk == NULL)
126
return (1);
127
sc = clknode_get_softc(clk);
128
sc->id = fw_clk_id;
129
sc->firmware = fw;
130
clknode_register(clkdom, clk);
131
return (0);
132
}
133
134