1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2 /*
3  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4  *  Copyright (C) 2021 Microchip
5  */
6 
7 #include <io.h>
8 #include <kernel/delay.h>
9 #include <mm/core_memprot.h>
10 #include <types_ext.h>
11 
12 #include "at91_clk.h"
13 
14 #define MASTER_PRES_MASK	0x7
15 #define MASTER_PRES_MAX		MASTER_PRES_MASK
16 #define MASTER_DIV_SHIFT	8
17 #define MASTER_DIV_MASK		0x7
18 
19 struct clk_master {
20 	vaddr_t base;
21 	const struct clk_master_layout *layout;
22 	const struct clk_master_charac *charac;
23 	uint32_t *mux_table;
24 	uint32_t mckr;
25 	int chg_pid;
26 	uint8_t div;
27 };
28 
clk_master_ready(struct clk_master * master)29 static bool clk_master_ready(struct clk_master *master)
30 {
31 	uint32_t status = io_read32(master->base + AT91_PMC_SR);
32 
33 	return status & AT91_PMC_MCKRDY;
34 }
35 
clk_master_enable(struct clk * clk)36 static TEE_Result clk_master_enable(struct clk *clk)
37 {
38 	struct clk_master *master = clk->priv;
39 
40 	while (!clk_master_ready(master))
41 		;
42 
43 	return TEE_SUCCESS;
44 }
45 
clk_master_div_get_rate(struct clk * clk,unsigned long parent_rate)46 static unsigned long clk_master_div_get_rate(struct clk *clk,
47 					     unsigned long parent_rate)
48 {
49 	uint8_t div = 1;
50 	uint32_t mckr = 0;
51 	unsigned long rate = parent_rate;
52 	struct clk_master *master = clk->priv;
53 	const struct clk_master_layout *layout = master->layout;
54 	const struct clk_master_charac *charac = master->charac;
55 
56 	mckr = io_read32(master->base + master->layout->offset);
57 
58 	mckr &= layout->mask;
59 
60 	div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
61 
62 	rate /= charac->divisors[div];
63 
64 	if (rate < charac->output.min)
65 		IMSG("master clk div is underclocked");
66 	else if (rate > charac->output.max)
67 		IMSG("master clk div is overclocked");
68 
69 	return rate;
70 }
71 
72 static const struct clk_ops master_div_ops = {
73 	.enable = clk_master_enable,
74 	.get_rate = clk_master_div_get_rate,
75 };
76 
clk_master_pres_get_rate(struct clk * clk,unsigned long parent_rate)77 static unsigned long clk_master_pres_get_rate(struct clk *clk,
78 					      unsigned long parent_rate)
79 {
80 	struct clk_master *master = clk->priv;
81 	const struct clk_master_charac *charac = master->charac;
82 	uint32_t val = 0;
83 	unsigned int pres = 0;
84 
85 	val = io_read32(master->base + master->layout->offset);
86 
87 	pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
88 	if (pres != 3 || !charac->have_div3_pres)
89 		pres = BIT(pres);
90 
91 	return UDIV_ROUND_NEAREST(parent_rate, pres);
92 }
93 
clk_master_pres_get_parent(struct clk * clk)94 static size_t clk_master_pres_get_parent(struct clk *clk)
95 {
96 	struct clk_master *master = clk->priv;
97 	uint32_t mckr = 0;
98 
99 	mckr = io_read32(master->base + master->layout->offset);
100 
101 	return mckr & AT91_PMC_CSS;
102 }
103 
104 static const struct clk_ops master_pres_ops = {
105 	.enable = clk_master_enable,
106 	.get_rate = clk_master_pres_get_rate,
107 	.get_parent = clk_master_pres_get_parent,
108 };
109 
110 static struct clk *
at91_clk_register_master_internal(struct pmc_data * pmc,const char * name,int num_parents,struct clk ** parents,const struct clk_master_layout * layout,const struct clk_master_charac * charac,const struct clk_ops * ops,int chg_pid)111 at91_clk_register_master_internal(struct pmc_data *pmc,
112 				  const char *name, int num_parents,
113 				  struct clk **parents,
114 				  const struct clk_master_layout *layout,
115 				  const struct clk_master_charac *charac,
116 				  const struct clk_ops *ops, int chg_pid)
117 {
118 	struct clk_master *master = NULL;
119 	struct clk *clk = NULL;
120 
121 	if (!name || !num_parents || !parents)
122 		return NULL;
123 
124 	clk = clk_alloc(name, ops, parents, num_parents);
125 	if (!clk)
126 		return NULL;
127 
128 	master = calloc(1, sizeof(*master));
129 	if (!master) {
130 		clk_free(clk);
131 		return NULL;
132 	}
133 
134 	master->layout = layout;
135 	master->charac = charac;
136 	master->base = pmc->base;
137 	master->chg_pid = chg_pid;
138 
139 	clk->priv = master;
140 	clk->flags = CLK_SET_RATE_GATE;
141 
142 	if (clk_register(clk)) {
143 		clk_free(clk);
144 		free(master);
145 		return NULL;
146 	}
147 
148 	return clk;
149 }
150 
151 struct clk *
at91_clk_register_master_pres(struct pmc_data * pmc,const char * name,int num_parents,struct clk ** parents,const struct clk_master_layout * layout,const struct clk_master_charac * charac,int chg_pid)152 at91_clk_register_master_pres(struct pmc_data *pmc,
153 			      const char *name, int num_parents,
154 			      struct clk **parents,
155 			      const struct clk_master_layout *layout,
156 			      const struct clk_master_charac *charac,
157 			      int chg_pid)
158 {
159 	return at91_clk_register_master_internal(pmc, name, num_parents,
160 						 parents, layout,
161 						 charac,
162 						 &master_pres_ops, chg_pid);
163 }
164 
165 struct clk *
at91_clk_register_master_div(struct pmc_data * pmc,const char * name,struct clk * parent,const struct clk_master_layout * layout,const struct clk_master_charac * charac)166 at91_clk_register_master_div(struct pmc_data *pmc,
167 			     const char *name, struct clk *parent,
168 			     const struct clk_master_layout *layout,
169 			     const struct clk_master_charac *charac)
170 {
171 	return at91_clk_register_master_internal(pmc, name, 1,
172 						 &parent, layout,
173 						 charac,
174 						 &master_div_ops, -1);
175 }
176 
177 const struct clk_master_layout at91sam9x5_master_layout = {
178 	.mask = 0x373,
179 	.pres_shift = 4,
180 	.offset = AT91_PMC_MCKR,
181 };
182