source: mainline/kernel/arch/arm32/src/mach/gta02/gta02.c@ eff1f033

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eff1f033 was eff1f033, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Match platform driver based on platform name instead of architecture name. Obtain platform name from kernel via sysinfo.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
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 arm32gxemul
30 * @{
31 */
32/** @file
33 * @brief Openmoko GTA02 (Neo FreeRunner) platform driver.
34 */
35
36#include <arch/exception.h>
37#include <arch/mach/gta02/gta02.h>
38#include <arch/mm/page.h>
39#include <mm/page.h>
40#include <genarch/fb/fb.h>
41#include <genarch/fb/visuals.h>
42#include <genarch/drivers/s3c24xx_uart/s3c24xx_uart.h>
43#include <genarch/drivers/s3c24xx_irqc/s3c24xx_irqc.h>
44#include <genarch/drivers/s3c24xx_timer/s3c24xx_timer.h>
45#include <genarch/srln/srln.h>
46#include <sysinfo/sysinfo.h>
47#include <interrupt.h>
48#include <ddi/ddi.h>
49#include <ddi/device.h>
50
51#define GTA02_MEMORY_START 0x30000000 /* physical */
52#define GTA02_MEMORY_SIZE 0x08000000 /* 128 MB */
53#define GTA02_MEMORY_SKIP 0x8000
54
55/** GTA02 serial console UART address (UART S3C24XX CPU UART channel 2). */
56#define GTA02_SCONS_BASE 0x50008000
57
58/** GTA02 framebuffer base address */
59#define GTA02_FB_BASE 0x08800000
60
61/** IRQ number used for clock */
62#define GTA02_TIMER_IRQ S3C24XX_INT_TIMER0
63
64static void gta02_init(void);
65static void gta02_timer_irq_start(void);
66static void gta02_cpu_halt(void);
67static void gta02_get_memory_extents(uintptr_t *start, uintptr_t *size);
68static void gta02_irq_exception(unsigned int exc_no, istate_t *istate);
69static void gta02_frame_init(void);
70static void gta02_output_init(void);
71static void gta02_input_init(void);
72static size_t gta02_get_irq_count(void);
73static const char *gta02_get_platform_name(void);
74
75static void gta02_timer_irq_init(void);
76static void gta02_timer_start(void);
77static irq_ownership_t gta02_timer_irq_claim(irq_t *irq);
78static void gta02_timer_irq_handler(irq_t *irq);
79
80static outdev_t *gta02_scons_dev;
81static s3c24xx_irqc_t gta02_irqc;
82static s3c24xx_timer_t *gta02_timer;
83
84static irq_t gta02_timer_irq;
85
86struct arm_machine_ops gta02_machine_ops = {
87 gta02_init,
88 gta02_timer_irq_start,
89 gta02_cpu_halt,
90 gta02_get_memory_extents,
91 gta02_irq_exception,
92 gta02_frame_init,
93 gta02_output_init,
94 gta02_input_init,
95 gta02_get_irq_count,
96 gta02_get_platform_name
97};
98
99static void gta02_init(void)
100{
101 s3c24xx_irqc_regs_t *irqc_regs;
102
103 gta02_timer = (void *) hw_map(S3C24XX_TIMER_ADDRESS, PAGE_SIZE);
104 irqc_regs = (void *) hw_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE);
105
106 /* Initialize interrupt controller. */
107 s3c24xx_irqc_init(&gta02_irqc, irqc_regs);
108}
109
110static void gta02_timer_irq_start(void)
111{
112 gta02_timer_irq_init();
113 gta02_timer_start();
114}
115
116static void gta02_cpu_halt(void)
117{
118}
119
120/** Get extents of available memory.
121 *
122 * @param start Place to store memory start address (physical).
123 * @param size Place to store memory size.
124 */
125static void gta02_get_memory_extents(uintptr_t *start, uintptr_t *size)
126{
127 *start = GTA02_MEMORY_START + GTA02_MEMORY_SKIP;
128 *size = GTA02_MEMORY_SIZE - GTA02_MEMORY_SKIP;
129}
130
131static void gta02_irq_exception(unsigned int exc_no, istate_t *istate)
132{
133 uint32_t inum;
134
135 /* Determine IRQ number. */
136 inum = s3c24xx_irqc_inum_get(&gta02_irqc);
137
138 /* Clear interrupt condition in the interrupt controller. */
139 s3c24xx_irqc_clear(&gta02_irqc, inum);
140
141 irq_t *irq = irq_dispatch_and_lock(inum);
142 if (irq) {
143 /* The IRQ handler was found. */
144 irq->handler(irq);
145 spinlock_unlock(&irq->lock);
146 } else {
147 /* Spurious interrupt.*/
148 printf("cpu%d: spurious interrupt (inum=%d)\n",
149 CPU->id, inum);
150 }
151}
152
153static void gta02_frame_init(void)
154{
155}
156
157static void gta02_output_init(void)
158{
159#ifdef CONFIG_FB
160 parea_t fb_parea;
161
162 fb_properties_t prop = {
163 .addr = GTA02_FB_BASE,
164 .offset = 0,
165 .x = 480,
166 .y = 640,
167 .scan = 960,
168 .visual = VISUAL_RGB_5_6_5_LE
169 };
170
171 outdev_t *fb_dev = fb_init(&prop);
172 if (fb_dev) {
173 stdout_wire(fb_dev);
174 fb_parea.pbase = GTA02_FB_BASE;
175 fb_parea.frames = 150;
176 ddi_parea_register(&fb_parea);
177 }
178#endif
179
180 /* Initialize serial port of the debugging console. */
181 s3c24xx_uart_io_t *scons_io;
182
183 scons_io = (void *) hw_map(GTA02_SCONS_BASE, PAGE_SIZE);
184 gta02_scons_dev = s3c24xx_uart_init(scons_io, S3C24XX_INT_UART2);
185
186 if (gta02_scons_dev) {
187 /* Create output device. */
188 stdout_wire(gta02_scons_dev);
189 }
190
191 /*
192 * This is the necessary evil until the userspace driver is entirely
193 * self-sufficient.
194 */
195 sysinfo_set_item_val("s3c24xx_uart", NULL, true);
196 sysinfo_set_item_val("s3c24xx_uart.inr", NULL, S3C24XX_INT_UART2);
197 sysinfo_set_item_val("s3c24xx_uart.address.physical", NULL,
198 (uintptr_t) GTA02_SCONS_BASE);
199
200}
201
202static void gta02_input_init(void)
203{
204 s3c24xx_uart_t *scons_inst;
205
206 if (gta02_scons_dev) {
207 /* Create input device. */
208 scons_inst = (void *) gta02_scons_dev->data;
209
210 srln_instance_t *srln_instance = srln_init();
211 if (srln_instance) {
212 indev_t *sink = stdin_wire();
213 indev_t *srln = srln_wire(srln_instance, sink);
214 s3c24xx_uart_input_wire(scons_inst, srln);
215
216 /* Enable interrupts from UART2 */
217 s3c24xx_irqc_src_enable(&gta02_irqc,
218 S3C24XX_INT_UART2);
219
220 /* Enable interrupts from UART2 RXD */
221 s3c24xx_irqc_subsrc_enable(&gta02_irqc,
222 S3C24XX_SUBINT_RXD2);
223 }
224 }
225
226 /* Enable interrupts from ADC */
227 s3c24xx_irqc_src_enable(&gta02_irqc, S3C24XX_INT_ADC);
228
229 /* Enable interrupts from ADC sub-sources */
230 s3c24xx_irqc_subsrc_enable(&gta02_irqc, S3C24XX_SUBINT_ADC_S);
231 s3c24xx_irqc_subsrc_enable(&gta02_irqc, S3C24XX_SUBINT_TC);
232}
233
234size_t gta02_get_irq_count(void)
235{
236 return GTA02_IRQ_COUNT;
237}
238
239const char *gta02_get_platform_name(void)
240{
241 return "gta02";
242}
243
244static void gta02_timer_irq_init(void)
245{
246 irq_initialize(&gta02_timer_irq);
247 gta02_timer_irq.devno = device_assign_devno();
248 gta02_timer_irq.inr = GTA02_TIMER_IRQ;
249 gta02_timer_irq.claim = gta02_timer_irq_claim;
250 gta02_timer_irq.handler = gta02_timer_irq_handler;
251
252 irq_register(&gta02_timer_irq);
253}
254
255static irq_ownership_t gta02_timer_irq_claim(irq_t *irq)
256{
257 return IRQ_ACCEPT;
258}
259
260static void gta02_timer_irq_handler(irq_t *irq)
261{
262 /*
263 * We are holding a lock which prevents preemption.
264 * Release the lock, call clock() and reacquire the lock again.
265 */
266 spinlock_unlock(&irq->lock);
267 clock();
268 spinlock_lock(&irq->lock);
269}
270
271static void gta02_timer_start(void)
272{
273 s3c24xx_timer_t *timer = gta02_timer;
274
275 /*
276 * See S3C2442B user manual chapter 10 (PWM Timer) for description
277 * of timer operation. Starting a timer is described in the
278 * section 'Timer initialization using manual update bit and
279 * inverter bit'.
280 */
281
282 /*
283 * GTA02 PCLK should be 100 MHz.
284 * Timer input freq. = PCLK / divider / (1+prescaler)
285 * 100 MHz / 2 / (1+7) / 62500 ~= 100 Hz
286 */
287#if HZ != 100
288#warning Other HZ than 100 not suppored.
289#endif
290
291 /* Set prescaler values. No pre-divison, no dead zone. */
292 pio_write_32(&timer->tcfg0, 7); /* prescale 1/8 */
293
294 /* No DMA request, divider value = 2 for all timers. */
295 pio_write_32(&timer->tcfg1, 0);
296
297 /* Stop all timers. */
298 pio_write_32(&timer->tcon, 0);
299
300 /* Start counting from 64k-1. Compare value is irrelevant. */
301 pio_write_32(&timer->timer[0].cntb, 62500);
302 pio_write_32(&timer->timer[0].cmpb, 0);
303
304 /* Enable interrupts from timer0 */
305 s3c24xx_irqc_src_enable(&gta02_irqc, S3C24XX_INT_TIMER0);
306
307 /* Load data from tcntb0/tcmpb0 into tcnt0/tcmp0. */
308 pio_write_32(&timer->tcon, TCON_T0_AUTO_RLD | TCON_T0_MUPDATE);
309
310 /* Start timer 0. Inverter is off. */
311 pio_write_32(&timer->tcon, TCON_T0_AUTO_RLD | TCON_T0_START);
312}
313
314/** @}
315 */
Note: See TracBrowser for help on using the repository browser.