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