Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

x1000: LCD DMA fix

Credit ZappBranigan2972 on the forums

Change-Id: Ia4d498d215d8f365156f15965b715832202bec8a

authored by

Dana Conrad and committed by
Solomon Peachy
1fb90650 d0aaa37d

+115 -41
+111 -41
firmware/target/mips/ingenic_x1000/lcd-x1000.c
··· 69 69 /* True if we're in sleep mode */ 70 70 static bool lcd_sleeping = false; 71 71 #endif 72 + static bool lcd_on = false; 72 73 73 74 /* Check if running with interrupts disabled (eg: panic screen) */ 74 75 #define lcd_panic_mode \ 75 76 UNLIKELY((read_c0_status() & 1) == 0) 76 77 78 + typedef enum { 79 + LCD_SEND0, LCD_SEND1, 80 + WAIT_FRAME, SLEEP_FRAME, 81 + WAIT_EOF, SLEEP_EOF, 82 + WAIT_QD, 83 + WAIT_FBCPF, WAIT_FBCPP 84 + } Lcd_ID; 85 + 86 + 87 + // TODO: This may need a yield? 88 + static void __attribute__ ((noinline)) lcd_wait(Lcd_ID id) 89 + { 90 + uint32_t i, done = 0; 91 + 92 + for(i=0; i<LCD_WAIT_STEPS; i++) { 93 + if (done) break; 94 + switch (id) { 95 + case LCD_SEND0: 96 + case LCD_SEND1: 97 + case WAIT_FRAME: 98 + case SLEEP_FRAME: done = !jz_readf(LCD_MSTATE, BUSY); break; 99 + case WAIT_EOF: 100 + case SLEEP_EOF: done = jz_readf(LCD_STATE, EOF) != 0; break; 101 + case WAIT_QD: done = jz_readf(LCD_STATE, QD) != 0; break; 102 + case WAIT_FBCPF: 103 + case WAIT_FBCPP: done = fbcopy_done != 0; break; 104 + } 105 + } 106 + } 107 + 77 108 static void lcd_init_controller(const struct lcd_tgt_config* cfg) 78 109 { 79 110 /* Set MCFG/MCFG_NEW according to target interface settings */ ··· 125 156 126 157 /* DMA settings */ 127 158 jz_writef(LCD_CTRL, ENABLE(0), BURST_V(64WORD), 128 - EOFM(1), SOFM(0), IFUM(0), QDM(0), 159 + EOFM(0), SOFM(0), IFUM(0), QDM(0), 129 160 BEDN(cfg->big_endian), PEDN(0)); 130 161 jz_write(LCD_DAH, LCD_WIDTH); 131 162 jz_write(LCD_DAV, LCD_HEIGHT); ··· 185 216 fbcopy_done = 1; 186 217 } 187 218 188 - static void lcd_fbcopy_dma_run(dma_desc* d) 219 + static void lcd_fbcopy_dma_run(dma_desc* d, Lcd_ID id) 189 220 { 190 221 if(lcd_panic_mode) { 191 222 /* Can't use DMA if interrupts are off, so just do a memcpy(). ··· 205 236 jz_set(DMA_DB, 1 << DMA_CHANNEL_FBCOPY); 206 237 jz_writef(DMA_CHN_CS(DMA_CHANNEL_FBCOPY), CTE(1)); 207 238 208 - while(!fbcopy_done); 239 + lcd_wait(id); 209 240 } 210 241 211 242 static void lcd_fbcopy_dma_full(void) ··· 221 252 d.rt = jz_orf(DMA_CHN_RT, TYPE_V(AUTO)); 222 253 d.pad0 = 0; 223 254 d.pad1 = 0; 224 - lcd_fbcopy_dma_run(&d); 255 + lcd_fbcopy_dma_run(&d, WAIT_FBCPF); 225 256 } 226 257 227 258 /* NOTE: DMA stride mode can only transfer up to 255 blocks at once. ··· 254 285 d.tc = width * height * sizeof(fb_data); 255 286 } 256 287 257 - lcd_fbcopy_dma_run(&d); 288 + lcd_fbcopy_dma_run(&d, WAIT_FBCPP); 258 289 } 259 290 260 291 #if STRIDE_MAIN(LCD_HEIGHT, LCD_WIDTH) > 255 ··· 274 305 # define lcd_fbcopy_dma_partial lcd_fbcopy_dma_partial1 275 306 #endif 276 307 277 - static void lcd_dma_start(void) 308 + typedef enum { 309 + MODE_INIT, 310 + MODE_SLEEP 311 + } DMA_Mode; 312 + 313 + static void lcd_dma_start(DMA_Mode mode) 278 314 { 279 315 /* Set format conversion bit, seems necessary for DMA mode. 280 316 * Must set DTIMES here if we use an 8-bit bus type. */ ··· 286 322 TE_INV(lcd_tgt_config.te_polarity ? 0 : 1), 287 323 NOT_USE_TE(lcd_tgt_config.te_enable ? 0 : 1)); 288 324 325 + /* ref PM sec. 4.9.1 DMA operation, 326 + * as well as sec. 4.5.2 Enabling the Controller. 327 + * I think we're effectively doing the last bit 328 + * of enabling the controller here, and then 329 + * doing dma start. 330 + */ 331 + jz_writef(LCD_MCTRL, DMA_MODE(1), DMA_START(1)); 332 + 333 + while(jz_readf(LCD_MSTATE, BUSY)); 334 + 335 + jz_writef(LCD_MCTRL, DMA_TX_EN(1)); 336 + 337 + /* clear any old flags */ 338 + jz_write(LCD_STATE, 0); 339 + 289 340 /* Begin DMA transfer. Need to start a dummy frame or else we will 290 341 * not be able to pass lcd_wait_frame() at the first lcd_update(). */ 291 - jz_write(LCD_STATE, 0); 342 + // if (mode == MODE_INIT) { // Run this only once on Startup 292 343 jz_write(LCD_DA, PHYSADDR(&lcd_dma_desc[0])); 293 - jz_writef(LCD_MCTRL, DMA_MODE(1), DMA_START(1), DMA_TX_EN(1)); 294 344 jz_writef(LCD_CTRL, ENABLE(1)); 345 + // } 346 + 347 + lcd_on = true; 295 348 } 296 349 297 350 static bool lcd_wait_frame(void) 298 351 { 299 352 /* Bail out if DMA is not enabled */ 300 - int irq = disable_irq_save(); 301 - int bit = jz_readf(LCD_CTRL, ENABLE); 302 - restore_irq(irq); 303 - if(!bit) 353 + if(!lcd_active()) 304 354 return false; 305 355 306 356 /* Usual case -- wait for EOF, wait for FIFO to drain, clear EOF */ 307 - while(jz_readf(LCD_STATE, EOF) == 0); 308 - while(jz_readf(LCD_MSTATE, BUSY)); 357 + lcd_wait(WAIT_EOF); 358 + lcd_wait(WAIT_FRAME); 309 359 jz_writef(LCD_STATE, EOF(0)); 310 360 return true; 311 361 } 312 362 313 - static void lcd_dma_stop(void) 363 + static void lcd_dma_stop(DMA_Mode mode) 314 364 { 365 + int irq = disable_irq_save(); 366 + lcd_on = false; 367 + restore_irq(irq); 368 + 369 + if (mode == MODE_INIT) { // Run this only once when endinng 315 370 #ifdef LCD_X1000_DMA_WAIT_FOR_FRAME 316 - /* Wait for frame to finish to avoid misaligning the write pointer */ 317 - lcd_wait_frame(); 371 + /* Wait for frame to finish to avoid misaligning the write pointer */ 372 + lcd_wait_frame(); 318 373 #endif 374 + /* Stop the DMA transfer */ 375 + jz_writef(LCD_CTRL, ENABLE(0)); 376 + jz_writef(LCD_MCTRL, DMA_TX_EN(0)); 319 377 320 - /* Stop the DMA transfer */ 321 - jz_writef(LCD_CTRL, ENABLE(0)); 322 - jz_writef(LCD_MCTRL, DMA_TX_EN(0)); 378 + /* Wait for disable to take effect */ 379 + lcd_wait(WAIT_QD); 380 + } else { // MODE_SLEEP 381 + jz_writef(LCD_CTRL, ENABLE(0)); 382 + 383 + /* Usual case -- wait for EOF, wait for FIFO to drain */ 384 + lcd_wait(SLEEP_EOF); 385 + lcd_wait(SLEEP_FRAME); 323 386 324 - /* Wait for disable to take effect */ 325 - while(jz_readf(LCD_STATE, QD) == 0); 326 - jz_writef(LCD_STATE, QD(0)); 387 + /* Stop the DMA transfer */ 388 + jz_writef(LCD_MCTRL, DMA_TX_EN(0)); 389 + } 390 + jz_write(LCD_STATE, 0); // clear State 327 391 328 392 /* Clear format conversion bit, disable vsync */ 329 393 jz_writef(LCD_MCFG_NEW, FMT_CONV(0), DTIMES(0)); ··· 332 396 333 397 static void lcd_send(uint32_t d) 334 398 { 335 - while(jz_readf(LCD_MSTATE, BUSY)); 399 + lcd_wait(LCD_SEND0); 336 400 REG_LCD_MDATA = d; 337 401 } 338 402 ··· 370 434 break; 371 435 } 372 436 } 437 + lcd_wait(LCD_SEND1); 373 438 } 374 439 375 440 void lcd_init_device(void) ··· 381 446 382 447 lcd_tgt_enable(true); 383 448 384 - lcd_dma_start(); 449 + lcd_dma_start(MODE_INIT); 385 450 } 386 451 387 452 #ifdef HAVE_LCD_SHUTDOWN ··· 389 454 { 390 455 if(lcd_sleeping) 391 456 lcd_tgt_sleep(false); 392 - else if(jz_readf(LCD_CTRL, ENABLE)) 393 - lcd_dma_stop(); 457 + else if(lcd_active()) 458 + lcd_dma_stop(MODE_INIT); 394 459 395 460 lcd_tgt_enable(false); 396 461 jz_writef(CPM_CLKGR, LCD(1)); ··· 400 465 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 401 466 bool lcd_active(void) 402 467 { 403 - return jz_readf(LCD_CTRL, ENABLE); 468 + return lcd_on; 404 469 } 405 470 406 471 void lcd_enable(bool en) 407 472 { 408 - /* Must disable IRQs to turn off the running LCD */ 409 - int irq = disable_irq_save(); 410 - int bit = jz_readf(LCD_CTRL, ENABLE); 411 - if(bit && !en) 412 - lcd_dma_stop(); 413 - restore_irq(irq); 473 + bool state = lcd_active(); 474 + if(state && !en) 475 + #if defined(BOOTLOADER) 476 + lcd_dma_stop(MODE_INIT); 477 + #else 478 + lcd_dma_stop(MODE_SLEEP); 479 + #endif 414 480 415 481 /* Deal with sleep mode */ 416 482 #if defined(HAVE_LCD_SLEEP) || defined(LCD_X1000_FASTSLEEP) 417 483 #if defined(LCD_X1000_FASTSLEEP) 418 - if(bit && !en) { 484 + if(state && !en) { 419 485 lcd_tgt_sleep(true); 420 486 lcd_sleeping = true; 421 487 } else 422 488 #endif 423 - if(!bit && en && lcd_sleeping) { 489 + if(!state && en && lcd_sleeping) { 424 490 lcd_tgt_sleep(false); 425 491 lcd_sleeping = false; 426 492 } 427 493 #endif 428 494 429 495 /* Handle turning the LCD back on */ 430 - if(!bit && en) 496 + if(!state && en) 431 497 { 432 498 send_event(LCD_EVENT_ACTIVATION, NULL); 433 - lcd_dma_start(); 499 + #if defined(BOOTLOADER) 500 + lcd_dma_start(MODE_INIT); 501 + #else 502 + lcd_dma_start(MODE_SLEEP); 503 + #endif 434 504 } 435 505 } 436 506 #endif ··· 466 536 * its entirety to the LCD through a different DMA process. */ 467 537 void lcd_update_rect(int x, int y, int width, int height) 468 538 { 539 + if(!lcd_wait_frame()) 540 + return; 541 + 469 542 /* Clamp the coordinates */ 470 543 if(x < 0) { 471 544 width += x; ··· 484 557 height = LCD_HEIGHT - y; 485 558 486 559 if(width < 0 || height < 0) 487 - return; 488 - 489 - if(!lcd_wait_frame()) 490 560 return; 491 561 492 562 commit_dcache();
+4
firmware/target/mips/ingenic_x1000/lcd-x1000.h
··· 77 77 size_t dma_wr_cmd_size; 78 78 }; 79 79 80 + #define LCD_WAIT_MAX_US 65500 /* µS max. Waittime */ 81 + #define LCD_WAIT_US 1 /* µS per Step */ 82 + #define LCD_WAIT_STEPS (LCD_WAIT_MAX_US / LCD_WAIT_US) 83 + 80 84 /* Static configuration for the target's LCD, must be defined by target. */ 81 85 extern const struct lcd_tgt_config lcd_tgt_config; 82 86