Subversion Repositories HelenOS

Rev

Rev 4632 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3528 pillai 1
/*
4629 pillai 2
 * Copyright (c) 2009 Vineeth Pillai
3528 pillai 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 arm32qemu_icp
30
 * @{
31
 */
32
/** @file
33
 *  @brief QEMU icp drivers.
34
 */
35
 
36
#include <interrupt.h>
37
#include <ipc/irq.h>
38
#include <console/chardev.h>
39
#include <arch/drivers/qemu.h>
4629 pillai 40
#include <arch/drivers/pl050.h>
3528 pillai 41
#include <console/console.h>
42
#include <sysinfo/sysinfo.h>
43
#include <print.h>
44
#include <ddi/device.h>
45
#include <mm/page.h>
4634 pillai 46
#include <mm/frame.h>
47
#include <arch/mm/frame.h>
3528 pillai 48
#include <arch/machine.h>
49
#include <arch/debug/print.h>
3529 pillai 50
#include <genarch/fb/fb.h>
51
#include <genarch/fb/visuals.h>
3528 pillai 52
 
53
/* Addresses of devices. */
4634 pillai 54
#define QEMU_ICP_UART            0x16000000
3528 pillai 55
#define QEMU_ICP_KBD                 0x18000000
4628 pillai 56
#define ICP_KBD_STAT             0x04
57
#define ICP_KBD_DATA             0x08
58
#define ICP_KBD_INTR_STAT        0x10
3528 pillai 59
#define QEMU_ICP_RTC                 0x13000000
4612 pillai 60
#define QEMU_ICP_RTC1_LOAD_OFFSET    0x100
61
#define QEMU_ICP_RTC1_READ_OFFSET    0x104
62
#define QEMU_ICP_RTC1_CTL_OFFSET     0x108
63
#define QEMU_ICP_RTC1_INTRCLR_OFFSET 0x10C
64
#define QEMU_ICP_RTC1_BGLOAD_OFFSET  0x118
65
#define QEMU_ICP_RTC_CTL_VALUE       0x00E2
3528 pillai 66
#define QEMU_ICP_IRQC                0x14000000
3759 pillai 67
#define QEMU_ICP_IRQC_MASK_OFFSET    0xC
68
#define QEMU_ICP_IRQC_UNMASK_OFFSET  0x8
4634 pillai 69
#define QEMU_ICP_FB                  0x00800000
70
#define QEMU_ICP_FB_FRAME        (QEMU_ICP_FB >> 12)
71
#define QEMU_ICP_FB_NUM_FRAME        300
3528 pillai 72
#define ICP_VGA              0xC0000000
73
#define ICP_CMCR             0x10000000
4634 pillai 74
#define QEMU_ICP_SDRAM_MASK      0x1C
75
#define QEMU_ICP_SDRAMCR_OFFSET      0x20
3528 pillai 76
 
77
/* IRQs */
4612 pillai 78
#define QEMU_ICP_KBD_IRQ        3
79
#define QEMU_ICP_TIMER_IRQ      6
3528 pillai 80
 
4634 pillai 81
#define SDRAM_SIZE  (sdram[((*(uint32_t *)(ICP_CMCR+QEMU_ICP_SDRAMCR_OFFSET) & QEMU_ICP_SDRAM_MASK) >> 2)])
82
 
3528 pillai 83
static qemu_icp_hw_map_t qemu_icp_hw_map;
84
static irq_t qemu_icp_timer_irq;
85
 
86
static bool hw_map_init_called = false;
87
static bool vga_init = false;
4634 pillai 88
uint32_t sdram[8] = {
89
    16777216,   /* 16mb */
90
    33554432,   /* 32mb */
91
    67108864,   /* 64mb */
92
    134217728,  /* 128mb */
93
    268435456,  /* 256mb */
94
    0,      /* Reserverd */
95
    0,      /* Reserverd */
96
 
97
    };
3528 pillai 98
 
99
void icp_vga_init(void);
100
 
101
/** Initializes the vga
102
 *
103
 */
104
void icp_vga_init(void)
105
{
106
    *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x14) = 0xA05F0000;
107
    *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0x1C) = 0x12C11000;
108
    *(uint32_t*)qemu_icp_hw_map.vga = 0x3F1F3F9C;
109
    *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x4) = 0x080B61DF;
110
    *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x8) = 0x067F3800;
111
    *(uint32_t*)((char *)(qemu_icp_hw_map.vga) + 0x10) = QEMU_ICP_FB;
112
    *(uint32_t *)((char *)(qemu_icp_hw_map.vga) + 0x1C) = 0x182B;
113
    *(uint32_t*)((char *)(qemu_icp_hw_map.cmcr)+0xC) = 0x33805000;
114
 
115
}
116
 
117
/** Returns the mask of active interrupts. */
118
static inline uint32_t qemu_icp_irqc_get_sources(void)
119
{
120
    return *((uint32_t *) qemu_icp_hw_map.irqc);
121
}
122
 
123
 
124
/** Masks interrupt.
125
 *
126
 * @param irq interrupt number
127
 */
