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

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

Use I/O structure to access S3C24xx UART registers.

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