The Pedigree Project  0.1
GPTimer.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 "GPTimer.h"
21 #include "Prcm.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24 #include "pedigree/kernel/processor/Processor.h"
25 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
26 
27 #include "pedigree/kernel/machine/Machine.h"
28 
29 SyncTimer g_SyncTimer;
30 
31 void SyncTimer::initialise(uintptr_t base)
32 {
33  // Map in the base
34  if (!PhysicalMemoryManager::instance().allocateRegion(
35  m_MmioBase, 1, PhysicalMemoryManager::continuous,
37  {
38  // Failed to allocate the region!
39  return;
40  }
41 
42  // Dump the hardware revision
43  uint32_t hardwareRevision =
44  *reinterpret_cast<volatile uint32_t *>(m_MmioBase.virtualAddress());
45  NOTICE(
46  "32-kHz sync timer at "
47  << Hex << reinterpret_cast<uintptr_t>(m_MmioBase.virtualAddress())
48  << " - revision " << Dec << ((hardwareRevision >> 4) & 0xF) << "."
49  << (hardwareRevision & 0xF) << Hex);
50 }
51 
52 uint32_t SyncTimer::getTickCount()
53 {
54  if (!m_MmioBase)
55  return 0;
56 
57  return reinterpret_cast<uint32_t *>(m_MmioBase.virtualAddress())[4];
58 }
59 
60 void GPTimer::initialise(size_t timer, uintptr_t base)
61 {
62  // Map in the base
63  if (!PhysicalMemoryManager::instance().allocateRegion(
64  m_MmioBase, 1, PhysicalMemoryManager::continuous,
66  {
67  // Failed to allocate the region!
68  return;
69  }
70 
71  if (timer > 0)
72  {
73  // Use the SYS_CLK as our time source during reset
74  Prcm::instance().SelectClockPER(timer, Prcm::SYS_CLK);
75 
76  // Enable the interface clock for the timer
77  Prcm::instance().SetIfaceClockPER(timer, true);
78 
79  // Enable the functional clock for the timer
80  Prcm::instance().SetFuncClockPER(timer, true);
81  }
82 
83  volatile uint32_t *registers =
84  reinterpret_cast<volatile uint32_t *>(m_MmioBase.virtualAddress());
85 
86  // Reset the timer
87  registers[TIOCP_CFG] = 2;
88  registers[TSICR] = 2;
89  while (!(registers[TISTAT] & 1))
90  ;
91 
92  if (timer > 0)
93  {
94  // Reset the clock source to the 32 kHz functional clock
95  Prcm::instance().SelectClockPER(timer, Prcm::FCLK_32K);
96  }
97 
98  // Dump the hardware revision
99  uint32_t hardwareRevision = registers[TIDR];
100  NOTICE(
101  "General Purpose timer at "
102  << Hex << reinterpret_cast<uintptr_t>(m_MmioBase.virtualAddress())
103  << " - revision " << Dec << ((hardwareRevision >> 4) & 0xF) << "."
104  << (hardwareRevision & 0xF) << Hex);
105 
106  // Section 16.2.4.2.1 in the OMAP35xx manual, page 2573
107  // GPTIMER1, GPTIMER2, GPTIMER10 can all do this 1-ms poll.
108  if (timer <= 2 || timer == 11)
109  {
110  registers[TPIR] = 232000;
111  registers[TNIR] = -768000;
112  registers[TLDR] = 0xFFFFFFE0;
113  registers[TTGR] = 1; // Trigger after one interval
114  }
115 
116  // Default load values.
117  registers[TCRR] = 0xFFFFFFE0;
118 
119  // Clear existing interrupts
120  registers[TISR] = 7;
121 
122  // Set the IRQ number for future reference
123  m_Irq = 37 + timer;
124 
125  // Enable the overflow and capture interrupts
126  registers[TIER] = 2;
127  registers[TWER] = 2;
128 
129  // Enable the timer in the right mode
130  registers[TCLR] = 3; // Autoreload and timer started
131 }
132 
133 bool GPTimer::registerHandler(TimerHandler *handler)
134 {
135  // Find a spare spot and install
136  size_t nHandler;
137  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
138  {
139  if (m_Handlers[nHandler] == 0)
140  {
141  m_Handlers[nHandler] = handler;
142 
143  if (!m_bIrqInstalled && m_Irq)
144  {
145  Spinlock install;
146  install.acquire();
147  m_bIrqInstalled =
149  m_Irq, this);
150  install.release();
151  }
152 
153  return true;
154  }
155  }
156 
157  // No room!
158  return false;
159 }
160 
161 bool GPTimer::unregisterHandler(TimerHandler *handler)
162 {
163  size_t nHandler;
164  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
165  {
166  if (m_Handlers[nHandler] == handler)
167  {
168  m_Handlers[nHandler] = 0;
169  return true;
170  }
171  }
172  return false;
173 }
174 
175 void GPTimer::addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs)
176 {
177 #ifdef THREADS
178  size_t time = (alarmSecs * 1000) + (alarmUsecs / 1000) + m_TickCount;
179  Alarm *pAlarm =
180  new Alarm(pEvent, time, Processor::information().getCurrentThread());
181  m_Alarms.pushBack(pAlarm);
182 #endif
183 }
184 
185 void GPTimer::removeAlarm(class Event *pEvent)
186 {
187 #ifdef THREADS
188  for (List<Alarm *>::Iterator it = m_Alarms.begin(); it != m_Alarms.end();
189  it++)
190  {
191  if ((*it)->m_pEvent == pEvent)
192  {
193  m_Alarms.erase(it);
194  return;
195  }
196  }
197 #endif
198 }
199 
200 size_t GPTimer::removeAlarm(class Event *pEvent, bool bRetZero)
201 {
202 #ifdef THREADS
203  size_t currTime = getTickCount();
204 
205  for (List<Alarm *>::Iterator it = m_Alarms.begin(); it != m_Alarms.end();
206  it++)
207  {
208  if ((*it)->m_pEvent == pEvent)
209  {
210  size_t ret = 0;
211  if (!bRetZero)
212  {
213  size_t alarmEndTime = (*it)->m_Time;
214 
215  // Is it later than the end of the alarm?
216  if (alarmEndTime < currTime)
217  ret = 0;
218  else
219  {
220  size_t diff = alarmEndTime - currTime;
221  ret = (diff / 1000) + 1;
222  }
223  }
224 
225  m_Alarms.erase(it);
226  return ret;
227  }
228  }
229 
230  return 0;
231 #else
232  return 0;
233 #endif
234 }
235 
236 void GPTimer::interrupt(size_t nInterruptnumber, InterruptState &state)
237 {
238  m_TickCount++;
239 
240  // Call handlers
241  size_t nHandler;
242  for (nHandler = 0; nHandler < MAX_TIMER_HANDLERS; nHandler++)
243  {
244  // Timer delta is in nanoseconds
245  if (m_Handlers[nHandler])
246  m_Handlers[nHandler]->timer(1000000, state);
247  }
248 
249  // Check for alarms.
250  for (List<Alarm *>::Iterator it = m_Alarms.begin(); it != m_Alarms.end();
251  it++)
252  {
253  Alarm *pA = *it;
254  if (pA->m_Time <= m_TickCount)
255  {
256  pA->m_pThread->sendEvent(pA->m_pEvent);
257  it = m_Alarms.erase(it);
258  }
259  }
260 
261  // Ack the interrupt source
262  volatile uint32_t *registers =
263  reinterpret_cast<volatile uint32_t *>(m_MmioBase.virtualAddress());
264  registers[TISR] = registers[TISR];
265 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
void release()
Definition: Spinlock.cc:273
virtual void removeAlarm(class Event *pEvent)
Definition: GPTimer.cc:185
static PhysicalMemoryManager & instance()
void SetIfaceClockPER(size_t clock, bool enabled)
Definition: Prcm.cc:138
void initialise(size_t timer, uintptr_t base)
Definition: GPTimer.cc:60
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
static ProcessorInformation & information()
Definition: Processor.cc:45
void SetFuncClockPER(size_t clock, bool enabled)
Definition: Prcm.cc:110
bool sendEvent(Event *pEvent)
Definition: Thread.cc:529
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
::Iterator< T, node_t > Iterator
Definition: List.h:71
Definition: Event.h:48
void * virtualAddress() const
Definition: MemoryRegion.cc:39
Definition: Log.h:138
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)
Definition: GPTimer.cc:175
static InterruptManager & instance()
void SelectClockPER(size_t clock, Clock which)
Definition: Prcm.cc:50
virtual void interrupt(size_t nInterruptnumber, InterruptState &state)
Definition: GPTimer.cc:236