source: mainline/kernel/arch/arm32/src/drivers/gxemul.c@ 3b122e9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3b122e9 was bffa876e, checked in by Jakub Jermar <jakub@…>, 17 years ago

Remove unnecessary stuff from arm32.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/*
2 * Copyright (c) 2007 Michal Kebrt, Petr Stepan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup arm32gxemul
30 * @{
31 */
32/** @file
33 * @brief GXemul drivers.
34 */
35
36#include <interrupt.h>
37#include <console/chardev.h>
38#include <arch/drivers/gxemul.h>
39#include <console/console.h>
40#include <sysinfo/sysinfo.h>
41#include <print.h>
42#include <ddi/device.h>
43#include <mm/page.h>
44#include <arch/machine.h>
45#include <arch/debug/print.h>
46
47/* Addresses of devices. */
48#define GXEMUL_VIDEORAM 0x10000000
49#define GXEMUL_KBD 0x10000000
50#define GXEMUL_HALT_OFFSET 0x10
51#define GXEMUL_RTC 0x15000000
52#define GXEMUL_RTC_FREQ_OFFSET 0x100
53#define GXEMUL_RTC_ACK_OFFSET 0x110
54#define GXEMUL_IRQC 0x16000000
55#define GXEMUL_IRQC_MASK_OFFSET 0x4
56#define GXEMUL_IRQC_UNMASK_OFFSET 0x8
57#define GXEMUL_MP 0x11000000
58#define GXEMUL_MP_MEMSIZE_OFFSET 0x0090
59#define GXEMUL_FB 0x12000000
60
61/* IRQs */
62#define GXEMUL_KBD_IRQ 2
63#define GXEMUL_TIMER_IRQ 4
64
65static gxemul_hw_map_t gxemul_hw_map;
66static chardev_t console;
67static irq_t gxemul_console_irq;
68static irq_t gxemul_timer_irq;
69
70static bool hw_map_init_called = false;
71
72static void gxemul_kbd_enable(chardev_t *dev);
73static void gxemul_kbd_disable(chardev_t *dev);
74static void gxemul_write(chardev_t *dev, const char ch, bool silent);
75static char gxemul_do_read(chardev_t *dev);
76
77static chardev_operations_t gxemul_ops = {
78 .resume = gxemul_kbd_enable,
79 .suspend = gxemul_kbd_disable,
80 .write = gxemul_write,
81 .read = gxemul_do_read,
82};
83
84
85/** Returns the mask of active interrupts. */
86static inline uint32_t gxemul_irqc_get_sources(void)
87{
88 return *((uint32_t *) gxemul_hw_map.irqc);
89}
90
91
92/** Masks interrupt.
93 *
94 * @param irq interrupt number
95 */
96static inline void gxemul_irqc_mask(uint32_t irq)
97{
98 *((uint32_t *) gxemul_hw_map.irqc_mask) = irq;
99}
100
101
102/** Unmasks interrupt.
103 *
104 * @param irq interrupt number
105 */
106static inline void gxemul_irqc_unmask(uint32_t irq)
107{
108 *((uint32_t *) gxemul_hw_map.irqc_unmask) = irq;
109}
110
111
112/** Initializes #gxemul_hw_map. */
113void gxemul_hw_map_init(void)
114{
115 gxemul_hw_map.videoram = hw_map(GXEMUL_VIDEORAM, PAGE_SIZE);
116 gxemul_hw_map.kbd = hw_map(GXEMUL_KBD, PAGE_SIZE);
117 gxemul_hw_map.rtc = hw_map(GXEMUL_RTC, PAGE_SIZE);
118 gxemul_hw_map.irqc = hw_map(GXEMUL_IRQC, PAGE_SIZE);
119
120 gxemul_hw_map.rtc_freq = gxemul_hw_map.rtc + GXEMUL_RTC_FREQ_OFFSET;
121 gxemul_hw_map.rtc_ack = gxemul_hw_map.rtc + GXEMUL_RTC_ACK_OFFSET;
122 gxemul_hw_map.irqc_mask = gxemul_hw_map.irqc + GXEMUL_IRQC_MASK_OFFSET;
123 gxemul_hw_map.irqc_unmask = gxemul_hw_map.irqc +
124 GXEMUL_IRQC_UNMASK_OFFSET;
125
126 hw_map_init_called = true;
127}
128
129
130/** Putchar that works with gxemul.
131 *
132 * @param dev Not used.
133 * @param ch Characted to be printed.
134 */
135static void gxemul_write(chardev_t *dev, const char ch, bool silent)
136{
137 if (!silent)
138 *((char *) gxemul_hw_map.videoram) = ch;
139}
140
141/** Enables gxemul keyboard (interrupt unmasked).
142 *
143 * @param dev Not used.
144 *
145 * Called from getc().
146 */
147static void gxemul_kbd_enable(chardev_t *dev)
148{
149 gxemul_irqc_unmask(GXEMUL_KBD_IRQ);
150}
151
152/** Disables gxemul keyboard (interrupt masked).
153 *
154 * @param dev not used
155 *
156 * Called from getc().
157 */
158static void gxemul_kbd_disable(chardev_t *dev)
159{
160 gxemul_irqc_mask(GXEMUL_KBD_IRQ);
161}
162
163/** Read character using polling, assume interrupts disabled.
164 *
165 * @param dev Not used.
166 */
167static char gxemul_do_read(chardev_t *dev)
168{
169 char ch;
170
171 while (1) {
172 ch = *((volatile char *) gxemul_hw_map.kbd);
173 if (ch) {
174 if (ch == '\r')
175 return '\n';
176 if (ch == 0x7f)
177 return '\b';
178 return ch;
179 }
180 }
181}
182
183/** Process keyboard interrupt.
184 *
185 * @param irq IRQ information.
186 */
187static void gxemul_irq_handler(irq_t *irq)
188{
189 char ch = 0;
190
191 ch = *((char *) gxemul_hw_map.kbd);
192 if (ch == '\r') {
193 ch = '\n';
194 }
195 if (ch == 0x7f) {
196 ch = '\b';
197 }
198 chardev_push_character(&console, ch);
199}
200
201static irq_ownership_t gxemul_claim(irq_t *irq)
202{
203 return IRQ_ACCEPT;
204}
205
206/** Initializes console object representing gxemul console.
207 *
208 * @param devno device number.
209 */
210void gxemul_console_init(devno_t devno)
211{
212 chardev_initialize("gxemul_console", &console, &gxemul_ops);
213 stdin = &console;
214 stdout = &console;
215
216 irq_initialize(&gxemul_console_irq);
217 gxemul_console_irq.devno = devno;
218 gxemul_console_irq.inr = GXEMUL_KBD_IRQ;
219 gxemul_console_irq.claim = gxemul_claim;
220 gxemul_console_irq.handler = gxemul_irq_handler;
221 irq_register(&gxemul_console_irq);
222
223 gxemul_irqc_unmask(GXEMUL_KBD_IRQ);
224
225 sysinfo_set_item_val("kbd", NULL, true);
226 sysinfo_set_item_val("kbd.devno", NULL, devno);
227 sysinfo_set_item_val("kbd.inr", NULL, GXEMUL_KBD_IRQ);
228 sysinfo_set_item_val("kbd.address.virtual", NULL, gxemul_hw_map.kbd);
229}
230
231/** Starts gxemul Real Time Clock device, which asserts regular interrupts.
232 *
233 * @param frequency Interrupts frequency (0 disables RTC).
234 */
235static void gxemul_timer_start(uint32_t frequency)
236{
237 *((uint32_t*) gxemul_hw_map.rtc_freq) = frequency;
238}
239
240static irq_ownership_t gxemul_timer_claim(irq_t *irq)
241{
242 return IRQ_ACCEPT;
243}
244
245/** Timer interrupt handler.
246 *
247 * @param irq Interrupt information.
248 * @param arg Not used.
249 */
250static void gxemul_timer_irq_handler(irq_t *irq)
251{
252 /*
253 * We are holding a lock which prevents preemption.
254 * Release the lock, call clock() and reacquire the lock again.
255 */
256 spinlock_unlock(&irq->lock);
257 clock();
258 spinlock_lock(&irq->lock);
259
260 /* acknowledge tick */
261 *((uint32_t*) gxemul_hw_map.rtc_ack) = 0;
262}
263
264/** Initializes and registers timer interrupt handler. */
265static void gxemul_timer_irq_init(void)
266{
267 irq_initialize(&gxemul_timer_irq);
268 gxemul_timer_irq.devno = device_assign_devno();
269 gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ;
270 gxemul_timer_irq.claim = gxemul_timer_claim;
271 gxemul_timer_irq.handler = gxemul_timer_irq_handler;
272
273 irq_register(&gxemul_timer_irq);
274}
275
276
277/** Starts timer.
278 *
279 * Initiates regular timer interrupts after initializing
280 * corresponding interrupt handler.
281 */
282void gxemul_timer_irq_start(void)
283{
284 gxemul_timer_irq_init();
285 gxemul_timer_start(GXEMUL_TIMER_FREQ);
286}
287
288/** Returns the size of emulated memory.
289 *
290 * @return Size in bytes.
291 */
292size_t gxemul_get_memory_size(void)
293{
294 return *((int *) (GXEMUL_MP + GXEMUL_MP_MEMSIZE_OFFSET));
295}
296
297/** Prints a character.
298 *
299 * @param ch Character to be printed.
300 */
301void gxemul_debug_putc(char ch)
302{
303 char *addr = 0;
304 if (!hw_map_init_called) {
305 addr = (char *) GXEMUL_KBD;
306 } else {
307 addr = (char *) gxemul_hw_map.videoram;
308 }
309
310 *(addr) = ch;
311}
312
313/** Stops gxemul. */
314void gxemul_cpu_halt(void)
315{
316 char * addr = 0;
317 if (!hw_map_init_called) {
318 addr = (char *) GXEMUL_KBD;
319 } else {
320 addr = (char *) gxemul_hw_map.videoram;
321 }
322
323 *(addr + GXEMUL_HALT_OFFSET) = '\0';
324}
325
326/** Gxemul specific interrupt exception handler.
327 *
328 * Determines sources of the interrupt from interrupt controller and
329 * calls high-level handlers for them.
330 *
331 * @param exc_no Interrupt exception number.
332 * @param istate Saved processor state.
333 */
334void gxemul_irq_exception(int exc_no, istate_t *istate)
335{
336 uint32_t sources = gxemul_irqc_get_sources();
337 int i;
338
339 for (i = 0; i < GXEMUL_IRQC_MAX_IRQ; i++) {
340 if (sources & (1 << i)) {
341 irq_t *irq = irq_dispatch_and_lock(i);
342 if (irq) {
343 /* The IRQ handler was found. */
344 irq->handler(irq);
345 spinlock_unlock(&irq->lock);
346 } else {
347 /* Spurious interrupt.*/
348 dprintf("cpu%d: spurious interrupt (inum=%d)\n",
349 CPU->id, i);
350 }
351 }
352 }
353}
354
355/** Returns address of framebuffer device.
356 *
357 * @return Address of framebuffer device.
358 */
359uintptr_t gxemul_get_fb_address(void)
360{
361 return (uintptr_t) GXEMUL_FB;
362}
363
364/** @}
365 */
Note: See TracBrowser for help on using the repository browser.