summaryrefslogtreecommitdiff
path: root/firmware/target/arm/tcc780x/system-tcc780x.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/tcc780x/system-tcc780x.c')
-rw-r--r--firmware/target/arm/tcc780x/system-tcc780x.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/firmware/target/arm/tcc780x/system-tcc780x.c b/firmware/target/arm/tcc780x/system-tcc780x.c
new file mode 100644
index 0000000000..30221d180e
--- /dev/null
+++ b/firmware/target/arm/tcc780x/system-tcc780x.c
@@ -0,0 +1,275 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Rob Purchase
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "kernel.h"
21#include "system.h"
22#include "panic.h"
23
24#if !defined(BOOTLOADER)
25
26#define default_interrupt(name) \
27 extern __attribute__((weak,alias("UIRQ"))) void name (void)
28
29void irq_handler(void) __attribute__((interrupt ("IRQ"), naked));
30void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked));
31
32default_interrupt(EXT0);
33default_interrupt(EXT1);
34default_interrupt(EXT2);
35default_interrupt(EXT3);
36default_interrupt(IRQ4);
37default_interrupt(IRQ5);
38default_interrupt(TIMER);
39default_interrupt(IRQ7);
40default_interrupt(IRQ8);
41default_interrupt(IRQ9);
42default_interrupt(IRQ10);
43default_interrupt(IRQ11);
44default_interrupt(IRQ12);
45default_interrupt(IRQ13);
46default_interrupt(DAI_RX);
47default_interrupt(DAI_TX);
48default_interrupt(IRQ16);
49default_interrupt(IRQ17);
50default_interrupt(IRQ18);
51default_interrupt(IRQ19);
52default_interrupt(IRQ20);
53default_interrupt(IRQ21);
54default_interrupt(IRQ22);
55default_interrupt(IRQ23);
56default_interrupt(IRQ24);
57default_interrupt(IRQ25);
58default_interrupt(IRQ26);
59default_interrupt(IRQ27);
60default_interrupt(IRQ28);
61default_interrupt(IRQ29);
62default_interrupt(IRQ30);
63default_interrupt(IRQ31);
64
65static void (* const irqvector[])(void) =
66{
67 EXT0,EXT1,EXT2,EXT3,IRQ4,IRQ5,TIMER,IRQ7,
68 IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,DAI_RX,DAI_TX,
69 IRQ16,IRQ17,IRQ18,IRQ19,IRQ20,IRQ21,IRQ22,IRQ23,
70 IRQ24,IRQ25,IRQ26,IRQ27,IRQ28,IRQ29,IRQ30,IRQ31
71};
72
73static const char * const irqname[] =
74{
75 "EXT0","EXT1","EXT2","EXT3","IRQ4","IRQ5","TIMER","IRQ7",
76 "IRQ8","IRQ9","IRQ10","IRQ11","IRQ12","IRQ13","DAI_RX","DAI_TX",
77 "IRQ16","IRQ17","IRQ18","IRQ19","IRQ20","IRQ21","IRQ22","IRQ23",
78 "IRQ24","IRQ25","IRQ26","IRQ27","IRQ28","IRQ29","IRQ30","IRQ31"
79};
80
81static void UIRQ(void)
82{
83 unsigned int offset = VNIRQ;
84 panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]);
85}
86
87void irq_handler(void)
88{
89 /*
90 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
91 */
92
93 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
94 "sub sp, sp, #8 \n"); /* Reserve stack */
95 irqvector[VNIRQ]();
96 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
97 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
98 "subs pc, lr, #4 \n"); /* Return from FIQ */
99}
100
101void fiq_handler(void)
102{
103 asm volatile (
104 "sub lr, lr, #4 \r\n"
105 "movs lr,pc \r\n"
106 );
107}
108#endif /* !defined(BOOTLOADER) */
109
110
111/* TODO:
112 a) this is not the place for this function
113 b) it currently ignores the supplied frequency and uses default values
114 c) if the PLL being set drives any PCKs, an appropriate new clock divider
115 will have to be re-calculated for those PCKs (the OF maintains a list of
116 PCK frequencies for this purpose).
117*/
118void set_pll_frequency(unsigned int pll_number, unsigned int frequency)
119{
120 int i = 0;
121
122 if (pll_number > 1) return;
123
124 /* The frequency parameter is currently ignored and temporary values are
125 used (PLL0=192Mhz, PLL1=216Mhz). The D2 firmware uses a lookup table
126 to derive the values of PLLxCFG from a the supplied frequency.
127 Presumably we will need to do something similar. */
128 if (pll_number == 0)
129 {
130 /* drive CPU off Xin while switching */
131 CLKCTRL = 0xB00FF014; /* Xin enable, Fsys driven by Xin, Fbus = Fsys,
132 MCPU=Fbus, SCPU=Fbus */
133
134 asm volatile (
135 "nop \n\t"
136 "nop \n\t"
137 );
138
139 PLL0CFG |= (1<<31); /* power down */
140 CLKDIVC = CLKDIVC &~ (0xff << 24); /* disable PLL0 divider */
141 PLL0CFG = 0x80019808; /* set for 192Mhz (with power down) */
142 PLL0CFG = PLL0CFG &~ (1<<31); /* power up */
143
144 CLKCTRL = (CLKCTRL & ~0x1f) | 0x800FF010;
145
146 asm volatile (
147 "nop \n\t"
148 "nop \n\t"
149 );
150 }
151 else if (pll_number == 1)
152 {
153 PLL1CFG |= (1<<31); /* power down */
154 CLKDIVC = CLKDIVC &~ (0xff << 16); /* disable PLL1 divider */
155 PLL1CFG = 0x80002503; /* set for 216Mhz (with power down)*/
156 PLL1CFG = PLL1CFG &~ (1<<31); /* power up */
157 }
158
159 i = 0x1000;
160 while (--i) {};
161}
162
163
164/* TODO - these should live in the target-specific directories and
165 once we understand what all the GPIO pins do, move the init to the
166 specific driver for that hardware. For now, we just perform the
167 same GPIO init as the original firmware - this makes it easier to
168 investigate what the GPIO pins do.
169*/
170
171#ifdef COWON_D2
172static void gpio_init(void)
173{
174 /* Do what the original firmware does */
175 GPIOA = 0x07000C83;
176 GPIOA_DIR = 0x0F010CE3;
177 GPIOB = 0;
178 GPIOB_DIR = 0x00080000;
179 GPIOC = 0x39000000;
180 GPIOC_DIR = 0xB9000000;
181 GPIOD = 0;
182 GPIOD_DIR = 0;
183 GPIOD = 0;
184 GPIOD_DIR = 0x00480000;
185
186 PORTCFG0 = 0x00034540;
187 PORTCFG1 = 0x0566A000;
188 PORTCFG2 = 0x000004C0;
189 PORTCFG3 = 0x0AA40455;
190}
191#endif
192
193
194/* Second function called in the original firmware's startup code - we just
195 set up the clocks in the same way as the original firmware for now. */
196#ifdef COWON_D2
197static void clock_init(void)
198{
199 int i;
200
201 CSCFG3 = (CSCFG3 &~ 0x3fff) | 0x841;
202 CLKCTRL = (CLKCTRL & ~0xff) | 0x14;
203
204 PCLK_RFREQ = 0x1401002d; /* RAM refresh source = Xin (4) / 0x2d = 266kHz */
205
206 MCFG |= 1;
207 SDCFG = (SDCFG &~ 0x7000) | 0x2000;
208
209 MCFG1 |= 1;
210 SDCFG1 = (SDCFG &~ 0x7000) | 0x2000;
211
212 PLL0CFG |= 0x80000000; /* power down */
213 PLL0CFG = 0x14010000; /* power up, source = Xin (4) undivided = 12Mhz */
214
215 i = 0x8000;
216 while (--i) {};
217
218 CLKCTRL = (CLKCTRL &~ 0x1f) | 0x800FF010; /* CPU and COP driven by PLL0 */
219
220 asm volatile (
221 "nop \n\t"
222 "nop \n\t"
223 );
224
225 /* configure PCK_TCT to 2Mhz (clock source 4 (Xin) divided by 6) */
226 PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
227}
228#endif
229
230
231#ifdef COWON_D2
232void system_init(void)
233{
234 MBCFG = 0x19;
235
236 if (TCC780_VER == 0)
237 ECFG0 = 0x309;
238 else
239 ECFG0 = 0x30d;
240
241 /* mask all interrupts */
242 MIRQ = -1;
243
244 gpio_init();
245 clock_init();
246
247 /* TODO: these almost certainly shouldn't be here */
248 set_pll_frequency(0, 192000000); /* drives CPU */
249 set_pll_frequency(1, 216000000); /* drives LCD PXCLK - divided by 2 */
250}
251#endif
252
253
254void system_reboot(void)
255{
256 #warning function not implemented
257}
258
259int system_memory_guard(int newmode)
260{
261 #warning function not implemented
262
263 (void)newmode;
264 return 0;
265}
266
267#ifdef HAVE_ADJUSTABLE_CPU_FREQ
268
269void set_cpu_frequency(long frequency)
270{
271 #warning function not implemented
272 (void)frequency;
273}
274
275#endif