2 Copyright © 2015, 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"
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
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);
59 struct cpu_ipidata
*bcm2708_cpuipid
[4] = { 0, 0, 0, 0};
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
;
79 uint32_t *cpu_fiq_stack
;
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 (cpu
= 1; cpu
< 4; cpu
++)
96 cpu_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
97 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&cpu_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
99 cpu_fiq_stack
= (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
100 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4] = (uint32_t)&cpu_fiq_stack
[1024-sizeof(IPTR
)];
102 __tls
= (tls_t
*)AllocMem(sizeof(tls_t
) + sizeof(struct cpu_ipidata
), 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 CPU #%d\n", __PRETTY_FUNCTION__
, cpu
));
110 D(bug("[KRN:BCM2708] %s: CPU #%d Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, cpu
, cpu_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2]));
111 D(bug("[KRN:BCM2708] %s: CPU #%d FIQ Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, cpu
, cpu_fiq_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4]));
112 D(bug("[KRN:BCM2708] %s: CPU #%d TLS @ 0x%p\n", __PRETTY_FUNCTION__
, cpu
, ((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 cpu */
120 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * cpu
))) = (uint32_t)trampoline_dst
;
123 * Try to obtain spinlock again.
124 * This should put this cpu to sleep since the locked was already obtained. Once the cpu 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_cpu(APTR _kernelBase
, APTR _sysBase
)
135 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
136 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
137 #if defined(__AROSEXEC_SMP__)
138 tls_t
*__tls
= TLS_PTR_GET();
140 int cpunum
= GetCPUNumber();
142 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, cpunum
));
144 /* Clear all pending FIQ sources on mailboxes */
145 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ (16 * cpunum
))) = 0xffffffff;
146 *((uint32_t *)(BCM2836_MAILBOX1_CLR0
+ (16 * cpunum
))) = 0xffffffff;
147 *((uint32_t *)(BCM2836_MAILBOX2_CLR0
+ (16 * cpunum
))) = 0xffffffff;
148 *((uint32_t *)(BCM2836_MAILBOX3_CLR0
+ (16 * cpunum
))) = 0xffffffff;
150 #if defined(__AROSEXEC_SMP__)
151 bcm2708_cpuipid
[cpunum
] = (unsigned int)__tls
+ sizeof(tls_t
);
152 D(bug("[KRN:BCM2708] %s: cpu #%d IPI data @ 0x%p\n", __PRETTY_FUNCTION__
, cpunum
, bcm2708_cpuipid
[cpunum
]));
154 // enable FIQ mailbox interupt
155 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * cpunum
))) = 0x10;
159 static unsigned int bcm2807_get_time(void)
161 return *((volatile unsigned int *)(SYSTIMER_CLO
));
164 static void bcm2807_irq_init(void)
167 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
169 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
170 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
171 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
174 static void bcm2807_send_ipi(uint32_t ipi
, uint32_t ipi_data
, uint32_t cpumask
)
178 for (cpu
= 0; cpu
< 4; cpu
++)
180 #if defined(__AROSEXEC_SMP__)
181 if ((cpumask
& (1 << cpu
)) && bcm2708_cpuipid
[cpu
])
183 /* TODO: check which mailbox is available and use it */
184 bcm2708_cpuipid
[cpu
]->ipi_data
[mbno
] = ipi_data
;
185 *((uint32_t *)(BCM2836_MAILBOX0_SET0
+ 4 * mbno
+ (0x10 * cpu
))) = ipi
;
191 static void bcm2807_irq_enable(int irq
)
193 int bank
= IRQ_BANK(irq
);
196 reg
= (unsigned int)IRQBANK_POINTER(bank
);
198 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
200 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
202 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
205 static void bcm2807_irq_disable(int irq
)
207 int bank
= IRQ_BANK(irq
);
210 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
212 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
214 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
216 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
219 static void bcm2807_irq_process()
221 unsigned int pendingarm
, pending0
, pending1
, irq
;
225 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
226 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
227 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
229 if (!(pendingarm
|| pending0
|| pending1
))
232 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm
));
233 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0
));
234 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1
));
236 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
238 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
240 if (pendingarm
& (1 << (irq
- (2 << 5))))
242 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
243 krnRunIRQHandlers(KernelBase
, irq
);
250 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
252 if (pending0
& (1 << (irq
- (0 << 5))))
254 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
255 krnRunIRQHandlers(KernelBase
, irq
);
262 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
264 if (pending1
& (1 << (irq
- (1 << 5))))
266 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
267 krnRunIRQHandlers(KernelBase
, irq
);
274 static void bcm2807_fiq_process()
276 int cpunum
= GetCPUNumber();
277 uint32_t fiq
, fiq_data
;
280 DFIQ(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, cpunum
));
282 fiq
= *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * cpunum
)));
284 DFIQ(bug("[KRN:BCM2708] %s: CPU #%d FIQ %x\n", __PRETTY_FUNCTION__
, cpunum
, fiq
));
288 for (mbno
=0; mbno
< 4; mbno
++)
290 if (fiq
& (0x10 << mbno
))
292 fiq_data
= *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4 * mbno
+ (16 * cpunum
)));
293 DFIQ(bug("[KRN:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__
, mbno
, fiq_data
));
294 #if defined(__AROSEXEC_SMP__)
295 if (bcm2708_cpuipid
[cpunum
])
296 handle_ipi(fiq_data
, bcm2708_cpuipid
[cpunum
]->ipi_data
[0]);
298 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4 * mbno
+ (16 * cpunum
))) = 0xffffffff;
304 static void bcm2708_toggle_led(int LED
, int state
)
306 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
309 APTR gpiofunc
= GPCLR1
;
311 if (LED
== ARM_LED_ACTIVITY
)
314 if (state
== ARM_LED_ON
)
317 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
321 // RasPi 1 only allows us to toggle the activity LED
323 *(volatile unsigned int *)GPCLR0
= (1 << 16);
325 *(volatile unsigned int *)GPSET0
= (1 << 16);
329 /* Use system timer 3 for our scheduling heartbeat */
330 #define VBLANK_TIMER 3
331 #define VBLANK_INTERVAL (1000000 / 50)
333 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
337 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
339 /* Aknowledge our timer interrupt */
340 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
342 /* Signal the Exec VBlankServer */
343 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
344 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
347 /* Refresh our timer interrupt */
348 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
349 stc
+= VBLANK_INTERVAL
;
350 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
352 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
355 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
357 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
358 struct IntrNode
*GPUTimerHandle
;
361 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
363 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
365 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
366 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
368 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
369 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
370 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
371 GPUTimerHandle
->in_type
= it_interrupt
;
372 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
374 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
376 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
378 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
379 stc
+= VBLANK_INTERVAL
;
380 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
381 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
383 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
386 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
388 return GPUTimerHandle
;
391 static inline void bcm2708_ser_waitout()
395 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
399 static void bcm2708_ser_putc(uint8_t chr
)
401 bcm2708_ser_waitout();
405 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
406 bcm2708_ser_waitout();
408 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
411 static int bcm2708_ser_getc(void)
413 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
414 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
419 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
421 void *bootPutC
= NULL
;
423 while(msg
->ti_Tag
!= TAG_DONE
)
428 bootPutC
= (void *)msg
->ti_Data
;
434 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
437 if (krnARMImpl
->ARMI_Family
== 7)
439 /* bcm2836 uses armv7 */
440 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
441 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_cpu
;
442 krnARMImpl
->ARMI_FIQProcess
= &bcm2807_fiq_process
;
443 krnARMImpl
->ARMI_SendIPI
= &bcm2807_send_ipi
;
446 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
448 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
449 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
450 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
452 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
453 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
454 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
455 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
457 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
458 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
459 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
460 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
462 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
467 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);