summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/system-x1000.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-02-27 22:08:58 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-03-28 00:01:37 +0000
commit3ec66893e377b088c1284d2d23adb2aeea6d7965 (patch)
treeb647717f83ad56b15dc42cfdef5d04d68cd9bd6b /firmware/target/mips/ingenic_x1000/system-x1000.c
parent83fcbedc65f4b9ae7e491ecf6f07c0af4b245f74 (diff)
downloadrockbox-3ec66893e377b088c1284d2d23adb2aeea6d7965.tar.gz
rockbox-3ec66893e377b088c1284d2d23adb2aeea6d7965.zip
New port: FiiO M3K on bare metal
Change-Id: I7517e7d5459e129dcfc9465c6fbd708619888fbe
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/system-x1000.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/system-x1000.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_x1000/system-x1000.c b/firmware/target/mips/ingenic_x1000/system-x1000.c
new file mode 100644
index 0000000000..54513cffb2
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/system-x1000.c
@@ -0,0 +1,418 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "system.h"
23#include "mips.h"
24#include "panic.h"
25#include "button.h"
26#include "gpio-x1000.h"
27#include "dma-x1000.h"
28#include "irq-x1000.h"
29#include "clk-x1000.h"
30#include "x1000/cpm.h"
31#include "x1000/ost.h"
32#include "x1000/tcu.h"
33#include "x1000/wdt.h"
34#include "x1000/intc.h"
35#include "x1000/msc.h"
36#include "x1000/aic.h"
37
38int __cpu_idle_avg = 0;
39int __cpu_idle_cur = 0;
40uint32_t __cpu_idle_ticks = 0;
41uint32_t __cpu_idle_reftick = 0;
42
43static void system_init_clk(void)
44{
45 /* Gate all clocks except CPU/bus/memory/RTC */
46 REG_CPM_CLKGR = ~jz_orm(CPM_CLKGR, CPU_BIT, DDR, AHB0, APB0, RTC);
47
48 /* Switch to EXCLK */
49 clk_set_ccr_mux(CLKMUX_SCLK_A(EXCLK) | CLKMUX_CPU(SCLK_A) |
50 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A));
51 clk_set_ccr_div(1, 1, 1, 1, 1);
52
53#ifdef FIIO_M3K
54 /* Nominal clock configuration
55 * ---------------------------
56 * APLL at 1 GHz, MPLL disabled
57 * CPU at 1 GHz, L2 cache at 500 MHz
58 * AHB0 and AHB2 at 200 MHz
59 * PCLK at 100 MHz
60 * DDR at 200 MHz
61 */
62 jz_writef(CPM_APCR, BS(1), PLLM(41), PLLN(0), PLLOD(0), ENABLE(1));
63 while(jz_readf(CPM_APCR, ON) == 0);
64
65 clk_set_ccr_div(1, 2, 5, 5, 10);
66 clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) |
67 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A));
68 clk_set_ddr(X1000_CLK_SCLK_A, 5);
69
70 /* Shut off MPLL, since nobody should be using it now */
71 jz_writef(CPM_MPCR, ENABLE(0));
72#else
73# error "Please define system clock configuration for target"
74#endif
75}
76
77/* Prepare the CPU to process interrupts, but don't enable them yet */
78static void system_init_irq(void)
79{
80 /* Mask all interrupts */
81 jz_set(INTC_MSK(0), 0xffffffff);
82 jz_set(INTC_MSK(1), 0xffffffff);
83
84 /* It's safe to unmask these unconditionally */
85 jz_clr(INTC_MSK(0), (1 << IRQ0_GPIO0) | (1 << IRQ0_GPIO1) |
86 (1 << IRQ0_GPIO2) | (1 << IRQ0_GPIO3) |
87 (1 << IRQ0_TCU1));
88
89 /* Setup CP0 registers */
90 write_c0_status(M_StatusCU0 | M_StatusIM2 | M_StatusIM3);
91 write_c0_cause(M_CauseIV);
92}
93
94/* First thing called from Rockbox main() */
95void system_init(void)
96{
97 /* Setup system clocks */
98 system_init_clk();
99
100 /* Ungate timers and turn them all off by default */
101 jz_writef(CPM_CLKGR, TCU(0), OST(0));
102 jz_clrf(OST_ENABLE, OST1, OST2);
103 jz_write(OST_1MSK, 1);
104 jz_write(OST_1FLG, 0);
105 jz_clr(TCU_ENABLE, 0x80ff);
106 jz_set(TCU_MASK, 0xff10ff);
107 jz_clr(TCU_FLAG, 0xff10ff);
108 jz_set(TCU_STOP, 0x180ff);
109
110 /* Start OST2, needed for delay timer */
111 jz_writef(OST_CTRL, PRESCALE2_V(BY_4));
112 jz_writef(OST_CLEAR, OST2(1));
113 jz_write(OST_2CNTH, 0);
114 jz_write(OST_2CNTL, 0);
115 jz_setf(OST_ENABLE, OST2);
116
117 /* Ensure CPU sleep mode is IDLE and not SLEEP */
118 jz_writef(CPM_LCR, LPM_V(IDLE));
119
120 /* All other init */
121 gpio_init();
122 system_init_irq();
123 dma_init();
124 mmu_init();
125}
126
127#ifdef HAVE_ADJUSTABLE_CPU_FREQ
128void set_cpu_frequency(long tgt_freq)
129{
130 /* Clamp target frequency to "sane" values */
131 if(tgt_freq < 0) tgt_freq = 0;
132 if(tgt_freq > CPU_FREQ) tgt_freq = CPU_FREQ;
133
134 /* Find out input clock */
135 uint32_t in_freq;
136 switch(jz_readf(CPM_CCR, SEL_CPLL)) {
137 case 1: in_freq = clk_get(X1000_CLK_SCLK_A); break;
138 case 2: in_freq = clk_get(X1000_CLK_MPLL); break;
139 default: return;
140 }
141
142 /* Clamp to valid range */
143 if(tgt_freq < 1)
144 tgt_freq = 1;
145 if(tgt_freq > (long)in_freq)
146 tgt_freq = in_freq;
147
148 /* Calculate CPU clock divider */
149 uint32_t cdiv = clk_calc_div(in_freq, tgt_freq);
150 if(cdiv > 16) cdiv = 16;
151 if(cdiv < 1) cdiv = 1;
152
153 /* Calculate L2 cache clock. */
154 uint32_t l2div = cdiv;
155 if(cdiv == 1)
156 l2div = 2;
157
158 /* Change CPU/L2 frequency */
159 jz_writef(CPM_CCR, CE_CPU(1), L2DIV(l2div - 1), CDIV(cdiv - 1));
160 while(jz_readf(CPM_CSR, CDIV_BUSY));
161 jz_writef(CPM_CCR, CE_CPU(0));
162
163 /* Update value for Rockbox */
164 cpu_frequency = in_freq / cdiv;
165}
166#endif
167
168void system_reboot(void)
169{
170 jz_clr(TCU_STOP, 0x10000);
171 jz_writef(WDT_CTRL, PRESCALE_V(BY_4), SOURCE_V(EXT));
172 jz_write(WDT_COUNT, 0);
173 jz_write(WDT_DATA, X1000_EXCLK_FREQ / 1000);
174 jz_write(WDT_ENABLE, 1);
175 while(1);
176}
177
178int system_memory_guard(int mode)
179{
180 /* unused */
181 (void)mode;
182 return 0;
183}
184
185/* Simple delay API -- slow path functions */
186
187void __udelay(uint32_t us)
188{
189 while(us > MAX_UDELAY_ARG) {
190 __ost_delay(MAX_UDELAY_ARG * OST_TICKS_PER_US);
191 us -= MAX_UDELAY_ARG;
192 }
193
194 __ost_delay(us * OST_TICKS_PER_US);
195}
196
197void __mdelay(uint32_t ms)
198{
199 while(ms > MAX_MDELAY_ARG) {
200 __ost_delay(MAX_MDELAY_ARG * 1000 * OST_TICKS_PER_US);
201 ms -= MAX_MDELAY_ARG;
202 }
203
204 __ost_delay(ms * 1000 * OST_TICKS_PER_US);
205}
206
207uint64_t __ost_read64(void)
208{
209 int irq = disable_irq_save();
210 uint64_t lcnt = REG_OST_2CNTL;
211 uint64_t hcnt = REG_OST_2CNTHB;
212 restore_irq(irq);
213 return (hcnt << 32) | lcnt;
214}
215
216/* IRQ handling */
217static int irq = 0;
218static unsigned ipr0 = 0, ipr1 = 0;
219
220static void UIRQ(void)
221{
222 panicf("Unhandled interrupt occurred: %d", irq);
223}
224
225#define intr(name) extern __attribute__((weak, alias("UIRQ"))) void name(void)
226
227/* Main interrupts */
228intr(DMIC); intr(AIC); intr(SFC); intr(SSI0); intr(OTG); intr(AES);
229intr(TCU2); intr(TCU1); intr(TCU0); intr(CIM); intr(LCD); intr(RTC);
230intr(MSC1); intr(MSC0); intr(SCC); intr(PCM0); intr(HARB2); intr(HARB0);
231intr(CPM); intr(UART2); intr(UART1); intr(UART0); intr(DDR); intr(EFUSE);
232intr(MAC); intr(I2C2); intr(I2C1); intr(I2C0); intr(JPEG);
233intr(PDMA); intr(PDMAD); intr(PDMAM);
234/* GPIO A - 32 pins */
235intr(GPIOA00); intr(GPIOA01); intr(GPIOA02); intr(GPIOA03); intr(GPIOA04);
236intr(GPIOA05); intr(GPIOA06); intr(GPIOA07); intr(GPIOA08); intr(GPIOA09);
237intr(GPIOA10); intr(GPIOA11); intr(GPIOA12); intr(GPIOA13); intr(GPIOA14);
238intr(GPIOA15); intr(GPIOA16); intr(GPIOA17); intr(GPIOA18); intr(GPIOA19);
239intr(GPIOA20); intr(GPIOA21); intr(GPIOA22); intr(GPIOA23); intr(GPIOA24);
240intr(GPIOA25); intr(GPIOA26); intr(GPIOA27); intr(GPIOA28); intr(GPIOA29);
241intr(GPIOA30); intr(GPIOA31);
242/* GPIO B - 32 pins */
243intr(GPIOB00); intr(GPIOB01); intr(GPIOB02); intr(GPIOB03); intr(GPIOB04);
244intr(GPIOB05); intr(GPIOB06); intr(GPIOB07); intr(GPIOB08); intr(GPIOB09);
245intr(GPIOB10); intr(GPIOB11); intr(GPIOB12); intr(GPIOB13); intr(GPIOB14);
246intr(GPIOB15); intr(GPIOB16); intr(GPIOB17); intr(GPIOB18); intr(GPIOB19);
247intr(GPIOB20); intr(GPIOB21); intr(GPIOB22); intr(GPIOB23); intr(GPIOB24);
248intr(GPIOB25); intr(GPIOB26); intr(GPIOB27); intr(GPIOB28); intr(GPIOB29);
249intr(GPIOB30); intr(GPIOB31);
250/* GPIO C - 26 pins */
251intr(GPIOC00); intr(GPIOC01); intr(GPIOC02); intr(GPIOC03); intr(GPIOC04);
252intr(GPIOC05); intr(GPIOC06); intr(GPIOC07); intr(GPIOC08); intr(GPIOC09);
253intr(GPIOC10); intr(GPIOC11); intr(GPIOC12); intr(GPIOC13); intr(GPIOC14);
254intr(GPIOC15); intr(GPIOC16); intr(GPIOC17); intr(GPIOC18); intr(GPIOC19);
255intr(GPIOC20); intr(GPIOC21); intr(GPIOC22); intr(GPIOC23); intr(GPIOC24);
256intr(GPIOC25);
257/* GPIO D - 6 pins */
258intr(GPIOD00); intr(GPIOD01); intr(GPIOD02); intr(GPIOD03); intr(GPIOD04);
259intr(GPIOD05);
260
261/* OST interrupt -- has no IRQ number since it's got special handling */
262intr(OST);
263
264#undef intr
265
266static void(*const irqvector[])(void) = {
267 /* ICSR0: 0 - 31 */
268 DMIC, AIC, UIRQ, UIRQ, UIRQ, UIRQ, UIRQ, SFC,
269 SSI0, UIRQ, PDMA, PDMAD, UIRQ, UIRQ, UIRQ, UIRQ,
270 UIRQ, UIRQ, UIRQ, UIRQ, UIRQ, OTG, UIRQ, AES,
271 UIRQ, TCU2, TCU1, TCU0, UIRQ, UIRQ, CIM, LCD,
272 /* ICSR1: 32 - 63 */
273 RTC, UIRQ, UIRQ, UIRQ, MSC1, MSC0, SCC, UIRQ,
274 PCM0, UIRQ, UIRQ, UIRQ, HARB2, UIRQ, HARB0, CPM,
275 UIRQ, UART2, UART1, UART0, DDR, UIRQ, EFUSE, MAC,
276 UIRQ, UIRQ, I2C2, I2C1, I2C0, PDMAM, JPEG, UIRQ,
277 /* GPIO A: 64 - 95 */
278 GPIOA00, GPIOA01, GPIOA02, GPIOA03, GPIOA04, GPIOA05, GPIOA06, GPIOA07,
279 GPIOA08, GPIOA09, GPIOA10, GPIOA11, GPIOA12, GPIOA13, GPIOA14, GPIOA15,
280 GPIOA16, GPIOA17, GPIOA18, GPIOA19, GPIOA20, GPIOA21, GPIOA22, GPIOA23,
281 GPIOA24, GPIOA25, GPIOA26, GPIOA27, GPIOA28, GPIOA29, GPIOA30, GPIOA31,
282 /* GPIO B: 96 - 127 */
283 GPIOB00, GPIOB01, GPIOB02, GPIOB03, GPIOB04, GPIOB05, GPIOB06, GPIOB07,
284 GPIOB08, GPIOB09, GPIOB10, GPIOB11, GPIOB12, GPIOB13, GPIOB14, GPIOB15,
285 GPIOB16, GPIOB17, GPIOB18, GPIOB19, GPIOB20, GPIOB21, GPIOB22, GPIOB23,
286 GPIOB24, GPIOB25, GPIOB26, GPIOB27, GPIOB28, GPIOB29, GPIOB30, GPIOB31,
287 /* GPIO C: 128 - 159 */
288 GPIOC00, GPIOC01, GPIOC02, GPIOC03, GPIOC04, GPIOC05, GPIOC06, GPIOC07,
289 GPIOC08, GPIOC09, GPIOC10, GPIOC11, GPIOC12, GPIOC13, GPIOC14, GPIOC15,
290 GPIOC16, GPIOC17, GPIOC18, GPIOC19, GPIOC20, GPIOC21, GPIOC22, GPIOC23,
291 GPIOC24, GPIOC25, UIRQ, UIRQ, UIRQ, UIRQ, UIRQ, UIRQ,
292 /* GPIO D: 160 - 165 */
293 GPIOD00, GPIOD01, GPIOD02, GPIOD03, GPIOD04, GPIOD05,
294};
295
296void system_enable_irq(int irq)
297{
298 if(IRQ_IS_GROUP0(irq)) {
299 jz_clr(INTC_MSK(0), 1 << IRQ_TO_GROUP0(irq));
300 } else if(IRQ_IS_GROUP1(irq)) {
301 jz_clr(INTC_MSK(1), 1 << IRQ_TO_GROUP1(irq));
302 }
303}
304
305void system_disable_irq(int irq)
306{
307 if(IRQ_IS_GROUP0(irq)) {
308 jz_set(INTC_MSK(0), 1 << IRQ_TO_GROUP0(irq));
309 } else if(IRQ_IS_GROUP1(irq)) {
310 jz_set(INTC_MSK(1), 1 << IRQ_TO_GROUP1(irq));
311 }
312}
313
314static int vector_gpio_irq(int port)
315{
316 int n = find_first_set_bit(REG_GPIO_FLAG(port));
317 if(n & 32)
318 return -1;
319
320 jz_clr(GPIO_FLAG(port), 1 << n);
321 return IRQ_GPIO(port, n);
322}
323
324static int vector_irq(void)
325{
326 int n = find_first_set_bit(ipr0);
327 if(n & 32) {
328 n = find_first_set_bit(ipr1);
329 if(n & 32)
330 return -1;
331 ipr1 &= ~(1 << n);
332 n += 32;
333 } else {
334 ipr0 &= ~(1 << n);
335 }
336
337 switch(n) {
338 case IRQ0_GPIO0: n = vector_gpio_irq(GPIO_A); break;
339 case IRQ0_GPIO1: n = vector_gpio_irq(GPIO_B); break;
340 case IRQ0_GPIO2: n = vector_gpio_irq(GPIO_C); break;
341 case IRQ0_GPIO3: n = vector_gpio_irq(GPIO_D); break;
342 default: break;
343 }
344
345 return n;
346}
347
348void intr_handler(unsigned cause)
349{
350 /* OST interrupt is handled separately */
351 if(cause & M_CauseIP3) {
352 OST();
353 return;
354 }
355
356 /* Gather pending interrupts */
357 ipr0 |= REG_INTC_PND(0);
358 ipr1 |= REG_INTC_PND(1);
359
360 /* Process and dispatch interrupt */
361 irq = vector_irq();
362 if(irq < 0)
363 return;
364
365 irqvector[irq]();
366}
367
368void tlb_refill_handler(void)
369{
370 panicf("TLB refill handler at 0x%08lx! [0x%x]",
371 read_c0_epc(), read_c0_badvaddr());
372}
373
374#define EXC(x,y) case (x): return (y);
375static char* parse_exception(unsigned cause)
376{
377 switch(cause & M_CauseExcCode)
378 {
379 EXC(EXC_INT, "Interrupt");
380 EXC(EXC_MOD, "TLB Modified");
381 EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
382 EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
383 EXC(EXC_ADES, "Address Error (Store)");
384 EXC(EXC_TLBS, "TLB Exception (Store)");
385 EXC(EXC_IBE, "Instruction Bus Error");
386 EXC(EXC_DBE, "Data Bus Error");
387 EXC(EXC_SYS, "Syscall");
388 EXC(EXC_BP, "Breakpoint");
389 EXC(EXC_RI, "Reserved Instruction");
390 EXC(EXC_CPU, "Coprocessor Unusable");
391 EXC(EXC_OV, "Overflow");
392 EXC(EXC_TR, "Trap Instruction");
393 EXC(EXC_FPE, "Floating Point Exception");
394 EXC(EXC_C2E, "COP2 Exception");
395 EXC(EXC_MDMX, "MDMX Exception");
396 EXC(EXC_WATCH, "Watch Exception");
397 EXC(EXC_MCHECK, "Machine Check Exception");
398 EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
399 default:
400 return 0;
401 }
402}
403#undef EXC
404
405void exception_handler(unsigned cause, unsigned epc, unsigned stack_ptr)
406{
407 panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)",
408 parse_exception(cause), read_c0_badvaddr(), epc, stack_ptr);
409}
410
411void system_exception_wait(void)
412{
413#ifdef FIIO_M3K
414 while(button_read_device() != (BUTTON_POWER|BUTTON_VOL_DOWN));
415#else
416 while(1);
417#endif
418}