FS#11417 by Joe Balough: fix audio/tuner on philips hdd6330
[kugel-rb.git] / firmware / target / arm / tcc780x / system-tcc780x.c
blobd1927c065feace0517c7753f32d3de10b43650c3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 by Rob Purchase
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "kernel.h"
23 #include "system.h"
24 #include "panic.h"
25 #include "power.h"
27 #define default_interrupt(name) \
28 extern __attribute__((weak,alias("UIRQ"))) void name (void)
30 void irq_handler(void) __attribute__((interrupt ("IRQ"), naked));
31 void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked));
33 default_interrupt(EXT0);
34 default_interrupt(EXT1);
35 default_interrupt(EXT2);
36 default_interrupt(EXT3);
37 default_interrupt(RTC);
38 default_interrupt(GPSB0);
39 default_interrupt(TIMER0);
40 default_interrupt(TIMER1);
41 default_interrupt(SCORE);
42 default_interrupt(SPDTX);
43 default_interrupt(VIDEO);
44 default_interrupt(GSIO);
45 default_interrupt(SCALER);
46 default_interrupt(I2C);
47 default_interrupt(DAI_RX);
48 default_interrupt(DAI_TX);
49 default_interrupt(CDRX);
50 default_interrupt(HPI);
51 default_interrupt(UART0);
52 default_interrupt(UART1);
53 default_interrupt(G2D);
54 default_interrupt(USB_DEVICE);
55 default_interrupt(USB_HOST);
56 default_interrupt(DMA);
57 default_interrupt(HDD);
58 default_interrupt(MSTICK);
59 default_interrupt(NFC);
60 default_interrupt(SDMMC);
61 default_interrupt(CAM);
62 default_interrupt(LCD);
63 default_interrupt(ADC);
64 default_interrupt(GPSB1);
66 /* TODO: Establish IRQ priorities (0 = highest priority) */
67 static const char irqpriority[] =
69 0, /* EXT0 */
70 1, /* EXT1 */
71 2, /* EXT2 */
72 3, /* EXT3 */
73 4, /* RTC */
74 5, /* GPSB0 */
75 6, /* TIMER0 */
76 7, /* TIMER1 */
77 8, /* SCORE */
78 9, /* SPDTX */
79 10, /* VIDEO */
80 11, /* GSIO */
81 12, /* SCALER */
82 13, /* I2C */
83 14, /* DAI_RX */
84 15, /* DAI_TX */
85 16, /* CDRX */
86 17, /* HPI */
87 18, /* UART0 */
88 19, /* UART1 */
89 20, /* G2D */
90 21, /* USB_DEVICE */
91 22, /* USB_HOST */
92 23, /* DMA */
93 24, /* HDD */
94 25, /* MSTICK */
95 26, /* NFC */
96 27, /* SDMMC */
97 28, /* CAM */
98 29, /* LCD */
99 30, /* ADC */
100 31, /* GPSB */
103 static void (* const irqvector[])(void) =
105 EXT0,EXT1,EXT2,EXT3,RTC,GPSB0,TIMER0,TIMER1,
106 SCORE,SPDTX,VIDEO,GSIO,SCALER,I2C,DAI_RX,DAI_TX,
107 CDRX,HPI,UART0,UART1,G2D,USB_DEVICE,USB_HOST,DMA,
108 HDD,MSTICK,NFC,SDMMC,CAM,LCD,ADC,GPSB1
111 static const char * const irqname[] =
113 "EXT0","EXT1","EXT2","EXT3","RTC","GPSB0","TIMER0","TIMER1",
114 "SCORE","SPDTX","VIDEO","GSIO","SCALER","I2C","DAI_RX","DAI_TX",
115 "CDRX","HPI","UART0","UART1","G2D","USB_DEVICE","USB_HOST","DMA",
116 "HDD","MSTICK","NFC","SDMMC","CAM","LCD","ADC","GPSB1"
119 static void UIRQ(void)
121 unsigned int offset = VNIRQ;
122 panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]);
125 void irq_handler(void)
128 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
131 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
132 "sub sp, sp, #8 \n"); /* Reserve stack */
134 int irq_no = VNIRQ; /* Read clears the corresponding IRQ status */
136 if ((irq_no & (1<<31)) == 0) /* Ensure invalid flag is not set */
138 irqvector[irq_no]();
141 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
142 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
143 "subs pc, lr, #4 \n"); /* Return from IRQ */
147 /* TODO - these should live in the target-specific directories and
148 once we understand what all the GPIO pins do, move the init to the
149 specific driver for that hardware. For now, we just perform the
150 same GPIO init as the original firmware - this makes it easier to
151 investigate what the GPIO pins do.
154 #ifdef COWON_D2
155 static void gpio_init(void)
157 /* Do what the original firmware does */
158 GPIOA = 0x07000C83;
159 GPIOA_DIR = 0x0F010CE3;
160 GPIOB = 0;
161 GPIOB_DIR = 0x00080000;
162 GPIOC = 0x39000000;
163 GPIOC_DIR = 0xB9000000;
164 GPIOD = 0;
165 GPIOD_DIR = 0;
166 GPIOD = 0;
167 GPIOD_DIR = 0x00480000;
169 PORTCFG0 = 0x00034540;
170 PORTCFG1 = 0x0566A000;
171 PORTCFG2 = 0x000004C0;
172 PORTCFG3 = 0x0AA40455;
174 #endif
177 /* Second function called in the original firmware's startup code - we just
178 set up the clocks in the same way as the original firmware for now. */
179 #ifdef COWON_D2
180 static void clock_init(void)
182 int i;
184 CSCFG3 = (CSCFG3 &~ 0x3fff) | 0x841;
186 /* Enable Xin (12Mhz), Fsys = Xin, Fbus = Fsys/2, MCPU=Fsys, SCPU=Fsys */
187 CLKCTRL = 0x800FF014;
189 asm volatile (
190 "nop \n\t"
191 "nop \n\t"
194 PCLK_RFREQ = 0x1401002d; /* RAM refresh source = Xin (4) / 0x2d = 266kHz */
196 MCFG |= 1;
197 SDCFG = (SDCFG &~ 0x7000) | 0x2000;
199 MCFG1 |= 1;
200 SDCFG1 = (SDCFG &~ 0x7000) | 0x2000;
202 /* Configure PLL0 to 192Mhz, for CPU scaling */
203 PLL0CFG |= (1<<31); /* power down */
204 CLKDIVC = CLKDIVC &~ (0xff << 24); /* disable PLL0 divider */
205 PLL0CFG = 0x80019808; /* set for 192Mhz (with power down) */
206 PLL0CFG = PLL0CFG &~ (1<<31); /* power up */
208 /* Configure PLL1 to 216Mz, for LCD clock (when divided by 2) */
209 PLL1CFG |= (1<<31); /* power down */
210 CLKDIVC = CLKDIVC &~ (0xff << 16); /* disable PLL1 divider */
211 PLL1CFG = 0x80002503; /* set for 216Mhz (with power down)*/
212 PLL1CFG = PLL1CFG &~ (1<<31); /* power up */
214 i = 0x8000;
215 while (--i) {};
217 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
218 set_cpu_frequency(CPUFREQ_NORMAL);
219 #else
220 /* 48Mhz: Fsys = PLL0 (192Mhz) Fbus = Fsys/4 CPU = Fbus, COP = Fbus */
221 CLKCTRL = (1<<31) | (3<<28) | (3<<4);
222 #endif
224 asm volatile (
225 "nop \n\t"
226 "nop \n\t"
229 /* Configure PCK_TCT to 2Mhz (Xin divided by 6) */
230 PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
232 /* Set TC32 timer to be our USEC_TIMER (Xin divided by 12 = 1MHz) */
233 TC32EN = (1<<24) | 11;
235 /* Unmask common timer IRQ (shared by tick and user timer) */
236 IEN |= TIMER0_IRQ_MASK;
238 #endif
241 #ifdef COWON_D2
242 void system_init(void)
244 MBCFG = 0x19;
246 if (TCC780_VER == 0)
247 ECFG0 = 0x309;
248 else
249 ECFG0 = 0x30d;
251 /* mask all interrupts */
252 IEN = 0;
254 /* Set DAI interrupts as FIQ, all others are IRQ. */
255 IRQSEL = ~(DAI_RX_IRQ_MASK | DAI_TX_IRQ_MASK);
257 POL = 0x200108; /* IRQs 3,8,21 active low (as OF) */
258 TMODE = 0x20ce07c0; /* IRQs 6-10,17-19,22-23,29 level-triggered (as OF) */
260 VCTRL |= (1<<31); /* Reading from VNIRQ clears that interrupt */
262 /* Write IRQ priority registers using ints - a freeze occurs otherwise */
263 int i;
264 for (i = 0; i < 7; i++)
266 IRQ_PRIORITY_TABLE[i] = ((int*)irqpriority)[i];
269 ALLMASK = 3; /* Global FIQ/IRQ unmask */
271 gpio_init();
272 clock_init();
274 #endif
277 void system_reboot(void)
279 disable_interrupt(IRQ_FIQ_DISABLED);
281 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
282 set_cpu_frequency(CPUFREQ_DEFAULT);
283 #endif
285 /* TODO: implement reboot (eg. jump to boot ROM?) */
286 power_off();
289 void system_exception_wait(void)
291 #ifdef COWON_D2
292 while ((GPIOA & 0x4) != 0); /* check for power button */
293 #else
294 #error "system_exception_wait not implemented for this target"
295 #endif
298 int system_memory_guard(int newmode)
300 (void)newmode;
301 return 0;
304 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
306 void set_cpu_frequency(long frequency)
308 if (cpu_frequency == frequency)
309 return;
311 /* CPU/COP frequencies can be scaled between Fbus (min) and Fsys (max).
312 Fbus should not be set below ~32Mhz with LCD enabled or the display
313 will be garbled. */
314 if (frequency == CPUFREQ_MAX)
316 /* 192Mhz:
317 Fsys = PLL0 (192Mhz)
318 Fbus = Fsys/2
319 CPU = Fsys, COP = Fsys */
320 CLKCTRL = (1<<31) | (0xFF<<12) | (1<<4);
322 else if (frequency == CPUFREQ_NORMAL)
324 /* 48Mhz:
325 Fsys = PLL0 (192Mhz)
326 Fbus = Fsys/4
327 CPU = Fbus, COP = Fbus */
328 CLKCTRL = (1<<31) | (3<<28) | (3<<4);
330 else
332 /* 32Mhz:
333 Fsys = PLL0 (192Mhz)
334 Fbus = Fsys/6
335 CPU = Fbus, COP = Fbus */
336 CLKCTRL = (1<<31) | (3<<28) | (5<<4);
339 asm volatile (
340 "nop \n\t"
341 "nop \n\t"
342 "nop \n\t"
345 cpu_frequency = frequency;
348 #endif