diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index ad62eff4..91decfc8 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -40,7 +40,8 @@ radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \ - radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o + radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o \ + amd_legacy_cbuffer.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/amd.h b/linux-core/amd.h new file mode 120000 index 00000000..b4882447 --- /dev/null +++ b/linux-core/amd.h @@ -0,0 +1 @@ +../shared-core/amd.h \ No newline at end of file diff --git a/linux-core/amd_cbuffer.h b/linux-core/amd_cbuffer.h deleted file mode 120000 index 780b9d8f..00000000 --- a/linux-core/amd_cbuffer.h +++ /dev/null @@ -1 +0,0 @@ -../shared-core/amd_cbuffer.h \ No newline at end of file diff --git a/linux-core/amd_legacy.h b/linux-core/amd_legacy.h new file mode 120000 index 00000000..1a7786fc --- /dev/null +++ b/linux-core/amd_legacy.h @@ -0,0 +1 @@ +../shared-core/amd_legacy.h \ No newline at end of file diff --git a/linux-core/amd_legacy_cbuffer.c b/linux-core/amd_legacy_cbuffer.c new file mode 120000 index 00000000..eab329b5 --- /dev/null +++ b/linux-core/amd_legacy_cbuffer.c @@ -0,0 +1 @@ +../shared-core/amd_legacy_cbuffer.c \ No newline at end of file diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index a8fba712..dbbddaf4 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -40,19 +40,15 @@ #include "drm.h" #include "drm_crtc.h" #include "radeon_ms.h" +#include "amd.h" -struct radeonfb_par { - struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; -}; static int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct amd_fb *par = info->par; + struct drm_framebuffer *fb = par->fb; struct drm_crtc *crtc = par->crtc; if (regno > 255) { @@ -87,8 +83,8 @@ static int radeonfb_setcolreg(unsigned regno, unsigned red, static int radeonfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct amd_fb *par = info->par; + struct drm_framebuffer *fb = par->fb; if (!var->pixclock) return -EINVAL; @@ -176,8 +172,8 @@ static bool radeonfb_mode_equal(struct drm_display_mode *mode1, static int radeonfb_set_par(struct fb_info *info) { - struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct amd_fb *par = info->par; + struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output; @@ -247,7 +243,9 @@ static int radeonfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode) || + par->crtc->fb != par->fb) { + par->crtc->fb = par->fb; if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) { return -EINVAL; } @@ -274,14 +272,15 @@ static struct fb_ops radeonfb_ops = { int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct fb_info *info; - struct radeonfb_par *par; + struct amd_fb *par; struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; int ret; - info = framebuffer_alloc(sizeof(struct radeonfb_par), device); + info = framebuffer_alloc(sizeof(struct amd_fb), device); if (!info){ DRM_INFO("[radeon_ms] framebuffer_alloc failed\n"); return -EINVAL; @@ -324,8 +323,10 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->fbdev = info; par = info->par; + dev_priv->fb = par; par->dev = dev; par->crtc = crtc; + par->fb = fb; info->fbops = &radeonfb_ops; strcpy(info->fix.id, "radeonfb"); info->fix.type = FB_TYPE_PACKED_PIXELS; @@ -439,16 +440,22 @@ EXPORT_SYMBOL(radeonfb_probe); int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) { - struct drm_framebuffer *fb = crtc->fb; - struct fb_info *info = fb->fbdev; - - if (info) { - unregister_framebuffer(info); - drm_bo_kunmap(&fb->kmap); - drm_bo_usage_deref_unlocked(&fb->bo); - drm_framebuffer_destroy(fb); - framebuffer_release(info); + struct drm_radeon_private *dev_priv = dev->dev_private; + struct amd_fb *fb = dev_priv->fb; + struct fb_info *info; + + if (fb == NULL || fb->fb == NULL || fb->fb->fbdev == NULL) { + DRM_INFO("[radeon_ms] %s: no crtc, or fb or fbdev\n", + __func__); + return 0; } + info = fb->fb->fbdev; + unregister_framebuffer(info); + drm_bo_kunmap(&fb->fb->kmap); + drm_bo_usage_deref_unlocked(&fb->fb->bo); + drm_framebuffer_destroy(fb->fb); + framebuffer_release(info); + dev_priv->fb = NULL; return 0; } EXPORT_SYMBOL(radeonfb_remove); diff --git a/shared-core/amd_cbuffer.h b/shared-core/amd.h similarity index 68% rename from shared-core/amd_cbuffer.h rename to shared-core/amd.h index bca05751..31cf3eff 100644 --- a/shared-core/amd_cbuffer.h +++ b/shared-core/amd.h @@ -24,14 +24,13 @@ * Authors: * Jerome Glisse */ -#ifndef __AMD_CBUFFER_H__ -#define __AMD_CBUFFER_H__ +#ifndef __AMD_H__ +#define __AMD_H__ /* struct amd_cbuffer are for command buffer, this is the structure passed * around during command validation (ie check that user have the right to * execute the given command). */ - struct amd_cbuffer_arg { struct list_head list; @@ -46,6 +45,33 @@ struct amd_cbuffer struct amd_cbuffer_arg arg_unused; struct amd_cbuffer_arg arg_used; struct amd_cbuffer_arg *args; + void *driver; +}; + +struct amd_cbuffer_checker +{ + uint32_t numof_p0_checkers; + uint32_t numof_p3_checkers; + int (*check)(struct drm_device *dev, struct amd_cbuffer *cbuffer); + int (**check_p0)(struct drm_device *dev, struct amd_cbuffer *cbuffer, + int dw_id, int reg); + int (**check_p3)(struct drm_device *dev, struct amd_cbuffer *cbuffer, + int dw_id, int op, int count); +}; + +struct amd_cbuffer_arg * +amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id); +int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer); + + +/* struct amd_fb amd is for storing amd framebuffer informations + */ +struct amd_fb +{ + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_display_mode *fb_mode; + struct drm_framebuffer *fb; }; #endif diff --git a/shared-core/amd_legacy.h b/shared-core/amd_legacy.h new file mode 100644 index 00000000..92997dcd --- /dev/null +++ b/shared-core/amd_legacy.h @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#ifndef __AMD_LEGACY_H__ +#define __AMD_LEGACY_H__ + +int amd_legacy_cbuffer_destroy(struct drm_device *dev); +int amd_legacy_cbuffer_initialize(struct drm_device *dev); + +#endif diff --git a/shared-core/amd_legacy_cbuffer.c b/shared-core/amd_legacy_cbuffer.c new file mode 100644 index 00000000..f1b7a44b --- /dev/null +++ b/shared-core/amd_legacy_cbuffer.c @@ -0,0 +1,306 @@ +/* + * Copyright 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "radeon_ms.h" +#include "amd.h" + +#define RADEON_DST_Y_X 0x1438 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_DP_CNTL 0x16c0 +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_DST_HEIGHT_WIDTH 0x143c + +struct legacy_check +{ + /* for 2D operations */ + uint32_t dp_gui_master_cntl; + uint32_t dst_offset; + uint32_t dst_pitch; + struct amd_cbuffer_arg *dst; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_h; + uint32_t dst_w; + struct amd_cbuffer_arg *src; + uint32_t src_pitch; + uint32_t src_x; + uint32_t src_y; +}; + +static int check_blit(struct drm_device *dev, struct amd_cbuffer *cbuffer) +{ + struct legacy_check *legacy_check; + long bpp, start, end; + + legacy_check = (struct legacy_check *)cbuffer->driver; + /* check that gui master cntl have been set */ + if (legacy_check->dp_gui_master_cntl == 0xffffffff) { + return -EINVAL; + } + switch ((legacy_check->dp_gui_master_cntl >> 8) & 0xf) { + case 2: + bpp = 1; + break; + case 3: + case 4: + bpp = 2; + break; + case 6: + bpp = 4; + break; + default: + return -EINVAL; + } + /* check that a destination have been set */ + if (legacy_check->dst == (void *)-1) { + return -EINVAL; + } + if (legacy_check->dst_pitch == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_x == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_y == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_w == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_h == 0xffffffff) { + return -EINVAL; + } + /* compute start offset of blit */ + start = legacy_check->dst_pitch * legacy_check->dst_y + + legacy_check->dst_x * bpp; + /* compute end offset of blit */ + end = legacy_check->dst_pitch * legacy_check->dst_h + + legacy_check->dst_w * bpp; + /* FIXME: check that end offset is inside dst bo */ + + /* check that a destination have been set */ + if (legacy_check->dp_gui_master_cntl & 1) { + if (legacy_check->src == (void *)-1) { + return -EINVAL; + } + if (legacy_check->src_pitch == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->src_x == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->src_y == 0xffffffff) { + return -EINVAL; + } + /* compute start offset of blit */ + start = legacy_check->src_pitch * legacy_check->src_y + + legacy_check->src_x * bpp; + /* compute end offset of blit */ + end = legacy_check->src_pitch * legacy_check->dst_h + + legacy_check->dst_w * bpp + start; + /* FIXME: check that end offset is inside src bo */ + } + return 0; +} + +static int p0_dp_gui_master_cntl(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dp_gui_master_cntl = cbuffer->cbuffer[dw_id]; + /* we only accept src data type to be same as dst */ + if (((legacy_check->dp_gui_master_cntl >> 12) & 0x3) != 3) { + return -EINVAL; + } + return 0; +} + +static int p0_dst_pitch_offset(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t gpu_addr; + int ret; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; + legacy_check->dst = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, + dw_id); + if (legacy_check->dst == NULL) { + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->buffer->mem, + &gpu_addr); + if (ret) { + return -EINVAL; + } + cbuffer->cbuffer[dw_id] &= 0xffc00000; + cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + return 0; +} + +static int p0_src_pitch_offset(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t gpu_addr; + int ret; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->src_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; + legacy_check->src = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, + dw_id); + if (legacy_check->dst == NULL) { + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->buffer->mem, + &gpu_addr); + if (ret) { + return -EINVAL; + } + cbuffer->cbuffer[dw_id] &= 0xffc00000; + cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + return 0; +} + +static int p0_dst_y_x(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_x = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->dst_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_src_y_x(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->src_x = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->src_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_dst_h_w(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_w = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->dst_h = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return check_blit(dev, cbuffer); +} + +static int legacy_cbuffer_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer) +{ + struct legacy_check legacy_check; + + memset(&legacy_check, 0xff, sizeof(struct legacy_check)); + cbuffer->driver = &legacy_check; + return amd_cbuffer_check(dev, cbuffer); +} + +int amd_legacy_cbuffer_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->cbuffer_checker.check = NULL; + if (dev_priv->cbuffer_checker.numof_p0_checkers) { + drm_free(dev_priv->cbuffer_checker.check_p0, + dev_priv->cbuffer_checker.numof_p0_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cbuffer_checker.numof_p0_checkers = 0; + } + if (dev_priv->cbuffer_checker.numof_p3_checkers) { + drm_free(dev_priv->cbuffer_checker.check_p3, + dev_priv->cbuffer_checker.numof_p3_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cbuffer_checker.numof_p3_checkers = 0; + } + return 0; +} + +int amd_legacy_cbuffer_initialize(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct amd_cbuffer_checker *checker = &dev_priv->cbuffer_checker; + long size; + + /* packet 0 */ + checker->numof_p0_checkers = 0x5000 >> 2; + size = checker->numof_p0_checkers * sizeof(void*); + checker->check_p0 = drm_alloc(size, DRM_MEM_DRIVER); + if (checker->check_p0 == NULL) { + amd_legacy_cbuffer_destroy(dev); + return -ENOMEM; + } + /* initialize to -1 */ + memset(checker->check_p0, 0xff, size); + + /* packet 3 */ + checker->numof_p3_checkers = 20; + size = checker->numof_p3_checkers * sizeof(void*); + checker->check_p3 = drm_alloc(size, DRM_MEM_DRIVER); + if (checker->check_p3 == NULL) { + amd_legacy_cbuffer_destroy(dev); + return -ENOMEM; + } + /* initialize to -1 */ + memset(checker->check_p3, 0xff, size); + + /* initialize packet0 checker */ + checker->check_p0[RADEON_DST_Y_X >> 2] = p0_dst_y_x; + checker->check_p0[RADEON_SRC_Y_X >> 2] = p0_src_y_x; + checker->check_p0[RADEON_DST_HEIGHT_WIDTH >> 2] = p0_dst_h_w; + checker->check_p0[RADEON_DST_PITCH_OFFSET >> 2] = p0_dst_pitch_offset; + checker->check_p0[RADEON_SRC_PITCH_OFFSET >> 2] = p0_src_pitch_offset; + checker->check_p0[RADEON_DP_GUI_MASTER_CNTL>>2] = p0_dp_gui_master_cntl; + checker->check_p0[RADEON_DP_BRUSH_FRGD_CLR >> 2] = NULL; + checker->check_p0[RADEON_DP_WRITE_MASK >> 2] = NULL; + checker->check_p0[RADEON_DP_CNTL >> 2] = NULL; + + checker->check = legacy_cbuffer_check; + return 0; +} diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index e4010d84..ec264207 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -35,7 +35,8 @@ #include "radeon_ms_drm.h" #include "radeon_ms_rom.h" #include "radeon_ms_properties.h" -#include "amd_cbuffer.h" +#include "amd.h" +#include "amd_legacy.h" #define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ "Keith Whitwell, others." @@ -292,6 +293,8 @@ struct drm_radeon_private { uint32_t *ring_buffer; uint32_t *write_back_area; const uint32_t *microcode; + /* framebuffer */ + struct amd_fb *fb; /* card family */ uint32_t usec_timeout; uint32_t family; @@ -326,6 +329,8 @@ struct drm_radeon_private { uint8_t cp_ready; uint8_t bus_ready; uint8_t write_back; + /* command buffer informations */ + struct amd_cbuffer_checker cbuffer_checker; /* abstract asic specific structures */ struct radeon_ms_rom rom; struct radeon_ms_properties properties; diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index b2383859..83dd0777 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -537,6 +537,10 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, adjusted_mode->hsync_end, adjusted_mode->htotal, adjusted_mode->vdisplay, adjusted_mode->vsync_start, adjusted_mode->vsync_end, adjusted_mode->vtotal, adjusted_mode->type); + if (crtc->fb == NULL) { + DRM_INFO("[radeon_ms] no FB bound\n"); + return; + } /* only support RGB555,RGB565,ARGB8888 should satisfy all users */ switch (crtc->fb->bits_per_pixel) { @@ -551,7 +555,7 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, format = 6; break; default: - DRM_ERROR("Unknown color depth\n"); + DRM_ERROR("Unknown color depth %d\n", crtc->fb->bits_per_pixel); return; } radeon_pll1_compute(crtc, adjusted_mode); @@ -638,6 +642,17 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, radeon_ms_crtc1_restore(dev, state); } +static void radeon_ms_crtc1_mode_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + DRM_INFO("[radeon_ms] mode_set_base\n"); + state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset); + radeon_ms_crtc1_restore(dev, state); +} + static void radeon_ms_crtc_mode_commit(struct drm_crtc *crtc) { crtc->funcs->dpms(crtc, DPMSModeOn); @@ -651,6 +666,10 @@ static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, struct radeon_state *state = &dev_priv->driver_state; uint32_t color; + if (regno >= 256) { + return; + } + DRM_INFO("[radeon_ms] gamma[%d]=(%d, %d, %d)\n", regno, r, g, b); switch(radeon_ms_crtc->crtc) { case 1: state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL; @@ -660,70 +679,22 @@ static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, break; } MMIO_W(DAC_CNTL2, state->dac_cntl2); - if (crtc->fb->bits_per_pixel == 16 && crtc->fb->depth == 16) { - if (regno >= 64) { - return; - } - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 4)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno * 4)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); - MMIO_W(PALETTE_30_DATA, color); - radeon_ms_crtc->lut_r[regno * 4] = r; - radeon_ms_crtc->lut_g[regno * 4] = g; - radeon_ms_crtc->lut_b[regno * 4] = b; - if (regno < 32) { - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 8)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 8)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R,r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G,g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B,b >> 6); - MMIO_W(PALETTE_30_DATA, color); - radeon_ms_crtc->lut_r[regno * 8] = r; - radeon_ms_crtc->lut_g[regno * 8] = g; - radeon_ms_crtc->lut_b[regno * 8] = b; - } - } else { - if (regno >= 256) { - return; - } - radeon_ms_crtc->lut_r[regno] = r; - radeon_ms_crtc->lut_g[regno] = g; - radeon_ms_crtc->lut_b[regno] = b; - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); - } + radeon_ms_crtc->lut_r[regno] = r; + radeon_ms_crtc->lut_g[regno] = g; + radeon_ms_crtc->lut_b[regno] = b; + MMIO_W(PALETTE_INDEX, REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); + MMIO_W(PALETTE_DATA, color); + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); + MMIO_W(PALETTE_30_DATA, color); } static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc) @@ -762,6 +733,7 @@ static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { .commit = radeon_ms_crtc_mode_commit, .mode_fixup = radeon_ms_crtc_mode_fixup, .mode_set = radeon_ms_crtc1_mode_set, + .mode_set_base = radeon_ms_crtc1_mode_set_base, .gamma_set = radeon_ms_crtc_gamma_set, .cleanup = NULL, /* XXX */ }; diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 869ccac4..0d327925 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -246,6 +246,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } + /* initialze driver specific */ + ret = amd_legacy_cbuffer_initialize(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + if (dev->primary && dev->control) { DRM_INFO("[radeon_ms] control 0x%lx, render 0x%lx\n", (long)dev->primary->device, (long)dev->control->device); @@ -277,6 +284,9 @@ int radeon_ms_driver_unload(struct drm_device *dev) radeon_ms_outputs_restore(dev, &dev_priv->load_state); radeon_ms_connectors_destroy(dev); radeon_ms_outputs_destroy(dev); + + /* shutdown specific driver */ + amd_legacy_cbuffer_destroy(dev); /* shutdown cp engine */ radeon_ms_cp_finish(dev); diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 574e5a06..28fcc180 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -25,7 +25,7 @@ * Jerome Glisse */ #include "radeon_ms.h" -#include "amd_cbuffer.h" +#include "amd.h" static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, struct amd_cbuffer *cbuffer, @@ -118,33 +118,103 @@ out_err: return ret; } -enum { - REGISTER_FORBIDDEN = 0, - REGISTER_SAFE, - REGISTER_SET_OFFSET, -}; -static uint8_t _r3xx_register_right[0x5000 >> 2]; - -static int amd_cbuffer_packet0_set_offset(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - uint32_t reg, int dw_id, - struct amd_cbuffer_arg *arg) +static int cbuffer_packet0_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id) { - uint32_t gpu_addr; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t reg, count, r, i; int ret; - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, &gpu_addr); - if (ret) { - return ret; - } - switch (reg) { - default: + reg = cbuffer->cbuffer[dw_id] & PACKET0_REG_MASK; + count = (cbuffer->cbuffer[dw_id] & PACKET0_COUNT_MASK) >> + PACKET0_COUNT_SHIFT; + if (reg + count > dev_priv->cbuffer_checker.numof_p0_checkers) { return -EINVAL; } + for (r = reg, i = 0; i <= count; i++, r++) { + if (dev_priv->cbuffer_checker.check_p0[r] == NULL) { + continue; + } + if (dev_priv->cbuffer_checker.check_p0[r] == (void *)-1) { + DRM_INFO("[radeon_ms] check_f: %d %d -1 checker\n", + r, r << 2); + return -EINVAL; + } + ret = dev_priv->cbuffer_checker.check_p0[r](dev, cbuffer, + dw_id + i + 1, reg); + if (ret) { + DRM_INFO("[radeon_ms] check_f: %d %d checker ret=%d\n", + r, r << 2, ret); + return -EINVAL; + } + } + /* header + N + 1 dword passed test */ + return count + 2; +} + +static int cbuffer_packet3_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t opcode, count; + int ret; + + opcode = (cbuffer->cbuffer[dw_id] & PACKET3_OPCODE_MASK) >> + PACKET3_OPCODE_SHIFT; + if (opcode > dev_priv->cbuffer_checker.numof_p3_checkers) { + return -EINVAL; + } + count = (cbuffer->cbuffer[dw_id] & PACKET3_COUNT_MASK) >> + PACKET3_COUNT_SHIFT; + if (dev_priv->cbuffer_checker.check_p3[opcode] == NULL) { + return -EINVAL; + } + ret = dev_priv->cbuffer_checker.check_p3[opcode](dev, cbuffer, + dw_id + 1, opcode, + count); + if (ret) { + return -EINVAL; + } + return count + 2; +} + +int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer) +{ + uint32_t i; + int ret; + + for (i = 0; i < cbuffer->cbuffer_dw_count;) { + switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { + case 0: + ret = cbuffer_packet0_check(dev, cbuffer, i); + if (ret <= 0) { + return ret; + } + /* advance to next packet */ + i += ret; + break; + case 1: + /* we don't accept packet 1 */ + return -EINVAL; + case 2: + /* FIXME: accept packet 2 */ + return -EINVAL; + case 3: + ret = cbuffer_packet3_check(dev, cbuffer, i); + if (ret <= 0) { + return ret; + } + /* advance to next packet */ + i += ret; + break; + } + } return 0; } -static struct amd_cbuffer_arg * +struct amd_cbuffer_arg * amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) { struct amd_cbuffer_arg *arg; @@ -158,164 +228,11 @@ amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) return NULL; } -static int amd_cbuffer_packet0_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer, - int dw_id, - uint8_t *register_right) -{ - struct amd_cbuffer_arg *arg; - uint32_t reg, count, r, i; - int ret; - - reg = cbuffer->cbuffer[dw_id] & PACKET0_REG_MASK; - count = (cbuffer->cbuffer[dw_id] & PACKET0_COUNT_MASK) >> - PACKET0_COUNT_SHIFT; - for (r = reg, i = 0; i <= count; i++, r++) { - switch (register_right[i]) { - case REGISTER_FORBIDDEN: - return -EINVAL; - case REGISTER_SAFE: - break; - case REGISTER_SET_OFFSET: - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, - dw_id + i +1); - if (arg == NULL) { - return -EINVAL; - } - /* remove from unparsed list */ - list_del(&arg->list); - list_add_tail(&arg->list, &cbuffer->arg_used.list); - /* set the offset */ - ret = amd_cbuffer_packet0_set_offset(dev, cbuffer, - r, dw_id + i + 1, - arg); - if (ret) { - return ret; - } - break; - } - } - /* header + N + 1 dword passed test */ - return count + 2; -} - -static int amd_cbuffer_packet3_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer, - int dw_id) -{ - struct amd_cbuffer_arg *arg; - uint32_t opcode, count; - uint32_t s_auth, s_mask; - uint32_t gpu_addr; - int ret; - - opcode = (cbuffer->cbuffer[dw_id] & PACKET3_OPCODE_MASK) >> - PACKET3_OPCODE_SHIFT; - count = (cbuffer->cbuffer[dw_id] & PACKET3_COUNT_MASK) >> - PACKET3_COUNT_SHIFT; - switch (opcode) { - case PACKET3_OPCODE_NOP: - break; - case PACKET3_OPCODE_BITBLT: - case PACKET3_OPCODE_BITBLT_MULTI: - DRM_INFO("[radeon_ms] exec step - [05][P3]00.00\n"); - /* we only alow simple blit */ - if (count != 5) { - return -EINVAL; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]01.00\n"); - s_mask = 0xf; - s_auth = 0x3; - if ((cbuffer->cbuffer[dw_id + 1] & s_mask) != s_auth) { - return -EINVAL; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]02.00\n"); - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+2); - if (arg == NULL) { - return -EINVAL; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]03.00\n"); - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, - &gpu_addr); - if (ret) { - return ret; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]04.00\n"); - gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; - cbuffer->cbuffer[dw_id + 2] &= 0xFFC00000; - cbuffer->cbuffer[dw_id + 2] |= gpu_addr; - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+3); - if (arg == NULL) { - return -EINVAL; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]05.00\n"); - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, - &gpu_addr); - if (ret) { - return ret; - } - DRM_INFO("[radeon_ms] exec step - [05][P3]06.00\n"); - gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; - cbuffer->cbuffer[dw_id + 3] &= 0xFFC00000; - cbuffer->cbuffer[dw_id + 3] |= gpu_addr; - DRM_INFO("[radeon_ms] exec step - [05][P3]07.00\n"); - /* FIXME: check that source & destination are big enough - * for requested blit */ - break; - default: - return -EINVAL; - } - /* header + N + 1 dword passed test */ - return count + 2; -} - -static int amd_cbuffer_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer) -{ - uint32_t i; - int ret; - - for (i = 0; i < cbuffer->cbuffer_dw_count;) { - DRM_INFO("[radeon_ms] exec step - [05]00.00 %d 0x%08X\n", - i, cbuffer->cbuffer[i]); - switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { - case 0: - ret = amd_cbuffer_packet0_check(dev, file_priv, - cbuffer, i, - _r3xx_register_right); - if (ret) { - return ret; - } - /* advance to next packet */ - i += ret; - break; - case 1: - /* we don't accept packet 1 */ - return -EINVAL; - case 2: - /* packet 2 */ - i += 1; - break; - case 3: - ret = amd_cbuffer_packet3_check(dev, file_priv, - cbuffer, i); - if (ret) { - return ret; - } - /* advance to next packet */ - i += ret; - break; - } - } - return 0; -} int radeon_ms_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_radeon_execbuffer *execbuffer = data; struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; struct drm_bo_kmap_obj cmd_kmap; @@ -331,13 +248,11 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, /* FIXME: Lock buffer manager, is this really needed ? */ - DRM_INFO("[radeon_ms] exec step - 00.00\n"); ret = drm_bo_read_lock(&dev->bm.bm_lock); if (ret) { return ret; } - DRM_INFO("[radeon_ms] exec step - 01.00\n"); cbuffer.args = drm_calloc(execbuffer->args_count, sizeof(struct amd_cbuffer_arg), DRM_MEM_DRIVER); @@ -350,7 +265,6 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, INIT_LIST_HEAD(&cbuffer.arg_used.list); /* process arguments */ - DRM_INFO("[radeon_ms] exec step - 02.00\n"); ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, &cbuffer); if (ret) { DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); @@ -358,14 +272,12 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, } /* map command buffer */ - DRM_INFO("[radeon_ms] exec step - 03.00\n"); cbuffer.cbuffer_dw_count = (cbuffer.args[0].buffer->mem.num_pages * PAGE_SIZE) >> 2; if (execbuffer->cmd_size > cbuffer.cbuffer_dw_count) { ret = -EINVAL; goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 04.00\n"); cbuffer.cbuffer_dw_count = execbuffer->cmd_size; memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); ret = drm_bo_kmap(cbuffer.args[0].buffer, 0, @@ -374,21 +286,21 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 05.00\n"); cbuffer.cbuffer = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); - DRM_INFO("[radeon_ms] exec step - 05.01\n"); list_del(&cbuffer.args[0].list); - DRM_INFO("[radeon_ms] exec step - 05.02\n"); list_add_tail(&cbuffer.args[0].list , &cbuffer.arg_used.list); - DRM_INFO("[radeon_ms] exec step - 05.03\n"); /* do cmd checking & relocations */ - ret = amd_cbuffer_check(dev, file_priv, &cbuffer); - if (ret) { + if (dev_priv->cbuffer_checker.check) { + ret = dev_priv->cbuffer_checker.check(dev, &cbuffer); + if (ret) { + drm_putback_buffer_objects(dev); + goto out_free_release; + } + } else { drm_putback_buffer_objects(dev); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 06.00\n"); ret = radeon_ms_ring_emit(dev, cbuffer.cbuffer, cbuffer.cbuffer_dw_count); @@ -396,7 +308,6 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, drm_putback_buffer_objects(dev); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 07.00\n"); /* fence */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); @@ -418,16 +329,13 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, } } drm_fence_usage_deref_unlocked(&fence); - DRM_INFO("[radeon_ms] exec step - 08.00\n"); out_free_release: drm_bo_kunmap(&cmd_kmap); radeon_ms_execbuffer_args_clean(dev, &cbuffer, execbuffer->args_count); - DRM_INFO("[radeon_ms] exec step - 09.00\n"); out_free: drm_free(cbuffer.args, (execbuffer->args_count * sizeof(struct amd_cbuffer_arg)), DRM_MEM_DRIVER); drm_bo_read_unlock(&dev->bm.bm_lock); - DRM_INFO("[radeon_ms] exec step - 10.00\n"); return ret; }