source: mainline/kernel/arch/arm32/src/mach/integratorcp/integratorcp.c@ 2d884ab

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2d884ab was 8ec4144, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

integratorcp: Add uart kernel driver.

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