Path: blob/main/sys/dev/clk/xilinx/zynqmp_clk_pll.c
39537 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/cdefs.h>2829#include <sys/param.h>30#include <sys/systm.h>31#include <sys/bus.h>3233#include <dev/clk/clk.h>3435#include <dev/clk/xilinx/zynqmp_clk_pll.h>3637#include "clkdev_if.h"38#include "zynqmp_firmware_if.h"3940struct zynqmp_clk_pll_softc {41device_t firmware;42uint32_t id;43};4445enum pll_mode {46PLL_MODE_INT = 0,47PLL_MODE_FRAC,48PLL_MODE_ERROR,49};5051static int52zynqmp_clk_pll_init(struct clknode *clk, device_t dev)53{5455clknode_init_parent_idx(clk, 0);56return (0);57}5859static int60zynqmp_clk_pll_recalc(struct clknode *clk, uint64_t *freq)61{62struct zynqmp_clk_pll_softc *sc;63uint64_t pll_freq, pll_frac;64uint32_t div, mode, frac;65int rv;6667sc = clknode_get_softc(clk);68rv = ZYNQMP_FIRMWARE_CLOCK_GETDIVIDER(sc->firmware, sc->id, &div);69if (rv != 0) {70printf("%s: Error while getting divider for %s\n",71__func__,72clknode_get_name(clk));73}74rv = ZYNQMP_FIRMWARE_PLL_GET_MODE(sc->firmware, sc->id, &mode);75if (rv != 0) {76printf("%s: Error while getting mode for %s\n",77__func__,78clknode_get_name(clk));79}80if (mode == PLL_MODE_ERROR)81return (0);8283pll_freq = *freq * div;84if (mode == PLL_MODE_FRAC) {85ZYNQMP_FIRMWARE_PLL_GET_FRAC_DATA(sc->firmware, sc->id, &frac);86pll_frac = (*freq * frac) / (1 << 16);87pll_freq += pll_frac;88}8990*freq = pll_freq;91return (0);92}9394static int95zynqmp_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,96int flags, int *stop)97{9899/* TODO probably at one point */100return (ENOTSUP);101}102103static clknode_method_t zynqmp_clk_pll_clknode_methods[] = {104/* Device interface */105CLKNODEMETHOD(clknode_init, zynqmp_clk_pll_init),106CLKNODEMETHOD(clknode_recalc_freq, zynqmp_clk_pll_recalc),107CLKNODEMETHOD(clknode_set_freq, zynqmp_clk_pll_set_freq),108CLKNODEMETHOD_END109};110111DEFINE_CLASS_1(zynqmp_clk_pll_clknode, zynqmp_clk_pll_clknode_class,112zynqmp_clk_pll_clknode_methods, sizeof(struct zynqmp_clk_pll_softc), clknode_class);113114int115zynqmp_clk_pll_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)116{117struct clknode *clk;118struct zynqmp_clk_pll_softc *sc;119uint32_t fw_clk_id;120121fw_clk_id = clkdef->id - 1;122clkdef->id = 0;123clk = clknode_create(clkdom, &zynqmp_clk_pll_clknode_class, clkdef);124if (clk == NULL)125return (1);126sc = clknode_get_softc(clk);127sc->id = fw_clk_id;128sc->firmware = fw;129clknode_register(clkdom, clk);130return (0);131}132133134