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

Last change on this file was b67ce1ff, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 2 years ago

Use irq_spinlock functions in arm32 code, to be consistent with all other code

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