128
static inline void qemu_icp_irqc_mask(uint32_t irq)
129
{
4612 pillai 130
    *((uint32_t *) qemu_icp_hw_map.irqc_mask) = (1 << irq);
3528 pillai 131
}
132
 
133
 
134
/** Unmasks interrupt.
135
 *
136
 * @param irq interrupt number
137
 */
138
static inline void qemu_icp_irqc_unmask(uint32_t irq)
139
{
4612 pillai 140
    *((uint32_t *) qemu_icp_hw_map.irqc_unmask) |= (1 << irq);
3528 pillai 141
}
142
 
3529 pillai 143
/** Initializes the icp frame buffer */
144
void qemu_icp_fb_init(void)
145
{
146
    fb_init(qemu_icp_get_fb_address(), 640, 480, 2560, VISUAL_BGR_8_8_8_0);
147
}
3528 pillai 148
 
149
/** Initializes #qemu_icp_hw_map. */
150
void qemu_icp_hw_map_init(void)
151
{
4634 pillai 152
    qemu_icp_hw_map.uart = hw_map(QEMU_ICP_UART, PAGE_SIZE);
4628 pillai 153
    qemu_icp_hw_map.kbd_ctrl = hw_map(QEMU_ICP_KBD, PAGE_SIZE);
154
    qemu_icp_hw_map.kbd_stat = qemu_icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
155
    qemu_icp_hw_map.kbd_data = qemu_icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
156
    qemu_icp_hw_map.kbd_intstat = qemu_icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
3528 pillai 157
    qemu_icp_hw_map.rtc = hw_map(QEMU_ICP_RTC, PAGE_SIZE);
4612 pillai 158
    qemu_icp_hw_map.rtc1_load = qemu_icp_hw_map.rtc + QEMU_ICP_RTC1_LOAD_OFFSET;
159
    qemu_icp_hw_map.rtc1_read = qemu_icp_hw_map.rtc + QEMU_ICP_RTC1_READ_OFFSET;
160
    qemu_icp_hw_map.rtc1_ctl = qemu_icp_hw_map.rtc + QEMU_ICP_RTC1_CTL_OFFSET;
161
    qemu_icp_hw_map.rtc1_intrclr = qemu_icp_hw_map.rtc + QEMU_ICP_RTC1_INTRCLR_OFFSET;
162
    qemu_icp_hw_map.rtc1_bgload = qemu_icp_hw_map.rtc + QEMU_ICP_RTC1_BGLOAD_OFFSET;
163
 
3528 pillai 164
    qemu_icp_hw_map.irqc = hw_map(QEMU_ICP_IRQC, PAGE_SIZE);
165
    qemu_icp_hw_map.irqc_mask = qemu_icp_hw_map.irqc + QEMU_ICP_IRQC_MASK_OFFSET;
4634 pillai 166
    qemu_icp_hw_map.irqc_unmask = qemu_icp_hw_map.irqc + QEMU_ICP_IRQC_UNMASK_OFFSET;
3528 pillai 167
    qemu_icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE);
4634 pillai 168
    qemu_icp_hw_map.sdramcr = qemu_icp_hw_map.cmcr + QEMU_ICP_SDRAMCR_OFFSET;
3528 pillai 169
    qemu_icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE);
170
 
171
    hw_map_init_called = true;
172
}
173
 
174
 
175
/** Acquire console back for kernel. */
176
void qemu_icp_grab_console(void)
177
{
4629 pillai 178
    pl050_grab();
3528 pillai 179
}
180
 
181
/** Return console to userspace. */
182
void qemu_icp_release_console(void)
183
{
4629 pillai 184
    pl050_release();
3528 pillai 185
}
186
 
187
/** Initializes console object representing qemu_icp console.
188
 *
189
 *  @param devno device number.
190
 */
191
void qemu_icp_console_init(devno_t devno)
192
{
193
 
4628 pillai 194
    qemu_icp_irqc_mask(QEMU_ICP_KBD_IRQ);
4629 pillai 195
    pl050_init(devno, QEMU_ICP_KBD_IRQ, QEMU_ICP_KBD, qemu_icp_hw_map.kbd_ctrl);
3528 pillai 196
    qemu_icp_irqc_unmask(QEMU_ICP_KBD_IRQ);
197
}
198
 
199
/** Starts qemu_icp Real Time Clock device, which asserts regular interrupts.
200
 *
201
 * @param frequency Interrupts frequency (0 disables RTC).
202
 */
203
static void qemu_icp_timer_start(uint32_t frequency)
204
{
4615 pillai 205
    qemu_icp_irqc_mask(QEMU_ICP_TIMER_IRQ);
4612 pillai 206
    *((uint32_t*) qemu_icp_hw_map.rtc1_load) = frequency;
207
    *((uint32_t*) qemu_icp_hw_map.rtc1_bgload) = frequency;
208
    *((uint32_t*) qemu_icp_hw_map.rtc1_ctl) = QEMU_ICP_RTC_CTL_VALUE;
209
    qemu_icp_irqc_unmask(QEMU_ICP_TIMER_IRQ);
3528 pillai 210
}
211
 
