DFBResult pxa3xxEngineSync( void *drv, void *dev ) { DFBResult ret = DFB_OK; PXA3XXDriverData *pdrv = drv; PXA3XXGfxSharedArea *shared = pdrv->gfx_shared; D_DEBUG_AT( PXA3XX_BLT, "%s()\n", __FUNCTION__ ); DUMP_INFO(); while (shared->hw_running && ioctl( pdrv->gfx_fd, PXA3XX_GCU_IOCTL_WAIT_IDLE ) < 0) { if (errno == EINTR) continue; ret = errno2result( errno ); D_PERROR( "PXA3XX/BLT: PXA3XX_GCU_IOCTL_WAIT_IDLE failed!\n" ); direct_log_printf( NULL, " -> %srunning, hw %d-%d, next %d-%d - %svalid\n", \ pdrv->gfx_shared->hw_running ? "" : "not ", \ pdrv->gfx_shared->hw_start, \ pdrv->gfx_shared->hw_end, \ pdrv->gfx_shared->next_start, \ pdrv->gfx_shared->next_end, \ pdrv->gfx_shared->next_valid ? "" : "not " ); break; } if (ret == DFB_OK) { D_ASSERT( !shared->hw_running ); } return ret; }
/* * Blend a rectangle using the alpha value from the color using the current hardware state. */ static bool pxa3xxBlitBlendColorAlpha( void *drv, void *dev, DFBRectangle *rect, int x, int y ) { PXA3XXDriverData *pdrv = drv; PXA3XXDeviceData *pdev = dev; u32 *prep = start_buffer( pdrv, 9 ); D_DEBUG_AT( PXA3XX_BLT, "%s( %d, %d - %dx%d -> %d, %d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ), x, y ); DUMP_INFO(); prep[0] = 0x47000138; prep[1] = x; prep[2] = y; prep[3] = rect->x; prep[4] = rect->y; prep[5] = x; prep[6] = y; prep[7] = PXA3XX_WH( rect->w, rect->h ); prep[8] = (pdev->color.a << 24) | (pdev->color.a << 16); submit_buffer( pdrv, 9 ); return true; }
static DFBResult flush_prepared( PXA3XXDriverData *pdrv ) { int result; D_DEBUG_AT( PXA3XX_BLT, "%s()\n", __FUNCTION__ ); DUMP_INFO(); D_ASSERT( pdrv->prep_num < PXA3XX_GCU_BUFFER_WORDS ); D_ASSERT( pdrv->prep_num <= D_ARRAY_SIZE(pdrv->prep_buf) ); /* Something prepared? */ if (pdrv->prep_num) { result = write( pdrv->gfx_fd, pdrv->prep_buf, pdrv->prep_num * 4 ); if (result < 0) { D_PERROR( "PXA3XX/BLT: write() failed!\n" ); return DFB_IO; } pdrv->prep_num = 0; } return DFB_OK; }
static inline DFBResult start_hardware( PXA3XXDriverData *pdrv ) { PXA3XXGfxSharedArea *shared = pdrv->gfx_shared; D_DEBUG_AT( PXA3XX_BLT, "%s()\n", __FUNCTION__ ); DUMP_INFO(); D_ASSERT( shared->next_valid ); if (shared->hw_running || shared->next_end == shared->next_start) return DFB_FAILURE; shared->hw_running = true; shared->hw_start = shared->next_start; shared->hw_end = shared->next_end; shared->next_start = shared->next_end = (shared->hw_end + 63) & ~0x3f; shared->num_words += shared->hw_end - shared->hw_start; shared->num_starts++; DUMP_INFO(); D_ASSERT( shared->buffer[shared->hw_end] == 0x08000000 ); #ifdef PXA3XX_GCU_REG_USE_IOCTLS ioctl( pdrv->gfx_fd, PXA3XX_GCU_IOCTL_START ); #else mb(); PXA_GCRBLR = 0; PXA_GCRBBR = shared->buffer_phys + shared->hw_start*4; PXA_GCRBTR = shared->buffer_phys + shared->hw_end*4; PXA_GCRBLR = ((shared->hw_end - shared->hw_start + 63) & ~0x3f) * 4; mb(); #endif return DFB_OK; }
void pxa3xxEngineReset( void *drv, void *dev ) { PXA3XXDriverData *pdrv = drv; D_DEBUG_AT( PXA3XX_BLT, "%s()\n", __FUNCTION__ ); DUMP_INFO(); ioctl( pdrv->gfx_fd, PXA3XX_GCU_IOCTL_RESET ); }
/* * Render a blended rectangle using the current hardware state. * * As the hardware does not directly support this, we blit a single * pixel with blending. */ static bool pxa3xxFillRectangleBlend( void *drv, void *dev, DFBRectangle *rect ) { PXA3XXDriverData *pdrv = drv; PXA3XXDeviceData *pdev = dev; u32 *prep = start_buffer( pdrv, 22 ); const u32 format = pixel_formats[DFB_PIXELFORMAT_INDEX( DSPF_ARGB )]; D_DEBUG_AT( PXA3XX_BLT, "%s( %d, %d - %dx%d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ) ); DUMP_INFO(); /* Set fake destination. */ prep[0] = 0x020000A2; prep[1] = pdev->fake_phys; prep[2] = (format << 19) | 4; /* Fill rectangle. */ prep[3] = 0x40000014 | (format << 8); prep[4] = 0; prep[5] = 0; prep[6] = PXA3XX_WH( rect->w, 1 ); prep[7] = PIXEL_ARGB( pdev->color.a, pdev->color.r, pdev->color.g, pdev->color.b ); /* Restore destination. */ prep[8] = 0x020000A2; prep[9] = pdev->dst_phys; prep[10] = (pixel_formats[pdev->dst_index] << 19) | (pdev->dst_pitch << 5) | pdev->dst_bpp; /* Set fake buffer as source. */ prep[11] = 0x02000002; prep[12] = pdev->fake_phys; prep[13] = (format << 19) | 4; /* Blit with blending. */ prep[14] = 0x47000107; prep[15] = rect->x; prep[16] = rect->y; prep[17] = 0; prep[18] = 0; prep[19] = rect->x; prep[20] = rect->y; prep[21] = PXA3XX_WH( rect->w, rect->h ); submit_buffer( pdrv, 22 ); /* Clear the flag. */ PXA3XX_INVALIDATE( SOURCE ); return true; }
/* * Render a filled rectangle using the current hardware state. */ static bool pxa3xxFillRectangle( void *drv, void *dev, DFBRectangle *rect ) { PXA3XXDriverData *pdrv = drv; u32 *prep = start_buffer( pdrv, 4 ); D_DEBUG_AT( PXA3XX_BLT, "%s( %d, %d - %dx%d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ) ); DUMP_INFO(); prep[0] = 0x40000003; prep[1] = rect->x; prep[2] = rect->y; prep[3] = PXA3XX_WH( rect->w, rect->h ); submit_buffer( pdrv, 4 ); return true; }
/* * Blit a glyph with alpha blending and colorizing using the current hardware state. */ static bool pxa3xxBlitGlyph( void *drv, void *dev, DFBRectangle *rect, int x, int y ) { PXA3XXDriverData *pdrv = drv; PXA3XXDeviceData *pdev = dev; u32 *prep = start_buffer( pdrv, 40 ); const u32 format = pixel_formats[DFB_PIXELFORMAT_INDEX( DSPF_ARGB )]; D_DEBUG_AT( PXA3XX_BLT, "%s( %d, %d - %dx%d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ) ); DUMP_INFO(); if (rect->w * (rect->h + 1) * 4 > pdev->fake_size) return false; /* Set fake destination. */ prep[0] = 0x020000A2; prep[1] = pdev->fake_phys; prep[2] = (format << 19) | ((rect->w << 2) << 5) | 4; /* Fill first row of fake buffer. */ prep[3] = 0x40000014 | (format << 8); prep[4] = 0; prep[5] = 0; prep[6] = PXA3XX_WH( rect->w, 1 ); prep[7] = PIXEL_ARGB( pdev->color.a, pdev->color.r, pdev->color.g, pdev->color.b ); /* Set first row of fake buffer as source1. */ prep[8] = 0x02000012; prep[9] = pdev->fake_phys; prep[10] = (format << 19) | 4; /* Blit with blending. */ prep[11] = 0x47000118; prep[12] = 0; prep[13] = 1; prep[14] = rect->x; prep[15] = rect->y; prep[16] = 0; prep[17] = 0; prep[18] = PXA3XX_WH( rect->w, rect->h ); prep[19] = 0; /* Restore destination. */ prep[20] = 0x020000A2; prep[21] = pdev->dst_phys; prep[22] = (pixel_formats[pdev->dst_index] << 19) | (pdev->dst_pitch << 5) | pdev->dst_bpp; /* Restore source1 to destination. */ prep[23] = 0x02000012; prep[24] = prep[21]; prep[25] = prep[22]; /* Set fake buffer as source0. */ prep[26] = 0x02000002; prep[27] = pdev->fake_phys; prep[28] = (format << 19) | ((rect->w << 2) << 5) | 4; /* Blit with blending. */ prep[29] = 0x47000107; prep[30] = x; prep[31] = y; prep[32] = 0; prep[33] = 1; prep[34] = x; prep[35] = y; prep[36] = PXA3XX_WH( rect->w, rect->h ); /* Restore source0. */ prep[37] = 0x02000002; prep[38] = pdev->src_phys; prep[39] = (pixel_formats[pdev->src_index] << 19) | (pdev->src_pitch << 5) | pdev->src_bpp; submit_buffer( pdrv, 40 ); return true; }
/* * Blit a rectangle using the current hardware state. */ static bool pxa3xxBlit( void *drv, void *dev, DFBRectangle *rect, int x, int y ) { PXA3XXDriverData *pdrv = drv; PXA3XXDeviceData *pdev = dev; u32 rotation = 0; u32 *prep = start_buffer( pdrv, 6 ); D_DEBUG_AT( PXA3XX_BLT, "%s( %d, %d - %dx%d -> %d, %d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ), x, y ); DUMP_INFO(); if (pdev->bflags & DSBLIT_ROTATE90) rotation = 3; else if (pdev->bflags & DSBLIT_ROTATE180) rotation = 2; else if (pdev->bflags & DSBLIT_ROTATE270) rotation = 1; prep[0] = 0x4A000005 | (rotation << 4); // FIXME: use 32byte alignment hint prep[1] = x; prep[2] = y; prep[3] = rect->x; prep[4] = rect->y; prep[5] = PXA3XX_WH( rect->w, rect->h ); submit_buffer( pdrv, 6 ); /* RASTER prep[0] = 0x4BCC0007; prep[1] = x; prep[2] = y; prep[3] = rect->x; prep[4] = rect->y; prep[5] = rect->x; prep[6] = rect->y; prep[7] = PXA3XX_WH( rect->w, rect->h ); submit_buffer( pdrv, 8 ); */ /* PATTERN prep[0] = 0x4C000006; prep[1] = x; prep[2] = y; prep[3] = rect->x; prep[4] = rect->y; prep[5] = PXA3XX_WH( rect->w, rect->h ); prep[6] = PXA3XX_WH( rect->w, rect->h ); submit_buffer( pdrv, 7 ); */ /* BIAS prep[0] = 0x49000016; prep[1] = x; prep[2] = y; prep[3] = rect->x; prep[4] = rect->y; prep[5] = PXA3XX_WH( rect->w, rect->h ); prep[6] = 0; submit_buffer( pdrv, 7 ); */ return true; }
/* * Make sure that the hardware is programmed for execution of 'accel' according to the 'state'. */ void pxa3xxSetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { PXA3XXDriverData *pdrv = drv; PXA3XXDeviceData *pdev = dev; StateModificationFlags modified = state->mod_hw; D_DEBUG_AT( PXA3XX_BLT, "%s( %p, 0x%08x ) <- modified 0x%08x\n", __FUNCTION__, state, accel, modified ); DUMP_INFO(); /* * 1) Invalidate hardware states * * Each modification to the hw independent state invalidates one or more hardware states. */ /* Simply invalidate all? */ if (modified == SMF_ALL) { PXA3XX_INVALIDATE( ALL ); } else if (modified) { /* Invalidate destination registers. */ if (modified & SMF_DESTINATION) PXA3XX_INVALIDATE( DEST | COLOR ); /* Invalidate source registers. */ if (modified & SMF_SOURCE) PXA3XX_INVALIDATE( SOURCE ); /* Invalidate color registers. */ if (modified & SMF_COLOR) PXA3XX_INVALIDATE( COLOR ); } /* * 2) Validate hardware states * * Each function has its own set of states that need to be validated. */ /* Always requiring valid destination. */ PXA3XX_CHECK_VALIDATE( DEST ); /* Depending on the function... */ switch (accel) { case DFXL_FILLRECTANGLE: /* ...require valid color. */ PXA3XX_CHECK_VALIDATE( COLOR ); if (state->drawingflags & DSDRAW_BLEND) funcs->FillRectangle = pxa3xxFillRectangleBlend; else funcs->FillRectangle = pxa3xxFillRectangle; /* * 3) Tell which functions can be called without further validation, i.e. SetState() * * When the hw independent state is changed, this collection is reset. */ state->set = PXA3XX_SUPPORTED_DRAWINGFUNCTIONS; break; case DFXL_BLIT: case DFXL_STRETCHBLIT: /* ...require valid source. */ PXA3XX_CHECK_VALIDATE( SOURCE ); if (state->blittingflags & DSBLIT_BLEND_ALPHACHANNEL && pdev->src_alpha) { if (state->blittingflags & DSBLIT_COLORIZE) funcs->Blit = pxa3xxBlitGlyph; else funcs->Blit = pxa3xxBlitBlend; } else { if (state->blittingflags & DSBLIT_BLEND_COLORALPHA) funcs->Blit = pxa3xxBlitBlendColorAlpha; else funcs->Blit = pxa3xxBlit; } /* * 3) Tell which functions can be called without further validation, i.e. SetState() * * When the hw independent state is changed, this collection is reset. */ state->set = PXA3XX_SUPPORTED_BLITTINGFUNCTIONS; break; default: D_BUG( "unexpected drawing/blitting function" ); break; } pdev->dflags = state->drawingflags; pdev->bflags = state->blittingflags; pdev->render_options = state->render_options; pdev->color = state->color; /* * 4) Clear modification flags * * All flags have been evaluated in 1) and remembered for further validation. * If the hw independent state is not modified, this function won't get called * for subsequent rendering functions, unless they aren't defined by 3). */ state->mod_hw = 0; }
static DFBResult flush_prepared( PXA3XXDriverData *pdrv ) { PXA3XXGfxSharedArea *shared = pdrv->gfx_shared; D_DEBUG_AT( PXA3XX_BLT, "%s()\n", __FUNCTION__ ); DUMP_INFO(); D_ASSERT( pdrv->prep_num < PXA3XX_GCU_BUFFER_WORDS ); D_ASSERT( pdrv->prep_num <= D_ARRAY_SIZE(pdrv->prep_buf) ); /* Something prepared? */ while (pdrv->prep_num) { int timeout = 2; int next_end; /* Mark shared information as invalid. From this point on the interrupt handler * will not continue with the next block, and we'll start the hardware ourself. */ shared->next_valid = false; mb(); /* Check if there's enough space at the end. * Wait until hardware has started next block before it gets too big. */ if (shared->next_end + pdrv->prep_num >= PXA3XX_GCU_BUFFER_WORDS || shared->next_end - shared->next_start >= PXA3XX_GCU_BUFFER_WORDS/4) { /* If there's no next block waiting, start at the beginning. */ if (shared->next_start == shared->next_end) shared->next_start = shared->next_end = 0; else { D_ASSERT( shared->buffer[shared->hw_end] == 0x08000000 ); /* Mark area as valid again. */ shared->next_valid = true; mb(); /* Start in case it got idle while doing the checks. */ if (start_hardware( pdrv )) { /* * Hardware has not been started (still running). * Check for timeout. */ if (!timeout--) { D_ERROR( "PXA3XX/Blt: Timeout waiting for processing!\n" ); direct_log_printf( NULL, " -> %srunning, hw %d-%d, next %d-%d - %svalid\n", \ pdrv->gfx_shared->hw_running ? "" : "not ", \ pdrv->gfx_shared->hw_start, \ pdrv->gfx_shared->hw_end, \ pdrv->gfx_shared->next_start, \ pdrv->gfx_shared->next_end, \ pdrv->gfx_shared->next_valid ? "" : "not " ); D_ASSERT( shared->buffer[shared->hw_end] == 0x08000000 ); // pxa3xxEngineReset( pdrv, pdrv->dev ); return DFB_TIMEOUT; } /* Wait til next block is started. */ ioctl( pdrv->gfx_fd, PXA3XX_GCU_IOCTL_WAIT_NEXT ); } /* Start over with the checks. */ continue; } } /* We are appending in case there was already a next block. */ next_end = shared->next_end + pdrv->prep_num; /* Reset the timeout counter. */ timeout = 20; /* While the hardware is running... */ while (shared->hw_running) { D_ASSERT( shared->buffer[shared->hw_end] == 0x08000000 ); /* ...make sure we don't over lap with its current buffer, otherwise wait. */ if (shared->hw_start > next_end || shared->hw_end < shared->next_start) break; /* Check for timeout. */ if (!timeout--) { D_ERROR( "PXA3XX/Blt: Timeout waiting for space!\n" ); direct_log_printf( NULL, " -> %srunning, hw %d-%d, next %d-%d - %svalid\n", \ pdrv->gfx_shared->hw_running ? "" : "not ", \ pdrv->gfx_shared->hw_start, \ pdrv->gfx_shared->hw_end, \ pdrv->gfx_shared->next_start, \ pdrv->gfx_shared->next_end, \ pdrv->gfx_shared->next_valid ? "" : "not " ); D_ASSERT( shared->buffer[shared->hw_end] == 0x08000000 ); // pxa3xxEngineReset( pdrv, pdrv->dev ); return DFB_TIMEOUT; } /* Wait til next block is started. */ ioctl( pdrv->gfx_fd, PXA3XX_GCU_IOCTL_WAIT_NEXT ); } /* Copy from local to shared buffer. */ direct_memcpy( (void*) &shared->buffer[shared->next_end], &pdrv->prep_buf[0], pdrv->prep_num * sizeof(u32) ); /* Terminate the block. */ shared->buffer[next_end] = 0x08000000; /* Update next block information and mark valid. */ shared->next_end = next_end; mb(); shared->next_valid = true; /* Reset local counter. */ pdrv->prep_num = 0; /* Start in case it is idle. */ return start_hardware( pdrv ); } return DFB_OK; }
void comm_error(uint16_t errnr, uint16_t param) { // FIXME: embed sender id to error number, we got dem bits struct { uint16_t nr, sender, arg; } x = {errnr, MY_ID, param}; DUMP_INFO(MSG_ERR, x); }