1/* 2 * Copyright 2013, winocm. <winocm@icloud.com> 3 * Copyright 2013, furkanmustafa. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without modification, 7 * are permitted provided that the following conditions are met: 8 * 9 * Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 12 * Redistributions in binary form must reproduce the above copyright notice, this 13 * list of conditions and the following disclaimer in the documentation and/or 14 * other materials provided with the distribution. 15 * 16 * If you are going to use this software in any form that does not involve 17 * releasing the source to this project or improving it, let me know beforehand. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30/* 31 * Platform Expert for OMAP335X 32 */ 33 34#if defined(BOARD_CONFIG_OMAP335X) 35 36#include <sys/types.h> 37#include <mach/vm_param.h> 38#include <machine/machine_routines.h> 39#include <pexpert/device_tree.h> 40#include <pexpert/protos.h> 41#include <pexpert/pexpert.h> 42#include <kern/debug.h> 43#include <kern/simple_lock.h> 44#include <machine/machine_routines.h> 45#include <vm/pmap.h> 46#include <arm/pmap.h> 47 48extern int disableConsoleOutput, serialmode; 49 50void Omap3_timer_enabled(int enable); 51uint64_t Omap3_timer_value(void); 52uint64_t Omap3_get_timebase(void); 53 54#include "pe_omap335x.h" 55 56#define mmio_read(a) (*(volatile uint32_t *)(a)) 57#define mmio_write(a,v) (*(volatile uint32_t *)(a) = (v)) 58#define mmio_set(a,v) mmio_write((a), mmio_read((a)) | (v)) 59#define mmio_clear(a,v) mmio_write((a), mmio_read((a)) & ~(v)) 60 61#define HwReg8(x) *((volatile uint8_t*)(x)) 62#define HwReg16(x) *((volatile uint16_t*)(x)) 63#define HwReg32(x) *((volatile uint32_t*)(x)) 64 65#define KPRINTF_PREFIX "PE_omap335x: " 66 67extern void rtclock_intr(arm_saved_state_t * regs); 68extern void rtc_configure(uint64_t hz); 69 70vm_offset_t gOmapSerialUartBase = 0x0; 71vm_offset_t gOmapInterruptControllerBase = 0x0; 72vm_offset_t gOmapTimerBase = 0x0; 73vm_offset_t gOmapDisplayControllerBase = 0x0; 74vm_offset_t gOmapPrcmBase = 0x0; 75 76static uint64_t clock_decrementer = 0; 77static boolean_t clock_initialized = FALSE; 78static boolean_t clock_had_irq = FALSE; 79static uint64_t clock_absolute_time = 0; 80 81#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 82#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 83#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 84 85static void timer_configure(void) 86{ 87 /* 88 * xxx hack for etimer since it does not know time yet 89 */ 90 uint64_t hz = 3276800; 91 gPEClockFrequencyInfo.timebase_frequency_hz = hz; 92 93 clock_decrementer = 1000; 94 kprintf(KPRINTF_PREFIX "decrementer frequency = %llu\n", clock_decrementer); 95 96 rtc_configure(hz); 97 return; 98} 99 100void Omap3_early_putc(int c) 101{ 102 if (c == '\n') 103 Omap3_early_putc('\r'); 104 105 while ((HwReg32(OMAP3_UART_BASE + SSR) & SSR_TXFIFOFULL)) 106 barrier(); 107 108 HwReg32(OMAP3_UART_BASE + THR) = c; 109} 110 111void Omap3_putc(int c) 112{ 113 if (!gOmapSerialUartBase) 114 return; 115 116 if (c == '\n') 117 Omap3_putc('\r'); 118 119 while ((HwReg32(gOmapSerialUartBase + SSR) & SSR_TXFIFOFULL)) 120 barrier(); 121 122 HwReg32(gOmapSerialUartBase + THR) = c; 123} 124 125int Omap3_getc(void) 126{ 127 int i = 0x80000; 128 while (!(HwReg32(gOmapSerialUartBase + LSR) & LSR_DR)) { 129 i--; if(!i) return -1; 130 } 131 132 return (HwReg32(gOmapSerialUartBase + RBR)); 133} 134 135void Omap3_uart_init(void) 136{ 137 int baudDivisor; 138 139 assert(OMAP3_UART_BAUDRATE != 0); 140 baudDivisor = (OMAP3_UART_CLOCK / 16 / OMAP3_UART_BAUDRATE); 141 142 HwReg32(gOmapSerialUartBase + IER) = 0x00; 143 HwReg32(gOmapSerialUartBase + LCR) = LCR_BKSE | LCRVAL; 144 HwReg32(gOmapSerialUartBase + DLL) = baudDivisor & 0xFF; 145 HwReg32(gOmapSerialUartBase + DLM) = (baudDivisor >> 8) & 0xFF; 146 HwReg32(gOmapSerialUartBase + LCR) = LCRVAL; 147 HwReg32(gOmapSerialUartBase + MCR) = MCRVAL; 148 HwReg32(gOmapSerialUartBase + FCR) = FCRVAL; 149} 150 151void Omap3_interrupt_init(void) 152{ 153 int i; 154 155 /* 156 * Disable interrupts 157 */ 158 ml_set_interrupts_enabled(FALSE); 159 160 /* 161 * Set MIR bits to enable all interrupts 162 */ 163 HwReg32(INTCPS_MIR(0)) = 0xffffffff; 164 HwReg32(INTCPS_MIR(1)) = 0xffffffff; 165 HwReg32(INTCPS_MIR(2)) = 0xffffffff; 166 167 /* 168 * Set the true bits (for interrupts we're interested in) 169 */ 170 mmio_write(INTCPS_MIR_CLEAR(OMAP335X_SCH_TIMER_IRQ >> 5), 1 << (OMAP335X_SCH_TIMER_IRQ & 0x1f)); 171 172 /* 173 * Set enable new IRQs/FIQs 174 */ 175 HwReg32(INTCPS_CONTROL) = (1 << 0); 176 177 barrier(); 178 return; 179} 180 181void Omap3_timebase_init(void) 182{ 183 /* 184 * Stop the timer. 185 */ 186 Omap3_timer_enabled(FALSE); 187 188 /* 189 * Enable interrupts 190 */ 191 ml_set_interrupts_enabled(TRUE); 192 193 /* 194 * Set rtclock stuff 195 */ 196 timer_configure(); 197 198 /* 199 * Set timer decrementer defaults 200 */ 201 HwReg32(gOmapTimerBase + TLDR) = 0xffffffe0; 202 HwReg32(gOmapTimerBase + TCRR) = 0xffffffe0; 203 204 HwReg32(gOmapTimerBase + TPIR) = 232000; 205 HwReg32(gOmapTimerBase + TNIR) = -768000; 206 207 HwReg32(gOmapTimerBase + TOCR) = 0; 208 HwReg32(gOmapTimerBase + TOWR) = 100; 209 210 HwReg32(gOmapTimerBase + TCLR) = (1 << 6); 211 212 /* 213 * !!! SET INTERRUPTS ENABLED ON OVERFLOW 214 */ 215 HwReg32(gOmapTimerBase + TISR) = 0x7; // 0x7; //0x2; 216 HwReg32(gOmapTimerBase + TIER) = 0x7; // 0x7; //0x2; 217 218 kprintf(KPRINTF_PREFIX "starting timer..\n"); 219 220 // /* 221 // * Set to 32KHz 222 // */ 223 // mmio_set(gOmapPrcmBase + 0xc40, 0x40); // CLKSEL_TIMER2_CLK = 32K_FCLK ???? 224 // HwReg32(gOmapPrcmBase + 0x08) &= 0x02; 225 // mmio_set(gOmapPrcmBase + 0x400 + 0xc4, 0x02); // CLKSEL_TIMER2_CLK = 32K_FCLK 226 227 /* 228 * Arm the timer 229 */ 230 HwReg32(gOmapTimerBase + TCLR) = (1 << 0) | (1 << 1) | (2 << 10); 231 232 /* 233 * Wait for it. 234 */ 235 clock_initialized = TRUE; 236 237 while (!clock_had_irq) 238 barrier(); 239 240 kprintf(KPRINTF_PREFIX "timer is now up, ticks %llu\n", Omap3_timer_value()); 241 242 return; 243} 244 245void Omap3_handle_interrupt(void *context) 246{ 247 uint32_t irq_number = (HwReg32(INTCPS_SIR_IRQ)) & 0x7F; 248 249 if (irq_number == OMAP335X_SCH_TIMER_IRQ) { 250 /* 251 * Stop the timer 252 */ 253 Omap3_timer_enabled(FALSE); 254 255 /* 256 * Clear interrupt status 257 */ 258 HwReg32(gOmapTimerBase + TISR) = 0x7; // 0x2; wrong? 259 260 /* 261 * FFFFF 262 */ 263 rtclock_intr((arm_saved_state_t *) context); 264 265 /* 266 * Set new IRQ generation 267 */ 268 HwReg32(INTCPS_CONTROL) = 0x1; 269 270 /* 271 * ARM IT. 272 */ 273 Omap3_timer_enabled(TRUE); 274 275 /* 276 * Update absolute time 277 */ 278 clock_absolute_time += (clock_decrementer - Omap3_timer_value()); 279 280 clock_had_irq = 1; 281 282 return; 283 } else { 284 irq_iokit_dispatch(irq_number); 285 } 286 287 return; 288} 289 290uint64_t Omap3_get_timebase(void) 291{ 292 uint32_t timestamp; 293 294 if (!clock_initialized) 295 return 0; 296 297 timestamp = Omap3_timer_value(); 298 299 if (timestamp) { 300 uint64_t v = clock_absolute_time; 301 v += (uint64_t) (((uint64_t) clock_decrementer) - (uint64_t) (timestamp)); 302 return v; 303 } else { 304 clock_absolute_time += clock_decrementer; 305 return clock_absolute_time; 306 } 307} 308 309uint64_t Omap3_timer_value(void) 310{ 311 /* 312 * Return overflow value minus the counter 313 */ 314 return 0xffffffff - (HwReg32(gOmapTimerBase + TCRR)); 315} 316 317void Omap3_timer_enabled(int enable) 318{ 319 320 /* 321 * Clear the TCLR [ST] bit 322 */ 323 if (enable) 324 mmio_set(gOmapTimerBase + TCLR, 0x1); 325 else 326 mmio_clear(gOmapTimerBase + TCLR, 0x1); 327 328 return; 329} 330 331/* 332 * Stub for printing out to framebuffer. 333 */ 334void vcputc(__unused int l, __unused int u, int c); 335 336static void _fb_putc(int c) 337{ 338 if (c == '\n') { 339 vcputc(0, 0, '\r'); 340 } 341 vcputc(0, 0, c); 342 Omap3_putc(c); 343} 344 345extern int serialmode; 346 347void Omap3_framebuffer_init(void) 348{ 349 /* 350 * This is an emulated framebuffer. 351 */ 352 void *framebuffer = pmap_steal_memory(1024 * 768 * 4); 353 void *framebuffer_phys = pmap_extract(kernel_pmap, framebuffer); 354 355 uint32_t depth = 4; 356 uint32_t width = 1024; 357 uint32_t height = 768; 358 359 uint32_t pitch = (width * depth); 360 uint32_t fb_length = (pitch * width); 361 362 PE_state.video.v_baseAddr = (unsigned long) framebuffer_phys; 363 PE_state.video.v_rowBytes = width * 2; 364 PE_state.video.v_width = width; 365 PE_state.video.v_height = height; 366 PE_state.video.v_depth = 2 * (8); // 16bpp 367 368 kprintf(KPRINTF_PREFIX "fake framebuffer initialized\n"); 369 bzero(framebuffer, (pitch * height)); 370 371 char tempbuf[16]; 372 initialize_screen((void *) &PE_state.video, kPETextMode); 373 374 // TEMPORARY, because beaglebone (usually) doesn't have a display 375 serialmode = 3; 376 switch_to_serial_console(); 377 disableConsoleOutput = FALSE; 378 379 return; 380} 381 382void Omap3_InitCaches(void) 383{ 384 kprintf(KPRINTF_PREFIX "initializing i+dcache\n"); 385 cache_initialize(); 386 kprintf(KPRINTF_PREFIX "done\n"); 387} 388 389void PE_init_SocSupport_omap3(void) 390{ 391 gPESocDispatch.uart_getc = Omap3_getc; 392 gPESocDispatch.uart_putc = Omap3_putc; 393 gPESocDispatch.uart_init = Omap3_uart_init; 394 395 gPESocDispatch.interrupt_init = Omap3_interrupt_init; 396 gPESocDispatch.timebase_init = Omap3_timebase_init; 397 398 gPESocDispatch.get_timebase = Omap3_get_timebase; 399 400 gPESocDispatch.handle_interrupt = Omap3_handle_interrupt; 401 402 gPESocDispatch.timer_value = Omap3_timer_value; 403 gPESocDispatch.timer_enabled = Omap3_timer_enabled; 404 405 gPESocDispatch.framebuffer_init = Omap3_framebuffer_init; 406 407 // init device base addresses 408 gOmapSerialUartBase = ml_io_map(OMAP3_UART_BASE, PAGE_SIZE); 409 gOmapTimerBase = ml_io_map(OMAP335X_SCH_TIMER_BASE, PAGE_SIZE); 410 gOmapInterruptControllerBase = ml_io_map(OMAP3_GIC_BASE, PAGE_SIZE); 411 // gOmapDisplayControllerBase = ml_io_map(OMAP3_DSS_BASE - 0x40, PAGE_SIZE); // doesn't apply for omap335x yet 412 413 gOmapPrcmBase = ml_io_map(0x44E00000, PAGE_SIZE); // 0x48004000 (L4 Core / Clock Manager) 414 415 Omap3_uart_init(); 416 PE_kputc = gPESocDispatch.uart_putc; 417 418 Omap3_framebuffer_init(); 419 420 mmio_set(gOmapPrcmBase + 0x404, 0x2); // Enable Timer1 Clock 421 mmio_set(gOmapPrcmBase + 0x4C4, 0x2); // Enable Timer1 Clock 422} 423 424void PE_init_SocSupport_stub(void) 425{ 426 PE_early_puts("PE_init_SocSupport: Initializing for OMAP335x\n"); 427 PE_init_SocSupport_omap3(); 428} 429 430#endif /* !BOARD_CONFIG_OMAP335X */ 431