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 <sam_sfr.h>
11 #include <types_ext.h>
12
13 #include "at91_clk.h"
14
15 /*
16 * The purpose of this clock is to generate a 480 MHz signal. A different
17 * rate can't be configured.
18 */
19 #define UTMI_RATE 480000000
20
21 struct clk_utmi {
22 vaddr_t pmc_base;
23 vaddr_t sfr_base;
24 };
25
clk_utmi_ready(vaddr_t pmc_base)26 static bool clk_utmi_ready(vaddr_t pmc_base)
27 {
28 uint32_t status = io_read32(pmc_base + AT91_PMC_SR);
29
30 return status & AT91_PMC_LOCKU;
31 }
32
clk_utmi_enable(struct clk * clk)33 static TEE_Result clk_utmi_enable(struct clk *clk)
34 {
35 struct clk *clk_parent = NULL;
36 struct clk_utmi *utmi = clk->priv;
37 unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
38 AT91_PMC_BIASEN;
39 unsigned int utmi_ref_clk_freq = 0;
40 unsigned long parent_rate = 0;
41
42 /*
43 * If mainck rate is different from 12 MHz, we have to configure the
44 * FREQ field of the SFR_UTMICKTRIM register to generate properly
45 * the utmi clock.
46 */
47 clk_parent = clk_get_parent(clk);
48 parent_rate = clk_get_rate(clk_parent);
49
50 switch (parent_rate) {
51 case 12000000:
52 utmi_ref_clk_freq = 0;
53 break;
54 case 16000000:
55 utmi_ref_clk_freq = 1;
56 break;
57 case 24000000:
58 utmi_ref_clk_freq = 2;
59 break;
60 /*
61 * Not supported on SAMA5D2 but it's not an issue since MAINCK
62 * maximum value is 24 MHz.
63 */
64 case 48000000:
65 utmi_ref_clk_freq = 3;
66 break;
67 default:
68 EMSG("UTMICK: unsupported mainck rate");
69 return TEE_ERROR_BAD_PARAMETERS;
70 }
71
72 if (utmi->sfr_base) {
73 io_clrsetbits32(utmi->sfr_base + AT91_SFR_UTMICKTRIM,
74 AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
75 } else if (utmi_ref_clk_freq) {
76 EMSG("UTMICK: sfr node required");
77 return TEE_ERROR_BAD_STATE;
78 }
79
80 io_clrsetbits32(utmi->pmc_base + AT91_CKGR_UCKR, uckr, uckr);
81
82 while (!clk_utmi_ready(utmi->pmc_base))
83 ;
84
85 return TEE_SUCCESS;
86 }
87
clk_utmi_disable(struct clk * clk)88 static void clk_utmi_disable(struct clk *clk)
89 {
90 struct clk_utmi *utmi = clk->priv;
91
92 io_clrbits32(utmi->pmc_base + AT91_CKGR_UCKR, AT91_PMC_UPLLEN);
93 }
94
clk_utmi_get_rate(struct clk * clk __unused,unsigned long parent_rate __unused)95 static unsigned long clk_utmi_get_rate(struct clk *clk __unused,
96 unsigned long parent_rate __unused)
97 {
98 /* UTMI clk rate is fixed. */
99 return UTMI_RATE;
100 }
101
102 static const struct clk_ops utmi_ops = {
103 .enable = clk_utmi_enable,
104 .disable = clk_utmi_disable,
105 .get_rate = clk_utmi_get_rate,
106 };
107
108 struct clk *
at91_clk_register_utmi(struct pmc_data * pmc,const char * name,struct clk * parent)109 at91_clk_register_utmi(struct pmc_data *pmc, const char *name,
110 struct clk *parent)
111 {
112 struct clk_utmi *utmi = NULL;
113 struct clk *clk = NULL;
114
115 clk = clk_alloc(name, &utmi_ops, &parent, 1);
116 if (!clk)
117 return NULL;
118
119 utmi = calloc(1, sizeof(*utmi));
120 if (!utmi) {
121 clk_free(clk);
122 return NULL;
123 }
124
125 utmi->pmc_base = pmc->base;
126 utmi->sfr_base = sam_sfr_base();
127 clk->flags = CLK_SET_RATE_GATE;
128
129 clk->priv = utmi;
130
131 if (clk_register(clk)) {
132 clk_free(clk);
133 free(utmi);
134 return NULL;
135 }
136
137 return clk;
138 }
139