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 OMAP35xx/36xx and AM/DM37x. 31 */ 32 33#if defined(BOARD_CONFIG_OMAP3530) 34 35#include <sys/types.h> 36#include <mach/vm_param.h> 37#include <machine/machine_routines.h> 38#include <pexpert/device_tree.h> 39#include <pexpert/protos.h> 40#include <pexpert/pexpert.h> 41#include <kern/debug.h> 42#include <kern/simple_lock.h> 43#include <machine/machine_routines.h> 44#include <vm/pmap.h> 45#include <arm/pmap.h> 46#include <kern/cpu_data.h> 47 48/* XXX: timer is so god awfully borked */ 49void Omap3_timer_enabled(int enable); 50uint64_t Omap3_timer_value(void); 51uint64_t Omap3_get_timebase(void); 52 53#include "pe_omap3530.h" 54 55#define mmio_read(a) (*(volatile uint32_t *)(a)) 56#define mmio_write(a,v) (*(volatile uint32_t *)(a) = (v)) 57#define mmio_set(a,v) mmio_write((a), mmio_read((a)) | (v)) 58#define mmio_clear(a,v) mmio_write((a), mmio_read((a)) & ~(v)) 59 60#define HwReg(x) *((volatile unsigned long*)(x)) 61 62#define KPRINTF_PREFIX "PE_omap3530: " 63 64extern void rtclock_intr(arm_saved_state_t * regs); 65extern void rtc_configure(uint64_t hz); 66 67vm_offset_t gOmapSerialUartBase = 0x0; 68vm_offset_t gOmapInterruptControllerBase = 0x0; 69vm_offset_t gOmapTimerBase = 0x0; 70vm_offset_t gOmapDisplayControllerBase = 0x0; 71vm_offset_t gOmapPrcmBase = 0x0; 72 73static uint64_t clock_decrementer = 0; 74static boolean_t clock_initialized = FALSE; 75static boolean_t clock_had_irq = FALSE; 76static uint64_t clock_absolute_time = 0; 77 78#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 79#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 80#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 81 82static void timer_configure(void) 83{ 84 /* 85 * xxx hack for etimer since it does not know time yet 86 */ 87 uint64_t hz = 3276800; 88 gPEClockFrequencyInfo.timebase_frequency_hz = hz; 89 90 clock_decrementer = 500; 91 kprintf(KPRINTF_PREFIX "decrementer frequency = %llu\n", clock_decrementer); 92 93 rtc_configure(hz); 94 return; 95} 96 97void Omap3_early_putc(int c) 98{ 99 if (c == '\n') 100 Omap3_early_putc('\r'); 101 102 while (!(HwReg(OMAP3_UART_BASE + LSR) & LSR_THRE)) 103 barrier(); 104 105 HwReg(OMAP3_UART_BASE + THR) = c; 106} 107 108void Omap3_putc(int c) 109{ 110 if (!gOmapSerialUartBase) 111 return; 112 113 if (c == '\n') 114 Omap3_putc('\r'); 115 116 while (!(HwReg(gOmapSerialUartBase + LSR) & LSR_THRE)) 117 barrier(); 118 119 HwReg(gOmapSerialUartBase + THR) = c; 120} 121 122int Omap3_getc(void) 123{ 124 int i = 0x20000; 125 while (!(HwReg(gOmapSerialUartBase + LSR) & LSR_DR)) { 126 i--; if(!i) return -1; 127 } 128 129 return (HwReg(gOmapSerialUartBase + RBR)); 130} 131 132void Omap3_uart_init(void) 133{ 134 gOmapTimerBase = ml_io_map(OMAP3_TIMER0_BASE, PAGE_SIZE); 135 gOmapInterruptControllerBase = ml_io_map(OMAP3_GIC_BASE, PAGE_SIZE); 136 gOmapDisplayControllerBase = ml_io_map(OMAP3_DSS_BASE - 0x40, PAGE_SIZE); 137 138 /* 139 * XXX: God. 140 */ 141 gOmapPrcmBase = ml_io_map(0x48004000, PAGE_SIZE); 142 143 int baudDivisor; 144 gOmapSerialUartBase = ml_io_map(OMAP3_UART_BASE, PAGE_SIZE); 145 146 assert(OMAP3_UART_BAUDRATE != 0); 147 baudDivisor = (OMAP3_UART_CLOCK / 16 / OMAP3_UART_BAUDRATE); 148 149 HwReg(gOmapSerialUartBase + IER) = 0x00; 150 HwReg(gOmapSerialUartBase + LCR) = LCR_BKSE | LCRVAL; 151 HwReg(gOmapSerialUartBase + DLL) = baudDivisor & 0xFF; 152 HwReg(gOmapSerialUartBase + DLM) = (baudDivisor >> 8) & 0xFF; 153 HwReg(gOmapSerialUartBase + LCR) = LCRVAL; 154 HwReg(gOmapSerialUartBase + MCR) = MCRVAL; 155 HwReg(gOmapSerialUartBase + FCR) = FCRVAL; 156} 157 158void Omap3_interrupt_init(void) 159{ 160 int i; 161 162 /* 163 * Disable interrupts 164 */ 165 ml_set_interrupts_enabled(FALSE); 166 167 /* 168 * Set MIR bits to enable all interrupts 169 */ 170 HwReg(INTCPS_MIR(0)) = 0xffffffff; 171 HwReg(INTCPS_MIR(1)) = 0xffffffff; 172 HwReg(INTCPS_MIR(2)) = 0xffffffff; 173 174 /* 175 * Set the true bits 176 */ 177 mmio_write(INTCPS_MIR_CLEAR(37 >> 5), 1 << (37 & 0x1f)); 178 179 /* 180 * Set enable new IRQs/FIQs 181 */ 182 HwReg(INTCPS_CONTROL) = (1 << 0); 183 184 barrier(); 185 return; 186} 187 188void Omap3_timebase_init(void) 189{ 190 /* 191 * Stop the timer. 192 */ 193 Omap3_timer_enabled(FALSE); 194 195 /* 196 * Enable interrupts 197 */ 198 ml_set_interrupts_enabled(TRUE); 199 200 /* 201 * Set rtclock stuff 202 */ 203 timer_configure(); 204 205 /* 206 * Set timer decrementer defaults 207 */ 208 HwReg(gOmapTimerBase + TLDR) = 0xffffffe0; 209 HwReg(gOmapTimerBase + TCRR) = 0xffffffe0; 210 211 HwReg(gOmapTimerBase + TPIR) = 232000; 212 HwReg(gOmapTimerBase + TNIR) = -768000; 213 214 HwReg(gOmapTimerBase + TOCR) = 0; 215 HwReg(gOmapTimerBase + TOWR) = 100; 216 217 HwReg(gOmapTimerBase + TCLR) = (1 << 6); 218 219 /* 220 * !!! SET INTERRUPTS ENABLED ON OVERFLOW 221 */ 222 HwReg(gOmapTimerBase + TISR) = 0x7; 223 HwReg(gOmapTimerBase + TIER) = 0x7; 224 225 /* 226 * Set to 32KHz 227 */ 228 mmio_set(gOmapPrcmBase + 0xc40, 0x40); 229 230 /* 231 * Arm the timer 232 */ 233 HwReg(gOmapTimerBase + TCLR) = (1 << 0) | (1 << 1) | (2 << 10); 234 235 /* 236 * Wait for it. 237 */ 238 clock_initialized = TRUE; 239 240 while (!clock_had_irq) 241 barrier(); 242 243 kprintf(KPRINTF_PREFIX "timer is now up, ticks %llu\n", Omap3_timer_value()); 244 245 return; 246} 247 248void Omap3_handle_interrupt(void *context) 249{ 250 uint32_t irq_number = (HwReg(INTCPS_SIR_IRQ)) & 0x7F; 251 252 if (irq_number == 37) { /* GPTimer1 IRQ */ 253 /* 254 * Stop the timer 255 */ 256 Omap3_timer_enabled(FALSE); 257 258 /* 259 * Clear interrupt status 260 */ 261 HwReg(gOmapTimerBase + TISR) = 0x7; 262 263 /* 264 * FFFFF 265 */ 266 rtclock_intr((arm_saved_state_t *) context); 267 268 /* 269 * Set new IRQ generation 270 */ 271 HwReg(INTCPS_CONTROL) = 0x1; 272 273 /* 274 * ARM IT. 275 */ 276 Omap3_timer_enabled(TRUE); 277 278 /* 279 * Update absolute time 280 */ 281 clock_absolute_time += (clock_decrementer - Omap3_timer_value()); 282 283 clock_had_irq = 1; 284 285 return; 286 } else { 287 irq_iokit_dispatch(irq_number); 288 } 289 290 return; 291} 292 293uint64_t Omap3_get_timebase(void) 294{ 295 uint32_t timestamp; 296 297 if (!clock_initialized) 298 return 0; 299 300 timestamp = Omap3_timer_value(); 301 302 if (timestamp) { 303 uint64_t v = clock_absolute_time; 304 v += (uint64_t) (((uint64_t) clock_decrementer) - (uint64_t) (timestamp)); 305 return v; 306 } else { 307 clock_absolute_time += clock_decrementer; 308 return clock_absolute_time; 309 } 310} 311 312uint64_t Omap3_timer_value(void) 313{ 314 /* 315 * Return overflow value minus the counter 316 */ 317 return 0xffffffff - (HwReg(gOmapTimerBase + TCRR)); 318} 319 320void Omap3_timer_enabled(int enable) 321{ 322 /* 323 * Clear the TCLR [ST] bit 324 */ 325 if (enable) 326 HwReg(gOmapTimerBase + TCLR) |= (1 << 0); 327 else 328 HwReg(gOmapTimerBase + TCLR) &= ~(1 << 0); 329 330 return; 331} 332 333/* 334 * Stub for printing out to framebuffer. 335 */ 336void vcputc(__unused int l, __unused int u, int c); 337 338static void _fb_putc(int c) 339{ 340 if (c == '\n') { 341 vcputc(0, 0, '\r'); 342 } 343 vcputc(0, 0, c); 344 Omap3_putc(c); 345} 346 347struct video_mode { 348 short width, height; 349 char *name; 350 uint32_t dispc_size; 351 uint32_t dispc_timing_h; 352 uint32_t dispc_timing_v; 353 uint32_t dispc_divisor; 354 uint32_t dss_divisor; 355}; 356 357/* DISPC_TIMING_H bits and masks */ 358#define DISPCB_HBP 20 359#define DISPCB_HFP 8 360#define DISPCB_HSW 0 361#define DISPCM_HBP 0xfff00000 362#define DISPCM_HFP 0x000fff00 363#define DISPCM_HSW 0x000000ff 364 365/* DISPC_TIMING_V bits and masks */ 366#define DISPCB_VBP 20 367#define DISPCB_VFP 8 368#define DISPCB_VSW 0 369#define DISPCM_VBP 0x0ff00000 370#define DISPCM_VFP 0x0000ff00 371#define DISPCM_VSW 0x0000003f 372 373// Master clock is 864 Mhz, and changing it is a pita since it cascades to other 374// devices. 375// Pixel clock is 864 / cm_clksel_dss.dss1_alwan_fclk / dispc_divisor.divisor.pcd 376// So most of these modes are just approximate. 377// List must be in ascending order. 378struct video_mode modes[] = { 379 // 640x480@72 31.500 640 24 40 128 480 9 3 28 380 { 381 640, 480, "640x480-71", 382 ((480-1) << 16) | (640-1), 383 (128 << DISPCB_HBP) | (24 << DISPCB_HFP) | (40 << DISPCB_HSW), 384 (28 << DISPCB_VBP) | (9 << DISPCB_VFP) | (3 << DISPCB_VSW), 385 2, 14 386 }, 387 // 800x600, 60Hz 40.000 800 40 128 88 600 1 4 23 388 { 389 800, 600, "800x600-59", 390 ((600-1) << 16) | (800-1), 391 (88 << DISPCB_HBP) | (40 << DISPCB_HFP) | (128 << DISPCB_HSW), 392 (23 << DISPCB_VBP) | (1 << DISPCB_VFP) | (4 << DISPCB_VSW), 393 2, 11 394 }, 395 // 1024x768, 60Hz 65.000 1024 24 136 160 768 3 6 29 396 { 397 1024, 768, "1024x768-61", 398 ((768-1) << 16) | (1024-1), 399 (160 << DISPCB_HBP) | (24 << DISPCB_HFP) | (136 << DISPCB_HSW), 400 (29 << DISPCB_VBP) | (3 << DISPCB_VFP) | (6 << DISPCB_VSW), 401 1, 13 402 }, 403 { 404 1280, 1024, "1280x1024-60", 405 ((1024-1) << 16) | (1280-1), 406 (248 << DISPCB_HBP) | (48 << DISPCB_HFP) | (112 << DISPCB_HSW), 407 (38 << DISPCB_VBP) | (1 << DISPCB_VFP) | (3 << DISPCB_VSW), 408 1, 8 409 }, 410 /* 1280x800, dotclock 83.46MHz, approximated 86.4MHz */ 411 { 412 1280, 800, "1280x800-60", 413 ((800 - 1) << 16) | (1280 - 1), 414 (200 << DISPCB_HBP) | (64 < DISPCB_HBP) | (136 << DISPCB_HSW), 415 (24 << DISPCB_VBP) | (1 << DISPCB_VFP) | (3 << DISPCB_HSW), 416 2, 5 417 }, 418 /* 1366x768, dotclock 85.86MHz, approximated 86.4MHz */ 419 { 420 1366, 768, "1366x768-60", 421 ((768 - 1) << 16) | (1366 - 1), 422 (216 << DISPCB_HBP) | (72 < DISPCB_HBP) | (144 << DISPCB_HSW), 423 (23 << DISPCB_VBP) | (1 << DISPCB_VFP) | (3 << DISPCB_HSW), 424 2, 5 425 }, 426 /* 1440x900, dotclock 106.47MHz, approximated 108MHz */ 427 { 428 1440, 900, "1440x900-60", 429 ((900 - 1) << 16) | (1440 - 1), 430 (232 << DISPCB_HBP) | (80 < DISPCB_HBP) | (152 << DISPCB_HSW), 431 (28 << DISPCB_VBP) | (1 << DISPCB_VFP) | (28 << DISPCB_HSW), 432 2, 4 433 }, 434}; 435 436void Omap3_framebuffer_init(void) 437{ 438 int dont_mess_with_this = 0; 439 char tempbuf[16]; 440 441 if (PE_parse_boot_argn("-dont-fuck-with-framebuffer", tempbuf, sizeof(tempbuf))) { 442 /* Do not fuck with the framebuffer whatsoever, rely on whatever u-boot set. */ 443 dont_mess_with_this = 1; 444 } 445 446 /* 447 * This *must* be page aligned. 448 */ 449 struct dispc_regs *OmapDispc = (struct dispc_regs *) (gOmapDisplayControllerBase + 0x440); 450 451 /* 452 * Set defaults 453 */ 454 uint32_t timing_h, timing_v; 455 uint32_t hbp, hfp, hsw, vsw, vfp, vbp; 456 457 char tmpbuf[16]; 458 struct video_mode *current_mode = &modes[0]; 459 460 if (PE_parse_boot_argn("omapfbres", tmpbuf, sizeof(tmpbuf))) { 461 int cur = 0; 462 while (cur != (sizeof(modes) / sizeof(struct video_mode))) { 463 if (!strcmp(tmpbuf, modes[cur].name)) { 464 current_mode = &modes[cur]; 465 break; 466 } 467 cur++; 468 } 469 } 470 471 uint32_t vs; 472 if(!dont_mess_with_this) { 473 OmapDispc->size_lcd = current_mode->dispc_size; 474 OmapDispc->timing_h = current_mode->dispc_timing_h; 475 OmapDispc->timing_v = current_mode->dispc_timing_v; 476 OmapDispc->pol_freq = 0x00007028; 477 OmapDispc->divisor = current_mode->dispc_divisor; 478 HwReg(gOmapPrcmBase + 0xE00 + 0x40) = current_mode->dss_divisor; 479 OmapDispc->config = (2 << 1); 480 OmapDispc->default_color0 = 0xffff0000; 481 OmapDispc->control = ((1 << 3) | (3 << 8)); 482 483 /* 484 * Initialize display control 485 */ 486 OmapDispc->control |= DISPC_ENABLE; 487 OmapDispc->default_color0 = 0xffff0000; 488 489 /* 490 * initialize lcd defaults 491 */ 492 barrier(); 493 } 494 495 vs = OmapDispc->size_lcd; 496 uint32_t lcd_width, lcd_height; 497 498 lcd_height = (vs >> 16) + 1; 499 lcd_width = (vs & 0xffff) + 1; 500 kprintf(KPRINTF_PREFIX "lcd size is %u x %u\n", lcd_width, lcd_height); 501 502 /* 503 * Allocate framebuffer 504 */ 505 void *framebuffer = pmap_steal_memory(lcd_width * lcd_width * 4); 506 void *framebuffer_phys = pmap_extract(kernel_pmap, framebuffer); 507 bzero(framebuffer, lcd_width * lcd_height * 4); 508 kprintf(KPRINTF_PREFIX "software framebuffer at %p\n", framebuffer); 509 510 /* 511 * Set attributes in display controller 512 */ 513 OmapDispc->gfx_ba0 = framebuffer_phys; 514 OmapDispc->gfx_ba1 = 0; 515 OmapDispc->gfx_position = 0; 516 OmapDispc->gfx_row_inc = 1; 517 OmapDispc->gfx_pixel_inc = 1; 518 OmapDispc->gfx_window_skip = 0; 519 OmapDispc->gfx_size = vs; 520 OmapDispc->gfx_attributes = 0x91; 521 522 /* 523 * Enable the display 524 */ 525 *((volatile unsigned long *) (&OmapDispc->control)) |= 1 | (1 << 1) | (1 << 5) | (1 << 6) | (1 << 15) | (1 << 16); 526 527 /* 528 * Hook to our framebuffer 529 */ 530 PE_state.video.v_baseAddr = (unsigned long) framebuffer_phys; 531 PE_state.video.v_rowBytes = lcd_width * 4; 532 PE_state.video.v_width = lcd_width; 533 PE_state.video.v_height = lcd_height; 534 PE_state.video.v_depth = 4 * (8); // 32bpp 535 536 kprintf(KPRINTF_PREFIX "framebuffer initialized\n"); 537 538 /* 539 * Enable early framebuffer. 540 */ 541 if (PE_parse_boot_argn("-early-fb-debug", tempbuf, sizeof(tempbuf))) { 542 initialize_screen((void *) &PE_state.video, kPEAcquireScreen); 543 } 544 545 if (PE_parse_boot_argn("-graphics-mode", tempbuf, sizeof(tempbuf))) { 546 /* 547 * BootX like framebuffer. 548 */ 549 memset(framebuffer, 0xb9, lcd_width * lcd_height * 4); 550 initialize_screen((void *) &PE_state.video, kPEGraphicsMode); 551 } else { 552 initialize_screen((void *) &PE_state.video, kPETextMode); 553 } 554 555 return; 556} 557 558void Omap3_InitCaches(void) 559{ 560 kprintf(KPRINTF_PREFIX "initializing i+dcache\n"); 561 cache_initialize(); 562 kprintf(KPRINTF_PREFIX "done\n"); 563} 564 565void PE_init_SocSupport_omap3(void) 566{ 567 gPESocDispatch.uart_getc = Omap3_getc; 568 gPESocDispatch.uart_putc = Omap3_putc; 569 gPESocDispatch.uart_init = Omap3_uart_init; 570 571 gPESocDispatch.interrupt_init = Omap3_interrupt_init; 572 gPESocDispatch.timebase_init = Omap3_timebase_init; 573 574 gPESocDispatch.get_timebase = Omap3_get_timebase; 575 576 gPESocDispatch.handle_interrupt = Omap3_handle_interrupt; 577 578 gPESocDispatch.timer_value = Omap3_timer_value; 579 gPESocDispatch.timer_enabled = Omap3_timer_enabled; 580 581 gPESocDispatch.framebuffer_init = Omap3_framebuffer_init; 582 583 Omap3_uart_init(); 584 PE_kputc = gPESocDispatch.uart_putc; 585 586 Omap3_framebuffer_init(); 587} 588 589void PE_init_SocSupport_stub(void) 590{ 591 PE_early_puts("PE_init_SocSupport: Initializing for OMAP3530\n"); 592 PE_init_SocSupport_omap3(); 593} 594 595#endif /* !BOARD_CONFIG_OMAP3530 */ 596