source: mainline/kernel/arch/arm32/src/mach/integratorcp/integratorcp.c@ 3666d386

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3666d386 was b366a6f4, checked in by Martin Decky <martin@…>, 14 years ago

automatic kernel console lockout

  • kernel automatically relinquishes the access to the kernel console when the uspace maps the respective physical memory area
  • kernel output before uspace initialization is currently broken on Ski (no physical memory area), but this is pending further unification
  • kernel console devices are now independent (there is no system-wide "silent" variable), thus on multiple devices the kernel console and uspace output might be usable at the same time
  • Property mode set to 100644
File size: 8.9 KB
Line 
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)])
55static icp_hw_map_t icp_hw_map;
56static irq_t icp_timer_irq;
57struct arm_machine_ops icp_machine_ops = {
58 icp_init,
59 icp_timer_irq_start,
60 icp_cpu_halt,
61 icp_get_memory_extents,
62 icp_irq_exception,
63 icp_frame_init,
64 icp_output_init,
65 icp_input_init,
66 icp_get_irq_count,
67 icp_get_platform_name
68};
69
70static bool hw_map_init_called = false;
71static bool vga_init = false;
72uint32_t sdram[8] = {
73 16777216, /* 16mb */
74 33554432, /* 32mb */
75 67108864, /* 64mb */
76 134217728, /* 128mb */
77 268435456, /* 256mb */
78 0, /* Reserverd */
79 0, /* Reserverd */
80 0 /* Reserverd */
81 };
82
83void icp_vga_init(void);
84
85/** Initializes the vga
86 *
87 */
88void icp_vga_init(void)
89{
90 *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
91 *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
92 *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
93 *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
94 *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
95 *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
96 *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
97 *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
98
99}
100
101/** Returns the mask of active interrupts. */
102static inline uint32_t icp_irqc_get_sources(void)
103{
104 return *((uint32_t *) icp_hw_map.irqc);
105}
106
107
108/** Masks interrupt.
109 *
110 * @param irq interrupt number
111 */
112static inline void icp_irqc_mask(uint32_t irq)
113{
114 *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
115}
116
117
118/** Unmasks interrupt.
119 *
120 * @param irq interrupt number
121 */
122static inline void icp_irqc_unmask(uint32_t irq)
123{
124 *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
125}
126
127/** Initializes icp_hw_map. */
128void icp_init(void)
129{
130 icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE);
131 icp_hw_map.kbd_ctrl = hw_map(ICP_KBD, PAGE_SIZE);
132 icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
133 icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
134 icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
135 icp_hw_map.rtc = hw_map(ICP_RTC, PAGE_SIZE);
136 icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
137 icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
138 icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
139 icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
140 icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
141 icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
142
143 icp_hw_map.irqc = hw_map(ICP_IRQC, PAGE_SIZE);
144 icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
145 icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
146 icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE);
147 icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
148 icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE);
149
150 hw_map_init_called = true;
151}
152
153/** Starts icp Real Time Clock device, which asserts regular interrupts.
154 *
155 * @param frequency Interrupts frequency (0 disables RTC).
156 */
157static void icp_timer_start(uint32_t frequency)
158{
159 icp_irqc_mask(ICP_TIMER_IRQ);
160 *((uint32_t*) icp_hw_map.rtc1_load) = frequency;
161 *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
162 *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
163 icp_irqc_unmask(ICP_TIMER_IRQ);
164}
165
166static irq_ownership_t icp_timer_claim(irq_t *irq)
167{
168 if (icp_hw_map.rtc1_intrstat) {
169 *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
170 return IRQ_ACCEPT;
171 } else
172 return IRQ_DECLINE;
173}
174
175/** Timer interrupt handler.
176 *
177 * @param irq Interrupt information.
178 * @param arg Not used.
179 */
180static void icp_timer_irq_handler(irq_t *irq)
181{
182 /*
183 * We are holding a lock which prevents preemption.
184 * Release the lock, call clock() and reacquire the lock again.
185 */
186
187 spinlock_unlock(&irq->lock);
188 clock();
189 spinlock_lock(&irq->lock);
190
191}
192
193/** Initializes and registers timer interrupt handler. */
194static void icp_timer_irq_init(void)
195{
196 irq_initialize(&icp_timer_irq);
197 icp_timer_irq.devno = device_assign_devno();
198 icp_timer_irq.inr = ICP_TIMER_IRQ;
199 icp_timer_irq.claim = icp_timer_claim;
200 icp_timer_irq.handler = icp_timer_irq_handler;
201
202 irq_register(&icp_timer_irq);
203}
204
205
206/** Starts timer.
207 *
208 * Initiates regular timer interrupts after initializing
209 * corresponding interrupt handler.
210 */
211void icp_timer_irq_start(void)
212{
213 icp_timer_irq_init();
214 icp_timer_start(ICP_TIMER_FREQ);
215}
216
217/** Get extents of available memory.
218 *
219 * @param start Place to store memory start address.
220 * @param size Place to store memory size.
221 */
222void icp_get_memory_extents(uintptr_t *start, uintptr_t *size)
223{
224 *start = 0;
225
226 if (hw_map_init_called) {
227 *size = (sdram[((*(uint32_t *)icp_hw_map.sdramcr &
228 ICP_SDRAM_MASK) >> 2)]);
229 } else {
230 *size = SDRAM_SIZE;
231 }
232}
233
234/** Stops icp. */
235void icp_cpu_halt(void)
236{
237 while (1);
238}
239
240/** interrupt exception handler.
241 *
242 * Determines sources of the interrupt from interrupt controller and
243 * calls high-level handlers for them.
244 *
245 * @param exc_no Interrupt exception number.
246 * @param istate Saved processor state.
247 */
248void icp_irq_exception(unsigned int exc_no, istate_t *istate)
249{
250 uint32_t sources = icp_irqc_get_sources();
251 unsigned int i;
252
253 for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) {
254 if (sources & (1 << i)) {
255 irq_t *irq = irq_dispatch_and_lock(i);
256 if (irq) {
257 /* The IRQ handler was found. */
258 irq->handler(irq);
259 spinlock_unlock(&irq->lock);
260 } else {
261 /* Spurious interrupt.*/
262 printf("cpu%d: spurious interrupt (inum=%d)\n",
263 CPU->id, i);
264 }
265 }
266 }
267}
268
269/*
270 * Integrator specific frame initialization
271 */
272void
273icp_frame_init(void)
274{
275 frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
276 frame_mark_unavailable(0, 256);
277}
278
279void icp_output_init(void)
280{
281#ifdef CONFIG_FB
282 if (!vga_init) {
283 icp_vga_init();
284 vga_init = true;
285 }
286
287 fb_properties_t prop = {
288 .addr = ICP_FB,
289 .offset = 0,
290 .x = 640,
291 .y = 480,
292 .scan = 2560,
293 .visual = VISUAL_RGB_8_8_8_0,
294 };
295
296 outdev_t *fbdev = fb_init(&prop);
297 if (fbdev)
298 stdout_wire(fbdev);
299#endif
300}
301
302void icp_input_init(void)
303{
304
305 pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
306 pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
307 pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
308 pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
309
310 pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
311 if (pl050_instance) {
312 kbrd_instance_t *kbrd_instance = kbrd_init();
313 if (kbrd_instance) {
314 icp_irqc_mask(ICP_KBD_IRQ);
315 indev_t *sink = stdin_wire();
316 indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
317 pl050_wire(pl050_instance, kbrd);
318 icp_irqc_unmask(ICP_KBD_IRQ);
319 }
320 }
321
322 /*
323 * This is the necessary evil until the userspace driver is entirely
324 * self-sufficient.
325 */
326 sysinfo_set_item_val("kbd", NULL, true);
327 sysinfo_set_item_val("kbd.inr", NULL, ICP_KBD_IRQ);
328 sysinfo_set_item_val("kbd.address.status", NULL,
329 (uintptr_t) icp_hw_map.kbd_stat);
330 sysinfo_set_item_val("kbd.address.data", NULL,
331 (uintptr_t) icp_hw_map.kbd_data);
332
333}
334
335size_t icp_get_irq_count(void)
336{
337 return ICP_IRQ_COUNT;
338}
339
340const char *icp_get_platform_name(void)
341{
342 return "integratorcp";
343}
344
345/** @}
346 */
Note: See TracBrowser for help on using the repository browser.