enable cores interupts
[AROS.git] / arch / arm-native / kernel / platform_bcm2708.c
blob8d81a9a2a94c4bd5f54db2612377941bbaa77a98
1 /*
2 Copyright © 2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/kernel.h>
7 #include <aros/symbolsets.h>
9 #include "kernel_base.h"
11 #include <proto/kernel.h>
12 #include <proto/exec.h>
14 #include <inttypes.h>
15 #include <hardware/intbits.h>
17 #include <strings.h>
19 #include "kernel_intern.h"
20 #include "kernel_debug.h"
21 #include "kernel_cpu.h"
22 #include "kernel_interrupts.h"
23 #include "kernel_intr.h"
24 #include "kernel_fb.h"
26 #include "exec_platform.h"
28 #define ARM_PERIIOBASE __arm_arosintern.ARMI_PeripheralBase
29 #include <hardware/bcm2708.h>
30 #include <hardware/bcm2708_boot.h>
31 #include <hardware/pl011uart.h>
33 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
35 #define IRQ_BANK1 0x00000100
36 #define IRQ_BANK2 0x00000200
38 #define D(x) x
39 #define DIRQ(x)
40 #define DTIMER(x)
42 extern void mpcore_trampoline();
43 extern uint32_t mpcore_end;
44 extern uint32_t mpcore_pde;
46 extern void cpu_Register(void);
47 extern void arm_flush_cache(uint32_t addr, uint32_t length);
49 static void bcm2708_init(APTR _kernelBase, APTR _sysBase)
51 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
52 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
54 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__));
56 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
58 void *trampoline_src = mpcore_trampoline;
59 void *trampoline_dst = (void *)BOOTMEMADDR(bm_mctrampoline);
60 uint32_t trampoline_length = (uintptr_t)&mpcore_end - (uintptr_t)mpcore_trampoline;
61 uint32_t trampoline_data_offset = (uintptr_t)&mpcore_pde - (uintptr_t)mpcore_trampoline;
62 int core;
63 uint32_t *core_stack;
64 uint32_t tmp;
65 tls_t *__tls;
67 bug("[KRN:BCM2708] Initialising Multicore System\n");
68 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__, trampoline_src, trampoline_dst, trampoline_length));
70 bcopy(trampoline_src, trampoline_dst, trampoline_length);
72 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__, trampoline_data_offset));
74 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp));
75 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[0] = tmp; // pde
76 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[1] = (uint32_t)cpu_Register;
78 for (core = 1; core < 4; core ++)
80 core_stack = (uint32_t *)AllocMem(AROS_STACKSIZE*sizeof(uint32_t), MEMF_CLEAR); /* MEMF_PRIVATE */
81 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[2] = (uint32_t)&core_stack[AROS_STACKSIZE-sizeof(IPTR)];
83 __tls = AllocMem(sizeof(tls_t), MEMF_CLEAR); /* MEMF_PRIVATE */
84 __tls->SysBase = _sysBase;
85 __tls->KernelBase = _kernelBase;
86 __tls->ThisTask = NULL;
87 arm_flush_cache(((uint32_t)__tls) & ~63, 512);
88 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3] = __tls;
90 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__, core));
91 D(bug("[KRN:BCM2708] %s: core #%d stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__, core, core_stack, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[2]));
92 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__, core, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3]));
94 arm_flush_cache((uint32_t)trampoline_dst, 512);
95 *((uint32_t *)(BCM2836_MAILBOX3_SET0 + (0x10 * core))) = (uint32_t)trampoline_dst;
97 if (__arm_arosintern.ARMI_Delay)
98 __arm_arosintern.ARMI_Delay(10000000);
103 static void bcm2708_init_core(APTR _kernelBase, APTR _sysBase)
105 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
106 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
108 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__));
110 // enable interrupts
111 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0 + (0x4 * core))) = 0x1;
114 static unsigned int bcm2807_get_time(void)
116 return *((volatile unsigned int *)(SYSTIMER_CLO));
119 static void bcm2807_irq_init(void)
121 // disable IRQ's
122 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
124 *(volatile unsigned int *)ARMIRQ_DIBL = ~0;
125 *(volatile unsigned int *)GPUIRQ_DIBL0 = ~0;
126 *(volatile unsigned int *)GPUIRQ_DIBL1 = ~0;
128 // aknowledge pending IRQ's
129 *(volatile unsigned int *)ARMIRQ_PEND = *(volatile unsigned int *)ARMIRQ_PEND;
130 *(volatile unsigned int *)GPUIRQ_PEND0 = *(volatile unsigned int *)GPUIRQ_PEND0;
131 *(volatile unsigned int *)GPUIRQ_PEND1 = *(volatile unsigned int *)GPUIRQ_PEND1;
134 static void bcm2807_irq_enable(int irq)
136 int bank = IRQ_BANK(irq);
137 unsigned int reg;
139 reg = (unsigned int)IRQBANK_POINTER(bank);
141 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
143 *((volatile unsigned int *)reg) = IRQ_MASK(irq);
145 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg)));
148 static void bcm2807_irq_disable(int irq)
150 int bank = IRQ_BANK(irq);
151 unsigned int reg;
153 reg = (unsigned int)IRQBANK_POINTER(bank) + 0x0c;
155 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
157 *((volatile unsigned int *)reg) = IRQ_MASK(irq);
159 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg)));
162 static void bcm2807_irq_process()
164 unsigned int pendingarm, pending0, pending1, irq;
166 for(;;)
168 pendingarm = *((volatile unsigned int *)(ARMIRQ_PEND));
169 pending0 = *((volatile unsigned int *)(GPUIRQ_PEND0));
170 pending1 = *((volatile unsigned int *)(GPUIRQ_PEND1));
172 if (!(pendingarm || pending0 || pending1))
173 break;
175 DIRQ(bug("[KRN] PendingARM %08x\n", pendingarm));
176 DIRQ(bug("[KRN] Pending0 %08x\n", pending0));
177 DIRQ(bug("[KRN] Pending1 %08x\n", pending1));
179 if (pendingarm & ~(IRQ_BANK1 | IRQ_BANK2))
181 for (irq = (2 << 5); irq < ((2 << 5) + 8); irq++)
183 if (pendingarm & (1 << (irq - (2 << 5))))
185 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq));
186 krnRunIRQHandlers(KernelBase, irq);
191 if (pending0)
193 for (irq = (0 << 5); irq < ((0 << 5) + 32); irq++)
195 if (pending0 & (1 << (irq - (0 << 5))))
197 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq));
198 krnRunIRQHandlers(KernelBase, irq);
203 if (pending1)
205 for (irq = (1 << 5); irq < ((1 << 5) + 32); irq++)
207 if (pending1 & (1 << (irq - (1 << 5))))
209 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq));
210 krnRunIRQHandlers(KernelBase, irq);
218 static void bcm2708_toggle_led(int LED, int state)
220 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
222 int pin = 35;
223 APTR gpiofunc = GPCLR1;
225 if (LED == ARM_LED_ACTIVITY)
226 pin = 47;
228 if (state == ARM_LED_ON)
229 gpiofunc = GPSET1;
231 *(volatile unsigned int *)gpiofunc = (1 << (pin-32));
233 else
235 // RasPi 1 only allows us to toggle the activity LED
236 if (state)
237 *(volatile unsigned int *)GPCLR0 = (1 << 16);
238 else
239 *(volatile unsigned int *)GPSET0 = (1 << 16);
243 /* Use system timer 3 for our scheduling heartbeat */
244 #define VBLANK_TIMER 3
245 #define VBLANK_INTERVAL (1000000 / 50)
247 static void bcm2708_gputimer_handler(unsigned int timerno, void *unused1)
249 unsigned int stc;
251 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, timerno));
253 /* Aknowledge our timer interrupt */
254 *((volatile unsigned int *)(SYSTIMER_CS)) = 1 << timerno;
256 /* Signal the Exec VBlankServer */
257 if (SysBase && (SysBase->IDNestCnt < 0)) {
258 core_Cause(INTB_VERTB, 1L << INTB_VERTB);
261 /* Refresh our timer interrupt */
262 stc = *((volatile unsigned int *)(SYSTIMER_CLO));
263 stc += VBLANK_INTERVAL;
264 *((volatile unsigned int *)(SYSTIMER_C0 + (timerno * 4))) = stc;
266 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__));
269 static APTR bcm2708_init_gputimer(APTR _kernelBase)
271 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
272 struct IntrNode *GPUTimerHandle;
273 unsigned int stc;
275 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__, KernelBase));
277 if ((GPUTimerHandle = AllocMem(sizeof(struct IntrNode), MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
279 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__, GPUTimerHandle));
280 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__, VBLANK_TIMER));
282 GPUTimerHandle->in_Handler = bcm2708_gputimer_handler;
283 GPUTimerHandle->in_HandlerData = (void *)VBLANK_TIMER;
284 GPUTimerHandle->in_HandlerData2 = KernelBase;
285 GPUTimerHandle->in_type = it_interrupt;
286 GPUTimerHandle->in_nr = IRQ_TIMER0 + VBLANK_TIMER;
288 ADDHEAD(&KernelBase->kb_Interrupts[IRQ_TIMER0 + VBLANK_TIMER], &GPUTimerHandle->in_Node);
290 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__));
292 stc = *((volatile unsigned int *)(SYSTIMER_CLO));
293 stc += VBLANK_INTERVAL;
294 *((volatile unsigned int *)(SYSTIMER_CS)) = (1 << VBLANK_TIMER);
295 *((volatile unsigned int *)(SYSTIMER_C0 + (VBLANK_TIMER * 4))) = stc;
297 ictl_enable_irq(IRQ_TIMER0 + VBLANK_TIMER, KernelBase);
300 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__));
302 return GPUTimerHandle;
305 static inline void bcm2708_ser_waitout()
307 while(1)
309 if ((*(volatile uint32_t *)(PL011_0_BASE + PL011_FR) & PL011_FR_TXFF) == 0) break;
313 static void bcm2708_ser_putc(uint8_t chr)
315 bcm2708_ser_waitout();
317 if (chr == '\n')
319 *(volatile uint32_t *)(PL011_0_BASE + PL011_DR) = '\r';
320 bcm2708_ser_waitout();
322 *(volatile uint32_t *)(PL011_0_BASE + PL011_DR) = chr;
325 static int bcm2708_ser_getc(void)
327 if ((*(volatile uint32_t *)(PL011_0_BASE + PL011_FR) & PL011_FR_RXFE) == 0)
328 return (int)*(volatile uint32_t *)(PL011_0_BASE + PL011_DR);
330 return -1;
333 static IPTR bcm2708_probe(struct ARM_Implementation *krnARMImpl, struct TagItem *msg)
335 void *bootPutC = NULL;
337 while(msg->ti_Tag != TAG_DONE)
339 switch (msg->ti_Tag)
341 case KRN_FuncPutC:
342 bootPutC = (void *)msg->ti_Data;
343 break;
345 msg++;
348 if (krnARMImpl->ARMI_Platform != 0xc42)
349 return FALSE;
351 if (krnARMImpl->ARMI_Family == 7)
353 /* bcm2836 uses armv7 */
354 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2836_PERIPHYSBASE;
355 krnARMImpl->ARMI_InitCore = &bcm2708_init_core;
357 else
358 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2835_PERIPHYSBASE;
360 krnARMImpl->ARMI_GetTime = &bcm2807_get_time;
361 krnARMImpl->ARMI_InitTimer = &bcm2708_init_gputimer;
362 krnARMImpl->ARMI_LED_Toggle = &bcm2708_toggle_led;
364 krnARMImpl->ARMI_SerPutChar = &bcm2708_ser_putc;
365 krnARMImpl->ARMI_SerGetChar = &bcm2708_ser_getc;
366 if ((krnARMImpl->ARMI_PutChar = bootPutC) != NULL)
367 krnARMImpl->ARMI_PutChar(0xFF); // Clear the display
369 krnARMImpl->ARMI_IRQInit = &bcm2807_irq_init;
370 krnARMImpl->ARMI_IRQEnable = &bcm2807_irq_enable;
371 krnARMImpl->ARMI_IRQDisable = &bcm2807_irq_disable;
372 krnARMImpl->ARMI_IRQProcess = &bcm2807_irq_process;
374 krnARMImpl->ARMI_Init = &bcm2708_init;
376 return TRUE;
379 ADD2SET(bcm2708_probe, ARMPLATFORMS, 0);