/* * Copyright (C) 2006 Claudio Ciccani * * Graphics driver for ATI Radeon cards written by * Claudio Ciccani . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "radeon.h" #include "radeon_regs.h" #include "radeon_mmio.h" typedef struct { CoreLayerRegionConfig config; float brightness; float contrast; float saturation; float hue; int field; int level; CoreScreen *screen; int crtc2; CoreSurface *surface; CoreSurfaceBufferLock *lock; /* overlay registers */ struct { u32 H_INC; u32 STEP_BY; u32 Y_X_START; u32 Y_X_END; u32 V_INC; u32 P1_BLANK_LINES_AT_TOP; u32 P23_BLANK_LINES_AT_TOP; u32 VID_BUF_PITCH0_VALUE; u32 VID_BUF_PITCH1_VALUE; u32 P1_X_START_END; u32 P2_X_START_END; u32 P3_X_START_END; u32 BASE_ADDR; u32 VID_BUF0_BASE_ADRS; u32 VID_BUF1_BASE_ADRS; u32 VID_BUF2_BASE_ADRS; u32 VID_BUF3_BASE_ADRS; u32 VID_BUF4_BASE_ADRS; u32 VID_BUF5_BASE_ADRS; u32 P1_V_ACCUM_INIT; u32 P23_V_ACCUM_INIT; u32 P1_H_ACCUM_INIT; u32 P23_H_ACCUM_INIT; u32 VID_KEY_CLR_LOW; u32 VID_KEY_CLR_HIGH; u32 GRPH_KEY_CLR_LOW; u32 GRPH_KEY_CLR_HIGH; u32 KEY_CNTL; u32 MERGE_CNTL; u32 SCALE_CNTL; } regs; } RadeonOverlayLayerData; static void ovl_calc_regs ( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreSurface *surface, CoreLayerRegionConfig *config, CoreSurfaceBufferLock *lock ); static void ovl_set_regs ( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl ); static void ovl_calc_buffers ( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreSurface *surface, CoreLayerRegionConfig *config, CoreSurfaceBufferLock *lock ); static void ovl_set_buffers ( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl ); static void ovl_set_colorkey ( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreLayerRegionConfig *config ); static void ovl_set_adjustment( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, float brightness, float contrast, float saturation, float hue ); #define OVL_SUPPORTED_OPTIONS \ ( DLOP_DST_COLORKEY | DLOP_OPACITY | DLOP_DEINTERLACING ) /**********************/ static int ovlLayerDataSize( void ) { return sizeof(RadeonOverlayLayerData); } static DFBResult ovlInitLayer( CoreLayer *layer, void *driver_data, void *layer_data, DFBDisplayLayerDescription *description, DFBDisplayLayerConfig *config, DFBColorAdjustment *adjustment ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; volatile u8 *mmio = rdrv->mmio_base; DFBScreenDescription dsc; dfb_screen_get_info( layer->screen, NULL, &dsc ); if (strstr( dsc.name, "CRTC2" )) rovl->crtc2 = 1; rovl->level = 1; /* fill layer description */ description->type = DLTF_GRAPHICS | DLTF_VIDEO | DLTF_STILL_PICTURE; description->caps = DLCAPS_SURFACE | DLCAPS_SCREEN_LOCATION | DLCAPS_BRIGHTNESS | DLCAPS_CONTRAST | DLCAPS_SATURATION | DLCAPS_HUE | DLCAPS_DST_COLORKEY | DLCAPS_OPACITY | DLCAPS_DEINTERLACING | DLCAPS_LEVELS; snprintf( description->name, DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "Radeon CRTC%c's Overlay", rovl->crtc2 ? '2' : '1' ); /* set default configuration */ config->flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS; config->width = 640; config->height = 480; config->pixelformat = DSPF_YUY2; config->buffermode = DLBM_FRONTONLY; config->options = DLOP_NONE; /* set default color adjustment */ adjustment->flags = DCAF_BRIGHTNESS | DCAF_CONTRAST | DCAF_SATURATION | DCAF_HUE; adjustment->brightness = 0x8000; adjustment->contrast = 0x8000; adjustment->saturation = 0x8000; adjustment->hue = 0x8000; /* reset overlay */ radeon_out32( mmio, OV0_SCALE_CNTL, SCALER_SOFT_RESET ); radeon_out32( mmio, OV0_AUTO_FLIP_CNTL, 0 ); radeon_out32( mmio, OV0_DEINTERLACE_PATTERN, 0 ); radeon_out32( mmio, OV0_EXCLUSIVE_HORZ, 0 ); radeon_out32( mmio, OV0_FILTER_CNTL, FILTER_HARDCODED_COEF ); radeon_out32( mmio, OV0_TEST, 0 ); /* reset color adjustments */ ovl_set_adjustment( rdrv, rovl, 0, 0, 0, 0 ); return DFB_OK; } static DFBResult ovlTestRegion( CoreLayer *layer, void *driver_data, void *layer_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags *failed ) { RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; CoreLayerRegionConfigFlags fail = 0; /* check for unsupported options */ if (config->options & ~OVL_SUPPORTED_OPTIONS) fail |= CLRCF_OPTIONS; if (rovl->level == -1) { if (config->options & ~DLOP_DEINTERLACING) fail |= CLRCF_OPTIONS; } else { if (config->options & DLOP_OPACITY && config->options & (DLOP_SRC_COLORKEY | DLOP_DST_COLORKEY)) fail |= CLRCF_OPTIONS; } /* check buffermode */ switch (config->buffermode) { case DLBM_FRONTONLY: case DLBM_BACKSYSTEM: case DLBM_BACKVIDEO: case DLBM_TRIPLE: break; default: fail |= CLRCF_BUFFERMODE; break; } /* check pixel format */ switch (config->format) { case DSPF_RGB555: case DSPF_ARGB1555: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: case DSPF_YUY2: case DSPF_UYVY: case DSPF_I420: case DSPF_YV12: break; default: fail |= CLRCF_FORMAT; break; } /* check width */ if (config->width > 2048 || config->width < 1) fail |= CLRCF_WIDTH; /* check height */ if (config->height > 2048 || config->height < 1) fail |= CLRCF_HEIGHT; /* write back failing fields */ if (failed) *failed = fail; /* return failure if any field failed */ if (fail) return DFB_UNSUPPORTED; return DFB_OK; } static DFBResult ovlAddRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonDeviceData *rdev = rdrv->device_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; if (rovl->crtc2 && !rdev->monitor2) { D_ERROR( "DirectFB/Radeon/Overlay: " "no secondary monitor connected!\n" ); return DFB_IO; } return DFB_OK; } static DFBResult ovlSetRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags updated, CoreSurface *surface, CorePalette *palette, CoreSurfaceBufferLock *lock ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; /* save configuration */ rovl->config = *config; rovl->surface = surface; rovl->screen = layer->screen; if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_SOURCE | CLRCF_DEST | CLRCF_OPTIONS | CLRCF_OPACITY)) { ovl_calc_regs( rdrv, rovl, surface, &rovl->config, lock ); ovl_set_regs( rdrv, rovl ); } if (updated & (CLRCF_SRCKEY | CLRCF_DSTKEY)) ovl_set_colorkey( rdrv, rovl, &rovl->config ); rovl->lock = lock; return DFB_OK; } static DFBResult ovlFlipRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, DFBSurfaceFlipFlags flags, CoreSurfaceBufferLock *lock ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; dfb_surface_flip( surface, false ); ovl_calc_buffers( rdrv, rovl, surface, &rovl->config, lock ); ovl_set_buffers( rdrv, rovl ); if (flags & DSFLIP_WAIT) dfb_layer_wait_vsync( layer ); rovl->lock = lock; return DFB_OK; } static DFBResult ovlSetColorAdjustment( CoreLayer *layer, void *driver_data, void *layer_data, DFBColorAdjustment *adj ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; if (adj->flags & DCAF_BRIGHTNESS) rovl->brightness = (float)(adj->brightness-0x8000) / 65535.0; if (adj->flags & DCAF_CONTRAST) rovl->contrast = (float)adj->contrast / 32768.0; if (adj->flags & DCAF_SATURATION) rovl->saturation = (float)adj->saturation / 32768.0; if (adj->flags & DCAF_HUE) rovl->hue = (float)(adj->hue-0x8000) * 3.1416 / 65535.0; ovl_set_adjustment( rdrv, rovl, rovl->brightness, rovl->contrast, rovl->saturation, rovl->hue ); return DFB_OK; } static DFBResult ovlSetInputField( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, int field ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; rovl->field = field; if (rovl->surface) { ovl_calc_buffers( rdrv, rovl, rovl->surface, &rovl->config, rovl->lock ); ovl_set_buffers( rdrv, rovl ); } return DFB_OK; } static DFBResult ovlGetLevel( CoreLayer *layer, void *driver_data, void *layer_data, int *level ) { RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; *level = rovl->level; return DFB_OK; } static DFBResult ovlSetLevel( CoreLayer *layer, void *driver_data, void *layer_data, int level ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonOverlayLayerData *rovl = (RadeonOverlayLayerData*) layer_data; if (!rovl->surface) return DFB_UNSUPPORTED; switch (level) { case -1: case 1: rovl->level = level; ovl_calc_regs( rdrv, rovl, rovl->surface, &rovl->config, rovl->lock ); ovl_set_regs( rdrv, rovl ); break; default: return DFB_UNSUPPORTED; } return DFB_OK; } static DFBResult ovlRemoveRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data ) { RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; RadeonDeviceData *rdev = rdrv->device_data; /* disable overlay */ radeon_waitfifo( rdrv, rdev, 1 ); radeon_out32( rdrv->mmio_base, OV0_SCALE_CNTL, 0 ); return DFB_OK; } DisplayLayerFuncs RadeonOverlayFuncs = { .LayerDataSize = ovlLayerDataSize, .InitLayer = ovlInitLayer, .TestRegion = ovlTestRegion, .AddRegion = ovlAddRegion, .SetRegion = ovlSetRegion, .RemoveRegion = ovlRemoveRegion, .FlipRegion = ovlFlipRegion, .SetColorAdjustment = ovlSetColorAdjustment, .SetInputField = ovlSetInputField, .GetLevel = ovlGetLevel, .SetLevel = ovlSetLevel }; /*** Internal Functions ***/ static void ovl_calc_coordinates( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreSurface *surface, CoreLayerRegionConfig *config ) { RadeonDeviceData *rdev = rdrv->device_data; DFBRectangle source = config->source; DFBRectangle dest = config->dest; u32 ecp_div = 0; u32 h_inc; u32 h_inc2; u32 v_inc; u32 step_by; u32 tmp; int xres; int yres; dfb_screen_get_screen_size( rovl->screen, &xres, &yres ); if (dest.w > (source.w << 4)) dest.w = source.w << 4; if (dest.h > (source.h << 4)) dest.h = source.h << 4; if (dest.x < 0) { source.w += dest.x * source.w / dest.w; dest.w += dest.x; dest.x = 0; } if (dest.y < 0) { source.h += dest.y * source.h / dest.h; dest.h += dest.y; dest.y = 0; } if ((dest.x + dest.w) > xres) { source.w = (xres - dest.x) * source.w / dest.w; dest.w = xres - dest.x; } if ((dest.y + dest.h) > yres) { source.h = (yres - dest.y) * source.h / dest.h; dest.h = yres - dest.y; } if (dest.w < 1 || dest.h < 1 || source.w < 1 || source.h < 1) { config->opacity = 0; return; } if (config->options & DLOP_DEINTERLACING) source.h /= 2; tmp = radeon_in32( rdrv->mmio_base, rovl->crtc2 ? CRTC2_GEN_CNTL : CRTC_GEN_CNTL ); if (tmp & CRTC_DBL_SCAN_EN) { dest.y *= 2; dest.h *= 2; } if (tmp & CRTC_INTERLACE_EN) { dest.y /= 2; dest.h /= 2; } /* FIXME: We need to know the VideoMode of the current screen. */ #if 0 if ((100000000 / mode->pixclock) >= 17500) ecp_div = 1; #endif h_inc = (source.w << (12 + ecp_div)) / dest.w; v_inc = (source.h << 20) / dest.h; for (step_by = 1; h_inc >= (2 << 12);) { step_by++; h_inc >>= 1; } switch (surface->config.format) { case DSPF_RGB555: case DSPF_ARGB1555: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: h_inc2 = h_inc; break; default: h_inc2 = h_inc >> 1; break; } rovl->regs.V_INC = v_inc; rovl->regs.H_INC = h_inc | (h_inc2 << 16); rovl->regs.STEP_BY = step_by | (step_by << 8); /* compute values for horizontal accumulators */ tmp = 0x00028000 + (h_inc << 3); rovl->regs.P1_H_ACCUM_INIT = ((tmp << 4) & 0x000f8000) | ((tmp << 12) & 0xf0000000); tmp = 0x00028000 + (h_inc2 << 3); rovl->regs.P23_H_ACCUM_INIT = ((tmp << 4) & 0x000f8000) | ((tmp << 12) & 0x70000000); /* compute values for vertical accumulators */ tmp = 0x00018000; rovl->regs.P1_V_ACCUM_INIT = ((tmp << 4) & OV0_P1_V_ACCUM_INIT_MASK) | (OV0_P1_MAX_LN_IN_PER_LN_OUT & 1); tmp = 0x00018000; rovl->regs.P23_V_ACCUM_INIT = ((tmp << 4) & OV0_P23_V_ACCUM_INIT_MASK) | (OV0_P23_MAX_LN_IN_PER_LN_OUT & 1); if (!rovl->crtc2) { if (rdev->chipset < CHIP_R300 && rdev->chipset != CHIP_R200 && rdev->chipset != CHIP_UNKNOWN) dest.x += 8; } /* compute destination coordinates */ rovl->regs.Y_X_START = (dest.x & 0xffff) | (dest.y << 16); rovl->regs.Y_X_END = ((dest.x + dest.w - 1) & 0xffff) | ((dest.y + dest.h - 1) << 16); /* compute source coordinates */ rovl->regs.P1_BLANK_LINES_AT_TOP = P1_BLNK_LN_AT_TOP_M1_MASK | ((source.h - 1) << 16); rovl->regs.P1_X_START_END = (source.w - 1) & 0xffff; if (DFB_PLANAR_PIXELFORMAT( surface->config.format )) { rovl->regs.P23_BLANK_LINES_AT_TOP = P23_BLNK_LN_AT_TOP_M1_MASK | ((source.h/2 - 1) << 16); rovl->regs.P2_X_START_END = (source.w/2 - 1) & 0xffff; rovl->regs.P3_X_START_END = rovl->regs.P2_X_START_END; } else { rovl->regs.P23_BLANK_LINES_AT_TOP = P23_BLNK_LN_AT_TOP_M1_MASK | ((source.h - 1) << 16); rovl->regs.P2_X_START_END = rovl->regs.P1_X_START_END; rovl->regs.P3_X_START_END = rovl->regs.P1_X_START_END; } } static void ovl_calc_buffers( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreSurface *surface, CoreLayerRegionConfig *config, CoreSurfaceBufferLock *lock ) { RadeonDeviceData *rdev = rdrv->device_data; DFBRectangle source = config->source; u32 offsets[3] = { 0, 0, 0 }; u32 pitch = lock->pitch; int even = 0; int cropleft; int croptop; if (config->options & DLOP_DEINTERLACING) { source.y /= 2; source.h /= 2; pitch *= 2; even = rovl->field; } cropleft = source.x; croptop = source.y; if (config->dest.x < 0) cropleft += -config->dest.x * source.w / config->dest.w; if (config->dest.y < 0) croptop += -config->dest.y * source.h / config->dest.h; if (DFB_PLANAR_PIXELFORMAT( surface->config.format )) { cropleft &= ~31; croptop &= ~1; offsets[0] = lock->offset; offsets[1] = offsets[0] + surface->config.size.h * lock->pitch; offsets[2] = offsets[1] + surface->config.size.h/2 * lock->pitch/2; offsets[0] += croptop * pitch + cropleft; offsets[1] += croptop/2 * pitch/2 + cropleft/2; offsets[2] += croptop/2 * pitch/2 + cropleft/2; if (even) { offsets[0] += lock->pitch; offsets[1] += lock->pitch/2; offsets[2] += lock->pitch/2; } if (surface->config.format == DSPF_YV12) { u32 tmp = offsets[1]; offsets[1] = offsets[2]; offsets[2] = tmp; } } else { offsets[0] = lock->offset + croptop * pitch + cropleft * DFB_BYTES_PER_PIXEL( surface->config.format ); if (even) offsets[0] += lock->pitch; offsets[1] = offsets[2] = offsets[0]; } if (lock->phys - lock->offset == rdev->fb_phys) rovl->regs.BASE_ADDR = rdev->fb_offset; else rovl->regs.BASE_ADDR = rdev->agp_offset; rovl->regs.VID_BUF0_BASE_ADRS = (offsets[0] & VIF_BUF0_BASE_ADRS_MASK); rovl->regs.VID_BUF1_BASE_ADRS = (offsets[1] & VIF_BUF1_BASE_ADRS_MASK) | VIF_BUF1_PITCH_SEL; rovl->regs.VID_BUF2_BASE_ADRS = (offsets[2] & VIF_BUF2_BASE_ADRS_MASK) | VIF_BUF2_PITCH_SEL; rovl->regs.VID_BUF3_BASE_ADRS = (offsets[0] & VIF_BUF3_BASE_ADRS_MASK); rovl->regs.VID_BUF4_BASE_ADRS = (offsets[1] & VIF_BUF4_BASE_ADRS_MASK) | VIF_BUF4_PITCH_SEL; rovl->regs.VID_BUF5_BASE_ADRS = (offsets[2] & VIF_BUF5_BASE_ADRS_MASK) | VIF_BUF5_PITCH_SEL; rovl->regs.VID_BUF_PITCH0_VALUE = pitch; rovl->regs.VID_BUF_PITCH1_VALUE = pitch/2; } static void ovl_calc_regs( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreSurface *surface, CoreLayerRegionConfig *config, CoreSurfaceBufferLock *lock ) { rovl->regs.SCALE_CNTL = 0; /* Configure coordinates */ ovl_calc_coordinates( rdrv, rovl, surface, config ); /* Configure buffers */ ovl_calc_buffers( rdrv, rovl, surface, config, lock ); /* Configure scaler */ if (rovl->level == -1) { rovl->regs.KEY_CNTL = GRAPHIC_KEY_FN_FALSE | VIDEO_KEY_FN_FALSE | CMP_MIX_AND; rovl->regs.MERGE_CNTL = DISP_ALPHA_MODE_PER_PIXEL | 0x00ff0000 | /* graphic alpha */ 0xff000000; /* overlay alpha */ } else if (config->options & DLOP_OPACITY) { rovl->regs.KEY_CNTL = GRAPHIC_KEY_FN_TRUE | VIDEO_KEY_FN_TRUE | CMP_MIX_AND; rovl->regs.MERGE_CNTL = DISP_ALPHA_MODE_GLOBAL | 0x00ff0000 | (config->opacity << 24); } else { rovl->regs.KEY_CNTL = CMP_MIX_AND; if (config->options & DLOP_SRC_COLORKEY) rovl->regs.KEY_CNTL |= VIDEO_KEY_FN_NE; else rovl->regs.KEY_CNTL |= VIDEO_KEY_FN_TRUE; if (config->options & DLOP_DST_COLORKEY) rovl->regs.KEY_CNTL |= GRAPHIC_KEY_FN_EQ; else rovl->regs.KEY_CNTL |= GRAPHIC_KEY_FN_TRUE; rovl->regs.MERGE_CNTL = 0xffff0000; } if (config->opacity) { rovl->regs.SCALE_CNTL = SCALER_SMART_SWITCH | SCALER_DOUBLE_BUFFER | SCALER_ADAPTIVE_DEINT | (rovl->crtc2 << 14); if (config->source.w == config->dest.w) rovl->regs.SCALE_CNTL |= SCALER_HORZ_PICK_NEAREST; if (config->source.h == config->dest.h) rovl->regs.SCALE_CNTL |= SCALER_VERT_PICK_NEAREST; switch (surface->config.format) { case DSPF_RGB555: case DSPF_ARGB1555: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_15BPP | SCALER_PRG_LOAD_START; break; case DSPF_RGB16: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_16BPP | SCALER_PRG_LOAD_START; break; case DSPF_RGB32: case DSPF_ARGB: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_32BPP | SCALER_PRG_LOAD_START; break; case DSPF_UYVY: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_YVYU422; break; case DSPF_YUY2: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_VYUY422; break; case DSPF_YV12: case DSPF_I420: rovl->regs.SCALE_CNTL |= SCALER_SOURCE_YUV12; break; default: D_BUG( "unexpected pixelformat" ); config->opacity = 0; return; } rovl->regs.SCALE_CNTL |= SCALER_ENABLE; } } static void ovl_set_regs( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl ) { RadeonDeviceData *rdev = rdrv->device_data; volatile u8 *mmio = rdrv->mmio_base; radeon_waitfifo( rdrv, rdev, 1 ); radeon_out32( mmio, OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK ); while(!(radeon_in32( mmio, OV0_REG_LOAD_CNTL ) & REG_LD_CTL_LOCK_READBACK)); radeon_waitfifo( rdrv, rdev, 17 ); radeon_out32( mmio, OV0_H_INC, rovl->regs.H_INC ); radeon_out32( mmio, OV0_STEP_BY, rovl->regs.STEP_BY ); if (rovl->crtc2) { radeon_out32( mmio, OV1_Y_X_START, rovl->regs.Y_X_START ); radeon_out32( mmio, OV1_Y_X_END, rovl->regs.Y_X_END ); } else { radeon_out32( mmio, OV0_Y_X_START, rovl->regs.Y_X_START ); radeon_out32( mmio, OV0_Y_X_END, rovl->regs.Y_X_END ); } radeon_out32( mmio, OV0_V_INC, rovl->regs.V_INC ); radeon_out32( mmio, OV0_P1_BLANK_LINES_AT_TOP, rovl->regs.P1_BLANK_LINES_AT_TOP ); radeon_out32( mmio, OV0_P23_BLANK_LINES_AT_TOP, rovl->regs.P23_BLANK_LINES_AT_TOP ); radeon_out32( mmio, OV0_VID_BUF_PITCH0_VALUE, rovl->regs.VID_BUF_PITCH0_VALUE ); radeon_out32( mmio, OV0_VID_BUF_PITCH1_VALUE, rovl->regs.VID_BUF_PITCH1_VALUE ); radeon_out32( mmio, OV0_P1_X_START_END, rovl->regs.P1_X_START_END ); radeon_out32( mmio, OV0_P2_X_START_END, rovl->regs.P2_X_START_END ); radeon_out32( mmio, OV0_P3_X_START_END, rovl->regs.P3_X_START_END ); radeon_out32( mmio, OV0_P1_V_ACCUM_INIT, rovl->regs.P1_V_ACCUM_INIT ); radeon_out32( mmio, OV0_BASE_ADDR, rovl->regs.BASE_ADDR ); radeon_out32( mmio, OV0_VID_BUF0_BASE_ADRS, rovl->regs.VID_BUF0_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF1_BASE_ADRS, rovl->regs.VID_BUF1_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF2_BASE_ADRS, rovl->regs.VID_BUF2_BASE_ADRS ); radeon_waitfifo( rdrv, rdev, 10 ); radeon_out32( mmio, OV0_VID_BUF3_BASE_ADRS, rovl->regs.VID_BUF3_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF4_BASE_ADRS, rovl->regs.VID_BUF4_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF5_BASE_ADRS, rovl->regs.VID_BUF5_BASE_ADRS ); radeon_out32( mmio, OV0_P1_H_ACCUM_INIT, rovl->regs.P1_H_ACCUM_INIT ); radeon_out32( mmio, OV0_P23_V_ACCUM_INIT, rovl->regs.P23_V_ACCUM_INIT ); radeon_out32( mmio, OV0_P23_H_ACCUM_INIT, rovl->regs.P23_H_ACCUM_INIT ); radeon_out32( mmio, DISP_MERGE_CNTL, rovl->regs.MERGE_CNTL ); radeon_out32( mmio, OV0_KEY_CNTL, rovl->regs.KEY_CNTL ); radeon_out32( mmio, OV0_SCALE_CNTL, rovl->regs.SCALE_CNTL ); radeon_out32( mmio, OV0_REG_LOAD_CNTL, 0 ); } static void ovl_set_buffers( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl ) { RadeonDeviceData *rdev = rdrv->device_data; volatile u8 *mmio = rdrv->mmio_base; radeon_waitfifo( rdrv, rdev, 1 ); radeon_out32( mmio, OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK ); while(!(radeon_in32( mmio, OV0_REG_LOAD_CNTL ) & REG_LD_CTL_LOCK_READBACK)); radeon_waitfifo( rdrv, rdev, 8 ); radeon_out32( mmio, OV0_BASE_ADDR, rovl->regs.BASE_ADDR ); radeon_out32( mmio, OV0_VID_BUF0_BASE_ADRS, rovl->regs.VID_BUF0_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF1_BASE_ADRS, rovl->regs.VID_BUF1_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF2_BASE_ADRS, rovl->regs.VID_BUF2_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF3_BASE_ADRS, rovl->regs.VID_BUF3_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF4_BASE_ADRS, rovl->regs.VID_BUF4_BASE_ADRS ); radeon_out32( mmio, OV0_VID_BUF5_BASE_ADRS, rovl->regs.VID_BUF5_BASE_ADRS ); radeon_out32( mmio, OV0_REG_LOAD_CNTL, 0 ); } static void ovl_set_colorkey( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, CoreLayerRegionConfig *config ) { volatile u8 *mmio = rdrv->mmio_base; u32 SkeyLow, SkeyHigh; u32 DkeyLow, DkeyHigh; u32 tmp; SkeyLow = PIXEL_RGB32( config->src_key.r, config->src_key.g, config->src_key.b ); SkeyHigh = SkeyLow | 0xff000000; tmp = radeon_in32( mmio, rovl->crtc2 ? CRTC2_GEN_CNTL : CRTC_GEN_CNTL ); switch ((tmp >> 8) & 0xf) { case DST_8BPP: case DST_8BPP_RGB332: DkeyLow = ((MAX( config->dst_key.r - 0x20, 0 ) & 0xe0) << 16) | ((MAX( config->dst_key.g - 0x20, 0 ) & 0xe0) << 8) | ((MAX( config->dst_key.b - 0x40, 0 ) & 0xc0) ); break; case DST_15BPP: DkeyLow = ((MAX( config->dst_key.r - 0x08, 0 ) & 0xf8) << 16) | ((MAX( config->dst_key.g - 0x08, 0 ) & 0xf8) << 8) | ((MAX( config->dst_key.b - 0x08, 0 ) & 0xf8) ); break; case DST_16BPP: DkeyLow = ((MAX( config->dst_key.r - 0x08, 0 ) & 0xf8) << 16) | ((MAX( config->dst_key.g - 0x04, 0 ) & 0xfc) << 8) | ((MAX( config->dst_key.b - 0x08, 0 ) & 0xf8) ); break; default: DkeyLow = PIXEL_RGB32( config->dst_key.r, config->dst_key.g, config->dst_key.b ); break; } DkeyHigh = PIXEL_RGB32( config->dst_key.r, config->dst_key.g, config->dst_key.b ) | 0xff000000; radeon_waitfifo( rdrv, rdrv->device_data, 4 ); radeon_out32( mmio, OV0_VID_KEY_CLR_LOW, SkeyLow ); radeon_out32( mmio, OV0_VID_KEY_CLR_HIGH, SkeyHigh ); radeon_out32( mmio, OV0_GRPH_KEY_CLR_LOW, DkeyLow ); radeon_out32( mmio, OV0_GRPH_KEY_CLR_HIGH, DkeyHigh ); } static void ovl_set_adjustment( RadeonDriverData *rdrv, RadeonOverlayLayerData *rovl, float brightness, float contrast, float saturation, float hue ) { volatile u8 *mmio = rdrv->mmio_base; float HueSin, HueCos; float Luma; float RCb, RCr; float GCb, GCr; float BCb, BCr; float AdjOff, ROff, GOff, BOff; u32 dwLuma, dwROff, dwGOff, dwBOff; u32 dwRCb, dwRCr; u32 dwGCb, dwGCr; u32 dwBCb, dwBCr; HueSin = sin( hue ); HueCos = cos( hue ); Luma = contrast * +1.1678; RCb = saturation * -HueSin * +1.6007; RCr = saturation * HueCos * +1.6007; GCb = saturation * (HueCos * -0.3929 - HueSin * -0.8154); GCr = saturation * (HueCos * -0.3929 + HueCos * -0.8154); BCb = saturation * HueCos * +2.0232; BCr = saturation * HueSin * +2.0232; AdjOff = contrast * 1.1678 * brightness * 1023.0; ROff = AdjOff - Luma * 64.0 - (RCb + RCr) * 512.0; GOff = AdjOff - Luma * 64.0 - (GCb + GCr) * 512.0; BOff = AdjOff - Luma * 64.0 - (BCb + BCr) * 512.0; ROff = CLAMP( ROff, -2048.0, 2047.5 ); GOff = CLAMP( GOff, -2048.0, 2047.5 ); BOff = CLAMP( BOff, -2048.0, 2047.5 ); dwROff = ((u32)(ROff * 2.0)) & 0x1fff; dwGOff = ((u32)(GOff * 2.0)) & 0x1fff; dwBOff = ((u32)(BOff * 2.0)) & 0x1fff; dwLuma = (((u32)(Luma * 256.0)) & 0xfff) << 20; dwRCb = (((u32)(RCb * 256.0)) & 0xfff) << 4; dwRCr = (((u32)(RCr * 256.0)) & 0xfff) << 20; dwGCb = (((u32)(GCb * 256.0)) & 0xfff) << 4; dwGCr = (((u32)(GCr * 256.0)) & 0xfff) << 20; dwBCb = (((u32)(BCb * 256.0)) & 0xfff) << 4; dwBCr = (((u32)(BCr * 256.0)) & 0xfff) << 20; radeon_waitfifo( rdrv, rdrv->device_data, 6 ); radeon_out32( mmio, OV0_LIN_TRANS_A, dwRCb | dwLuma ); radeon_out32( mmio, OV0_LIN_TRANS_B, dwROff | dwRCr ); radeon_out32( mmio, OV0_LIN_TRANS_C, dwGCb | dwLuma ); radeon_out32( mmio, OV0_LIN_TRANS_D, dwGOff | dwGCr ); radeon_out32( mmio, OV0_LIN_TRANS_E, dwBCb | dwLuma ); radeon_out32( mmio, OV0_LIN_TRANS_F, dwBOff | dwBCr ); }