2 Copyright © 2015-2016, The AROS Development Team. All rights reserved.
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>
16 #include <hardware/intbits.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"
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
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);
62 struct cpu_ipidata
*bcm2708_cpuipid
[4] = { 0, 0, 0, 0};
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
;
82 uint32_t *cpu_fiq_stack
;
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 */
109 __tls
= (tls_t
*)AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
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
);
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
;
150 #if defined(__AROSEXEC_SMP__)
151 tls_t
*__tls
= TLS_PTR_GET();
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);
172 static unsigned int bcm2708_get_time(void)
174 return rd32le(SYSTIMER_CLO
);
177 static void bcm2708_irq_init(void)
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
)
191 for (cpu
= 0; cpu
< 4; cpu
++)
193 #if defined(__AROSEXEC_SMP__)
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
);
205 static void bcm2708_irq_enable(int irq
)
207 int bank
= IRQ_BANK(irq
);
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
);
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
;
239 pendingarm
= rd32le(ARMIRQ_PEND
);
240 pending0
= rd32le(GPUIRQ_PEND0
);
241 pending1
= rd32le(GPUIRQ_PEND1
);
243 if (!(pendingarm
|| pending0
|| pending1
))
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
);
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
);
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
;
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
));
302 for (mbno
=0; mbno
< 4; mbno
++)
304 if (fiq
& (0x10 << mbno
))
306 fiq_data
= rd32le(BCM2836_MAILBOX0_CLR0
+ 4 * mbno
+ (16 * cpunum
));
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]);
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
)
324 IPTR gpiofunc
= GPCLR1
;
326 if (LED
== ARM_LED_ACTIVITY
)
329 if (state
== ARM_LED_ON
)
332 wr32le(gpiofunc
, (1 << (pin
-32)));
336 // RasPi 1 only allows us to toggle the activity LED
338 wr32le(GPCLR0
, (1 << 16));
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
)
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
;
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()
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();
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
);
434 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
436 void *bootPutC
= NULL
;
438 while(msg
->ti_Tag
!= TAG_DONE
)
443 bootPutC
= (void *)msg
->ti_Data
;
449 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
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
;
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
;
482 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);