allocate storage for the per core ipi data and use it to pass the ipi param(s)
[AROS.git] / arch / arm-native / kernel / platform_bcm2708.c
blob9a65348b20514840b9b78675897dbfedde5fd518
1 /*
2 Copyright © 2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/types/spinlock_s.h>
7 #include <aros/kernel.h>
8 #include <aros/symbolsets.h>
10 #include "kernel_base.h"
12 #include <proto/kernel.h>
13 #include <proto/exec.h>
15 #include <inttypes.h>
16 #include <hardware/intbits.h>
18 #include <strings.h>
20 #include "kernel_intern.h"
21 #include "kernel_debug.h"
22 #include "kernel_cpu.h"
23 #include "kernel_interrupts.h"
24 #include "kernel_intr.h"
25 #include "kernel_fb.h"
27 #include "exec_platform.h"
29 #define ARM_PERIIOBASE __arm_arosintern.ARMI_PeripheralBase
30 #include <hardware/bcm2708.h>
31 #include <hardware/bcm2708_boot.h>
32 #include <hardware/pl011uart.h>
34 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
36 #define IRQ_BANK1 0x00000100
37 #define IRQ_BANK2 0x00000200
39 #define D(x) x
40 #define DIRQ(x)
41 #define DFIQ(x)
42 #define DTIMER(x)
44 extern void mpcore_trampoline();
45 extern uint32_t mpcore_end;
46 extern uint32_t mpcore_pde;
47 extern spinlock_t startup_lock;
49 extern void cpu_Register(void);
50 extern void arm_flush_cache(uint32_t, uint32_t);
51 #if defined(__AROSEXEC_SMP__)
52 extern void handle_ipi(uint32_t, uint32_t);
54 struct cpu_ipidata
56 uint32_t ipi_data[4];
59 struct cpu_ipidata *bcm2708_cpuipid[4] = { 0, 0, 0, 0};
60 #endif
62 static void bcm2708_init(APTR _kernelBase, APTR _sysBase)
64 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
65 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
67 KrnSpinInit(&startup_lock);
69 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__));
71 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
73 void *trampoline_src = mpcore_trampoline;
74 void *trampoline_dst = (void *)BOOTMEMADDR(bm_mctrampoline);
75 uint32_t trampoline_length = (uintptr_t)&mpcore_end - (uintptr_t)mpcore_trampoline;
76 uint32_t trampoline_data_offset = (uintptr_t)&mpcore_pde - (uintptr_t)mpcore_trampoline;
77 int core;
78 uint32_t *core_stack;
79 uint32_t *core_fiq_stack;
80 uint32_t tmp;
81 tls_t *__tls;
83 bug("[KRN:BCM2708] Initialising Multicore System\n");
84 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__, trampoline_src, trampoline_dst, trampoline_length));
86 bcopy(trampoline_src, trampoline_dst, trampoline_length);
88 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__, trampoline_data_offset));
90 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp));
91 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[0] = tmp; // pde
92 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[1] = (uint32_t)cpu_Register;
94 for (core = 1; core < 4; core ++)
96 core_stack = (uint32_t *)AllocMem(AROS_STACKSIZE*sizeof(uint32_t), MEMF_CLEAR); /* MEMF_PRIVATE */
97 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[2] = (uint32_t)&core_stack[AROS_STACKSIZE-sizeof(IPTR)];
99 core_fiq_stack = (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR); /* MEMF_PRIVATE */
100 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[4] = (uint32_t)&core_fiq_stack[1024-sizeof(IPTR)];
102 __tls = (tls_t *)AllocMem(sizeof(tls_t), MEMF_CLEAR); /* MEMF_PRIVATE */
103 __tls->SysBase = _sysBase;
104 __tls->KernelBase = _kernelBase;
105 __tls->ThisTask = NULL;
106 arm_flush_cache(((uint32_t)__tls) & ~63, 512);
107 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3] = (uint32_t)__tls;
109 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__, core));
110 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]));
111 D(bug("[KRN:BCM2708] %s: core #%d fiq stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__, core, core_fiq_stack, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[4]));
112 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__, core, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3]));
114 arm_flush_cache((uint32_t)trampoline_dst, 512);
116 /* Lock the startup spinlock */
117 KrnSpinLock(&startup_lock, SPINLOCK_MODE_WRITE);
119 /* Wake up the core */
120 *((uint32_t *)(BCM2836_MAILBOX3_SET0 + (0x10 * core))) = (uint32_t)trampoline_dst;
123 * Try to obtain spinlock again.
124 * This should put this core to sleep since the locked was already obtained. Once the core startup
125 * is ready, it will call KrnSpinUnLock too
127 KrnSpinLock(&startup_lock, SPINLOCK_MODE_WRITE);
128 KrnSpinUnLock(&startup_lock);
133 static void bcm2708_init_core(APTR _kernelBase, APTR _sysBase)
135 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
136 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
137 struct cpu_ipidata *core_ipidata;
138 uint32_t tmp;
140 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp));
142 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, (tmp & 0x3)));
144 /* Clear all pending FIQ sources on mailboxes */
145 *((uint32_t *)(BCM2836_MAILBOX0_CLR0 + (16 * (tmp & 0x3)))) = 0xffffffff;
146 *((uint32_t *)(BCM2836_MAILBOX1_CLR0 + (16 * (tmp & 0x3)))) = 0xffffffff;
147 *((uint32_t *)(BCM2836_MAILBOX2_CLR0 + (16 * (tmp & 0x3)))) = 0xffffffff;
148 *((uint32_t *)(BCM2836_MAILBOX3_CLR0 + (16 * (tmp & 0x3)))) = 0xffffffff;
150 #if defined(__AROSEXEC_SMP__)
151 if ((core_ipidata = (struct cpu_ipidata *)AllocMem(sizeof(struct cpu_ipidata), MEMF_CLEAR)) != NULL)
153 bcm2708_cpuipid[(tmp & 0x3)] = core_ipidata;
155 // enable FIQ mailbox interupt
156 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0 + (0x4 * (tmp & 0x3)))) = 0x10;
158 #endif
161 static unsigned int bcm2807_get_time(void)
163 return *((volatile unsigned int *)(SYSTIMER_CLO));
166 static void bcm2807_irq_init(void)
168 // disable IRQ's
169 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
171 *(volatile unsigned int *)ARMIRQ_DIBL = ~0;
172 *(volatile unsigned int *)GPUIRQ_DIBL0 = ~0;
173 *(volatile unsigned int *)GPUIRQ_DIBL1 = ~0;
176 static void bcm2807_send_ipi(uint32_t ipi, uint32_t ipi_data, uint32_t cpumask)
178 int i = 0;
179 for (i = 0; i < 4; i++)
181 #if defined(__AROSEXEC_SMP__)
182 if ((cpumask & (1 << i)) && bcm2708_cpuipid[i])
184 /* TODO: check which mailbox is available and use it */
185 bcm2708_cpuipid[i]->ipi_data[0] = ipi_data;
186 *((uint32_t *)(BCM2836_MAILBOX0_SET0 + (0x10 * i))) = ipi;
188 #endif
192 static void bcm2807_irq_enable(int irq)
194 int bank = IRQ_BANK(irq);
195 unsigned int reg;
197 reg = (unsigned int)IRQBANK_POINTER(bank);
199 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
201 *((volatile unsigned int *)reg) = IRQ_MASK(irq);
203 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg)));
206 static void bcm2807_irq_disable(int irq)
208 int bank = IRQ_BANK(irq);
209 unsigned int reg;
211 reg = (unsigned int)IRQBANK_POINTER(bank) + 0x0c;
213 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
215 *((volatile unsigned int *)reg) = IRQ_MASK(irq);
217 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg)));
220 static void bcm2807_irq_process()
222 unsigned int pendingarm, pending0, pending1, irq;
224 for(;;)
226 pendingarm = *((volatile unsigned int *)(ARMIRQ_PEND));
227 pending0 = *((volatile unsigned int *)(GPUIRQ_PEND0));
228 pending1 = *((volatile unsigned int *)(GPUIRQ_PEND1));
230 if (!(pendingarm || pending0 || pending1))
231 break;
233 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm));
234 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0));
235 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1));
237 if (pendingarm & ~(IRQ_BANK1 | IRQ_BANK2))
239 for (irq = (2 << 5); irq < ((2 << 5) + 8); irq++)
241 if (pendingarm & (1 << (irq - (2 << 5))))
243 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq));
244 krnRunIRQHandlers(KernelBase, irq);
249 if (pending0)
251 for (irq = (0 << 5); irq < ((0 << 5) + 32); irq++)
253 if (pending0 & (1 << (irq - (0 << 5))))
255 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq));
256 krnRunIRQHandlers(KernelBase, irq);
261 if (pending1)
263 for (irq = (1 << 5); irq < ((1 << 5) + 32); irq++)
265 if (pending1 & (1 << (irq - (1 << 5))))
267 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq));
268 krnRunIRQHandlers(KernelBase, irq);
275 static void bcm2807_fiq_process()
277 uint32_t tmp, fiq, fiq_data;
278 int i;
280 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp));
282 DFIQ(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, (tmp & 0x3)));
284 fiq = *((uint32_t *)(BCM2836_FIQ_PEND0 + (0x4 * (tmp & 0x3))));
286 DFIQ(bug("[KRN:BCM2708] %s: Core #%d FIQ %x\n", __PRETTY_FUNCTION__, (tmp & 0x3), fiq));
288 if (fiq)
290 for (i=0; i < 4; i++)
292 if (fiq & (0x10 << i))
294 fiq_data = *((uint32_t *)(BCM2836_MAILBOX0_CLR0 + 4*i + (16 * (tmp & 0x3))));
295 DFIQ(bug("[KRN:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__, i, fiq_data));
296 #if defined(__AROSEXEC_SMP__)
297 if (bcm2708_cpuipid[(tmp & 0x3)])
298 handle_ipi(fiq_data, bcm2708_cpuipid[(tmp & 0x3)]->ipi_data[0]);
299 #endif
300 *((uint32_t *)(BCM2836_MAILBOX0_CLR0 + 4*i + (16 * (tmp & 0x3)))) = 0xffffffff;
306 static void bcm2708_toggle_led(int LED, int state)
308 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
310 int pin = 35;
311 APTR gpiofunc = GPCLR1;
313 if (LED == ARM_LED_ACTIVITY)
314 pin = 47;
316 if (state == ARM_LED_ON)
317 gpiofunc = GPSET1;
319 *(volatile unsigned int *)gpiofunc = (1 << (pin-32));
321 else
323 // RasPi 1 only allows us to toggle the activity LED
324 if (state)
325 *(volatile unsigned int *)GPCLR0 = (1 << 16);
326 else
327 *(volatile unsigned int *)GPSET0 = (1 << 16);
331 /* Use system timer 3 for our scheduling heartbeat */
332 #define VBLANK_TIMER 3
333 #define VBLANK_INTERVAL (1000000 / 50)
335 static void bcm2708_gputimer_handler(unsigned int timerno, void *unused1)
337 unsigned int stc;
339 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, timerno));
341 /* Aknowledge our timer interrupt */
342 *((volatile unsigned int *)(SYSTIMER_CS)) = 1 << timerno;
344 /* Signal the Exec VBlankServer */
345 if (SysBase && (SysBase->IDNestCnt < 0)) {
346 core_Cause(INTB_VERTB, 1L << INTB_VERTB);
349 /* Refresh our timer interrupt */
350 stc = *((volatile unsigned int *)(SYSTIMER_CLO));
351 stc += VBLANK_INTERVAL;
352 *((volatile unsigned int *)(SYSTIMER_C0 + (timerno * 4))) = stc;
354 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__));
357 static APTR bcm2708_init_gputimer(APTR _kernelBase)
359 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
360 struct IntrNode *GPUTimerHandle;
361 unsigned int stc;
363 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__, KernelBase));
365 if ((GPUTimerHandle = AllocMem(sizeof(struct IntrNode), MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
367 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__, GPUTimerHandle));
368 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__, VBLANK_TIMER));
370 GPUTimerHandle->in_Handler = bcm2708_gputimer_handler;
371 GPUTimerHandle->in_HandlerData = (void *)VBLANK_TIMER;
372 GPUTimerHandle->in_HandlerData2 = KernelBase;
373 GPUTimerHandle->in_type = it_interrupt;
374 GPUTimerHandle->in_nr = IRQ_TIMER0 + VBLANK_TIMER;
376 ADDHEAD(&KernelBase->kb_Interrupts[IRQ_TIMER0 + VBLANK_TIMER], &GPUTimerHandle->in_Node);
378 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__));
380 stc = *((volatile unsigned int *)(SYSTIMER_CLO));
381 stc += VBLANK_INTERVAL;
382 *((volatile unsigned int *)(SYSTIMER_CS)) = (1 << VBLANK_TIMER);
383 *((volatile unsigned int *)(SYSTIMER_C0 + (VBLANK_TIMER * 4))) = stc;
385 ictl_enable_irq(IRQ_TIMER0 + VBLANK_TIMER, KernelBase);
388 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__));
390 return GPUTimerHandle;
393 static inline void bcm2708_ser_waitout()
395 while(1)
397 if ((*(volatile uint32_t *)(PL011_0_BASE + PL011_FR) & PL011_FR_TXFF) == 0) break;
401 static void bcm2708_ser_putc(uint8_t chr)
403 bcm2708_ser_waitout();
405 if (chr == '\n')
407 *(volatile uint32_t *)(PL011_0_BASE + PL011_DR) = '\r';
408 bcm2708_ser_waitout();
410 *(volatile uint32_t *)(PL011_0_BASE + PL011_DR) = chr;
413 static int bcm2708_ser_getc(void)
415 if ((*(volatile uint32_t *)(PL011_0_BASE + PL011_FR) & PL011_FR_RXFE) == 0)
416 return (int)*(volatile uint32_t *)(PL011_0_BASE + PL011_DR);
418 return -1;
421 static IPTR bcm2708_probe(struct ARM_Implementation *krnARMImpl, struct TagItem *msg)
423 void *bootPutC = NULL;
425 while(msg->ti_Tag != TAG_DONE)
427 switch (msg->ti_Tag)
429 case KRN_FuncPutC:
430 bootPutC = (void *)msg->ti_Data;
431 break;
433 msg++;
436 if (krnARMImpl->ARMI_Platform != 0xc42)
437 return FALSE;
439 if (krnARMImpl->ARMI_Family == 7)
441 /* bcm2836 uses armv7 */
442 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2836_PERIPHYSBASE;
443 krnARMImpl->ARMI_InitCore = &bcm2708_init_core;
444 krnARMImpl->ARMI_FIQProcess = &bcm2807_fiq_process;
445 krnARMImpl->ARMI_SendIPI = &bcm2807_send_ipi;
447 else
448 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2835_PERIPHYSBASE;
450 krnARMImpl->ARMI_GetTime = &bcm2807_get_time;
451 krnARMImpl->ARMI_InitTimer = &bcm2708_init_gputimer;
452 krnARMImpl->ARMI_LED_Toggle = &bcm2708_toggle_led;
454 krnARMImpl->ARMI_SerPutChar = &bcm2708_ser_putc;
455 krnARMImpl->ARMI_SerGetChar = &bcm2708_ser_getc;
456 if ((krnARMImpl->ARMI_PutChar = bootPutC) != NULL)
457 krnARMImpl->ARMI_PutChar(0xFF); // Clear the display
459 krnARMImpl->ARMI_IRQInit = &bcm2807_irq_init;
460 krnARMImpl->ARMI_IRQEnable = &bcm2807_irq_enable;
461 krnARMImpl->ARMI_IRQDisable = &bcm2807_irq_disable;
462 krnARMImpl->ARMI_IRQProcess = &bcm2807_irq_process;
464 krnARMImpl->ARMI_Init = &bcm2708_init;
466 return TRUE;
469 ADD2SET(bcm2708_probe, ARMPLATFORMS, 0);