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
42 extern void mpcore_trampoline();
43 extern uint32_t mpcore_end
;
44 extern uint32_t mpcore_pde
;
46 extern void cpu_Register(void);
47 extern void arm_flush_cache(uint32_t addr
, uint32_t length
);
49 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
51 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
52 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
54 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
56 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
58 void *trampoline_src
= mpcore_trampoline
;
59 void *trampoline_dst
= (void *)BOOTMEMADDR(bm_mctrampoline
);
60 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
61 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
67 bug("[KRN:BCM2708] Initialising Multicore System\n");
68 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
70 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
72 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
74 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
75 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
76 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
78 for (core
= 1; core
< 4; core
++)
80 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
81 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
83 __tls
= AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
84 __tls
->SysBase
= _sysBase
;
85 __tls
->KernelBase
= _kernelBase
;
86 __tls
->ThisTask
= NULL
;
87 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
88 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = __tls
;
90 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
91 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]));
92 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__
, core
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
94 arm_flush_cache((uint32_t)trampoline_dst
, 512);
95 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * core
))) = (uint32_t)trampoline_dst
;
97 if (__arm_arosintern
.ARMI_Delay
)
98 __arm_arosintern
.ARMI_Delay(10000000);
103 static void bcm2708_init_core(APTR _kernelBase
, APTR _sysBase
)
105 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
106 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
108 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
111 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * core
))) = 0x1;
114 static unsigned int bcm2807_get_time(void)
116 return *((volatile unsigned int *)(SYSTIMER_CLO
));
119 static void bcm2807_irq_init(void)
122 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
124 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
125 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
126 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
128 // aknowledge pending IRQ's
129 *(volatile unsigned int *)ARMIRQ_PEND
= *(volatile unsigned int *)ARMIRQ_PEND
;
130 *(volatile unsigned int *)GPUIRQ_PEND0
= *(volatile unsigned int *)GPUIRQ_PEND0
;
131 *(volatile unsigned int *)GPUIRQ_PEND1
= *(volatile unsigned int *)GPUIRQ_PEND1
;
134 static void bcm2807_irq_enable(int irq
)
136 int bank
= IRQ_BANK(irq
);
139 reg
= (unsigned int)IRQBANK_POINTER(bank
);
141 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
143 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
145 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
148 static void bcm2807_irq_disable(int irq
)
150 int bank
= IRQ_BANK(irq
);
153 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
155 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
157 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
159 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
162 static void bcm2807_irq_process()
164 unsigned int pendingarm
, pending0
, pending1
, irq
;
168 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
169 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
170 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
172 if (!(pendingarm
|| pending0
|| pending1
))
175 DIRQ(bug("[KRN] PendingARM %08x\n", pendingarm
));
176 DIRQ(bug("[KRN] Pending0 %08x\n", pending0
));
177 DIRQ(bug("[KRN] Pending1 %08x\n", pending1
));
179 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
181 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
183 if (pendingarm
& (1 << (irq
- (2 << 5))))
185 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
186 krnRunIRQHandlers(KernelBase
, irq
);
193 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
195 if (pending0
& (1 << (irq
- (0 << 5))))
197 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
198 krnRunIRQHandlers(KernelBase
, irq
);
205 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
207 if (pending1
& (1 << (irq
- (1 << 5))))
209 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
210 krnRunIRQHandlers(KernelBase
, irq
);
218 static void bcm2708_toggle_led(int LED
, int state
)
220 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
223 APTR gpiofunc
= GPCLR1
;
225 if (LED
== ARM_LED_ACTIVITY
)
228 if (state
== ARM_LED_ON
)
231 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
235 // RasPi 1 only allows us to toggle the activity LED
237 *(volatile unsigned int *)GPCLR0
= (1 << 16);
239 *(volatile unsigned int *)GPSET0
= (1 << 16);
243 /* Use system timer 3 for our scheduling heartbeat */
244 #define VBLANK_TIMER 3
245 #define VBLANK_INTERVAL (1000000 / 50)
247 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
251 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
253 /* Aknowledge our timer interrupt */
254 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
256 /* Signal the Exec VBlankServer */
257 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
258 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
261 /* Refresh our timer interrupt */
262 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
263 stc
+= VBLANK_INTERVAL
;
264 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
266 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
269 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
271 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
272 struct IntrNode
*GPUTimerHandle
;
275 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
277 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
279 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
280 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
282 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
283 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
284 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
285 GPUTimerHandle
->in_type
= it_interrupt
;
286 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
288 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
290 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
292 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
293 stc
+= VBLANK_INTERVAL
;
294 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
295 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
297 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
300 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
302 return GPUTimerHandle
;
305 static inline void bcm2708_ser_waitout()
309 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
313 static void bcm2708_ser_putc(uint8_t chr
)
315 bcm2708_ser_waitout();
319 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
320 bcm2708_ser_waitout();
322 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
325 static int bcm2708_ser_getc(void)
327 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
328 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
333 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
335 void *bootPutC
= NULL
;
337 while(msg
->ti_Tag
!= TAG_DONE
)
342 bootPutC
= (void *)msg
->ti_Data
;
348 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
351 if (krnARMImpl
->ARMI_Family
== 7)
353 /* bcm2836 uses armv7 */
354 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
355 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_core
;
358 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
360 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
361 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
362 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
364 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
365 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
366 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
367 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
369 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
370 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
371 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
372 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
374 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
379 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);