212
static irq_ownership_t qemu_icp_timer_claim(void)
213
{
214
    return IRQ_ACCEPT;
215
}
216
 
217
/** Timer interrupt handler.
218
 *
219
 * @param irq Interrupt information.
220
 * @param arg Not used.
221
 */
222
static void qemu_icp_timer_irq_handler(irq_t *irq, void *arg, ...)
223
{
224
    /*
225
    * We are holding a lock which prevents preemption.
226
    * Release the lock, call clock() and reacquire the lock again.
227
    */
4632 pillai 228
 
4628 pillai 229
    *((uint32_t*) qemu_icp_hw_map.rtc1_intrclr) = 1;
3528 pillai 230
    spinlock_unlock(&irq->lock);
231
    clock();
232
    spinlock_lock(&irq->lock);
233
 
234
}
235
 
236
/** Initializes and registers timer interrupt handler. */
237
static void qemu_icp_timer_irq_init(void)
238
{
239
    irq_initialize(&qemu_icp_timer_irq);
240
    qemu_icp_timer_irq.devno = device_assign_devno();
241
    qemu_icp_timer_irq.inr = QEMU_ICP_TIMER_IRQ;
242
    qemu_icp_timer_irq.claim = qemu_icp_timer_claim;
243
    qemu_icp_timer_irq.handler = qemu_icp_timer_irq_handler;
244
 
245
    irq_register(&qemu_icp_timer_irq);
246
}
247
 
248
 
249
/** Starts timer.
250
 *
251
 * Initiates regular timer interrupts after initializing
252
 * corresponding interrupt handler.
253
 */
254
void qemu_icp_timer_irq_start(void)
255
{
256
    qemu_icp_timer_irq_init();
257
    qemu_icp_timer_start(QEMU_ICP_TIMER_FREQ);
258
}
259
 
260
/** Returns the size of emulated memory.
261
 *
262
 * @return Size in bytes.
263
 */
264
size_t qemu_icp_get_memory_size(void)
265
{
4634 pillai 266
    if (hw_map_init_called) {
267
        return (sdram[((*(uint32_t *)qemu_icp_hw_map.sdramcr & QEMU_ICP_SDRAM_MASK) >> 2)]);
268
    } else {
269
        return SDRAM_SIZE;
270
    }
271
 
3528 pillai 272
}
273
 
274
/** Prints a character.
275
 *
276
 *  @param ch Character to be printed.
277
 */
278
void qemu_icp_debug_putc(char ch)
279
{
280
    char *addr = 0;
281
    if (!hw_map_init_called) {
282
        addr = (char *) QEMU_ICP_KBD;
283
    } else {
4634 pillai 284
        addr = (char *) qemu_icp_hw_map.uart;
3528 pillai 285
    }
286
 
287
    if (ch == '\n')
288
        *(addr) = '\r';
289
    *(addr) = ch;
290
}
291
 
292
/** Stops qemu_icp. */
293
void qemu_icp_cpu_halt(void)
294
{
4628 pillai 295
    while (1);
3528 pillai 296
}
297
 
4634 pillai 298
/** interrupt exception handler.
3528 pillai 299
 *
300
 * Determines sources of the interrupt from interrupt controller and
301
 * calls high-level handlers for them.
302
 *
303
 * @param exc_no Interrupt exception number.
304
 * @param istate Saved processor state.
305
 */
306
void qemu_icp_irq_exception(int exc_no, istate_t *istate)
307
{
308
    uint32_t sources = qemu_icp_irqc_get_sources();
309
    int i;
310
 
311
    for (i = 0; i < QEMU_ICP_IRQC_MAX_IRQ; i++) {
312
        if (sources & (1 << i)) {
313
            irq_t *irq = irq_dispatch_and_lock(i);
314
            if (irq) {
315
                /* The IRQ handler was found. */
316
                irq->handler(irq, irq->arg);
317
                spinlock_unlock(&irq->lock);
318
            } else {
319
                /* Spurious interrupt.*/
320
                dprintf("cpu%d: spurious interrupt (inum=%d)\n",
321
                    CPU->id, i);
322
            }
323
        }
324
    }
325
}
326
 
327
/** Returns address of framebuffer device.
328
 *
329
 *  @return Address of framebuffer device.
330
 */
331
uintptr_t qemu_icp_get_fb_address(void)
332
{
333
    if (!vga_init) {
334
        icp_vga_init();
335
        vga_init = true;
336
    }
337
    return (uintptr_t) QEMU_ICP_FB;
338
}
339
 
4634 pillai 340
/*
341
 * Integrator specific frame initialization
342
 */
343
void
344
qemu_icp_frame_init(void)
345
{
346
    frame_mark_unavailable(QEMU_ICP_FB_FRAME, QEMU_ICP_FB_NUM_FRAME);
347
}
3528 pillai 348
 
4634 pillai 349
 
3528 pillai 350
/** @}
351
 */