Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
4651 pillai 1
/*
2
 * Copyright (c) 2009 Vineeth 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 arm32integratorcp
30
 * @{
31
 */
32
/** @file
33
 *  @brief ICP drivers.
34
 */
35
 
36
#include <interrupt.h>
37
#include <ipc/irq.h>
38
#include <console/chardev.h>
39
#include <genarch/drivers/pl050/pl050.h>
40
#include <genarch/kbrd/kbrd.h>
41
#include <console/console.h>
42
#include <sysinfo/sysinfo.h>
43
#include <print.h>
44
#include <ddi/device.h>
45
#include <mm/page.h>
46
#include <mm/frame.h>
47
#include <arch/mm/frame.h>
48
#include <arch/mach/integratorcp/integratorcp.h>
49
#include <genarch/fb/fb.h>
50
#include <genarch/fb/visuals.h>
51
#include <ddi/ddi.h>
52
#include <print.h>
53
 
54
#define SDRAM_SIZE  (sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)])
55
static parea_t fb_parea;
56
static icp_hw_map_t icp_hw_map;
57
static irq_t icp_timer_irq;
58
struct arm_machine_ops machine_ops = {
59
    MACHINE_GENFUNC,
60
    MACHINE_GENFUNC,
61
    icp_init,
62
    icp_timer_irq_start,
63
    icp_cpu_halt,
64
    icp_get_memory_size,
65
    icp_fb_init,
66
    icp_irq_exception,
67
    icp_get_fb_address,
68
    icp_frame_init,
69
    icp_output_init,
70
    icp_input_init
71
};
72
 
73
static bool hw_map_init_called = false;
74
static bool vga_init = false;
75
uint32_t sdram[8] = {
76
    16777216,   /* 16mb */
77
    33554432,   /* 32mb */
78
    67108864,   /* 64mb */
79
    134217728,  /* 128mb */
80
    268435456,  /* 256mb */
81
    0,      /* Reserverd */
82
    0,      /* Reserverd */
83
 
84
    };
85
 
86
void icp_vga_init(void);
87
 
88
/** Initializes the vga
89
 *
90
 */
91
void icp_vga_init(void)
92
{
93
    *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
94
    *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
95
    *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
96
    *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
97
    *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
98
    *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
99
    *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
100
    *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
101
 
102
}
103
 
104
/** Returns the mask of active interrupts. */
105
static inline uint32_t icp_irqc_get_sources(void)
106
{
107
    return *((uint32_t *) icp_hw_map.irqc);
108
}
109
 
110
 
111
/** Masks interrupt.
112
 *
113
 * @param irq interrupt number
114
 */
115
static inline void icp_irqc_mask(uint32_t irq)
116
{
117
    *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
118
}
119
 
120
 
121
/** Unmasks interrupt.
122
 *
123
 * @param irq interrupt number
124
 */
125
static inline void icp_irqc_unmask(uint32_t irq)
126
{
127
    *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
128
}
129
 
130
/** Initializes the icp frame buffer */
131
void icp_fb_init(void)
132
{
133
    fb_properties_t prop = {
134
        .addr = 0,
135
        .offset = 0,
136
        .x = 640,
137
        .y = 480,
138
        .scan = 2560,
139
        .visual = VISUAL_RGB_8_8_8_0,
140
    };
141
    prop.addr = icp_get_fb_address();
142
    fb_init(&prop);
143
    fb_parea.pbase = ICP_FB;
144
    fb_parea.frames = 300;
145
    ddi_parea_register(&fb_parea);
146
}
147
 
148
/** Initializes icp_hw_map. */
149
void icp_init(void)
150
{
151
    icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE);
152
    icp_hw_map.kbd_ctrl = hw_map(ICP_KBD, PAGE_SIZE);
153
    icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
154
    icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
155
    icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
156
    icp_hw_map.rtc = hw_map(ICP_RTC, PAGE_SIZE);
157
    icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
158
    icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
159
    icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
160
    icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
161
    icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
162
    icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
163
 
164
    icp_hw_map.irqc = hw_map(ICP_IRQC, PAGE_SIZE);
165
    icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
166
    icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
167
    icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE);
168
    icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
169
    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 icp_grab_console(void)
177
{
178
}
179
 
180
/** Return console to userspace. */
181
void icp_release_console(void)
182
{
183
}
184
 
185
/** Starts icp Real Time Clock device, which asserts regular interrupts.
186
 *
187
 * @param frequency Interrupts frequency (0 disables RTC).
188
 */
189
static void icp_timer_start(uint32_t frequency)
190
{
191
    icp_irqc_mask(ICP_TIMER_IRQ);
192
    *((uint32_t*) icp_hw_map.rtc1_load) = frequency;
193
    *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
194
    *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
195
    icp_irqc_unmask(ICP_TIMER_IRQ);
196
}
197
 
