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 #define ARM_PERIIOBASE __arm_arosintern.ARMI_PeripheralBase
27 #include <hardware/bcm2708.h>
28 #include <hardware/pl011uart.h>
30 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
32 #define IRQ_BANK1 0x00000100
33 #define IRQ_BANK2 0x00000200
38 extern mpcore_trampoline();
39 extern uint32_t mpcore_end
;
40 extern uint32_t mpcore_pde
;
42 extern void cpu_Register(void);
43 extern void arm_flush_cache(uint32_t addr
, uint32_t length
);
45 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
47 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
48 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
50 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
52 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
54 void *trampoline_src
= mpcore_trampoline
;
55 void *trampoline_dst
= (void *)0x2000;
56 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
57 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
62 bug("[KRN:BCM2708] Initialising Multicore System\n");
63 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
65 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
67 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
69 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
70 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
71 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
73 for (core
= 1; core
< 4; core
++)
75 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
76 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = &core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
78 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
79 D(bug("[KRN:BCM2708] %s: core #%d stack @ 0x%p : 0x%p)\n", __PRETTY_FUNCTION__
, core
, core_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2]));
81 arm_flush_cache((uint32_t)trampoline_dst
, 512);
82 *((uint32_t *)(0x4000008c + (0x10 * core
))) = trampoline_dst
;
84 if (__arm_arosintern
.ARMI_Delay
)
85 __arm_arosintern
.ARMI_Delay(10000000);
90 static unsigned int bcm2807_get_time(void)
92 return *((volatile unsigned int *)(SYSTIMER_CLO
));
95 static void bcm2807_irq_init(void)
98 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
99 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
100 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
103 static void bcm2807_irq_enable(int irq
)
105 int bank
= IRQ_BANK(irq
);
108 reg
= (unsigned int)IRQBANK_POINTER(bank
);
110 (bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
112 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
114 (bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
117 static void bcm2807_irq_disable(int irq
)
119 int bank
= IRQ_BANK(irq
);
122 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
124 (bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
126 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
128 (bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
131 static void bcm2807_irq_process()
133 unsigned int pendingarm
, pending0
, pending1
, irq
;
137 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
138 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
139 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
141 if (!(pendingarm
|| pending0
|| pending1
))
144 DIRQ(bug("[KRN] PendingARM %08x\n", pendingarm
));
145 DIRQ(bug("[KRN] Pending0 %08x\n", pending0
));
146 DIRQ(bug("[KRN] Pending1 %08x\n", pending1
));
148 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
150 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
152 if (pendingarm
& (1 << (irq
- (2 << 5))))
154 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
155 krnRunIRQHandlers(KernelBase
, irq
);
162 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
164 if (pending0
& (1 << (irq
- (0 << 5))))
166 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
167 krnRunIRQHandlers(KernelBase
, irq
);
174 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
176 if (pending1
& (1 << (irq
- (1 << 5))))
178 DIRQ(bug("[KRN] Handling IRQ %d ..\n", irq
));
179 krnRunIRQHandlers(KernelBase
, irq
);
187 static void bcm2708_toggle_led(int LED
, int state
)
189 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
192 APTR gpiofunc
= GPCLR1
;
194 if (LED
== ARM_LED_ACTIVITY
)
197 if (state
== ARM_LED_ON
)
200 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
204 // RasPi 1 only allows us to toggle the activity LED
206 *(volatile unsigned int *)GPCLR0
= (1 << 16);
208 *(volatile unsigned int *)GPSET0
= (1 << 16);
212 /* Use system timer 3 for our scheduling heartbeat */
213 #define VBLANK_TIMER 3
214 #define VBLANK_INTERVAL (1000000 / 50)
216 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
220 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
222 /* Aknowledge our timer interrupt */
223 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
225 /* Signal the Exec VBlankServer */
226 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
227 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
230 /* Refresh our timer interrupt */
231 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
232 stc
+= VBLANK_INTERVAL
;
233 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
235 D(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
238 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
240 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
241 struct IntrNode
*GPUTimerHandle
;
244 D(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
246 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
248 D(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
249 D(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
251 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
252 GPUTimerHandle
->in_HandlerData
= VBLANK_TIMER
;
253 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
254 GPUTimerHandle
->in_type
= it_interrupt
;
255 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
257 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
259 D(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
261 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
262 stc
+= VBLANK_INTERVAL
;
263 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
264 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
266 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
269 D(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
271 return GPUTimerHandle
;
274 static inline void bcm2708_ser_waitout()
278 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
282 static void bcm2708_ser_putc(uint8_t chr
)
284 bcm2708_ser_waitout();
288 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
289 bcm2708_ser_waitout();
291 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
294 static int bcm2708_ser_getc(void)
296 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
297 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
302 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
304 BOOL bcm2708found
= FALSE
;
305 void *bootPutC
= NULL
;
307 while(msg
->ti_Tag
!= TAG_DONE
)
312 if (msg
->ti_Data
== 0xc42)
316 bootPutC
= (void *)msg
->ti_Data
;
325 if (krnARMImpl
->ARMI_Family
== 7) /* bcm2836 uses armv7 */
326 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
328 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
330 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
331 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
332 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
334 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
335 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
336 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
337 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
339 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
340 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
341 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
342 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
344 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
349 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);