Path: blob/main/sys/arm64/nvidia/tegra210/tegra210_clk_super.c
48266 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright 2020 Michal Meloun <[email protected]>4*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/param.h>28#include <sys/systm.h>29#include <sys/bus.h>30#include <sys/lock.h>31#include <sys/mutex.h>32#include <sys/rman.h>3334#include <machine/bus.h>3536#include <dev/clk/clk.h>3738#include <dt-bindings/clock/tegra210-car.h>39#include "tegra210_car.h"4041struct super_mux_def {42struct clknode_init_def clkdef;43uint32_t base_reg;44uint32_t flags;45};4647#define PLIST(x) static const char *x[]48#define SM(_id, cn, pl, r) \49{ \50.clkdef.id = _id, \51.clkdef.name = cn, \52.clkdef.parent_names = pl, \53.clkdef.parent_cnt = nitems(pl), \54.clkdef.flags = CLK_NODE_STATIC_STRINGS, \55.base_reg = r, \56}575859PLIST(cclk_g_parents) = {60"clk_m", NULL, "clk_s", NULL,61"pllP_out0", "pllP_out4", NULL, NULL,62"pllX_out0", "dfllCPU_out_alias", NULL, NULL,63NULL, NULL, "pllX_out0_alias", "dfllCPU_out",64};6566PLIST(cclk_lp_parents) = {67"clk_m", NULL, "clk_s", NULL,68"pllP_out0", "pllP_out4", NULL, NULL,69"pllX_out0", "dfllCPU_out_alias", NULL, NULL,70NULL, NULL, "pllX_out0_alias", "dfllCPU_out",71};7273PLIST(sclk_parents) = {74"clk_m", "pllC_out1", "pllC4_out3", "pllP_out0",75"pllP_out2", "pllC4_out1", "clk_s", "pllC4_out1",76};7778static struct super_mux_def super_mux_def[] = {79SM(TEGRA210_CLK_CCLK_G, "cclk_g", cclk_g_parents, CCLKG_BURST_POLICY),80SM(TEGRA210_CLK_CCLK_LP, "cclk_lp", cclk_lp_parents, CCLKLP_BURST_POLICY),81SM(TEGRA210_CLK_SCLK, "sclk", sclk_parents, SCLK_BURST_POLICY),82};8384static int super_mux_init(struct clknode *clk, device_t dev);85static int super_mux_set_mux(struct clknode *clk, int idx);8687struct super_mux_sc {88device_t clkdev;89uint32_t base_reg;90uint32_t flags;9192int mux;93};9495static clknode_method_t super_mux_methods[] = {96/* Device interface */97CLKNODEMETHOD(clknode_init, super_mux_init),98CLKNODEMETHOD(clknode_set_mux, super_mux_set_mux),99CLKNODEMETHOD_END100};101DEFINE_CLASS_1(tegra210_super_mux, tegra210_super_mux_class, super_mux_methods,102sizeof(struct super_mux_sc), clknode_class);103104/* Mux status. */105#define SUPER_MUX_STATE_STDBY 0106#define SUPER_MUX_STATE_IDLE 1107#define SUPER_MUX_STATE_RUN 2108#define SUPER_MUX_STATE_IRQ 3109#define SUPER_MUX_STATE_FIQ 4110111/* Mux register bits. */112#define SUPER_MUX_STATE_BIT_SHIFT 28113#define SUPER_MUX_STATE_BIT_MASK 0xF114/* State is Priority encoded */115#define SUPER_MUX_STATE_BIT_STDBY 0x00116#define SUPER_MUX_STATE_BIT_IDLE 0x01117#define SUPER_MUX_STATE_BIT_RUN 0x02118#define SUPER_MUX_STATE_BIT_IRQ 0x04119#define SUPER_MUX_STATE_BIT_FIQ 0x08120121#define SUPER_MUX_MUX_WIDTH 4122123static uint32_t124super_mux_get_state(uint32_t reg)125{126reg = (reg >> SUPER_MUX_STATE_BIT_SHIFT) & SUPER_MUX_STATE_BIT_MASK;127if (reg & SUPER_MUX_STATE_BIT_FIQ)128return (SUPER_MUX_STATE_FIQ);129if (reg & SUPER_MUX_STATE_BIT_IRQ)130return (SUPER_MUX_STATE_IRQ);131if (reg & SUPER_MUX_STATE_BIT_RUN)132return (SUPER_MUX_STATE_RUN);133if (reg & SUPER_MUX_STATE_BIT_IDLE)134return (SUPER_MUX_STATE_IDLE);135return (SUPER_MUX_STATE_STDBY);136}137138static int139super_mux_init(struct clknode *clk, device_t dev)140{141struct super_mux_sc *sc;142uint32_t reg;143int shift, state;144145sc = clknode_get_softc(clk);146147DEVICE_LOCK(sc);148RD4(sc, sc->base_reg, ®);149DEVICE_UNLOCK(sc);150state = super_mux_get_state(reg);151152if ((state != SUPER_MUX_STATE_RUN) &&153(state != SUPER_MUX_STATE_IDLE)) {154panic("Unexpected super mux state: %u", state);155}156157shift = state * SUPER_MUX_MUX_WIDTH;158sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);159160clknode_init_parent_idx(clk, sc->mux);161162return(0);163}164165static int166super_mux_set_mux(struct clknode *clk, int idx)167{168169struct super_mux_sc *sc;170int shift, state;171uint32_t reg, dummy;172173sc = clknode_get_softc(clk);174175DEVICE_LOCK(sc);176RD4(sc, sc->base_reg, ®);177state = super_mux_get_state(reg);178179if ((state != SUPER_MUX_STATE_RUN) &&180(state != SUPER_MUX_STATE_IDLE)) {181panic("Unexpected super mux state: %u", state);182}183184shift = (state - 1) * SUPER_MUX_MUX_WIDTH;185sc->mux = idx;186reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);187reg |= idx << shift;188189WR4(sc, sc->base_reg, reg);190RD4(sc, sc->base_reg, &dummy);191DEVICE_UNLOCK(sc);192193return(0);194}195196static int197super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)198{199struct clknode *clk;200struct super_mux_sc *sc;201202clk = clknode_create(clkdom, &tegra210_super_mux_class,203&clkdef->clkdef);204if (clk == NULL)205return (1);206207sc = clknode_get_softc(clk);208sc->clkdev = clknode_get_device(clk);209sc->base_reg = clkdef->base_reg;210sc->flags = clkdef->flags;211212clknode_register(clkdom, clk);213return (0);214}215216void217tegra210_super_mux_clock(struct tegra210_car_softc *sc)218{219int i, rv;220221for (i = 0; i < nitems(super_mux_def); i++) {222rv = super_mux_register(sc->clkdom, &super_mux_def[i]);223if (rv != 0)224panic("super_mux_register failed");225}226227}228229230