~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to kernel/arch/arm32/src/mach/integratorcp/integratorcp.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        0               /* Reserverd */
 
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_BGR_0_8_8_8,
 
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
 */