when waking up secondary cores send an event() since they are spinning on mailbox...
[AROS.git] / arch / arm-native / kernel / platform_bcm2708.c
blob39b8c524f47eb34b2884452107418c768dd8732b
1 /*
2 Copyright � 2015-2016, 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"
26 #include "tls.h"
27 #include "io.h"
29 #include "exec_platform.h"
31 #define ARM_PERIIOBASE ((IPTR)__arm_arosintern.ARMI_PeripheralBase)
32 #include <hardware/bcm2708.h>
33 #include <hardware/bcm2708_boot.h>
34 #include <hardware/pl011uart.h>
36 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
38 #define IRQ_BANK1 0x00000100
39 #define IRQ_BANK2 0x00000200
41 #undef D
42 #define D(x) x
43 #define DIRQ(x)
44 #define DFIQ(x)
45 #define DTIMER(x)
47 extern void mpcore_trampoline();
48 extern uint32_t mpcore_end;
49 extern uint32_t mpcore_pde;
50 extern spinlock_t startup_lock;
52 extern void cpu_Register(void);
53 extern void arm_flush_cache(uint32_t, uint32_t);
54 #if defined(__AROSEXEC_SMP__)
55 extern void handle_ipi(uint32_t, uint32_t);
57 struct cpu_ipidata
59 uint32_t ipi_data[4];
62 struct cpu_ipidata *bcm2708_cpuipid[4] = { 0, 0, 0, 0};
63 #endif
65 static void bcm2708_init(APTR _kernelBase, APTR _sysBase)
67 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
68 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
70 KrnSpinInit(&startup_lock);
72 D(bug("[Kernel:BCM2708] %s()\n", __PRETTY_FUNCTION__));
74 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
76 void *trampoline_src = mpcore_trampoline;
77 void *trampoline_dst = (void *)BOOTMEMADDR(bm_mctrampoline);
78 uint32_t trampoline_length = (uintptr_t)&mpcore_end - (uintptr_t)mpcore_trampoline;
79 uint32_t trampoline_data_offset = (uintptr_t)&mpcore_pde - (uintptr_t)mpcore_trampoline;
80 int cpu;
81 uint32_t *cpu_stack;
82 uint32_t *cpu_fiq_stack;
83 uint32_t tmp;
84 tls_t *__tls;
86 bug("[Kernel:BCM2708] Initialising Multicore System\n");
87 D(bug("[Kernel:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__, trampoline_src, trampoline_dst, trampoline_length));
89 bcopy(trampoline_src, trampoline_dst, trampoline_length);
91 D(bug("[Kernel:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__, trampoline_data_offset));
93 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp));
94 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[0] = tmp; // pde
95 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[1] = (uint32_t)cpu_Register;
97 for (cpu = 1; cpu < 4; cpu ++)
99 cpu_stack = (uint32_t *)AllocMem(AROS_STACKSIZE*sizeof(uint32_t), MEMF_CLEAR); /* MEMF_PRIVATE */
100 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[2] = (uint32_t)&cpu_stack[AROS_STACKSIZE-sizeof(IPTR)];
102 cpu_fiq_stack = (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR); /* MEMF_PRIVATE */
103 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[4] = (uint32_t)&cpu_fiq_stack[1024-sizeof(IPTR)];
106 #if defined(__AROSEXEC_SMP)
107 __tls = (tls_t *)AllocMem(sizeof(tls_t) + sizeof(struct cpu_ipidata), MEMF_CLEAR); /* MEMF_PRIVATE */
108 #else
109 __tls = (tls_t *)AllocMem(sizeof(tls_t), MEMF_CLEAR); /* MEMF_PRIVATE */
110 #endif
111 __tls->SysBase = _sysBase;
112 __tls->KernelBase = _kernelBase;
113 __tls->ThisTask = NULL;
114 arm_flush_cache(((uint32_t)__tls) & ~63, 512);
115 ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3] = (uint32_t)__tls;
117 D(bug("[Kernel:BCM2708] %s: Attempting to wake CPU #%02d\n", __PRETTY_FUNCTION__, cpu));
118 D(bug("[Kernel:BCM2708] %s: CPU #%02d Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__, cpu, cpu_stack, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[2]));
119 D(bug("[Kernel:BCM2708] %s: CPU #%02d FIQ Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__, cpu, cpu_fiq_stack, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[4]));
120 D(bug("[Kernel:BCM2708] %s: CPU #%02d TLS @ 0x%p\n", __PRETTY_FUNCTION__, cpu, ((uint32_t *)(trampoline_dst + trampoline_data_offset))[3]));
122 arm_flush_cache((uint32_t)trampoline_dst, 512);
124 /* Lock the startup spinlock */
125 KrnSpinLock(&startup_lock, NULL, SPINLOCK_MODE_WRITE);
127 /* Wake up the cpu */
128 wr32le(BCM2836_MAILBOX3_SET0 + (0x10 * cpu), (uint32_t)trampoline_dst);
130 dsb();
132 sev();
135 * Try to obtain spinlock again.
136 * This should put this cpu to sleep since the lock was already obtained. Once the cpu startup
137 * is ready, it will call KrnSpinUnLock() too
139 KrnSpinLock(&startup_lock, NULL, SPINLOCK_MODE_WRITE);
140 KrnSpinUnLock(&startup_lock);
145 static void bcm2708_init_cpu(APTR _kernelBase, APTR _sysBase)
147 struct ExecBase *SysBase = (struct ExecBase *)_sysBase;
148 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
149 (void)SysBase;
150 #if defined(__AROSEXEC_SMP__)
151 tls_t *__tls = TLS_PTR_GET();
152 #endif
153 int cpunum = GetCPUNumber();
155 D(bug("[Kernel:BCM2708] %s(#%02d)\n", __PRETTY_FUNCTION__, cpunum));
157 /* Clear all pending FIQ sources on mailboxes */
158 wr32le(BCM2836_MAILBOX0_CLR0 + (16 * cpunum), 0xffffffff);
159 wr32le(BCM2836_MAILBOX1_CLR0 + (16 * cpunum), 0xffffffff);
160 wr32le(BCM2836_MAILBOX2_CLR0 + (16 * cpunum), 0xffffffff);
161 wr32le(BCM2836_MAILBOX3_CLR0 + (16 * cpunum), 0xffffffff);
163 #if defined(__AROSEXEC_SMP__)
164 bcm2708_cpuipid[cpunum] = (unsigned int)__tls + sizeof(tls_t);
165 D(bug("[Kernel:BCM2708] %s: CPU #%02d IPI data @ 0x%p\n", __PRETTY_FUNCTION__, cpunum, bcm2708_cpuipid[cpunum]));
167 // enable FIQ mailbox interupt
168 wr32le(BCM2836_MAILBOX_INT_CTRL0 + (0x4 * cpunum), 0x10);
169 #endif
172 static unsigned int bcm2708_get_time(void)
174 return rd32le(SYSTIMER_CLO);
177 static void bcm2708_irq_init(void)
179 // disable IRQ's
180 // wr32le(ARMFIQ_CTRL, 0);
182 wr32le(ARMIRQ_DIBL, ~0);
183 wr32le(GPUIRQ_DIBL0, ~0);
184 wr32le(GPUIRQ_DIBL1, ~0);
187 static void bcm2708_send_ipi(uint32_t ipi, uint32_t ipi_data, uint32_t cpumask)
189 int cpu;
191 for (cpu = 0; cpu < 4; cpu++)
193 #if defined(__AROSEXEC_SMP__)
194 int mbno = 0;
195 if ((cpumask & (1 << cpu)) && bcm2708_cpuipid[cpu])
197 /* TODO: check which mailbox is available and use it */
198 bcm2708_cpuipid[cpu]->ipi_data[mbno] = ipi_data;
199 wr32le(BCM2836_MAILBOX0_SET0 + 4 * mbno + (0x10 * cpu), ipi);
201 #endif
205 static void bcm2708_irq_enable(int irq)
207 int bank = IRQ_BANK(irq);
208 unsigned int reg;
210 reg = (unsigned int)IRQBANK_POINTER(bank);
212 DIRQ(bug("[Kernel:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
214 wr32le(reg, IRQ_MASK(irq));
216 DIRQ(bug("[Kernel:BCM2708] irqmask=%08x\n", rd32le(reg)));
219 static void bcm2708_irq_disable(int irq)
221 int bank = IRQ_BANK(irq);
222 unsigned int reg;
224 reg = (unsigned int)IRQBANK_POINTER(bank) + 0x0c;
226 DIRQ(bug("[Kernel:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq, bank, reg));
228 wr32le(reg, IRQ_MASK(irq));
230 DIRQ(bug("[Kernel:BCM2708] irqmask=%08x\n", rd32le(reg)));
233 static void bcm2708_irq_process()
235 unsigned int pendingarm, pending0, pending1, irq;
237 for(;;)
239 pendingarm = rd32le(ARMIRQ_PEND);
240 pending0 = rd32le(GPUIRQ_PEND0);
241 pending1 = rd32le(GPUIRQ_PEND1);
243 if (!(pendingarm || pending0 || pending1))
244 break;
246 DIRQ(bug("[Kernel:BCM2708] PendingARM %08x\n", pendingarm));
247 DIRQ(bug("[Kernel:BCM2708] Pending0 %08x\n", pending0));
248 DIRQ(bug("[Kernel:BCM2708] Pending1 %08x\n", pending1));
250 if (pendingarm & ~(IRQ_BANK1 | IRQ_BANK2))
252 for (irq = (2 << 5); irq < ((2 << 5) + 8); irq++)
254 if (pendingarm & (1 << (irq - (2 << 5))))
256 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq));
257 krnRunIRQHandlers(KernelBase, irq);
262 if (pending0)
264 for (irq = (0 << 5); irq < ((0 << 5) + 32); irq++)
266 if (pending0 & (1 << (irq - (0 << 5))))
268 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq));
269 krnRunIRQHandlers(KernelBase, irq);
274 if (pending1)
276 for (irq = (1 << 5); irq < ((1 << 5) + 32); irq++)
278 if (pending1 & (1 << (irq - (1 << 5))))
280 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq));
281 krnRunIRQHandlers(KernelBase, irq);
288 static void bcm2708_fiq_process()
290 int cpunum = GetCPUNumber();
291 uint32_t fiq, fiq_data;
292 int mbno;
294 DFIQ(bug("[Kernel:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, cpunum));
296 fiq = rd32le(BCM2836_FIQ_PEND0 + (0x4 * cpunum));
298 DFIQ(bug("[Kernel:BCM2708] %s: CPU #%02d FIQ %x\n", __PRETTY_FUNCTION__, cpunum, fiq));
300 if (fiq)
302 for (mbno=0; mbno < 4; mbno++)
304 if (fiq & (0x10 << mbno))
306 fiq_data = rd32le(BCM2836_MAILBOX0_CLR0 + 4 * mbno + (16 * cpunum));
307 (void)fiq_data;
308 DFIQ(bug("[Kernel:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__, mbno, fiq_data));
309 #if defined(__AROSEXEC_SMP__)
310 if (bcm2708_cpuipid[cpunum])
311 handle_ipi(fiq_data, bcm2708_cpuipid[cpunum]->ipi_data[0]);
312 #endif
313 wr32le(BCM2836_MAILBOX0_CLR0 + 4 * mbno + (16 * cpunum), 0xffffffff);
319 static void bcm2708_toggle_led(int LED, int state)
321 if (__arm_arosintern.ARMI_PeripheralBase == (APTR)BCM2836_PERIPHYSBASE)
323 int pin = 35;
324 IPTR gpiofunc = GPCLR1;
326 if (LED == ARM_LED_ACTIVITY)
327 pin = 47;
329 if (state == ARM_LED_ON)
330 gpiofunc = GPSET1;
332 wr32le(gpiofunc, (1 << (pin-32)));
334 else
336 // RasPi 1 only allows us to toggle the activity LED
337 if (state)
338 wr32le(GPCLR0, (1 << 16));
339 else
340 wr32le(GPSET0, (1 << 16));
344 /* Use system timer 3 for our scheduling heartbeat */
345 #define VBLANK_TIMER 3
346 #define VBLANK_INTERVAL (1000000 / 50)
348 static void bcm2708_gputimer_handler(unsigned int timerno, void *unused1)
350 unsigned int stc;
352 DTIMER(bug("[Kernel:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__, timerno));
354 /* Acknowledge our timer interrupt */
355 wr32le(SYSTIMER_CS, 1 << timerno);
357 /* Signal the Exec VBlankServer */
358 if (SysBase && (IDNESTCOUNT_GET /*SysBase->IDNestCnt*/ < 0)) {
359 core_Cause(INTB_VERTB, 1L << INTB_VERTB);
362 /* Refresh our timer interrupt */
363 stc = rd32le(SYSTIMER_CLO);
364 stc += VBLANK_INTERVAL;
365 wr32le(SYSTIMER_C0 + (timerno * 4), stc);
367 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__));
370 static APTR bcm2708_init_gputimer(APTR _kernelBase)
372 struct KernelBase *KernelBase = (struct KernelBase *)_kernelBase;
373 struct IntrNode *GPUTimerHandle;
374 unsigned int stc;
376 DTIMER(bug("[Kernel:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__, KernelBase));
378 if ((GPUTimerHandle = AllocMem(sizeof(struct IntrNode), MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
380 DTIMER(bug("[Kernel:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__, GPUTimerHandle));
381 DTIMER(bug("[Kernel:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__, VBLANK_TIMER));
383 GPUTimerHandle->in_Handler = bcm2708_gputimer_handler;
384 GPUTimerHandle->in_HandlerData = (void *)VBLANK_TIMER;
385 GPUTimerHandle->in_HandlerData2 = KernelBase;
386 GPUTimerHandle->in_type = it_interrupt;
387 GPUTimerHandle->in_nr = IRQ_TIMER0 + VBLANK_TIMER;
389 ADDHEAD(&KernelBase->kb_Interrupts[IRQ_TIMER0 + VBLANK_TIMER], &GPUTimerHandle->in_Node);
391 DTIMER(bug("[Kernel:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__));
393 stc = rd32le(SYSTIMER_CLO);
394 stc += VBLANK_INTERVAL;
395 wr32le(SYSTIMER_CS, 1 << VBLANK_TIMER);
396 wr32le(SYSTIMER_C0 + (VBLANK_TIMER * 4), stc);
398 ictl_enable_irq(IRQ_TIMER0 + VBLANK_TIMER, KernelBase);
401 DTIMER(bug("[Kernel:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__));
403 return GPUTimerHandle;
406 static inline void bcm2708_ser_waitout()
408 while(1)
410 if ((rd32le(PL011_0_BASE + PL011_FR) & PL011_FR_TXFF) == 0) break;
414 static void bcm2708_ser_putc(uint8_t chr)
416 bcm2708_ser_waitout();
418 if (chr == '\n')
420 wr32le(PL011_0_BASE + PL011_DR, '\r');
421 bcm2708_ser_waitout();
423 wr32le(PL011_0_BASE + PL011_DR, chr);
426 static int bcm2708_ser_getc(void)
428 if ((rd32le(PL011_0_BASE + PL011_FR) & PL011_FR_RXFE) == 0)
429 return (int)rd32le(PL011_0_BASE + PL011_DR);
431 return -1;
434 static IPTR bcm2708_probe(struct ARM_Implementation *krnARMImpl, struct TagItem *msg)
436 void *bootPutC = NULL;
438 while(msg->ti_Tag != TAG_DONE)
440 switch (msg->ti_Tag)
442 case KRN_FuncPutC:
443 bootPutC = (void *)msg->ti_Data;
444 break;
446 msg++;
449 if (krnARMImpl->ARMI_Platform != 0xc42)
450 return FALSE;
452 if (krnARMImpl->ARMI_Family == 7)
454 /* bcm2836 uses armv7 */
455 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2836_PERIPHYSBASE;
456 krnARMImpl->ARMI_InitCore = &bcm2708_init_cpu;
457 krnARMImpl->ARMI_FIQProcess = &bcm2708_fiq_process;
458 krnARMImpl->ARMI_SendIPI = &bcm2708_send_ipi;
460 else
461 krnARMImpl->ARMI_PeripheralBase = (APTR)BCM2835_PERIPHYSBASE;
463 krnARMImpl->ARMI_GetTime = &bcm2708_get_time;
464 krnARMImpl->ARMI_InitTimer = &bcm2708_init_gputimer;
465 krnARMImpl->ARMI_LED_Toggle = &bcm2708_toggle_led;
467 krnARMImpl->ARMI_SerPutChar = &bcm2708_ser_putc;
468 krnARMImpl->ARMI_SerGetChar = &bcm2708_ser_getc;
469 if ((krnARMImpl->ARMI_PutChar = bootPutC) != NULL)
470 krnARMImpl->ARMI_PutChar(0xFF); // Clear the display
472 krnARMImpl->ARMI_IRQInit = &bcm2708_irq_init;
473 krnARMImpl->ARMI_IRQEnable = &bcm2708_irq_enable;
474 krnARMImpl->ARMI_IRQDisable = &bcm2708_irq_disable;
475 krnARMImpl->ARMI_IRQProcess = &bcm2708_irq_process;
477 krnARMImpl->ARMI_Init = &bcm2708_init;
479 return TRUE;
482 ADD2SET(bcm2708_probe, ARMPLATFORMS, 0);