1*e48dcdadSClément Léger // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2*e48dcdadSClément Léger /*
3*e48dcdadSClément Léger * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4*e48dcdadSClément Léger * Copyright (C) 2021 Microchip
5*e48dcdadSClément Léger */
6*e48dcdadSClément Léger
7*e48dcdadSClément Léger #include <io.h>
8*e48dcdadSClément Léger #include <kernel/delay.h>
9*e48dcdadSClément Léger #include <kernel/panic.h>
10*e48dcdadSClément Léger #include <mm/core_memprot.h>
11*e48dcdadSClément Léger #include <types_ext.h>
12*e48dcdadSClément Léger
13*e48dcdadSClément Léger #include "at91_clk.h"
14*e48dcdadSClément Léger
clk_plldiv_get_rate(struct clk * clk,unsigned long parent_rate)15*e48dcdadSClément Léger static unsigned long clk_plldiv_get_rate(struct clk *clk,
16*e48dcdadSClément Léger unsigned long parent_rate)
17*e48dcdadSClément Léger {
18*e48dcdadSClément Léger struct pmc_data *pmc = clk->priv;
19*e48dcdadSClément Léger unsigned int mckr = io_read32(pmc->base + AT91_PMC_MCKR);
20*e48dcdadSClément Léger
21*e48dcdadSClément Léger if (mckr & AT91_PMC_PLLADIV2)
22*e48dcdadSClément Léger return parent_rate / 2;
23*e48dcdadSClément Léger
24*e48dcdadSClément Léger return parent_rate;
25*e48dcdadSClément Léger }
26*e48dcdadSClément Léger
clk_plldiv_set_rate(struct clk * clk,unsigned long rate,unsigned long parent_rate)27*e48dcdadSClément Léger static TEE_Result clk_plldiv_set_rate(struct clk *clk, unsigned long rate,
28*e48dcdadSClément Léger unsigned long parent_rate)
29*e48dcdadSClément Léger {
30*e48dcdadSClément Léger struct pmc_data *pmc = clk->priv;
31*e48dcdadSClément Léger
32*e48dcdadSClément Léger if (parent_rate != rate && (parent_rate / 2 != rate))
33*e48dcdadSClément Léger return TEE_ERROR_GENERIC;
34*e48dcdadSClément Léger
35*e48dcdadSClément Léger io_clrsetbits32(pmc->base + AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
36*e48dcdadSClément Léger parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
37*e48dcdadSClément Léger
38*e48dcdadSClément Léger return TEE_SUCCESS;
39*e48dcdadSClément Léger }
40*e48dcdadSClément Léger
41*e48dcdadSClément Léger static const struct clk_ops plldiv_ops = {
42*e48dcdadSClément Léger .get_rate = clk_plldiv_get_rate,
43*e48dcdadSClément Léger .set_rate = clk_plldiv_set_rate,
44*e48dcdadSClément Léger };
45*e48dcdadSClément Léger
46*e48dcdadSClément Léger struct clk *
at91_clk_register_plldiv(struct pmc_data * pmc,const char * name,struct clk * parent)47*e48dcdadSClément Léger at91_clk_register_plldiv(struct pmc_data *pmc, const char *name,
48*e48dcdadSClément Léger struct clk *parent)
49*e48dcdadSClément Léger {
50*e48dcdadSClément Léger struct clk *clk = NULL;
51*e48dcdadSClément Léger
52*e48dcdadSClément Léger clk = clk_alloc(name, &plldiv_ops, &parent, 1);
53*e48dcdadSClément Léger if (!clk)
54*e48dcdadSClément Léger return NULL;
55*e48dcdadSClément Léger
56*e48dcdadSClément Léger clk->priv = pmc;
57*e48dcdadSClément Léger clk->flags = CLK_SET_RATE_GATE;
58*e48dcdadSClément Léger
59*e48dcdadSClément Léger if (clk_register(clk)) {
60*e48dcdadSClément Léger clk_free(clk);
61*e48dcdadSClément Léger return NULL;
62*e48dcdadSClément Léger }
63*e48dcdadSClément Léger
64*e48dcdadSClément Léger return clk;
65*e48dcdadSClément Léger }
66