1/*
2 * Copyright 2013, winocm. <winocm@icloud.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *   Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 *
11 *   Redistributions in binary form must reproduce the above copyright notice, this
12 *   list of conditions and the following disclaimer in the documentation and/or
13 *   other materials provided with the distribution.
14 *
15 *   If you are going to use this software in any form that does not involve
16 *   releasing the source to this project or improving it, let me know beforehand.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * Platform Expert for Raspberry Pi.
31 */
32
33#if defined(BOARD_CONFIG_RASPBERRYPI)
34
35#include <mach/mach_types.h>
36
37#include <pexpert/pexpert.h>
38#include <pexpert/arm/protos.h>
39#include <pexpert/arm/boot.h>
40
41#include <machine/machine_routines.h>
42
43#include <vm/pmap.h>
44#include <arm/pmap.h>
45
46#include "pe_bcm2835.h"
47
48/*
49 * This is board specific stuff.
50 */
51
52#define KPRINTF_PREFIX  "PE_RaspberryPi: "
53
54extern void rtclock_intr(arm_saved_state_t * regs);
55extern void rtc_configure(uint64_t hz);
56
57#define gpio_base   gRaspberryPiGPIOBase
58vm_offset_t     gRaspberryPiGPIOBase;
59#define uart_base   gRaspberryPiUartBase
60vm_offset_t     gRaspberryPiUartBase;
61#define systimer_base   gRaspberryPiSystimerBase
62vm_offset_t     gRaspberryPiSystimerBase;
63#define mb_base   gRaspberryPiMailboxBase
64vm_offset_t       gRaspberryPiMailboxBase;
65
66struct fb_info __attribute__((aligned(16))) gFBInfo;
67
68static uint64_t clock_decrementer = 0;
69static boolean_t clock_initialized = FALSE;
70static boolean_t clock_had_irq = FALSE;
71static uint64_t clock_absolute_time = 0;
72
73static void timer_configure(void)
74{
75    return;
76}
77
78void RaspberryPi_putc(int c)
79{
80    while(!GET32(uart_base + AUX_MU_LSR_REG) & 0x20)
81        barrier();
82    PUT32(uart_base + AUX_MU_IO_REG, c);
83}
84
85int RaspberryPi_getc(void)
86{
87    while(!GET32(uart_base + AUX_MU_LSR_REG) & 0x01)
88        barrier();
89    return GET32(uart_base + AUX_MU_IO_REG);
90}
91
92void RaspberryPi_uart_init(void)
93{
94    unsigned int i;
95	gRaspberryPiUartBase = ml_io_map(AUX_BASE, PAGE_SIZE);
96    gRaspberryPiGPIOBase = ml_io_map(GP_BASE, PAGE_SIZE);
97
98    PUT32(uart_base + AUX_ENABLES,       1);
99    PUT32(uart_base + AUX_MU_IER_REG,    0);
100    PUT32(uart_base + AUX_MU_CNTL_REG,   0);
101    PUT32(uart_base + AUX_MU_LCR_REG,    3);
102    PUT32(uart_base + AUX_MU_MCR_REG,    0);
103    PUT32(uart_base + AUX_MU_IER_REG,    0);
104    PUT32(uart_base + AUX_MU_IIR_REG, 0xC6);
105    PUT32(uart_base + AUX_MU_BAUD_REG, 270); // 115200 bps
106
107    i = GET32(gpio_base + GPFSEL1);
108    i &= ~(7<<12); // Configure GPIO14 as..
109    i |= 2<<12; // ..TXD for UART
110    i &= ~(7<<15); // Configure GPIO15 as..
111    i |= 2<<15; // ..RXD for UART
112    PUT32(gpio_base + GPFSEL1, i);
113
114    PUT32(gpio_base + GPPUD, 0);
115    for(i = 0; i<150; i++) barrier();
116    PUT32(gpio_base + GPPUDCLK0, (1<<14) | (1<<15));
117    for(i = 0; i<150; i++) barrier();
118    PUT32(gpio_base + GPPUDCLK0, 0);
119
120    PUT32(uart_base + AUX_MU_CNTL_REG, 3);
121
122    kprintf(KPRINTF_PREFIX "serial is up\n");
123}
124
125void RaspberryPi_interrupt_init(void)
126{
127    return;
128}
129
130void RaspberryPi_timebase_init(void)
131{
132    gRaspberryPiSystimerBase = ml_io_map(SYSTIMER_BASE, PAGE_SIZE);
133}
134
135void RaspberryPi_handle_interrupt(void *context)
136{
137    return;
138}
139
140uint64_t RaspberryPi_get_timebase(void)
141{
142    return 0;
143}
144
145uint64_t RaspberryPi_timer_value(void)
146{
147    return GET64(systimer_base + SYSTIMERCLK); // free-running 64 bit timer, about 1 MHz
148}
149
150void RaspberryPi_timer_enabled(int enable)
151{
152    return;
153}
154
155/*
156 * Stub for printing out to framebuffer.
157 */
158void vcputc(__unused int l, __unused int u, int c);
159
160static void _fb_putc(int c)
161{
162    RaspberryPi_putc(c);
163}
164
165void mb_send(uint8_t num, uint32_t msg)
166{
167    while(!GET32(mb_base + MB_STATUS) & 0x80000000)
168        barrier();
169    PUT32(mb_base + MB_WRITE, num & 0xf | msg & 0xfffffff0);
170    //  0  1  2  3  4  5  6  ..  31
171    // [0  1  2  3][4  5  6  ..  31] Like this..
172    // [0  1  2  3][0  1  2  ..  27] ..but not like this
173    // [    num   ][      msg      ]
174}
175
176uint32_t mb_read(uint8_t num)
177{
178    while(1)
179    {
180        while(!GET32(mb_base + MB_STATUS) & 0x40000000)
181            barrier();
182        if((GET32(mb_base + MB_READ) & 0xf) == (num & 0xf))
183            return GET32(mb_base + MB_READ) & 0xfffffff0;
184    }
185}
186
187void RaspberryPi_framebuffer_init(void)
188{
189    gRaspberryPiMailboxBase = ml_io_map(MAILBOX_BASE, PAGE_SIZE);
190    gFBInfo.phys_w = 1280;
191    gFBInfo.phys_h = 768;
192    gFBInfo.virt_w = gFBInfo.phys_w;
193    gFBInfo.virt_h = gFBInfo.phys_h;
194    gFBInfo.bpp = 4 * (8); // 32bpp
195
196    mb_send(1, pmap_extract(kernel_pmap, &gFBInfo) + 0x40000000);
197    if(mb_read(1) == 0)
198    {
199        PE_state.video.v_baseAddr = (unsigned long) ml_io_map((void*) gFBInfo.gpu_ptr, PAGE_SIZE);
200        PE_state.video.v_rowBytes = gFBInfo.phys_w * (gFBInfo.bpp / 8);
201        PE_state.video.v_width = gFBInfo.phys_w;
202        PE_state.video.v_height = gFBInfo.phys_h;
203        PE_state.video.v_depth = gFBInfo.bpp;
204
205        kprintf(KPRINTF_PREFIX "framebuffer initialized\n");
206
207        initialize_screen((void*)&PE_state.video, kPEAcquireScreen);
208        initialize_screen((void*)&PE_state.video, kPEEnableScreen);
209    }
210    else
211    {
212        kprintf(KPRINTF_PREFIX "Failed to get frambuffer :-/\n");
213    }
214}
215
216void PE_init_SocSupport_raspberrypi(void)
217{
218    gPESocDispatch.uart_getc = RaspberryPi_getc;
219    gPESocDispatch.uart_putc = RaspberryPi_putc;
220    gPESocDispatch.uart_init = RaspberryPi_uart_init;
221
222    gPESocDispatch.interrupt_init = RaspberryPi_interrupt_init;
223    gPESocDispatch.timebase_init = RaspberryPi_timebase_init;
224
225    gPESocDispatch.get_timebase = RaspberryPi_get_timebase;
226
227    gPESocDispatch.handle_interrupt = RaspberryPi_handle_interrupt;
228
229    gPESocDispatch.timer_value = RaspberryPi_timer_value;
230    gPESocDispatch.timer_enabled = RaspberryPi_timer_enabled;
231
232    gPESocDispatch.framebuffer_init = RaspberryPi_framebuffer_init;
233
234    RaspberryPi_framebuffer_init();
235    RaspberryPi_uart_init();
236
237    PE_kputc = _fb_putc; //gPESocDispatch.uart_putc;
238
239}
240
241void PE_init_SocSupport_stub(void)
242{
243    PE_early_puts("PE_init_SocSupport: Initializing for RASPBERRYPI\n");
244    PE_init_SocSupport_raspberrypi();
245}
246
247#endif /* !BOARD_CONFIG_RASPBERRYPI */
248