1*447e3228SClément Léger // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2*447e3228SClément Léger /*
3*447e3228SClément Léger * Copyright (C) 2014 Atmel
4*447e3228SClément Léger *
5*447e3228SClément Léger * Alexandre Belloni <alexandre.belloni@free-electrons.com>
6*447e3228SClément Léger */
7*447e3228SClément Léger
8*447e3228SClément Léger #include <io.h>
9*447e3228SClément Léger #include <kernel/delay.h>
10*447e3228SClément Léger #include <mm/core_memprot.h>
11*447e3228SClément Léger #include <types_ext.h>
12*447e3228SClément Léger
13*447e3228SClément Léger #include "at91_clk.h"
14*447e3228SClément Léger
15*447e3228SClément Léger #define H32MX_MAX_FREQ 90000000
16*447e3228SClément Léger
clk_sama5d4_h32mx_get_rate(struct clk * clk,unsigned long parent_rate)17*447e3228SClément Léger static unsigned long clk_sama5d4_h32mx_get_rate(struct clk *clk,
18*447e3228SClément Léger unsigned long parent_rate)
19*447e3228SClément Léger {
20*447e3228SClément Léger struct pmc_data *pmc = clk->priv;
21*447e3228SClément Léger unsigned int mckr = io_read32(pmc->base + AT91_PMC_MCKR);
22*447e3228SClément Léger
23*447e3228SClément Léger if (mckr & AT91_PMC_H32MXDIV)
24*447e3228SClément Léger return parent_rate / 2;
25*447e3228SClément Léger
26*447e3228SClément Léger if (parent_rate > H32MX_MAX_FREQ)
27*447e3228SClément Léger IMSG("H32MX clock is too fast");
28*447e3228SClément Léger
29*447e3228SClément Léger return parent_rate;
30*447e3228SClément Léger }
31*447e3228SClément Léger
clk_sama5d4_h32mx_set_rate(struct clk * clk,unsigned long rate,unsigned long parent_rate)32*447e3228SClément Léger static TEE_Result clk_sama5d4_h32mx_set_rate(struct clk *clk,
33*447e3228SClément Léger unsigned long rate,
34*447e3228SClément Léger unsigned long parent_rate)
35*447e3228SClément Léger {
36*447e3228SClément Léger struct pmc_data *pmc = clk->priv;
37*447e3228SClément Léger uint32_t mckr = 0;
38*447e3228SClément Léger
39*447e3228SClément Léger if (parent_rate != rate && (parent_rate / 2) != rate)
40*447e3228SClément Léger return TEE_ERROR_BAD_PARAMETERS;
41*447e3228SClément Léger
42*447e3228SClément Léger if ((parent_rate / 2) == rate)
43*447e3228SClément Léger mckr = AT91_PMC_H32MXDIV;
44*447e3228SClément Léger
45*447e3228SClément Léger io_clrsetbits32(pmc->base + AT91_PMC_MCKR, AT91_PMC_H32MXDIV, mckr);
46*447e3228SClément Léger
47*447e3228SClément Léger return TEE_SUCCESS;
48*447e3228SClément Léger }
49*447e3228SClément Léger
50*447e3228SClément Léger static const struct clk_ops h32mx_ops = {
51*447e3228SClément Léger .get_rate = clk_sama5d4_h32mx_get_rate,
52*447e3228SClément Léger .set_rate = clk_sama5d4_h32mx_set_rate,
53*447e3228SClément Léger };
54*447e3228SClément Léger
55*447e3228SClément Léger struct clk *
at91_clk_register_h32mx(struct pmc_data * pmc,const char * name,struct clk * parent)56*447e3228SClément Léger at91_clk_register_h32mx(struct pmc_data *pmc, const char *name,
57*447e3228SClément Léger struct clk *parent)
58*447e3228SClément Léger {
59*447e3228SClément Léger struct clk *clk = NULL;
60*447e3228SClément Léger
61*447e3228SClément Léger clk = clk_alloc(name, &h32mx_ops, &parent, 1);
62*447e3228SClément Léger if (!clk)
63*447e3228SClément Léger return NULL;
64*447e3228SClément Léger
65*447e3228SClément Léger clk->ops = &h32mx_ops;
66*447e3228SClément Léger clk->priv = pmc;
67*447e3228SClément Léger clk->name = name;
68*447e3228SClément Léger clk->flags = CLK_SET_RATE_GATE;
69*447e3228SClément Léger
70*447e3228SClément Léger if (clk_register(clk)) {
71*447e3228SClément Léger clk_free(clk);
72*447e3228SClément Léger return NULL;
73*447e3228SClément Léger }
74*447e3228SClément Léger
75*447e3228SClément Léger return clk;
76*447e3228SClément Léger }
77