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
RevLine 
[7c866dc]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
[c5429fe]29/** @addtogroup kernel_arm32_gta02
[7c866dc]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>
[d7ef14b]38#include <arch/mm/page.h>
[f1fc83a]39#include <mm/page.h>
[d4673296]40#include <mm/km.h>
[5c032932]41#include <genarch/fb/fb.h>
[c0699467]42#include <abi/fb/visuals.h>
[96b9724]43#include <genarch/drivers/s3c24xx/uart.h>
44#include <genarch/drivers/s3c24xx/irqc.h>
45#include <genarch/drivers/s3c24xx/timer.h>
[ec08286]46#include <genarch/srln/srln.h>
[a9b5b5f]47#include <sysinfo/sysinfo.h>
[41ce4d9]48#include <interrupt.h>
[5c032932]49#include <ddi/ddi.h>
[b2fa1204]50#include <log.h>
[d7ef14b]51
52#define GTA02_MEMORY_START 0x30000000 /* physical */
53#define GTA02_MEMORY_SIZE 0x08000000 /* 128 MB */
[f1fc83a]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
[7c866dc]58
[5c032932]59/** GTA02 framebuffer base address */
60#define GTA02_FB_BASE 0x08800000
61
[41ce4d9]62/** IRQ number used for clock */
63#define GTA02_TIMER_IRQ S3C24XX_INT_TIMER0
64
[7c866dc]65static void gta02_init(void);
66static void gta02_timer_irq_start(void);
67static void gta02_cpu_halt(void);
[2686705]68static void gta02_get_memory_extents(uintptr_t *start, size_t *size);
[7c866dc]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);
[ecf083dd]73static size_t gta02_get_irq_count(void);
[eff1f033]74static const char *gta02_get_platform_name(void);
[7c866dc]75
[41ce4d9]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
[ec08286]81static outdev_t *gta02_scons_dev;
82static s3c24xx_irqc_t gta02_irqc;
[41ce4d9]83static s3c24xx_timer_t *gta02_timer;
84
85static irq_t gta02_timer_irq;
[f1fc83a]86
[7c866dc]87struct arm_machine_ops gta02_machine_ops = {
88 gta02_init,
89 gta02_timer_irq_start,
90 gta02_cpu_halt,
[d7ef14b]91 gta02_get_memory_extents,
[7c866dc]92 gta02_irq_exception,
93 gta02_frame_init,
94 gta02_output_init,
[ecf083dd]95 gta02_input_init,
[eff1f033]96 gta02_get_irq_count,
97 gta02_get_platform_name
[7c866dc]98};
99
100static void gta02_init(void)
101{
[ec08286]102 s3c24xx_irqc_regs_t *irqc_regs;
103
[adec5b45]104 gta02_timer = (void *) km_map(S3C24XX_TIMER_ADDRESS, PAGE_SIZE,
[a1b9f63]105 PAGE_SIZE, PAGE_NOT_CACHEABLE);
106 irqc_regs = (void *) km_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE, PAGE_SIZE,
[adec5b45]107 PAGE_NOT_CACHEABLE);
[41ce4d9]108
[ec08286]109 /* Initialize interrupt controller. */
110 s3c24xx_irqc_init(&gta02_irqc, irqc_regs);
[7c866dc]111}
112
113static void gta02_timer_irq_start(void)
114{
[41ce4d9]115 gta02_timer_irq_init();
116 gta02_timer_start();
[7c866dc]117}
118
119static void gta02_cpu_halt(void)
120{
121}
122
[d7ef14b]123/** Get extents of available memory.
124 *
[6250c37]125 * @param start Place to store memory start address (physical).
[d7ef14b]126 * @param size Place to store memory size.
127 */
[2686705]128static void gta02_get_memory_extents(uintptr_t *start, size_t *size)
[7c866dc]129{
[6250c37]130 *start = GTA02_MEMORY_START + GTA02_MEMORY_SKIP;
[d7ef14b]131 *size = GTA02_MEMORY_SIZE - GTA02_MEMORY_SKIP;
[7c866dc]132}
133
134static void gta02_irq_exception(unsigned int exc_no, istate_t *istate)
135{
[41ce4d9]136 uint32_t inum;
137
[ec08286]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);
[41ce4d9]143
144 irq_t *irq = irq_dispatch_and_lock(inum);
145 if (irq) {
146 /* The IRQ handler was found. */
147 irq->handler(irq);
[b67ce1ff]148 irq_spinlock_unlock(&irq->lock, false);
[41ce4d9]149 } else {
[d1582b50]150 /* Spurious interrupt. */
[b2fa1204]151 log(LF_ARCH, LVL_DEBUG, "cpu%d: spurious interrupt (inum=%d)",
[41ce4d9]152 CPU->id, inum);
153 }
[7c866dc]154}
155
156static void gta02_frame_init(void)
157{
158}
159
160static void gta02_output_init(void)
161{
[5c032932]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);
[b366a6f4]173 if (fb_dev)
[5c032932]174 stdout_wire(fb_dev);
175#endif
[f1fc83a]176
[ec08286]177 /* Initialize serial port of the debugging console. */
[b366a6f4]178 gta02_scons_dev =
179 s3c24xx_uart_init(GTA02_SCONS_BASE, S3C24XX_INT_UART2);
[ec08286]180
[277cf60]181 if (gta02_scons_dev) {
[ec08286]182 /* Create output device. */
183 stdout_wire(gta02_scons_dev);
184 }
[a9b5b5f]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
[7c866dc]195}
196
197static void gta02_input_init(void)
198{
[277cf60]199 s3c24xx_uart_t *scons_inst;
[ec08286]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 }
[527298a]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);
[7c866dc]227}
228
[ecf083dd]229size_t gta02_get_irq_count(void)
230{
231 return GTA02_IRQ_COUNT;
232}
233
[eff1f033]234const char *gta02_get_platform_name(void)
235{
236 return "gta02";
237}
238
[41ce4d9]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 */
[b67ce1ff]260 irq_spinlock_unlock(&irq->lock, false);
[41ce4d9]261 clock();
[b67ce1ff]262 irq_spinlock_lock(&irq->lock, false);
[41ce4d9]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
[24697c3]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 */
[41ce4d9]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. */
[24697c3]295 pio_write_32(&timer->timer[0].cntb, 62500);
[41ce4d9]296 pio_write_32(&timer->timer[0].cmpb, 0);
297
298 /* Enable interrupts from timer0 */
[ec08286]299 s3c24xx_irqc_src_enable(&gta02_irqc, S3C24XX_INT_TIMER0);
[41ce4d9]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
[7c866dc]308/** @}
309 */
Note: See TracBrowser for help on using the repository browser.