2 Copyright © 2015, The AROS Development Team. All rights reserved.
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>
15 #include <hardware/intbits.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
43 extern void mpcore_trampoline();
44 extern uint32_t mpcore_end
;
45 extern uint32_t mpcore_pde
;
47 extern void cpu_Register(void);
48 extern void arm_flush_cache(uint32_t addr
, uint32_t length
);
50 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
52 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
53 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
55 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
57 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
59 void *trampoline_src
= mpcore_trampoline
;
60 void *trampoline_dst
= (void *)BOOTMEMADDR(bm_mctrampoline
);
61 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
62 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
68 bug("[KRN:BCM2708] Initialising Multicore System\n");
69 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
71 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
73 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
75 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
76 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
77 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
79 for (core
= 1; core
< 4; core
++)
81 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
82 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
84 __tls
= AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
85 __tls
->SysBase
= _sysBase
;
86 __tls
->KernelBase
= _kernelBase
;
87 __tls
->ThisTask
= NULL
;
88 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
89 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = __tls
;
91 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
92 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]));
93 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__
, core
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
95 arm_flush_cache((uint32_t)trampoline_dst
, 512);
96 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * core
))) = (uint32_t)trampoline_dst
;
98 if (__arm_arosintern
.ARMI_Delay
)
99 __arm_arosintern
.ARMI_Delay(10000000);
104 static void bcm2708_init_core(APTR _kernelBase
, APTR _sysBase
)
106 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
107 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
110 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
112 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
114 // enable FIQ mailbox interupt
115 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * (tmp
& 0x3)))) = (1 << 3);
118 static unsigned int bcm2807_get_time(void)
120 return *((volatile unsigned int *)(SYSTIMER_CLO
));
123 static void bcm2807_irq_init(void)
126 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
128 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
129 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
130 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
132 // aknowledge pending IRQ's
133 *(volatile unsigned int *)ARMIRQ_PEND
= *(volatile unsigned int *)ARMIRQ_PEND
;
134 *(volatile unsigned int *)GPUIRQ_PEND0
= *(volatile unsigned int *)GPUIRQ_PEND0
;
135 *(volatile unsigned int *)GPUIRQ_PEND1
= *(volatile unsigned int *)GPUIRQ_PEND1
;
138 static void bcm2807_irq_enable(int irq
)
140 int bank
= IRQ_BANK(irq
);
143 reg
= (unsigned int)IRQBANK_POINTER(bank
);
145 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
147 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
149 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
152 static void bcm2807_irq_disable(int irq
)
154 int bank
= IRQ_BANK(irq
);
157 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
159 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
161 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
163 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
166 static void bcm2807_irq_process()
168 unsigned int pendingarm
, pending0
, pending1
, irq
;
172 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
173 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
174 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
176 if (!(pendingarm
|| pending0
|| pending1
))
179 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm
));
180 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0
));
181 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1
));
183 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
185 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
187 if (pendingarm
& (1 << (irq
- (2 << 5))))
189 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
190 krnRunIRQHandlers(KernelBase
, irq
);
197 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
199 if (pending0
& (1 << (irq
- (0 << 5))))
201 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
202 krnRunIRQHandlers(KernelBase
, irq
);
209 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
211 if (pending1
& (1 << (irq
- (1 << 5))))
213 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
214 krnRunIRQHandlers(KernelBase
, irq
);
221 static void bcm2807_fiq_process()
225 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
227 DFIQ(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
229 fiq
= *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * (tmp
& 0x3))));
231 DFIQ(bug("[KRN:BCM2708] %s: FIQ %x\n", __PRETTY_FUNCTION__
, fiq
));
233 *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * (tmp
& 0x3)))) = fiq
;
236 static void bcm2708_toggle_led(int LED
, int state
)
238 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
241 APTR gpiofunc
= GPCLR1
;
243 if (LED
== ARM_LED_ACTIVITY
)
246 if (state
== ARM_LED_ON
)
249 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
253 // RasPi 1 only allows us to toggle the activity LED
255 *(volatile unsigned int *)GPCLR0
= (1 << 16);
257 *(volatile unsigned int *)GPSET0
= (1 << 16);
261 /* Use system timer 3 for our scheduling heartbeat */
262 #define VBLANK_TIMER 3
263 #define VBLANK_INTERVAL (1000000 / 50)
265 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
269 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
271 /* Aknowledge our timer interrupt */
272 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
274 /* Signal the Exec VBlankServer */
275 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
276 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
279 /* Refresh our timer interrupt */
280 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
281 stc
+= VBLANK_INTERVAL
;
282 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
284 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
287 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
289 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
290 struct IntrNode
*GPUTimerHandle
;
293 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
295 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
297 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
298 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
300 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
301 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
302 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
303 GPUTimerHandle
->in_type
= it_interrupt
;
304 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
306 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
308 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
310 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
311 stc
+= VBLANK_INTERVAL
;
312 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
313 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
315 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
318 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
320 return GPUTimerHandle
;
323 static inline void bcm2708_ser_waitout()
327 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
331 static void bcm2708_ser_putc(uint8_t chr
)
333 bcm2708_ser_waitout();
337 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
338 bcm2708_ser_waitout();
340 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
343 static int bcm2708_ser_getc(void)
345 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
346 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
351 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
353 void *bootPutC
= NULL
;
355 while(msg
->ti_Tag
!= TAG_DONE
)
360 bootPutC
= (void *)msg
->ti_Data
;
366 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
369 if (krnARMImpl
->ARMI_Family
== 7)
371 /* bcm2836 uses armv7 */
372 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
373 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_core
;
374 krnARMImpl
->ARMI_FIQProcess
= &bcm2807_fiq_process
;
377 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
379 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
380 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
381 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
383 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
384 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
385 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
386 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
388 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
389 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
390 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
391 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
393 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
398 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);