198
static irq_ownership_t icp_timer_claim(irq_t *irq)
199
{
200
    if (icp_hw_map.rtc1_intrstat) {
201
        *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
202
        return IRQ_ACCEPT;
203
    } else
204
        return IRQ_DECLINE;
205
}
206
 
207
/** Timer interrupt handler.
208
 *
209
 * @param irq Interrupt information.
210
 * @param arg Not used.
211
 */
212
static void icp_timer_irq_handler(irq_t *irq)
213
{
214
    /*
215
    * We are holding a lock which prevents preemption.
216
    * Release the lock, call clock() and reacquire the lock again.
217
    */
218
 
219
    spinlock_unlock(&irq->lock);
220
    clock();
221
    spinlock_lock(&irq->lock);
222
 
223
}
224
 
225
/** Initializes and registers timer interrupt handler. */
226
static void icp_timer_irq_init(void)
227
{
228
    irq_initialize(&icp_timer_irq);
229
    icp_timer_irq.devno = device_assign_devno();
230
    icp_timer_irq.inr = ICP_TIMER_IRQ;
231
    icp_timer_irq.claim = icp_timer_claim;
232
    icp_timer_irq.handler = icp_timer_irq_handler;
233
 
234
    irq_register(&icp_timer_irq);
235
}
236
 
237
 
238
/** Starts timer.
239
 *
240
 * Initiates regular timer interrupts after initializing
241
 * corresponding interrupt handler.
242
 */
243
void icp_timer_irq_start(void)
244
{
245
    icp_timer_irq_init();
246
    icp_timer_start(ICP_TIMER_FREQ);
247
}
248
 
249
/** Returns the size of emulated memory.
250
 *
251
 * @return Size in bytes.
252
 */
253
size_t icp_get_memory_size(void)
254
{
255
    if (hw_map_init_called) {
256
        return (sdram[((*(uint32_t *)icp_hw_map.sdramcr & ICP_SDRAM_MASK) >> 2)]);
257
    } else {
258
        return SDRAM_SIZE;
259
    }
260
 
261
}
262
 
263
/** Stops icp. */
264
void icp_cpu_halt(void)
265
{
266
    while (1);
267
}
268
 
269
/** interrupt exception handler.
270
 *
271
 * Determines sources of the interrupt from interrupt controller and
272
 * calls high-level handlers for them.
273
 *
274
 * @param exc_no Interrupt exception number.
275
 * @param istate Saved processor state.
276
 */
277
void icp_irq_exception(int exc_no, istate_t *istate)
278
{
279
    uint32_t sources = icp_irqc_get_sources();
280
    int i;
281
 
282
    for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) {
283
        if (sources & (1 << i)) {
284
            irq_t *irq = irq_dispatch_and_lock(i);
285
            if (irq) {
286
                /* The IRQ handler was found. */
287
                irq->handler(irq);
288
                spinlock_unlock(&irq->lock);
289
            } else {
290
                /* Spurious interrupt.*/
291
                printf("cpu%d: spurious interrupt (inum=%d)\n",
292
                    CPU->id, i);
293
            }
294
        }
295
    }
296
}
297
 
298
/** Returns address of framebuffer device.
299
 *
300
 *  @return Address of framebuffer device.
301
 */
302
uintptr_t icp_get_fb_address(void)
303
{
304
    if (!vga_init) {
305
        icp_vga_init();
306
        vga_init = true;
307
    }
308
    return (uintptr_t) ICP_FB;
309
}
310
 
311
/*
312
 * Integrator specific frame initialization
313
 */
314
void
315
icp_frame_init(void)
316
{
317
    frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
318
    frame_mark_unavailable(0, 256);
319
}
320
 
321
void icp_output_init(void)
322
{
323
}
324
 
325
void icp_input_init(void)
326
{
327
 
328
    pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
329
    pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
330
    pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
331
    pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
332
 
333
    pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
334
    if (pl050_instance) {
335
        kbrd_instance_t *kbrd_instance = kbrd_init();
336
        if (kbrd_instance) {
337
            icp_irqc_mask(ICP_KBD_IRQ);
338
            indev_t *sink = stdin_wire();
339
            indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
340
            pl050_wire(pl050_instance, kbrd);
341
            icp_irqc_unmask(ICP_KBD_IRQ);
342
        }
343
    }
344
 
345
    /*
346
     * This is the necessary evil until the userspace driver is entirely
347
     * self-sufficient.
348
     */
349
    sysinfo_set_item_val("kbd", NULL, true);
350
    sysinfo_set_item_val("kbd.inr", NULL, ICP_KBD_IRQ);
351
    sysinfo_set_item_val("kbd.address.status", NULL,
352
        (uintptr_t) icp_hw_map.kbd_stat);
353
    sysinfo_set_item_val("kbd.address.data", NULL,
354
        (uintptr_t) icp_hw_map.kbd_data);
355
 
356
}
357
 
358
 
359
/** @}
360
 */