The Pedigree Project  0.1
Prcm.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Prcm.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
23 #include "pedigree/kernel/processor/Processor.h"
24 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
25 
26 Prcm Prcm::m_Instance;
27 
28 Prcm::Prcm() : m_Base("PRCM Module")
29 {
30 }
31 
32 Prcm::~Prcm()
33 {
34 }
35 
36 void Prcm::initialise(uintptr_t base)
37 {
38  // Map in the base
39  if (!PhysicalMemoryManager::instance().allocateRegion(
42  {
43  // Failed to allocate the region!
44  return;
45  }
46 
48 }
49 
50 void Prcm::SelectClockPER(size_t clock, Clock which)
51 {
52  if (!m_Base)
53  {
54  ERROR("PRCM: Not initialised");
55  return;
56  }
57 
58  if (clock == 0) // GPTIMER1 not handled
59  return;
60  clock -= 1; // GPTIMER2 = 1, starts at bit 0 in the register
61  uint32_t bit = 1 << clock;
62 
63  // CM_CLKSEL_PER register
64  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
65  vaddr += PER_CM;
66  vaddr += CM_CLKSEL_PER;
67  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
68 
69  // Set the value if needed
70  uint32_t val = *clksel;
71  if ((which == FCLK_32K) && (val & bit))
72  val &= ~bit;
73  else if ((which == SYS_CLK) && (!(val & bit)))
74  val |= bit;
75  *clksel = val;
76 }
77 
78 void Prcm::SelectClockCORE(size_t clock, Clock which)
79 {
80  if (!m_Base)
81  {
82  ERROR("PRCM: Not initialised");
83  return;
84  }
85 
86  uint32_t bit = 1 << clock;
87  uint32_t set = which << clock;
88 
89  uint32_t mask = 0;
90  if (clock == 0)
91  mask = 0x3;
92  else if (clock == 2)
93  mask = 0xC;
94  else
95  mask = bit;
96 
97  // CM_CLKSEL_CORE register
98  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
99  vaddr += CORE_CM;
100  vaddr += CM_CLKSEL_CORE;
101  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
102 
103  // Set the value if needed
104  uint32_t val = *clksel;
105  val &= ~mask;
106  val |= set;
107  *clksel = val;
108 }
109 
110 void Prcm::SetFuncClockPER(size_t clock, bool enabled)
111 {
112  if (!m_Base)
113  {
114  ERROR("PRCM: Not initialised");
115  return;
116  }
117 
118  if (clock == 0) // GPTIMER1 not handled
119  return;
120  clock += 2; // GPTIMER2 = 1, starts at bit 3 in the register
121  uint32_t bit = 1 << clock;
122 
123  // CM_CLKSEL_PER register
124  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
125  vaddr += PER_CM;
126  vaddr += CM_FCLKEN_PER;
127  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
128 
129  // Set the value if needed
130  uint32_t val = *clksel;
131  if ((!enabled) && (val & bit))
132  val &= ~bit;
133  else if (enabled && (!(val & bit)))
134  val |= bit;
135  *clksel = val;
136 }
137 
138 void Prcm::SetIfaceClockPER(size_t clock, bool enabled)
139 {
140  if (!m_Base)
141  {
142  ERROR("PRCM: Not initialised");
143  return;
144  }
145 
146  if (clock == 0) // GPTIMER1 not handled
147  return;
148  clock += 2; // GPTIMER2 = 1, starts at bit 3 in the register
149  uint32_t bit = 1 << clock;
150 
151  // CM_CLKSEL_PER register
152  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
153  vaddr += PER_CM;
154  vaddr += CM_ICLKEN_PER;
155  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
156 
157  // Set the value if needed
158  uint32_t val = *clksel;
159  if ((!enabled) && (val & bit))
160  val &= ~bit;
161  else if (enabled && (!(val & bit)))
162  val |= bit;
163  *clksel = val;
164 }
165 
166 void Prcm::SetFuncClockCORE(size_t n, size_t clock, bool enabled)
167 {
168  if (!m_Base)
169  {
170  ERROR("PRCM: Not initialised");
171  return;
172  }
173 
174  // Bit to set
175  uint32_t bit = 1 << clock;
176 
177  // CM_FCLKENn_CORE register
178  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
179  vaddr += CORE_CM;
180  if (n == 1)
181  vaddr += CM_FCLKEN1_CORE;
182  else if (n == 3)
183  vaddr += CM_FCLKEN3_CORE;
184  else
185  {
186  WARNING("PRCM: Invalid functional clock enable bank (CORE domain)");
187  return;
188  }
189  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
190 
191  // Set the value if needed
192  uint32_t val = *clksel;
193  if ((!enabled) && (val & bit))
194  val &= ~bit;
195  else if (enabled && (!(val & bit)))
196  val |= bit;
197  *clksel = val;
198 }
199 
200 void Prcm::SetIfaceClockCORE(size_t n, size_t clock, bool enabled)
201 {
202  if (!m_Base)
203  {
204  ERROR("PRCM: Not initialised");
205  return;
206  }
207 
208  // Bit to set
209  uint32_t bit = 1 << clock;
210 
211  // CM_ICLKENn_CORE register
212  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
213  vaddr += CORE_CM;
214  if (n == 1)
215  vaddr += CM_ICLKEN1_CORE;
216  else if (n == 3)
217  vaddr += CM_ICLKEN3_CORE;
218  else
219  {
220  WARNING("PRCM: Invalid interface clock enable bank (CORE domain)");
221  return;
222  }
223  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
224 
225  // Set the value if needed
226  uint32_t val = *clksel;
227  if ((!enabled) && (val & bit))
228  val &= ~bit;
229  else if (enabled && (!(val & bit)))
230  val |= bit;
231  *clksel = val;
232 }
233 
234 void Prcm::WaitCoreIdleStatus(size_t n, size_t clock, bool waitForOn)
235 {
236  if (!m_Base)
237  {
238  ERROR("PRCM: Not initialised");
239  return;
240  }
241 
242  // Bit to set
243  uint32_t bit = 1 << clock;
244 
245  // CM_IDLESTn_CORE register
246  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
247  vaddr += CORE_CM;
248  if (n == 1)
249  vaddr += CM_IDLEST1_CORE;
250  else if (n == 3)
251  vaddr += CM_IDLEST3_CORE;
252  else
253  {
254  WARNING("PRCM: Invalid idle status bank (CORE domain)");
255  return;
256  }
257  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
258 
259  // When the bit transitions to zero, the module is accessible
261  if (waitForOn)
262  while (*clksel & bit)
263  ;
264  else
265  while (!(*clksel & bit))
266  ;
267 }
268 
269 void Prcm::WaitPllIdleStatus(size_t n, size_t clock, bool waitForOn)
270 {
271  if (!m_Base)
272  {
273  ERROR("PRCM: Not initialised");
274  return;
275  }
276 
277  // Bit to set
278  uint32_t bit = 1 << clock;
279 
280  // CM_IDLESTn_PLL register
281  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
282  vaddr += Clock_Control_Reg_CM;
283  if (n == 1)
284  vaddr += CM_IDLEST_CKGEN;
285  else if (n == 2)
286  vaddr += CM_IDLEST2_CKGEN;
287  else
288  {
289  WARNING("PRCM: Invalid idle status bank (CORE domain)");
290  return;
291  }
292  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
293 
294  // When the bit transitions to one, the clock is locked
296  if (waitForOn)
297  {
298  while (!(*clksel & bit))
299  ;
300  }
301  else
302  {
303  while (*clksel & bit)
304  ;
305  }
306 }
307 
308 void Prcm::SelectClockPLL(size_t n, size_t value)
309 {
310  if (!m_Base)
311  {
312  ERROR("PRCM: Not initialised");
313  return;
314  }
315 
316  // CM_CLKSELn_PLL register
317  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
318  vaddr += Clock_Control_Reg_CM;
319  if (n == 1)
320  vaddr += CM_CLKSEL1_PLL;
321  else if (n == 2)
322  vaddr += CM_CLKSEL2_PLL;
323  else if (n == 3)
324  vaddr += CM_CLKSEL3_PLL;
325  else if (n == 4)
326  vaddr += CM_CLKSEL4_PLL;
327  else if (n == 5)
328  vaddr += CM_CLKSEL5_PLL;
329  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
330 
331  // Set it!
332  *clksel = value;
333 }
334 
335 void Prcm::SetClockPLL(size_t n, size_t value)
336 {
337  if (!m_Base)
338  {
339  ERROR("PRCM: Not initialised");
340  return;
341  }
342 
343  // CM_CLKENn_PLL register
344  uintptr_t vaddr = reinterpret_cast<uintptr_t>(m_Base.virtualAddress());
345  vaddr += Clock_Control_Reg_CM;
346  if (n == 1)
347  vaddr += CM_CLKEN_PLL;
348  else if (n == 2)
349  vaddr += CM_CLKEN2_PLL;
350  else
351  {
352  WARNING("PRCM: Invalid interface clock enable bank (CORE domain)");
353  return;
354  }
355  volatile uint32_t *clksel = reinterpret_cast<volatile uint32_t *>(vaddr);
356 
357  // Set it!
358  *clksel = value;
359 }
static PhysicalMemoryManager & instance()
void WaitPllIdleStatus(size_t n, size_t clock, bool waitForOn)
Definition: Prcm.cc:269
void SetClockPLL(size_t n, size_t value)
Definition: Prcm.cc:335
void SetIfaceClockPER(size_t clock, bool enabled)
Definition: Prcm.cc:138
void SelectClockPLL(size_t n, size_t value)
Definition: Prcm.cc:308
void SetFuncClockCORE(size_t n, size_t clock, bool enabled)
Definition: Prcm.cc:166
void SetFuncClockPER(size_t clock, bool enabled)
Definition: Prcm.cc:110
void initialise(uintptr_t base)
Definition: Prcm.cc:36
#define WARNING(text)
Definition: Log.h:78
void SelectClockCORE(size_t clock, Clock which)
Definition: Prcm.cc:78
void WaitCoreIdleStatus(size_t n, size_t clock, bool waitForOn)
Definition: Prcm.cc:234
Definition: Prcm.h:27
void SetIfaceClockCORE(size_t n, size_t clock, bool enabled)
Definition: Prcm.cc:200
#define ERROR(text)
Definition: Log.h:82
void SelectClockPER(size_t clock, Clock which)
Definition: Prcm.cc:50