dvhstx.cpp
1 #include <string.h> 2 #include <pico/stdlib.h> 3 4 extern "C" { 5 #include <pico/lock_core.h> 6 } 7 8 #include <algorithm> 9 #include "hardware/dma.h" 10 #include "hardware/gpio.h" 11 #include "hardware/irq.h" 12 #include "hardware/structs/bus_ctrl.h" 13 #include "hardware/structs/hstx_ctrl.h" 14 #include "hardware/structs/hstx_fifo.h" 15 #include "hardware/structs/sio.h" 16 17 #include "hardware/structs/ioqspi.h" 18 #include "hardware/vreg.h" 19 #include "hardware/structs/qmi.h" 20 #include "hardware/pll.h" 21 #include "hardware/clocks.h" 22 23 #include "dvi.hpp" 24 #include "dvhstx.hpp" 25 26 using namespace pimoroni; 27 28 #ifdef MICROPY_BUILD_TYPE 29 #define FRAME_BUFFER_SIZE (640*360) 30 __attribute__((section(".uninitialized_data"))) static uint8_t frame_buffer_a[FRAME_BUFFER_SIZE]; 31 __attribute__((section(".uninitialized_data"))) static uint8_t frame_buffer_b[FRAME_BUFFER_SIZE]; 32 #endif 33 34 #include "font.h" 35 36 // If changing the font, note this code will not handle glyphs wider than 13 pixels 37 #define FONT (&intel_one_mono) 38 39 #ifdef MICROPY_BUILD_TYPE 40 extern "C" { 41 void dvhstx_debug(const char *fmt, ...); 42 } 43 #elif defined(ARDUINO) 44 #include <Arduino.h> 45 // #define dvhstx_debug Serial.printf 46 #define dvhstx_debug(...) ((void)0) 47 #else 48 #include <cstdio> 49 #define dvhstx_debug printf 50 #endif 51 52 static inline __attribute__((always_inline)) uint32_t render_char_line(int c, int y) { 53 if (c < 0x20 || c > 0x7e) return 0; 54 const lv_font_fmt_txt_glyph_dsc_t* g = &FONT->dsc->glyph_dsc[c - 0x20 + 1]; 55 const uint8_t *b = FONT->dsc->glyph_bitmap + g->bitmap_index; 56 const int ey = y - FONT_HEIGHT + FONT->base_line + g->ofs_y + g->box_h; 57 if (ey < 0 || ey >= g->box_h || g->box_w == 0) { 58 return 0; 59 } 60 else { 61 int bi = (g->box_w * ey); 62 63 uint32_t bits = (b[bi >> 2] << 24) | (b[(bi >> 2) + 1] << 16) | (b[(bi >> 2) + 2] << 8) | b[(bi >> 2) + 3]; 64 bits >>= 6 - ((bi & 3) << 1); 65 bits &= 0x3ffffff & (0x3ffffff << ((13 - g->box_w) << 1)); 66 bits >>= g->ofs_x << 1; 67 68 return bits; 69 } 70 } 71 72 // ---------------------------------------------------------------------------- 73 // HSTX command lists 74 75 // Lists are padded with NOPs to be >= HSTX FIFO size, to avoid DMA rapidly 76 // pingponging and tripping up the IRQs. 77 78 static const uint32_t vblank_line_vsync_off_src[] = { 79 HSTX_CMD_RAW_REPEAT, 80 SYNC_V1_H1, 81 HSTX_CMD_RAW_REPEAT, 82 SYNC_V1_H0, 83 HSTX_CMD_RAW_REPEAT, 84 SYNC_V1_H1 85 }; 86 static uint32_t vblank_line_vsync_off[count_of(vblank_line_vsync_off_src)]; 87 88 static const uint32_t vblank_line_vsync_on_src[] = { 89 HSTX_CMD_RAW_REPEAT, 90 SYNC_V0_H1, 91 HSTX_CMD_RAW_REPEAT, 92 SYNC_V0_H0, 93 HSTX_CMD_RAW_REPEAT, 94 SYNC_V0_H1 95 }; 96 static uint32_t vblank_line_vsync_on[count_of(vblank_line_vsync_on_src)]; 97 98 static const uint32_t vactive_line_header_src[] = { 99 HSTX_CMD_RAW_REPEAT, 100 SYNC_V1_H1, 101 HSTX_CMD_RAW_REPEAT, 102 SYNC_V1_H0, 103 HSTX_CMD_RAW_REPEAT, 104 SYNC_V1_H1, 105 HSTX_CMD_TMDS 106 }; 107 static uint32_t vactive_line_header[count_of(vactive_line_header_src)]; 108 109 static const uint32_t vactive_text_line_header_src[] = { 110 HSTX_CMD_RAW_REPEAT, 111 SYNC_V1_H1, 112 HSTX_CMD_RAW_REPEAT, 113 SYNC_V1_H0, 114 HSTX_CMD_RAW_REPEAT, 115 SYNC_V1_H1, 116 HSTX_CMD_RAW | 6, 117 BLACK_PIXEL_A, 118 BLACK_PIXEL_B, 119 BLACK_PIXEL_A, 120 BLACK_PIXEL_B, 121 BLACK_PIXEL_A, 122 BLACK_PIXEL_B, 123 HSTX_CMD_TMDS 124 }; 125 static uint32_t vactive_text_line_header[count_of(vactive_text_line_header_src)]; 126 127 #define NUM_FRAME_LINES 2 128 #define NUM_CHANS 3 129 130 static DVHSTX* display = nullptr; 131 132 // ---------------------------------------------------------------------------- 133 // DMA logic 134 135 void __scratch_x("display") dma_irq_handler() { 136 display->gfx_dma_handler(); 137 } 138 139 void __scratch_x("display") DVHSTX::gfx_dma_handler() { 140 // ch_num indicates the channel that just finished, which is the one 141 // we're about to reload. 142 dma_channel_hw_t *ch = &dma_hw->ch[ch_num]; 143 dma_hw->intr = 1u << ch_num; 144 if (++ch_num == NUM_CHANS) ch_num = 0; 145 146 if (v_scanline >= timing_mode->v_front_porch && v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) { 147 ch->read_addr = (uintptr_t)vblank_line_vsync_on; 148 ch->transfer_count = count_of(vblank_line_vsync_on); 149 } else if (v_scanline < v_inactive_total) { 150 ch->read_addr = (uintptr_t)vblank_line_vsync_off; 151 ch->transfer_count = count_of(vblank_line_vsync_off); 152 } else { 153 const int y = (v_scanline - v_inactive_total) >> v_repeat_shift; 154 const int new_line_num = (v_repeat_shift == 0) ? ch_num : (y & (NUM_FRAME_LINES - 1)); 155 const uint line_buf_total_len = ((timing_mode->h_active_pixels * line_bytes_per_pixel) >> 2) + count_of(vactive_line_header); 156 157 ch->read_addr = (uintptr_t)&line_buffers[new_line_num * line_buf_total_len]; 158 ch->transfer_count = line_buf_total_len; 159 160 // Fill line buffer 161 if (line_num != new_line_num) 162 { 163 line_num = new_line_num; 164 uint32_t* dst_ptr = &line_buffers[line_num * line_buf_total_len + count_of(vactive_line_header)]; 165 166 if (line_bytes_per_pixel == 2) { 167 uint16_t* src_ptr = (uint16_t*)&frame_buffer_display[y * 2 * (timing_mode->h_active_pixels >> h_repeat_shift)]; 168 if (h_repeat_shift == 2) { 169 for (int i = 0; i < timing_mode->h_active_pixels >> 1; i += 2) { 170 uint32_t val = (uint32_t)(*src_ptr++) * 0x10001; 171 *dst_ptr++ = val; 172 *dst_ptr++ = val; 173 } 174 } 175 else { 176 for (int i = 0; i < timing_mode->h_active_pixels >> 1; ++i) { 177 uint32_t val = (uint32_t)(*src_ptr++) * 0x10001; 178 *dst_ptr++ = val; 179 } 180 } 181 } 182 else if (line_bytes_per_pixel == 1) { 183 uint8_t* src_ptr = &frame_buffer_display[y * (timing_mode->h_active_pixels >> h_repeat_shift)]; 184 if (h_repeat_shift == 2) { 185 for (int i = 0; i < timing_mode->h_active_pixels >> 2; ++i) { 186 uint32_t val = (uint32_t)(*src_ptr++) * 0x01010101; 187 *dst_ptr++ = val; 188 } 189 } 190 else { 191 for (int i = 0; i < timing_mode->h_active_pixels >> 2; ++i) { 192 uint32_t val = ((uint32_t)(*src_ptr++) * 0x0101); 193 val |= ((uint32_t)(*src_ptr++) * 0x01010000); 194 *dst_ptr++ = val; 195 } 196 } 197 } 198 else if (line_bytes_per_pixel == 4) { 199 uint8_t* src_ptr = &frame_buffer_display[y * (timing_mode->h_active_pixels >> h_repeat_shift)]; 200 if (h_repeat_shift == 2) { 201 for (int i = 0; i < timing_mode->h_active_pixels; i += 4) { 202 uint32_t val = display_palette[*src_ptr++]; 203 *dst_ptr++ = val; 204 *dst_ptr++ = val; 205 *dst_ptr++ = val; 206 *dst_ptr++ = val; 207 } 208 } 209 else { 210 for (int i = 0; i < timing_mode->h_active_pixels; i += 2) { 211 uint32_t val = display_palette[*src_ptr++]; 212 *dst_ptr++ = val; 213 *dst_ptr++ = val; 214 } 215 } 216 } 217 } 218 } 219 220 if (++v_scanline == v_total_active_lines) { 221 v_scanline = 0; 222 line_num = -1; 223 if (flip_next) { 224 flip_next = false; 225 display->flip_now(); 226 } 227 __sev(); 228 } 229 } 230 231 void __scratch_x("display") dma_irq_handler_text() { 232 display->text_dma_handler(); 233 } 234 235 void __scratch_x("display") DVHSTX::text_dma_handler() { 236 // ch_num indicates the channel that just finished, which is the one 237 // we're about to reload. 238 dma_channel_hw_t *ch = &dma_hw->ch[ch_num]; 239 dma_hw->intr = 1u << ch_num; 240 if (++ch_num == NUM_CHANS) ch_num = 0; 241 242 if (v_scanline >= timing_mode->v_front_porch && v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) { 243 ch->read_addr = (uintptr_t)vblank_line_vsync_on; 244 ch->transfer_count = count_of(vblank_line_vsync_on); 245 } else if (v_scanline < v_inactive_total) { 246 ch->read_addr = (uintptr_t)vblank_line_vsync_off; 247 ch->transfer_count = count_of(vblank_line_vsync_off); 248 } else { 249 const int y = (v_scanline - v_inactive_total); 250 const uint line_buf_total_len = (frame_width * line_bytes_per_pixel + 3) / 4 + count_of(vactive_text_line_header); 251 252 ch->read_addr = (uintptr_t)&line_buffers[ch_num * line_buf_total_len]; 253 ch->transfer_count = line_buf_total_len; 254 255 // Fill line buffer 256 int char_y = y % 24; 257 if (line_bytes_per_pixel == 4) { 258 uint32_t* dst_ptr = &line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)]; 259 uint8_t* src_ptr = &frame_buffer_display[(y / 24) * frame_width]; 260 for (int i = 0; i < frame_width; ++i) { 261 *dst_ptr++ = render_char_line(*src_ptr++, char_y); 262 } 263 } 264 else { 265 uint8_t* dst_ptr = (uint8_t*)&line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)]; 266 uint8_t* src_ptr = &frame_buffer_display[(y / 24) * frame_width * 2]; 267 #ifdef __riscv 268 for (int i = 0; i < frame_width; ++i) { 269 const uint8_t c = (*src_ptr++ - 0x20); 270 uint32_t bits = (c < 95) ? font_cache[c * 24 + char_y] : 0; 271 const uint8_t colour = *src_ptr++; 272 273 *dst_ptr++ = colour * ((bits >> 24) & 3); 274 *dst_ptr++ = colour * ((bits >> 22) & 3); 275 *dst_ptr++ = colour * ((bits >> 20) & 3); 276 *dst_ptr++ = colour * ((bits >> 18) & 3); 277 *dst_ptr++ = colour * ((bits >> 16) & 3); 278 *dst_ptr++ = colour * ((bits >> 14) & 3); 279 *dst_ptr++ = colour * ((bits >> 12) & 3); 280 *dst_ptr++ = colour * ((bits >> 10) & 3); 281 *dst_ptr++ = colour * ((bits >> 8) & 3); 282 *dst_ptr++ = colour * ((bits >> 6) & 3); 283 *dst_ptr++ = colour * ((bits >> 4) & 3); 284 *dst_ptr++ = colour * ((bits >> 2) & 3); 285 *dst_ptr++ = colour * (bits & 3); 286 *dst_ptr++ = 0; 287 } 288 #else 289 int i = 0; 290 for (; i < frame_width-1; i += 2) { 291 uint8_t c = (*src_ptr++ - 0x20); 292 uint32_t bits = (c < 95) ? font_cache[c * 24 + char_y] : 0; 293 uint8_t colour = *src_ptr++; 294 c = (*src_ptr++ - 0x20); 295 uint32_t bits2 = (c < 95) ? font_cache[c * 24 + char_y] : 0; 296 uint8_t colour2 = *src_ptr++; 297 298 // This ASM works around a compiler bug where the optimizer decides 299 // to unroll so hard it spills to the stack. 300 uint32_t tmp, tmp2; 301 asm volatile ( 302 "ubfx %[tmp], %[cbits], #24, #2\n\t" 303 "ubfx %[tmp2], %[cbits], #22, #2\n\t" 304 "bfi %[tmp], %[tmp2], #8, #8\n\t" 305 "ubfx %[tmp2], %[cbits], #20, #2\n\t" 306 "bfi %[tmp], %[tmp2], #16, #8\n\t" 307 "ubfx %[tmp2], %[cbits], #18, #2\n\t" 308 "bfi %[tmp], %[tmp2], #24, #8\n\t" 309 "muls %[tmp], %[colour], %[tmp]\n\t" 310 "str %[tmp], [%[dst_ptr]]\n\t" 311 312 "ubfx %[tmp], %[cbits], #16, #2\n\t" 313 "ubfx %[tmp2], %[cbits], #14, #2\n\t" 314 "bfi %[tmp], %[tmp2], #8, #8\n\t" 315 "ubfx %[tmp2], %[cbits], #12, #2\n\t" 316 "bfi %[tmp], %[tmp2], #16, #8\n\t" 317 "ubfx %[tmp2], %[cbits], #10, #2\n\t" 318 "bfi %[tmp], %[tmp2], #24, #8\n\t" 319 "muls %[tmp], %[colour], %[tmp]\n\t" 320 "str %[tmp], [%[dst_ptr], #4]\n\t" 321 322 "ubfx %[tmp], %[cbits], #8, #2\n\t" 323 "ubfx %[tmp2], %[cbits], #6, #2\n\t" 324 "bfi %[tmp], %[tmp2], #8, #8\n\t" 325 "ubfx %[tmp2], %[cbits], #4, #2\n\t" 326 "bfi %[tmp], %[tmp2], #16, #8\n\t" 327 "ubfx %[tmp2], %[cbits], #2, #2\n\t" 328 "bfi %[tmp], %[tmp2], #24, #8\n\t" 329 "muls %[tmp], %[colour], %[tmp]\n\t" 330 "str %[tmp], [%[dst_ptr], #8]\n\t" 331 332 "ubfx %[tmp], %[cbits2], #24, #2\n\t" 333 "ubfx %[tmp2], %[cbits2], #22, #2\n\t" 334 "bfi %[tmp], %[tmp2], #8, #8\n\t" 335 "muls %[tmp], %[colour2], %[tmp]\n\t" 336 "and %[tmp2], %[cbits], #3\n\t" 337 "muls %[tmp2], %[colour], %[tmp2]\n\t" 338 "bfi %[tmp2], %[tmp], #16, #16\n\t" 339 "str %[tmp2], [%[dst_ptr], #12]\n\t" 340 341 "ubfx %[tmp], %[cbits2], #20, #2\n\t" 342 "ubfx %[tmp2], %[cbits2], #18, #2\n\t" 343 "bfi %[tmp], %[tmp2], #8, #8\n\t" 344 "ubfx %[tmp2], %[cbits2], #16, #2\n\t" 345 "bfi %[tmp], %[tmp2], #16, #8\n\t" 346 "ubfx %[tmp2], %[cbits2], #14, #2\n\t" 347 "bfi %[tmp], %[tmp2], #24, #8\n\t" 348 "muls %[tmp], %[colour2], %[tmp]\n\t" 349 "str %[tmp], [%[dst_ptr], #16]\n\t" 350 351 "ubfx %[tmp], %[cbits2], #12, #2\n\t" 352 "ubfx %[tmp2], %[cbits2], #10, #2\n\t" 353 "bfi %[tmp], %[tmp2], #8, #8\n\t" 354 "ubfx %[tmp2], %[cbits2], #8, #2\n\t" 355 "bfi %[tmp], %[tmp2], #16, #8\n\t" 356 "ubfx %[tmp2], %[cbits2], #6, #2\n\t" 357 "bfi %[tmp], %[tmp2], #24, #8\n\t" 358 "muls %[tmp], %[colour2], %[tmp]\n\t" 359 "str %[tmp], [%[dst_ptr], #20]\n\t" 360 361 "ubfx %[tmp], %[cbits2], #4, #2\n\t" 362 "ubfx %[tmp2], %[cbits2], #2, #2\n\t" 363 "bfi %[tmp], %[tmp2], #8, #8\n\t" 364 "bfi %[tmp], %[cbits2], #16, #2\n\t" 365 "muls %[tmp], %[colour2], %[tmp]\n\t" 366 "str %[tmp], [%[dst_ptr], #24]\n\t" 367 : [tmp] "=&l" (tmp), 368 [tmp2] "=&l" (tmp2) 369 : [cbits] "r" (bits), 370 [colour] "l" (colour), 371 [cbits2] "r" (bits2), 372 [colour2] "l" (colour2), 373 [dst_ptr] "r" (dst_ptr) 374 : "cc", "memory" ); 375 dst_ptr += 14 * 2; 376 } 377 if (i != frame_width) { 378 const uint8_t c = (*src_ptr++ - 0x20); 379 uint32_t bits = (c < 95) ? font_cache[c * 24 + char_y] : 0; 380 const uint8_t colour = *src_ptr++; 381 382 *dst_ptr++ = colour * ((bits >> 24) & 3); 383 *dst_ptr++ = colour * ((bits >> 22) & 3); 384 *dst_ptr++ = colour * ((bits >> 20) & 3); 385 *dst_ptr++ = colour * ((bits >> 18) & 3); 386 *dst_ptr++ = colour * ((bits >> 16) & 3); 387 *dst_ptr++ = colour * ((bits >> 14) & 3); 388 *dst_ptr++ = colour * ((bits >> 12) & 3); 389 *dst_ptr++ = colour * ((bits >> 10) & 3); 390 *dst_ptr++ = colour * ((bits >> 8) & 3); 391 *dst_ptr++ = colour * ((bits >> 6) & 3); 392 *dst_ptr++ = colour * ((bits >> 4) & 3); 393 *dst_ptr++ = colour * ((bits >> 2) & 3); 394 *dst_ptr++ = colour * (bits & 3); 395 *dst_ptr++ = 0; 396 } 397 #endif 398 if (y / 24 == cursor_y) { 399 uint8_t* dst_ptr = (uint8_t*)&line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)] + 14 * cursor_x; 400 *dst_ptr++ ^= 0xff; 401 *dst_ptr++ ^= 0xff; 402 *dst_ptr++ ^= 0xff; 403 *dst_ptr++ ^= 0xff; 404 *dst_ptr++ ^= 0xff; 405 *dst_ptr++ ^= 0xff; 406 *dst_ptr++ ^= 0xff; 407 *dst_ptr++ ^= 0xff; 408 *dst_ptr++ ^= 0xff; 409 *dst_ptr++ ^= 0xff; 410 *dst_ptr++ ^= 0xff; 411 *dst_ptr++ ^= 0xff; 412 *dst_ptr++ ^= 0xff; 413 } 414 } 415 } 416 417 if (++v_scanline == v_total_active_lines) { 418 v_scanline = 0; 419 line_num = -1; 420 if (flip_next) { 421 flip_next = false; 422 display->flip_now(); 423 } 424 __sev(); 425 } 426 } 427 428 // ---------------------------------------------------------------------------- 429 // Experimental clock config 430 431 #ifndef MICROPY_BUILD_TYPE 432 static void __no_inline_not_in_flash_func(set_qmi_timing)() { 433 // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!) 434 while ((ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) 435 ; 436 437 qmi_hw->m[0].timing = 0x40000202; 438 //qmi_hw->m[0].timing = 0x40000101; 439 // Force a read through XIP to ensure the timing is applied 440 volatile uint32_t* ptr = (volatile uint32_t*)0x14000000; 441 (void) *ptr; 442 } 443 #endif 444 445 extern "C" void __no_inline_not_in_flash_func(display_setup_clock_preinit)() { 446 uint32_t intr_stash = save_and_disable_interrupts(); 447 448 // Before messing with clock speeds ensure QSPI clock is nice and slow 449 hw_write_masked(&qmi_hw->m[0].timing, 6, QMI_M0_TIMING_CLKDIV_BITS); 450 451 // We're going to go fast, boost the voltage a little 452 vreg_set_voltage(VREG_VOLTAGE_1_15); 453 454 // Force a read through XIP to ensure the timing is applied before raising the clock rate 455 volatile uint32_t* ptr = (volatile uint32_t*)0x14000000; 456 (void) *ptr; 457 458 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. 459 hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS); 460 while (clocks_hw->clk[clk_sys].selected != 0x1) 461 tight_loop_contents(); 462 hw_write_masked(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, CLOCKS_CLK_REF_CTRL_SRC_BITS); 463 while (clocks_hw->clk[clk_ref].selected != 0x4) 464 tight_loop_contents(); 465 466 // Stop the other clocks so we don't worry about overspeed 467 clock_stop(clk_usb); 468 clock_stop(clk_adc); 469 clock_stop(clk_peri); 470 clock_stop(clk_hstx); 471 472 // Set USB PLL to 528MHz 473 pll_init(pll_usb, PLL_COMMON_REFDIV, 1584 * MHZ, 3, 1); 474 475 const uint32_t usb_pll_freq = 528 * MHZ; 476 477 // CLK SYS = PLL USB 528MHz / 2 = 264MHz 478 clock_configure(clk_sys, 479 CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, 480 CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, 481 usb_pll_freq, usb_pll_freq / 2); 482 483 // CLK PERI = PLL USB 528MHz / 4 = 132MHz 484 clock_configure(clk_peri, 485 0, // Only AUX mux on ADC 486 CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, 487 usb_pll_freq, usb_pll_freq / 4); 488 489 // CLK USB = PLL USB 528MHz / 11 = 48MHz 490 clock_configure(clk_usb, 491 0, // No GLMUX 492 CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, 493 usb_pll_freq, 494 USB_CLK_KHZ * KHZ); 495 496 // CLK ADC = PLL USB 528MHz / 11 = 48MHz 497 clock_configure(clk_adc, 498 0, // No GLMUX 499 CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, 500 usb_pll_freq, 501 USB_CLK_KHZ * KHZ); 502 503 // Now we are running fast set fast QSPI clock and read delay 504 // On MicroPython this is setup by main. 505 #ifndef MICROPY_BUILD_TYPE 506 set_qmi_timing(); 507 #endif 508 509 restore_interrupts(intr_stash); 510 } 511 512 #ifndef MICROPY_BUILD_TYPE 513 // Trigger clock setup early - on MicroPython this is done by a hook in main. 514 namespace { 515 class DV_preinit { 516 public: 517 DV_preinit() { 518 display_setup_clock_preinit(); 519 } 520 }; 521 DV_preinit dv_preinit __attribute__ ((init_priority (101))) ; 522 } 523 #endif 524 525 void DVHSTX::display_setup_clock() { 526 const uint32_t dvi_clock_khz = timing_mode->bit_clk_khz >> 1; 527 uint vco_freq, post_div1, post_div2; 528 if (!check_sys_clock_khz(dvi_clock_khz, &vco_freq, &post_div1, &post_div2)) 529 panic("System clock of %u kHz cannot be exactly achieved", dvi_clock_khz); 530 const uint32_t freq = vco_freq / (post_div1 * post_div2); 531 532 // Set the sys PLL to the requested freq 533 pll_init(pll_sys, PLL_COMMON_REFDIV, vco_freq, post_div1, post_div2); 534 535 // CLK HSTX = Requested freq 536 clock_configure(clk_hstx, 537 0, 538 CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 539 freq, freq); 540 } 541 542 RGB888* DVHSTX::get_palette() 543 { 544 return palette; 545 } 546 547 DVHSTX::DVHSTX() 548 { 549 // Always use the bottom channels 550 dma_claim_mask((1 << NUM_CHANS) - 1); 551 } 552 553 bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_, bool double_buffered, const DVHSTXPinout &pinout) 554 { 555 if (inited) reset(); 556 557 cursor_y = -1; 558 ch_num = 0; 559 line_num = -1; 560 v_scanline = 2; 561 flip_next = false; 562 563 display_width = width; 564 display_height = height; 565 frame_width = width; 566 frame_height = height; 567 mode = mode_; 568 569 timing_mode = nullptr; 570 if (mode == MODE_TEXT_MONO || mode == MODE_TEXT_RGB111) { 571 width = 1280; 572 height = 720; 573 display_width = 91; 574 frame_width = 91; 575 display_height = 30; 576 frame_height = 30; 577 h_repeat_shift = 0; 578 v_repeat_shift = 0; 579 timing_mode = &dvi_timing_1280x720p_rb_50hz; 580 } 581 else if (width == 320 && height == 180) { 582 h_repeat_shift = 2; 583 v_repeat_shift = 2; 584 timing_mode = &dvi_timing_1280x720p_rb_50hz; 585 } 586 else if (width == 640 && height == 360) { 587 h_repeat_shift = 1; 588 v_repeat_shift = 1; 589 timing_mode = &dvi_timing_1280x720p_rb_50hz; 590 } 591 else if (width == 480 && height == 270) { 592 h_repeat_shift = 2; 593 v_repeat_shift = 2; 594 timing_mode = &dvi_timing_1920x1080p_rb2_30hz; 595 } 596 else 597 { 598 uint16_t full_width = display_width; 599 uint16_t full_height = display_height; 600 h_repeat_shift = 0; 601 v_repeat_shift = 0; 602 603 if (display_width < 640) { 604 h_repeat_shift = 1; 605 full_width *= 2; 606 } 607 608 if (display_height < 400) { 609 v_repeat_shift = 1; 610 full_height *= 2; 611 } 612 613 if (full_width == 640) { 614 if (full_height == 480) timing_mode = &dvi_timing_640x480p_60hz; 615 } 616 else if (full_width == 720) { 617 if (full_height == 480) timing_mode = &dvi_timing_720x480p_60hz; 618 else if (full_height == 400) timing_mode = &dvi_timing_720x400p_70hz; 619 else if (full_height == 576) timing_mode = &dvi_timing_720x576p_50hz; 620 } 621 else if (full_width == 800) { 622 if (full_height == 600) timing_mode = &dvi_timing_800x600p_60hz; 623 else if (full_height == 480) timing_mode = &dvi_timing_800x480p_60hz; 624 else if (full_height == 450) timing_mode = &dvi_timing_800x450p_60hz; 625 } 626 else if (full_width == 960) { 627 if (full_height == 540) timing_mode = &dvi_timing_960x540p_60hz; 628 } 629 else if (full_width == 1024) { 630 if (full_height == 768) timing_mode = &dvi_timing_1024x768_rb_60hz; 631 } 632 } 633 634 if (!timing_mode) { 635 dvhstx_debug("Unsupported resolution %dx%d", width, height); 636 return false; 637 } 638 639 display = this; 640 display_palette = get_palette(); 641 642 dvhstx_debug("Setup clock\n"); 643 display_setup_clock(); 644 645 #if !defined(MICROPY_BUILD_TYPE) && !defined(ARDUINO) 646 stdio_init_all(); 647 #endif 648 dvhstx_debug("Clock setup done\n"); 649 650 v_inactive_total = timing_mode->v_front_porch + timing_mode->v_sync_width + timing_mode->v_back_porch; 651 v_total_active_lines = v_inactive_total + timing_mode->v_active_lines; 652 v_repeat = 1 << v_repeat_shift; 653 h_repeat = 1 << h_repeat_shift; 654 655 memcpy(vblank_line_vsync_off, vblank_line_vsync_off_src, sizeof(vblank_line_vsync_off_src)); 656 vblank_line_vsync_off[0] |= timing_mode->h_front_porch; 657 vblank_line_vsync_off[2] |= timing_mode->h_sync_width; 658 vblank_line_vsync_off[4] |= timing_mode->h_back_porch + timing_mode->h_active_pixels; 659 660 memcpy(vblank_line_vsync_on, vblank_line_vsync_on_src, sizeof(vblank_line_vsync_on_src)); 661 vblank_line_vsync_on[0] |= timing_mode->h_front_porch; 662 vblank_line_vsync_on[2] |= timing_mode->h_sync_width; 663 vblank_line_vsync_on[4] |= timing_mode->h_back_porch + timing_mode->h_active_pixels; 664 665 memcpy(vactive_line_header, vactive_line_header_src, sizeof(vactive_line_header_src)); 666 vactive_line_header[0] |= timing_mode->h_front_porch; 667 vactive_line_header[2] |= timing_mode->h_sync_width; 668 vactive_line_header[4] |= timing_mode->h_back_porch; 669 vactive_line_header[6] |= timing_mode->h_active_pixels; 670 671 memcpy(vactive_text_line_header, vactive_text_line_header_src, sizeof(vactive_text_line_header_src)); 672 vactive_text_line_header[0] |= timing_mode->h_front_porch; 673 vactive_text_line_header[2] |= timing_mode->h_sync_width; 674 vactive_text_line_header[4] |= timing_mode->h_back_porch; 675 vactive_text_line_header[7+6] |= timing_mode->h_active_pixels - 6; 676 677 switch (mode) { 678 case MODE_RGB565: 679 frame_bytes_per_pixel = 2; 680 line_bytes_per_pixel = 2; 681 break; 682 case MODE_PALETTE: 683 frame_bytes_per_pixel = 1; 684 line_bytes_per_pixel = 4; 685 break; 686 case MODE_RGB888: 687 frame_bytes_per_pixel = 4; 688 line_bytes_per_pixel = 4; 689 break; 690 case MODE_TEXT_MONO: 691 frame_bytes_per_pixel = 1; 692 line_bytes_per_pixel = 4; 693 break; 694 case MODE_TEXT_RGB111: 695 frame_bytes_per_pixel = 2; 696 line_bytes_per_pixel = 14; 697 break; 698 default: 699 dvhstx_debug("Unsupported mode %d", (int)mode); 700 return false; 701 } 702 703 #ifdef MICROPY_BUILD_TYPE 704 if (frame_width * frame_height * frame_bytes_per_pixel > sizeof(frame_buffer_a)) { 705 panic("Frame buffer too large"); 706 } 707 708 frame_buffer_display = frame_buffer_a; 709 frame_buffer_back = double_buffered ? frame_buffer_b : frame_buffer_a; 710 #else 711 frame_buffer_display = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel); 712 frame_buffer_back = double_buffered ? (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel) : frame_buffer_display; 713 #endif 714 memset(frame_buffer_display, 0, frame_width * frame_height * frame_bytes_per_pixel); 715 memset(frame_buffer_back, 0, frame_width * frame_height * frame_bytes_per_pixel); 716 717 memset(palette, 0, PALETTE_SIZE * sizeof(palette[0])); 718 719 frame_buffer_display = frame_buffer_display; 720 dvhstx_debug("Frame buffers inited\n"); 721 722 const bool is_text_mode = (mode == MODE_TEXT_MONO || mode == MODE_TEXT_RGB111); 723 const int frame_pixel_words = (frame_width * h_repeat * line_bytes_per_pixel + 3) >> 2; 724 const int frame_line_words = frame_pixel_words + (is_text_mode ? count_of(vactive_text_line_header) : count_of(vactive_line_header)); 725 const int frame_lines = (v_repeat == 1) ? NUM_CHANS : NUM_FRAME_LINES; 726 line_buffers = (uint32_t*)malloc(frame_line_words * 4 * frame_lines); 727 728 for (int i = 0; i < frame_lines; ++i) 729 { 730 if (is_text_mode) memcpy(&line_buffers[i * frame_line_words], vactive_text_line_header, count_of(vactive_text_line_header) * sizeof(uint32_t)); 731 else memcpy(&line_buffers[i * frame_line_words], vactive_line_header, count_of(vactive_line_header) * sizeof(uint32_t)); 732 } 733 734 if (mode == MODE_TEXT_RGB111) { 735 // Need to pre-render the font to RAM to be fast enough. 736 font_cache = (uint32_t*)malloc(4 * FONT->line_height * 96); 737 uint32_t* font_cache_ptr = font_cache; 738 for (int c = 0x20; c < 128; ++c) { 739 for (int y = 0; y < FONT->line_height; ++y) { 740 *font_cache_ptr++ = render_char_line(c, y); 741 } 742 } 743 } 744 745 // Ensure HSTX FIFO is clear 746 reset_block_num(RESET_HSTX); 747 sleep_us(10); 748 unreset_block_num_wait_blocking(RESET_HSTX); 749 sleep_us(10); 750 751 switch (mode) { 752 case MODE_RGB565: 753 // Configure HSTX's TMDS encoder for RGB565 754 hstx_ctrl_hw->expand_tmds = 755 4 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | 756 8 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | 757 5 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB | 758 3 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | 759 4 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | 760 29 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; 761 762 // Pixels (TMDS) come in 2 16-bit chunks. Control symbols (RAW) are an 763 // entire 32-bit word. 764 hstx_ctrl_hw->expand_shift = 765 2 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | 766 16 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | 767 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | 768 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; 769 break; 770 771 case MODE_PALETTE: 772 // Configure HSTX's TMDS encoder for RGB888 773 hstx_ctrl_hw->expand_tmds = 774 7 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | 775 16 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | 776 7 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB | 777 8 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | 778 7 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | 779 0 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; 780 781 // Pixels and control symbols (RAW) are an 782 // entire 32-bit word. 783 hstx_ctrl_hw->expand_shift = 784 1 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | 785 0 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | 786 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | 787 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; 788 break; 789 790 case MODE_TEXT_MONO: 791 // Configure HSTX's TMDS encoder for 2bpp 792 hstx_ctrl_hw->expand_tmds = 793 1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | 794 18 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | 795 1 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB | 796 18 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | 797 1 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | 798 18 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; 799 800 // Pixels and control symbols (RAW) are an 801 // entire 32-bit word. 802 hstx_ctrl_hw->expand_shift = 803 14 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | 804 30 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | 805 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | 806 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; 807 break; 808 809 case MODE_TEXT_RGB111: 810 // Configure HSTX's TMDS encoder for RGB222 811 hstx_ctrl_hw->expand_tmds = 812 1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | 813 0 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | 814 1 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB | 815 29 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | 816 1 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | 817 26 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; 818 819 // Pixels (TMDS) come in 4 8-bit chunks. Control symbols (RAW) are an 820 // entire 32-bit word. 821 hstx_ctrl_hw->expand_shift = 822 4 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | 823 8 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | 824 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | 825 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; 826 break; 827 828 default: 829 dvhstx_debug("Unsupported mode %d", (int)mode); 830 return false; 831 } 832 833 // Serial output config: clock period of 5 cycles, pop from command 834 // expander every 5 cycles, shift the output shiftreg by 2 every cycle. 835 hstx_ctrl_hw->csr = 0; 836 hstx_ctrl_hw->csr = 837 HSTX_CTRL_CSR_EXPAND_EN_BITS | 838 5u << HSTX_CTRL_CSR_CLKDIV_LSB | 839 5u << HSTX_CTRL_CSR_N_SHIFTS_LSB | 840 2u << HSTX_CTRL_CSR_SHIFT_LSB | 841 HSTX_CTRL_CSR_EN_BITS; 842 843 // HSTX outputs 0 through 7 appear on GPIO 12 through 19. 844 constexpr int HSTX_FIRST_PIN = 12; 845 // Assign clock pair to two neighbouring pins: 846 hstx_ctrl_hw->bit[(pinout.clk_p ) - HSTX_FIRST_PIN] = HSTX_CTRL_BIT0_CLK_BITS; 847 hstx_ctrl_hw->bit[(pinout.clk_p ^ 1) - HSTX_FIRST_PIN] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS; 848 for (uint lane = 0; lane < 3; ++lane) { 849 // For each TMDS lane, assign it to the correct GPIO pair based on the 850 // desired pinout: 851 int bit = pinout.rgb_p[lane]; 852 // Output even bits during first half of each HSTX cycle, and odd bits 853 // during second half. The shifter advances by two bits each cycle. 854 uint32_t lane_data_sel_bits = 855 (lane * 10 ) << HSTX_CTRL_BIT0_SEL_P_LSB | 856 (lane * 10 + 1) << HSTX_CTRL_BIT0_SEL_N_LSB; 857 // The two halves of each pair get identical data, but one pin is inverted. 858 hstx_ctrl_hw->bit[(bit ) - HSTX_FIRST_PIN] = lane_data_sel_bits; 859 hstx_ctrl_hw->bit[(bit ^ 1) - HSTX_FIRST_PIN] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS; 860 } 861 862 for (int i = 12; i <= 19; ++i) { 863 gpio_set_function(i, GPIO_FUNC_HSTX); 864 gpio_set_drive_strength(i, GPIO_DRIVE_STRENGTH_4MA); 865 } 866 867 dvhstx_debug("GPIO configured\n"); 868 869 // The channels are set up identically, to transfer a whole scanline and 870 // then chain to the next channel. Each time a channel finishes, we 871 // reconfigure the one that just finished, meanwhile the other channel(s) 872 // are already making progress. 873 // Using just 2 channels was insufficient to avoid issues with the IRQ. 874 dma_channel_config c; 875 c = dma_channel_get_default_config(0); 876 channel_config_set_chain_to(&c, 1); 877 channel_config_set_dreq(&c, DREQ_HSTX); 878 dma_channel_configure( 879 0, 880 &c, 881 &hstx_fifo_hw->fifo, 882 vblank_line_vsync_off, 883 count_of(vblank_line_vsync_off), 884 false 885 ); 886 c = dma_channel_get_default_config(1); 887 channel_config_set_chain_to(&c, 2); 888 channel_config_set_dreq(&c, DREQ_HSTX); 889 dma_channel_configure( 890 1, 891 &c, 892 &hstx_fifo_hw->fifo, 893 vblank_line_vsync_off, 894 count_of(vblank_line_vsync_off), 895 false 896 ); 897 for (int i = 2; i < NUM_CHANS; ++i) { 898 c = dma_channel_get_default_config(i); 899 channel_config_set_chain_to(&c, (i+1) % NUM_CHANS); 900 channel_config_set_dreq(&c, DREQ_HSTX); 901 dma_channel_configure( 902 i, 903 &c, 904 &hstx_fifo_hw->fifo, 905 vblank_line_vsync_off, 906 count_of(vblank_line_vsync_off), 907 false 908 ); 909 } 910 911 dvhstx_debug("DMA channels claimed\n"); 912 913 dma_hw->intr = (1 << NUM_CHANS) - 1; 914 dma_hw->ints2 = (1 << NUM_CHANS) - 1; 915 dma_hw->inte2 = (1 << NUM_CHANS) - 1; 916 if (is_text_mode) irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler_text); 917 else irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler); 918 irq_set_enabled(DMA_IRQ_2, true); 919 920 dma_channel_start(0); 921 922 dvhstx_debug("DVHSTX started\n"); 923 924 inited = true; 925 return true; 926 } 927 928 void DVHSTX::reset() { 929 if (!inited) return; 930 inited = false; 931 932 hstx_ctrl_hw->csr = 0; 933 934 irq_set_enabled(DMA_IRQ_2, false); 935 irq_remove_handler(DMA_IRQ_2, irq_get_exclusive_handler(DMA_IRQ_2)); 936 937 for (int i = 0; i < NUM_CHANS; ++i) 938 dma_channel_abort(i); 939 940 if (font_cache) { 941 free(font_cache); 942 font_cache = nullptr; 943 } 944 free(line_buffers); 945 line_buffers = nullptr; 946 947 #ifndef MICROPY_BUILD_TYPE 948 free(frame_buffer_display); 949 if (frame_buffer_display != frame_buffer_back) { 950 free(frame_buffer_back); 951 } 952 frame_buffer_display = frame_buffer_back = nullptr; 953 #endif 954 } 955 956 void DVHSTX::flip_blocking() { 957 if (get_single_buffered()) 958 return; 959 wait_for_vsync(); 960 flip_now(); 961 } 962 963 void DVHSTX::flip_now() { 964 if (get_single_buffered()) 965 return; 966 std::swap(frame_buffer_display, frame_buffer_back); 967 } 968 969 void DVHSTX::wait_for_vsync() { 970 while (v_scanline >= timing_mode->v_front_porch) __wfe(); 971 } 972 973 void DVHSTX::flip_async() { 974 if (get_single_buffered()) 975 return; 976 flip_next = true; 977 } 978 979 void DVHSTX::wait_for_flip() { 980 if (get_single_buffered()) 981 return; 982 while (flip_next) __wfe(); 983 }