182444cc2SClément Léger // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
282444cc2SClément Léger /*
382444cc2SClément Léger * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
482444cc2SClément Léger * Copyright (C) 2021 Microchip
582444cc2SClément Léger */
682444cc2SClément Léger
782444cc2SClément Léger #include <io.h>
882444cc2SClément Léger #include <kernel/delay.h>
982444cc2SClément Léger #include <mm/core_memprot.h>
1082444cc2SClément Léger #include <sam_sfr.h>
1182444cc2SClément Léger #include <types_ext.h>
1282444cc2SClément Léger
1382444cc2SClément Léger #include "at91_clk.h"
1482444cc2SClément Léger
1582444cc2SClément Léger /*
1682444cc2SClément Léger * The purpose of this clock is to generate a 480 MHz signal. A different
1782444cc2SClément Léger * rate can't be configured.
1882444cc2SClément Léger */
1982444cc2SClément Léger #define UTMI_RATE 480000000
2082444cc2SClément Léger
2182444cc2SClément Léger struct clk_utmi {
2282444cc2SClément Léger vaddr_t pmc_base;
2382444cc2SClément Léger vaddr_t sfr_base;
2482444cc2SClément Léger };
2582444cc2SClément Léger
clk_utmi_ready(vaddr_t pmc_base)2682444cc2SClément Léger static bool clk_utmi_ready(vaddr_t pmc_base)
2782444cc2SClément Léger {
2882444cc2SClément Léger uint32_t status = io_read32(pmc_base + AT91_PMC_SR);
2982444cc2SClément Léger
3082444cc2SClément Léger return status & AT91_PMC_LOCKU;
3182444cc2SClément Léger }
3282444cc2SClément Léger
clk_utmi_enable(struct clk * clk)3382444cc2SClément Léger static TEE_Result clk_utmi_enable(struct clk *clk)
3482444cc2SClément Léger {
3582444cc2SClément Léger struct clk *clk_parent = NULL;
3682444cc2SClément Léger struct clk_utmi *utmi = clk->priv;
3782444cc2SClément Léger unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
3882444cc2SClément Léger AT91_PMC_BIASEN;
3982444cc2SClément Léger unsigned int utmi_ref_clk_freq = 0;
4082444cc2SClément Léger unsigned long parent_rate = 0;
4182444cc2SClément Léger
4282444cc2SClément Léger /*
4382444cc2SClément Léger * If mainck rate is different from 12 MHz, we have to configure the
4482444cc2SClément Léger * FREQ field of the SFR_UTMICKTRIM register to generate properly
4582444cc2SClément Léger * the utmi clock.
4682444cc2SClément Léger */
4782444cc2SClément Léger clk_parent = clk_get_parent(clk);
4882444cc2SClément Léger parent_rate = clk_get_rate(clk_parent);
4982444cc2SClément Léger
5082444cc2SClément Léger switch (parent_rate) {
5182444cc2SClément Léger case 12000000:
5282444cc2SClément Léger utmi_ref_clk_freq = 0;
5382444cc2SClément Léger break;
5482444cc2SClément Léger case 16000000:
5582444cc2SClément Léger utmi_ref_clk_freq = 1;
5682444cc2SClément Léger break;
5782444cc2SClément Léger case 24000000:
5882444cc2SClément Léger utmi_ref_clk_freq = 2;
5982444cc2SClément Léger break;
6082444cc2SClément Léger /*
6182444cc2SClément Léger * Not supported on SAMA5D2 but it's not an issue since MAINCK
6282444cc2SClément Léger * maximum value is 24 MHz.
6382444cc2SClément Léger */
6482444cc2SClément Léger case 48000000:
6582444cc2SClément Léger utmi_ref_clk_freq = 3;
6682444cc2SClément Léger break;
6782444cc2SClément Léger default:
6882444cc2SClément Léger EMSG("UTMICK: unsupported mainck rate");
6982444cc2SClément Léger return TEE_ERROR_BAD_PARAMETERS;
7082444cc2SClément Léger }
7182444cc2SClément Léger
7282444cc2SClément Léger if (utmi->sfr_base) {
7382444cc2SClément Léger io_clrsetbits32(utmi->sfr_base + AT91_SFR_UTMICKTRIM,
7482444cc2SClément Léger AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
7582444cc2SClément Léger } else if (utmi_ref_clk_freq) {
7682444cc2SClément Léger EMSG("UTMICK: sfr node required");
7782444cc2SClément Léger return TEE_ERROR_BAD_STATE;
7882444cc2SClément Léger }
7982444cc2SClément Léger
8082444cc2SClément Léger io_clrsetbits32(utmi->pmc_base + AT91_CKGR_UCKR, uckr, uckr);
8182444cc2SClément Léger
8282444cc2SClément Léger while (!clk_utmi_ready(utmi->pmc_base))
8382444cc2SClément Léger ;
8482444cc2SClément Léger
8582444cc2SClément Léger return TEE_SUCCESS;
8682444cc2SClément Léger }
8782444cc2SClément Léger
clk_utmi_disable(struct clk * clk)8882444cc2SClément Léger static void clk_utmi_disable(struct clk *clk)
8982444cc2SClément Léger {
9082444cc2SClément Léger struct clk_utmi *utmi = clk->priv;
9182444cc2SClément Léger
9282444cc2SClément Léger io_clrbits32(utmi->pmc_base + AT91_CKGR_UCKR, AT91_PMC_UPLLEN);
9382444cc2SClément Léger }
9482444cc2SClément Léger
clk_utmi_get_rate(struct clk * clk __unused,unsigned long parent_rate __unused)9582444cc2SClément Léger static unsigned long clk_utmi_get_rate(struct clk *clk __unused,
9682444cc2SClément Léger unsigned long parent_rate __unused)
9782444cc2SClément Léger {
9882444cc2SClément Léger /* UTMI clk rate is fixed. */
9982444cc2SClément Léger return UTMI_RATE;
10082444cc2SClément Léger }
10182444cc2SClément Léger
10282444cc2SClément Léger static const struct clk_ops utmi_ops = {
10382444cc2SClément Léger .enable = clk_utmi_enable,
10482444cc2SClément Léger .disable = clk_utmi_disable,
10582444cc2SClément Léger .get_rate = clk_utmi_get_rate,
10682444cc2SClément Léger };
10782444cc2SClément Léger
at91_clk_register_utmi_internal(struct pmc_data * pmc,const char * name,const struct clk_ops * ops,struct clk * parent)108*417a10d1STony Han static struct clk *at91_clk_register_utmi_internal(struct pmc_data *pmc,
109*417a10d1STony Han const char *name,
110*417a10d1STony Han const struct clk_ops *ops,
11182444cc2SClément Léger struct clk *parent)
11282444cc2SClément Léger {
11382444cc2SClément Léger struct clk_utmi *utmi = NULL;
11482444cc2SClément Léger struct clk *clk = NULL;
11582444cc2SClément Léger
116*417a10d1STony Han clk = clk_alloc(name, ops, &parent, 1);
11782444cc2SClément Léger if (!clk)
11882444cc2SClément Léger return NULL;
11982444cc2SClément Léger
12082444cc2SClément Léger utmi = calloc(1, sizeof(*utmi));
12182444cc2SClément Léger if (!utmi) {
12282444cc2SClément Léger clk_free(clk);
12382444cc2SClément Léger return NULL;
12482444cc2SClément Léger }
12582444cc2SClément Léger
12682444cc2SClément Léger utmi->pmc_base = pmc->base;
12782444cc2SClément Léger utmi->sfr_base = sam_sfr_base();
12882444cc2SClément Léger clk->flags = CLK_SET_RATE_GATE;
12982444cc2SClément Léger
13082444cc2SClément Léger clk->priv = utmi;
13182444cc2SClément Léger
13282444cc2SClément Léger if (clk_register(clk)) {
13382444cc2SClément Léger clk_free(clk);
13482444cc2SClément Léger free(utmi);
13582444cc2SClément Léger return NULL;
13682444cc2SClément Léger }
13782444cc2SClément Léger
13882444cc2SClément Léger return clk;
13982444cc2SClément Léger }
140*417a10d1STony Han
at91_clk_register_utmi(struct pmc_data * pmc,const char * name,struct clk * parent)141*417a10d1STony Han struct clk *at91_clk_register_utmi(struct pmc_data *pmc,
142*417a10d1STony Han const char *name,
143*417a10d1STony Han struct clk *parent)
144*417a10d1STony Han {
145*417a10d1STony Han return at91_clk_register_utmi_internal(pmc, name, &utmi_ops, parent);
146*417a10d1STony Han }
147*417a10d1STony Han
clk_utmi_sama7g5_prepare(struct clk * clk)148*417a10d1STony Han static TEE_Result clk_utmi_sama7g5_prepare(struct clk *clk)
149*417a10d1STony Han {
150*417a10d1STony Han struct clk *clk_parent = NULL;
151*417a10d1STony Han struct clk_utmi *utmi = clk->priv;
152*417a10d1STony Han unsigned long parent_rate = 0;
153*417a10d1STony Han uint32_t val = 0;
154*417a10d1STony Han
155*417a10d1STony Han clk_parent = clk_get_parent(clk);
156*417a10d1STony Han parent_rate = clk_get_rate(clk_parent);
157*417a10d1STony Han
158*417a10d1STony Han switch (parent_rate) {
159*417a10d1STony Han case 16000000:
160*417a10d1STony Han val = 0;
161*417a10d1STony Han break;
162*417a10d1STony Han case 20000000:
163*417a10d1STony Han val = 2;
164*417a10d1STony Han break;
165*417a10d1STony Han case 24000000:
166*417a10d1STony Han val = 3;
167*417a10d1STony Han break;
168*417a10d1STony Han case 32000000:
169*417a10d1STony Han val = 5;
170*417a10d1STony Han break;
171*417a10d1STony Han default:
172*417a10d1STony Han EMSG("UTMICK: unsupported main_xtal rate");
173*417a10d1STony Han return TEE_ERROR_BAD_PARAMETERS;
174*417a10d1STony Han }
175*417a10d1STony Han
176*417a10d1STony Han io_clrsetbits32(utmi->pmc_base + AT91_PMC_XTALF, AT91_PMC_XTALF_XTALF,
177*417a10d1STony Han val);
178*417a10d1STony Han
179*417a10d1STony Han return TEE_SUCCESS;
180*417a10d1STony Han }
181*417a10d1STony Han
182*417a10d1STony Han static const struct clk_ops sama7g5_utmi_ops = {
183*417a10d1STony Han .enable = clk_utmi_sama7g5_prepare,
184*417a10d1STony Han .get_rate = clk_utmi_get_rate,
185*417a10d1STony Han };
186*417a10d1STony Han
at91_clk_sama7g5_register_utmi(struct pmc_data * pmc,const char * name,struct clk * parent)187*417a10d1STony Han struct clk *at91_clk_sama7g5_register_utmi(struct pmc_data *pmc,
188*417a10d1STony Han const char *name,
189*417a10d1STony Han struct clk *parent)
190*417a10d1STony Han {
191*417a10d1STony Han return at91_clk_register_utmi_internal(pmc, name, &sama7g5_utmi_ops,
192*417a10d1STony Han parent);
193*417a10d1STony Han }
194