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

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

Program timer with the right frequency. (Expect HZ to be 100 Hz for now.)

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