Rev 4651 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4651 | Rev 4669 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2009 Vineeth Pillai |
2 | * Copyright (c) 2009 Vineeth Pillai |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
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 |
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. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
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 |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
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 |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
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 |
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. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup arm32integratorcp |
29 | /** @addtogroup arm32integratorcp |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | /** @file |
32 | /** @file |
33 | * @brief ICP drivers. |
33 | * @brief ICP drivers. |
34 | */ |
34 | */ |
35 | 35 | ||
36 | #include <interrupt.h> |
36 | #include <interrupt.h> |
37 | #include <ipc/irq.h> |
37 | #include <ipc/irq.h> |
38 | #include <console/chardev.h> |
38 | #include <console/chardev.h> |
39 | #include <genarch/drivers/pl050/pl050.h> |
39 | #include <genarch/drivers/pl050/pl050.h> |
40 | #include <genarch/kbrd/kbrd.h> |
40 | #include <genarch/kbrd/kbrd.h> |
41 | #include <console/console.h> |
41 | #include <console/console.h> |
42 | #include <sysinfo/sysinfo.h> |
42 | #include <sysinfo/sysinfo.h> |
43 | #include <print.h> |
43 | #include <print.h> |
44 | #include <ddi/device.h> |
44 | #include <ddi/device.h> |
45 | #include <mm/page.h> |
45 | #include <mm/page.h> |
46 | #include <mm/frame.h> |
46 | #include <mm/frame.h> |
47 | #include <arch/mm/frame.h> |
47 | #include <arch/mm/frame.h> |
48 | #include <arch/mach/integratorcp/integratorcp.h> |
48 | #include <arch/mach/integratorcp/integratorcp.h> |
49 | #include <genarch/fb/fb.h> |
49 | #include <genarch/fb/fb.h> |
50 | #include <genarch/fb/visuals.h> |
50 | #include <genarch/fb/visuals.h> |
51 | #include <ddi/ddi.h> |
51 | #include <ddi/ddi.h> |
52 | #include <print.h> |
52 | #include <print.h> |
53 | 53 | ||
54 | #define SDRAM_SIZE (sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)]) |
54 | #define SDRAM_SIZE (sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)]) |
55 | static parea_t fb_parea; |
55 | static parea_t fb_parea; |
56 | static icp_hw_map_t icp_hw_map; |
56 | static icp_hw_map_t icp_hw_map; |
57 | static irq_t icp_timer_irq; |
57 | static irq_t icp_timer_irq; |
58 | struct arm_machine_ops machine_ops = { |
58 | struct arm_machine_ops machine_ops = { |
59 | MACHINE_GENFUNC, |
59 | MACHINE_GENFUNC, |
60 | MACHINE_GENFUNC, |
60 | MACHINE_GENFUNC, |
61 | icp_init, |
61 | icp_init, |
62 | icp_timer_irq_start, |
62 | icp_timer_irq_start, |
63 | icp_cpu_halt, |
63 | icp_cpu_halt, |
64 | icp_get_memory_size, |
64 | icp_get_memory_size, |
65 | icp_fb_init, |
65 | icp_fb_init, |
66 | icp_irq_exception, |
66 | icp_irq_exception, |
67 | icp_get_fb_address, |
67 | icp_get_fb_address, |
68 | icp_frame_init, |
68 | icp_frame_init, |
69 | icp_output_init, |
69 | icp_output_init, |
70 | icp_input_init |
70 | icp_input_init |
71 | }; |
71 | }; |
72 | 72 | ||
73 | static bool hw_map_init_called = false; |
73 | static bool hw_map_init_called = false; |
74 | static bool vga_init = false; |
74 | static bool vga_init = false; |
75 | uint32_t sdram[8] = { |
75 | uint32_t sdram[8] = { |
76 | 16777216, /* 16mb */ |
76 | 16777216, /* 16mb */ |
77 | 33554432, /* 32mb */ |
77 | 33554432, /* 32mb */ |
78 | 67108864, /* 64mb */ |
78 | 67108864, /* 64mb */ |
79 | 134217728, /* 128mb */ |
79 | 134217728, /* 128mb */ |
80 | 268435456, /* 256mb */ |
80 | 268435456, /* 256mb */ |
81 | 0, /* Reserverd */ |
81 | 0, /* Reserverd */ |
82 | 0, /* Reserverd */ |
82 | 0, /* Reserverd */ |
83 | 0 /* Reserverd */ |
83 | 0 /* Reserverd */ |
84 | }; |
84 | }; |
85 | 85 | ||
86 | void icp_vga_init(void); |
86 | void icp_vga_init(void); |
87 | 87 | ||
88 | /** Initializes the vga |
88 | /** Initializes the vga |
89 | * |
89 | * |
90 | */ |
90 | */ |
91 | void icp_vga_init(void) |
91 | void icp_vga_init(void) |
92 | { |
92 | { |
93 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
93 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000; |
94 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
94 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000; |
95 | *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C; |
95 | *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C; |
96 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF; |
96 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF; |
97 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800; |
97 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800; |
98 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB; |
98 | *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB; |
99 | *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B; |
99 | *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B; |
100 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000; |
100 | *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000; |
101 | 101 | ||
102 | } |
102 | } |
103 | 103 | ||
104 | /** Returns the mask of active interrupts. */ |
104 | /** Returns the mask of active interrupts. */ |
105 | static inline uint32_t icp_irqc_get_sources(void) |
105 | static inline uint32_t icp_irqc_get_sources(void) |
106 | { |
106 | { |
107 | return *((uint32_t *) icp_hw_map.irqc); |
107 | return *((uint32_t *) icp_hw_map.irqc); |
108 | } |
108 | } |
109 | 109 | ||
110 | 110 | ||
111 | /** Masks interrupt. |
111 | /** Masks interrupt. |
112 | * |
112 | * |
113 | * @param irq interrupt number |
113 | * @param irq interrupt number |
114 | */ |
114 | */ |
115 | static inline void icp_irqc_mask(uint32_t irq) |
115 | static inline void icp_irqc_mask(uint32_t irq) |
116 | { |
116 | { |
117 | *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq); |
117 | *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq); |
118 | } |
118 | } |
119 | 119 | ||
120 | 120 | ||
121 | /** Unmasks interrupt. |
121 | /** Unmasks interrupt. |
122 | * |
122 | * |
123 | * @param irq interrupt number |
123 | * @param irq interrupt number |
124 | */ |
124 | */ |
125 | static inline void icp_irqc_unmask(uint32_t irq) |
125 | static inline void icp_irqc_unmask(uint32_t irq) |
126 | { |
126 | { |
127 | *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq); |
127 | *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq); |
128 | } |
128 | } |
129 | 129 | ||
130 | /** Initializes the icp frame buffer */ |
130 | /** Initializes the icp frame buffer */ |
131 | void icp_fb_init(void) |
131 | void icp_fb_init(void) |
132 | { |
132 | { |
133 | fb_properties_t prop = { |
133 | fb_properties_t prop = { |
134 | .addr = 0, |
134 | .addr = 0, |
135 | .offset = 0, |
135 | .offset = 0, |
136 | .x = 640, |
136 | .x = 640, |
137 | .y = 480, |
137 | .y = 480, |
138 | .scan = 2560, |
138 | .scan = 2560, |
139 | .visual = VISUAL_RGB_8_8_8_0, |
139 | .visual = VISUAL_RGB_8_8_8_0, |
140 | }; |
140 | }; |
141 | prop.addr = icp_get_fb_address(); |
141 | prop.addr = icp_get_fb_address(); |
142 | fb_init(&prop); |
142 | fb_init(&prop); |
143 | fb_parea.pbase = ICP_FB; |
143 | fb_parea.pbase = ICP_FB; |
144 | fb_parea.frames = 300; |
144 | fb_parea.frames = 300; |
145 | ddi_parea_register(&fb_parea); |
145 | ddi_parea_register(&fb_parea); |
146 | } |
146 | } |
147 | 147 | ||
148 | /** Initializes icp_hw_map. */ |
148 | /** Initializes icp_hw_map. */ |
149 | void icp_init(void) |
149 | void icp_init(void) |
150 | { |
150 | { |
151 | icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE); |
151 | icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE); |
152 | icp_hw_map.kbd_ctrl = hw_map(ICP_KBD, 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; |
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; |
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; |
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); |
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; |
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; |
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; |
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; |
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; |
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; |
162 | icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET; |
163 | 163 | ||
164 | icp_hw_map.irqc = hw_map(ICP_IRQC, PAGE_SIZE); |
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; |
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; |
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); |
167 | icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE); |
168 | icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET; |
168 | icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET; |
169 | icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
169 | icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE); |
170 | 170 | ||
171 | hw_map_init_called = true; |
171 | hw_map_init_called = true; |
172 | } |
172 | } |
173 | 173 | ||
174 | 174 | ||
175 | /** Acquire console back for kernel. */ |
175 | /** Acquire console back for kernel. */ |
176 | void icp_grab_console(void) |
176 | void icp_grab_console(void) |
177 | { |
177 | { |
178 | } |
178 | } |
179 | 179 | ||
180 | /** Return console to userspace. */ |
180 | /** Return console to userspace. */ |
181 | void icp_release_console(void) |
181 | void icp_release_console(void) |
182 | { |
182 | { |
183 | } |
183 | } |
184 | 184 | ||
185 | /** Starts icp Real Time Clock device, which asserts regular interrupts. |
185 | /** Starts icp Real Time Clock device, which asserts regular interrupts. |
186 | * |
186 | * |
187 | * @param frequency Interrupts frequency (0 disables RTC). |
187 | * @param frequency Interrupts frequency (0 disables RTC). |
188 | */ |
188 | */ |
189 | static void icp_timer_start(uint32_t frequency) |
189 | static void icp_timer_start(uint32_t frequency) |
190 | { |
190 | { |
191 | icp_irqc_mask(ICP_TIMER_IRQ); |
191 | icp_irqc_mask(ICP_TIMER_IRQ); |
192 | *((uint32_t*) icp_hw_map.rtc1_load) = frequency; |
192 | *((uint32_t*) icp_hw_map.rtc1_load) = frequency; |
193 | *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency; |
193 | *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency; |
194 | *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE; |
194 | *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE; |
195 | icp_irqc_unmask(ICP_TIMER_IRQ); |
195 | icp_irqc_unmask(ICP_TIMER_IRQ); |
196 | } |
196 | } |
197 | 197 | ||
198 | static irq_ownership_t icp_timer_claim(irq_t *irq) |
198 | static irq_ownership_t icp_timer_claim(irq_t *irq) |
199 | { |
199 | { |
200 | if (icp_hw_map.rtc1_intrstat) { |
200 | if (icp_hw_map.rtc1_intrstat) { |
201 | *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1; |
201 | *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1; |
202 | return IRQ_ACCEPT; |
202 | return IRQ_ACCEPT; |
203 | } else |
203 | } else |
204 | return IRQ_DECLINE; |
204 | return IRQ_DECLINE; |
205 | } |
205 | } |
206 | 206 | ||
207 | /** Timer interrupt handler. |
207 | /** Timer interrupt handler. |
208 | * |
208 | * |
209 | * @param irq Interrupt information. |
209 | * @param irq Interrupt information. |
210 | * @param arg Not used. |
210 | * @param arg Not used. |
211 | */ |
211 | */ |
212 | static void icp_timer_irq_handler(irq_t *irq) |
212 | static void icp_timer_irq_handler(irq_t *irq) |
213 | { |
213 | { |
214 | /* |
214 | /* |
215 | * We are holding a lock which prevents preemption. |
215 | * We are holding a lock which prevents preemption. |
216 | * Release the lock, call clock() and reacquire the lock again. |
216 | * Release the lock, call clock() and reacquire the lock again. |
217 | */ |
217 | */ |
218 | 218 | ||
219 | spinlock_unlock(&irq->lock); |
219 | spinlock_unlock(&irq->lock); |
220 | clock(); |
220 | clock(); |
221 | spinlock_lock(&irq->lock); |
221 | spinlock_lock(&irq->lock); |
222 | 222 | ||
223 | } |
223 | } |
224 | 224 | ||
225 | /** Initializes and registers timer interrupt handler. */ |
225 | /** Initializes and registers timer interrupt handler. */ |
226 | static void icp_timer_irq_init(void) |
226 | static void icp_timer_irq_init(void) |
227 | { |
227 | { |
228 | irq_initialize(&icp_timer_irq); |
228 | irq_initialize(&icp_timer_irq); |
229 | icp_timer_irq.devno = device_assign_devno(); |
229 | icp_timer_irq.devno = device_assign_devno(); |
230 | icp_timer_irq.inr = ICP_TIMER_IRQ; |
230 | icp_timer_irq.inr = ICP_TIMER_IRQ; |
231 | icp_timer_irq.claim = icp_timer_claim; |
231 | icp_timer_irq.claim = icp_timer_claim; |
232 | icp_timer_irq.handler = icp_timer_irq_handler; |
232 | icp_timer_irq.handler = icp_timer_irq_handler; |
233 | 233 | ||
234 | irq_register(&icp_timer_irq); |
234 | irq_register(&icp_timer_irq); |
235 | } |
235 | } |
236 | 236 | ||
237 | 237 | ||
238 | /** Starts timer. |
238 | /** Starts timer. |
239 | * |
239 | * |
240 | * Initiates regular timer interrupts after initializing |
240 | * Initiates regular timer interrupts after initializing |
241 | * corresponding interrupt handler. |
241 | * corresponding interrupt handler. |
242 | */ |
242 | */ |
243 | void icp_timer_irq_start(void) |
243 | void icp_timer_irq_start(void) |
244 | { |
244 | { |
245 | icp_timer_irq_init(); |
245 | icp_timer_irq_init(); |
246 | icp_timer_start(ICP_TIMER_FREQ); |
246 | icp_timer_start(ICP_TIMER_FREQ); |
247 | } |
247 | } |
248 | 248 | ||
249 | /** Returns the size of emulated memory. |
249 | /** Returns the size of emulated memory. |
250 | * |
250 | * |
251 | * @return Size in bytes. |
251 | * @return Size in bytes. |
252 | */ |
252 | */ |
253 | size_t icp_get_memory_size(void) |
253 | size_t icp_get_memory_size(void) |
254 | { |
254 | { |
255 | if (hw_map_init_called) { |
255 | if (hw_map_init_called) { |
256 | return (sdram[((*(uint32_t *)icp_hw_map.sdramcr & ICP_SDRAM_MASK) >> 2)]); |
256 | return (sdram[((*(uint32_t *)icp_hw_map.sdramcr & ICP_SDRAM_MASK) >> 2)]); |
257 | } else { |
257 | } else { |
258 | return SDRAM_SIZE; |
258 | return SDRAM_SIZE; |
259 | } |
259 | } |
260 | 260 | ||
261 | } |
261 | } |
262 | 262 | ||
263 | /** Stops icp. */ |
263 | /** Stops icp. */ |
264 | void icp_cpu_halt(void) |
264 | void icp_cpu_halt(void) |
265 | { |
265 | { |
266 | while (1); |
266 | while (1); |
267 | } |
267 | } |
268 | 268 | ||
269 | /** interrupt exception handler. |
269 | /** interrupt exception handler. |
270 | * |
270 | * |
271 | * Determines sources of the interrupt from interrupt controller and |
271 | * Determines sources of the interrupt from interrupt controller and |
272 | * calls high-level handlers for them. |
272 | * calls high-level handlers for them. |
273 | * |
273 | * |
274 | * @param exc_no Interrupt exception number. |
274 | * @param exc_no Interrupt exception number. |
275 | * @param istate Saved processor state. |
275 | * @param istate Saved processor state. |
276 | */ |
276 | */ |
277 | void icp_irq_exception(int exc_no, istate_t *istate) |
277 | void icp_irq_exception(int exc_no, istate_t *istate) |
278 | { |
278 | { |
279 | uint32_t sources = icp_irqc_get_sources(); |
279 | uint32_t sources = icp_irqc_get_sources(); |
280 | int i; |
280 | int i; |
281 | 281 | ||
282 | for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) { |
282 | for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) { |
283 | if (sources & (1 << i)) { |
283 | if (sources & (1 << i)) { |
284 | irq_t *irq = irq_dispatch_and_lock(i); |
284 | irq_t *irq = irq_dispatch_and_lock(i); |
285 | if (irq) { |
285 | if (irq) { |
286 | /* The IRQ handler was found. */ |
286 | /* The IRQ handler was found. */ |
287 | irq->handler(irq); |
287 | irq->handler(irq); |
288 | spinlock_unlock(&irq->lock); |
288 | spinlock_unlock(&irq->lock); |
289 | } else { |
289 | } else { |
290 | /* Spurious interrupt.*/ |
290 | /* Spurious interrupt.*/ |
291 | printf("cpu%d: spurious interrupt (inum=%d)\n", |
291 | printf("cpu%d: spurious interrupt (inum=%d)\n", |
292 | CPU->id, i); |
292 | CPU->id, i); |
293 | } |
293 | } |
294 | } |
294 | } |
295 | } |
295 | } |
296 | } |
296 | } |
297 | 297 | ||
298 | /** Returns address of framebuffer device. |
298 | /** Returns address of framebuffer device. |
299 | * |
299 | * |
300 | * @return Address of framebuffer device. |
300 | * @return Address of framebuffer device. |
301 | */ |
301 | */ |
302 | uintptr_t icp_get_fb_address(void) |
302 | uintptr_t icp_get_fb_address(void) |
303 | { |
303 | { |
304 | if (!vga_init) { |
304 | if (!vga_init) { |
305 | icp_vga_init(); |
305 | icp_vga_init(); |
306 | vga_init = true; |
306 | vga_init = true; |
307 | } |
307 | } |
308 | return (uintptr_t) ICP_FB; |
308 | return (uintptr_t) ICP_FB; |
309 | } |
309 | } |
310 | 310 | ||
311 | /* |
311 | /* |
312 | * Integrator specific frame initialization |
312 | * Integrator specific frame initialization |
313 | */ |
313 | */ |
314 | void |
314 | void |
315 | icp_frame_init(void) |
315 | icp_frame_init(void) |
316 | { |
316 | { |
317 | frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME); |
317 | frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME); |
318 | frame_mark_unavailable(0, 256); |
318 | frame_mark_unavailable(0, 256); |
319 | } |
319 | } |
320 | 320 | ||
321 | void icp_output_init(void) |
321 | void icp_output_init(void) |
322 | { |
322 | { |
323 | } |
323 | } |
324 | 324 | ||
325 | void icp_input_init(void) |
325 | void icp_input_init(void) |
326 | { |
326 | { |
327 | 327 | ||
328 | pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC); |
328 | pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC); |
329 | pl050->status = (ioport8_t *)icp_hw_map.kbd_stat; |
329 | pl050->status = (ioport8_t *)icp_hw_map.kbd_stat; |
330 | pl050->data = (ioport8_t *)icp_hw_map.kbd_data; |
330 | pl050->data = (ioport8_t *)icp_hw_map.kbd_data; |
331 | pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl; |
331 | pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl; |
332 | 332 | ||
333 | pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ); |
333 | pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ); |
334 | if (pl050_instance) { |
334 | if (pl050_instance) { |
335 | kbrd_instance_t *kbrd_instance = kbrd_init(); |
335 | kbrd_instance_t *kbrd_instance = kbrd_init(); |
336 | if (kbrd_instance) { |
336 | if (kbrd_instance) { |
337 | icp_irqc_mask(ICP_KBD_IRQ); |
337 | icp_irqc_mask(ICP_KBD_IRQ); |
338 | indev_t *sink = stdin_wire(); |
338 | indev_t *sink = stdin_wire(); |
339 | indev_t *kbrd = kbrd_wire(kbrd_instance, sink); |
339 | indev_t *kbrd = kbrd_wire(kbrd_instance, sink); |
340 | pl050_wire(pl050_instance, kbrd); |
340 | pl050_wire(pl050_instance, kbrd); |
341 | icp_irqc_unmask(ICP_KBD_IRQ); |
341 | icp_irqc_unmask(ICP_KBD_IRQ); |
342 | } |
342 | } |
343 | } |
343 | } |
344 | 344 | ||
345 | /* |
345 | /* |
346 | * This is the necessary evil until the userspace driver is entirely |
346 | * This is the necessary evil until the userspace driver is entirely |
347 | * self-sufficient. |
347 | * self-sufficient. |
348 | */ |
348 | */ |
349 | sysinfo_set_item_val("kbd", NULL, true); |
349 | sysinfo_set_item_val("kbd", NULL, true); |
350 | sysinfo_set_item_val("kbd.inr", NULL, ICP_KBD_IRQ); |
350 | sysinfo_set_item_val("kbd.inr", NULL, ICP_KBD_IRQ); |
351 | sysinfo_set_item_val("kbd.address.status", NULL, |
351 | sysinfo_set_item_val("kbd.address.status", NULL, |
352 | (uintptr_t) icp_hw_map.kbd_stat); |
352 | (uintptr_t) icp_hw_map.kbd_stat); |
353 | sysinfo_set_item_val("kbd.address.data", NULL, |
353 | sysinfo_set_item_val("kbd.address.data", NULL, |
354 | (uintptr_t) icp_hw_map.kbd_data); |
354 | (uintptr_t) icp_hw_map.kbd_data); |
355 | 355 | ||
356 | } |
356 | } |
357 | 357 | ||
358 | 358 | ||
359 | /** @} |
359 | /** @} |
360 | */ |
360 | */ |
361 | 361 |