2
* Copyright (c) 2009 Vineeth Pillai
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
29
/** @addtogroup arm32integratorcp
36
#include <interrupt.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>
44
#include <ddi/device.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>
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 = {
73
static bool hw_map_init_called = false;
74
static bool vga_init = false;
79
134217728, /* 128mb */
80
268435456, /* 256mb */
86
void icp_vga_init(void);
88
/** Initializes the vga
91
void icp_vga_init(void)
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;
104
/** Returns the mask of active interrupts. */
105
static inline uint32_t icp_irqc_get_sources(void)
107
return *((uint32_t *) icp_hw_map.irqc);
113
* @param irq interrupt number
115
static inline void icp_irqc_mask(uint32_t irq)
117
*((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
121
/** Unmasks interrupt.
123
* @param irq interrupt number
125
static inline void icp_irqc_unmask(uint32_t irq)
127
*((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
130
/** Initializes the icp frame buffer */
131
void icp_fb_init(void)
133
fb_properties_t prop = {
139
.visual = VISUAL_BGR_0_8_8_8,
141
prop.addr = icp_get_fb_address();
143
fb_parea.pbase = ICP_FB;
144
fb_parea.frames = 300;
145
ddi_parea_register(&fb_parea);
148
/** Initializes icp_hw_map. */
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;
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);
171
hw_map_init_called = true;
175
/** Acquire console back for kernel. */
176
void icp_grab_console(void)
180
/** Return console to userspace. */
181
void icp_release_console(void)
185
/** Starts icp Real Time Clock device, which asserts regular interrupts.
187
* @param frequency Interrupts frequency (0 disables RTC).
189
static void icp_timer_start(uint32_t frequency)
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);
198
static irq_ownership_t icp_timer_claim(irq_t *irq)
200
if (icp_hw_map.rtc1_intrstat) {
201
*((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
207
/** Timer interrupt handler.
209
* @param irq Interrupt information.
210
* @param arg Not used.
212
static void icp_timer_irq_handler(irq_t *irq)
215
* We are holding a lock which prevents preemption.
216
* Release the lock, call clock() and reacquire the lock again.
219
spinlock_unlock(&irq->lock);
221
spinlock_lock(&irq->lock);
225
/** Initializes and registers timer interrupt handler. */
226
static void icp_timer_irq_init(void)
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;
234
irq_register(&icp_timer_irq);
240
* Initiates regular timer interrupts after initializing
241
* corresponding interrupt handler.
243
void icp_timer_irq_start(void)
245
icp_timer_irq_init();
246
icp_timer_start(ICP_TIMER_FREQ);
249
/** Returns the size of emulated memory.
251
* @return Size in bytes.
253
size_t icp_get_memory_size(void)
255
if (hw_map_init_called) {
256
return (sdram[((*(uint32_t *)icp_hw_map.sdramcr & ICP_SDRAM_MASK) >> 2)]);
264
void icp_cpu_halt(void)
269
/** interrupt exception handler.
271
* Determines sources of the interrupt from interrupt controller and
272
* calls high-level handlers for them.
274
* @param exc_no Interrupt exception number.
275
* @param istate Saved processor state.
277
void icp_irq_exception(int exc_no, istate_t *istate)
279
uint32_t sources = icp_irqc_get_sources();
282
for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) {
283
if (sources & (1 << i)) {
284
irq_t *irq = irq_dispatch_and_lock(i);
286
/* The IRQ handler was found. */
288
spinlock_unlock(&irq->lock);
290
/* Spurious interrupt.*/
291
printf("cpu%d: spurious interrupt (inum=%d)\n",
298
/** Returns address of framebuffer device.
300
* @return Address of framebuffer device.
302
uintptr_t icp_get_fb_address(void)
308
return (uintptr_t) ICP_FB;
312
* Integrator specific frame initialization
317
frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
318
frame_mark_unavailable(0, 256);
321
void icp_output_init(void)
325
void icp_input_init(void)
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;
333
pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
334
if (pl050_instance) {
335
kbrd_instance_t *kbrd_instance = kbrd_init();
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);
346
* This is the necessary evil until the userspace driver is entirely
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);