diff options
Diffstat (limited to 'shared-core')
49 files changed, 13703 insertions, 725 deletions
diff --git a/shared-core/Makefile.am b/shared-core/Makefile.am index 7193e527..42e08e75 100644 --- a/shared-core/Makefile.am +++ b/shared-core/Makefile.am @@ -32,6 +32,7 @@ klibdrminclude_HEADERS = \ nouveau_drm.h \ r128_drm.h \ radeon_drm.h \ + radeon_ms_drm.h \ savage_drm.h \ sis_drm.h \ via_drm.h \ diff --git a/shared-core/amd.h b/shared-core/amd.h new file mode 100644 index 00000000..f8096053 --- /dev/null +++ b/shared-core/amd.h @@ -0,0 +1,94 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#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_cmd_bo +{ + struct list_head list; + uint64_t *offsets; + uint32_t *cdw_id; + struct drm_buffer_object *bo; + unsigned int handle; + uint64_t mask; + uint64_t flags; + uint32_t type; +}; + +struct amd_cmd +{ + uint32_t *cdw; + uint32_t cdw_count; + struct drm_bo_kmap_obj cdw_kmap; + size_t cdw_size; + struct amd_cmd_bo *cdw_bo; + struct amd_cmd_bo bo_unused; + struct amd_cmd_bo bo_used; + struct amd_cmd_bo *bo; + uint32_t bo_count; + void *driver; +}; + +struct amd_cmd_module +{ + uint32_t numof_p0_checkers; + uint32_t numof_p3_checkers; + int (*check)(struct drm_device *dev, struct amd_cmd *cmd); + int (**check_p0)(struct drm_device *dev, struct amd_cmd *cmd, + int cdw_id, int reg); + int (**check_p3)(struct drm_device *dev, struct amd_cmd *cmd, + int cdw_id, int op, int count); +}; + +int amd_cmd_check(struct drm_device *dev, struct amd_cmd *cmd); +int amd_ioctl_cmd(struct drm_device *dev, void *data, struct drm_file *file); + +static inline struct amd_cmd_bo *amd_cmd_get_bo(struct amd_cmd *cmd, int i) +{ + if (i < cmd->bo_count && cmd->bo[i].type == DRM_AMD_CMD_BO_TYPE_DATA) { + list_del(&cmd->bo[i].list); + list_add_tail(&cmd->bo[i].list, &cmd->bo_used.list); + return &cmd->bo[i]; + } + return NULL; +} + +/* 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..c1e5f5da --- /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 <glisse@freedesktop.org> + */ +#ifndef __AMD_LEGACY_H__ +#define __AMD_LEGACY_H__ + +int amd_legacy_cmd_module_destroy(struct drm_device *dev); +int amd_legacy_cmd_module_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..7971ee67 --- /dev/null +++ b/shared-core/amd_legacy_cbuffer.c @@ -0,0 +1,320 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#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_cmd_bo *dst; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_h; + uint32_t dst_w; + struct amd_cmd_bo *src; + uint32_t src_pitch; + uint32_t src_x; + uint32_t src_y; +}; + +static int check_blit(struct drm_device *dev, struct amd_cmd *cmd) +{ + struct legacy_check *legacy_check; + long bpp, start, end; + + legacy_check = (struct legacy_check *)cmd->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_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dp_gui_master_cntl = cmd->cdw[cdw_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_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t tmp; + int ret; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6; + tmp = cmd->cdw[cdw_id] & 0x003fffff; + legacy_check->dst = amd_cmd_get_bo(cmd, tmp); + if (legacy_check->dst == NULL) { + DRM_ERROR("invalid bo (%d) for DST_PITCH_OFFSET register.\n", + tmp); + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->bo->mem, &tmp); + if (ret) { + DRM_ERROR("failed to get GPU offset for bo 0x%x.\n", + legacy_check->dst->handle); + return -EINVAL; + } + if (tmp & 0x3fff) { + DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n", + legacy_check->dst->handle, tmp); + } + cmd->cdw[cdw_id] &= 0xffc00000; + cmd->cdw[cdw_id] |= (tmp >> 10); + return 0; +} + +static int p0_src_pitch_offset(struct drm_device *dev, + struct amd_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t tmp; + int ret; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->src_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6; + tmp = cmd->cdw[cdw_id] & 0x003fffff; + legacy_check->src = amd_cmd_get_bo(cmd, tmp); + if (legacy_check->src == NULL) { + DRM_ERROR("invalid bo (%d) for SRC_PITCH_OFFSET register.\n", + tmp); + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->bo->mem, &tmp); + if (ret) { + DRM_ERROR("failed to get GPU offset for bo 0x%x.\n", + legacy_check->src->handle); + return -EINVAL; + } + if (tmp & 0x3fff) { + DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n", + legacy_check->src->handle, tmp); + } + cmd->cdw[cdw_id] &= 0xffc00000; + cmd->cdw[cdw_id] |= (tmp >> 10); + return 0; +} + +static int p0_dst_y_x(struct drm_device *dev, + struct amd_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_x = cmd->cdw[cdw_id] & 0xffff; + legacy_check->dst_y = (cmd->cdw[cdw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_src_y_x(struct drm_device *dev, + struct amd_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->src_x = cmd->cdw[cdw_id] & 0xffff; + legacy_check->src_y = (cmd->cdw[cdw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_dst_h_w(struct drm_device *dev, + struct amd_cmd *cmd, + int cdw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_w = cmd->cdw[cdw_id] & 0xffff; + legacy_check->dst_h = (cmd->cdw[cdw_id] >> 16) & 0xffff; + return check_blit(dev, cmd); +} + +static int legacy_cmd_check(struct drm_device *dev, + struct amd_cmd *cmd) +{ + struct legacy_check legacy_check; + + memset(&legacy_check, 0xff, sizeof(struct legacy_check)); + cmd->driver = &legacy_check; + return amd_cmd_check(dev, cmd); +} + +int amd_legacy_cmd_module_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->cmd_module.check = NULL; + if (dev_priv->cmd_module.numof_p0_checkers) { + drm_free(dev_priv->cmd_module.check_p0, + dev_priv->cmd_module.numof_p0_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cmd_module.numof_p0_checkers = 0; + } + if (dev_priv->cmd_module.numof_p3_checkers) { + drm_free(dev_priv->cmd_module.check_p3, + dev_priv->cmd_module.numof_p3_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cmd_module.numof_p3_checkers = 0; + } + return 0; +} + +int amd_legacy_cmd_module_initialize(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct amd_cmd_module *checker = &dev_priv->cmd_module; + 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_cmd_module_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_cmd_module_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_cmd_check; + return 0; +} diff --git a/shared-core/amd_legacy_fence.h b/shared-core/amd_legacy_fence.h new file mode 100644 index 00000000..d82138ba --- /dev/null +++ b/shared-core/amd_legacy_fence.h @@ -0,0 +1,39 @@ +/* + * 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: + * Dave Airlie + * Jerome Glisse <glisse@freedesktop.org> + */ +#ifndef __AMD_LEGACY_FENCE_H__ +#define __AMD_LEGACY_FENCE_H__ + +struct legacy_fence +{ + uint32_t sequence; + uint32_t sequence_last_reported; + uint32_t sequence_last_flush; + uint32_t fence_reg; +}; + +#endif diff --git a/shared-core/drm.h b/shared-core/drm.h index 7f1ccd1d..dd03bf9b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -236,7 +236,7 @@ enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ - _DRM_TTM = 6 + _DRM_TTM = 6, }; /** @@ -555,9 +555,43 @@ union drm_wait_vblank { struct drm_wait_vblank_reply reply; }; +/* Handle monitor hotplug. + * + * May want to extend this later to pass reply information which + * details the connectors which generated the hotplug event. + * Some chipsets can't determine that though, and we'd need to leave + * it to the higher levels to determine exactly what changed. + */ +enum drm_hotplug_seq_type { + _DRM_HOTPLUG_SIGNAL = 0x00000001, /**< Send signal instead of blocking */ +}; +struct drm_wait_hotplug_request { + enum drm_hotplug_seq_type type; + unsigned long signal; +}; + +struct drm_wait_hotplug_reply { + enum drm_hotplug_seq_type type; + unsigned int counter; + long tval_sec; + long tval_usec; +}; + +/** + * DRM_IOCTL_WAIT_HOTPLUG ioctl argument type. + * + * \sa drmWaitHotplug(). + */ +union drm_wait_hotplug { + struct drm_wait_hotplug_request request; + struct drm_wait_hotplug_reply reply; +}; + +enum drm_modeset_ctl_cmd { + _DRM_PRE_MODESET = 1, + _DRM_POST_MODESET = 2, +}; -#define _DRM_PRE_MODESET 1 -#define _DRM_POST_MODESET 2 /** * DRM_IOCTL_MODESET_CTL ioctl argument type @@ -959,6 +993,275 @@ struct drm_mm_info_arg { uint64_t p_size; }; +struct drm_gem_close { + /** Handle of the object to be closed. */ + uint32_t handle; + uint32_t pad; +}; + +struct drm_gem_flink { + /** Handle for the object being named */ + uint32_t handle; + + /** Returned global name */ + uint32_t name; +}; + +struct drm_gem_open { + /** Name of object being opened */ + uint32_t name; + + /** Returned handle for the object */ + uint32_t handle; + + /** Returned size of the object */ + uint64_t size; +}; + +/* + * Drm mode setting + */ +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_CONNECTOR_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +/* Video mode flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) +#define DRM_MODE_FLAG_PIXMUX (1<<11) +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) + +/* DPMS flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 + +/* Scaling mode options */ +#define DRM_MODE_SCALE_NON_GPU 0 +#define DRM_MODE_SCALE_FULLSCREEN 1 +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_SCALE_ASPECT 3 + +/* Dithering mode options */ +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 + +struct drm_mode_modeinfo { + unsigned int clock; + unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; + unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + + unsigned int vrefresh; /* vertical refresh * 1000 */ + + unsigned int flags; + unsigned int type; + char name[DRM_DISPLAY_MODE_LEN]; +}; + +struct drm_mode_card_res { + uint64_t fb_id_ptr; + uint64_t crtc_id_ptr; + uint64_t connector_id_ptr; + uint64_t encoder_id_ptr; + int count_fbs; + int count_crtcs; + int count_connectors; + int count_encoders; + int min_width, max_width; + int min_height, max_height; +}; + +struct drm_mode_crtc { + uint64_t set_connectors_ptr; + int count_connectors; + + unsigned int crtc_id; /**< Id */ + unsigned int fb_id; /**< Id of framebuffer */ + + int x, y; /**< Position on the frameuffer */ + + uint32_t gamma_size; + int mode_valid; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 + +struct drm_mode_get_encoder { + + unsigned int encoder_type; + unsigned int encoder_id; + + unsigned int crtc_id; /**< Id of crtc */ + + uint32_t possible_crtcs; + uint32_t possible_clones; +}; + +/* This is for connectors with multiple signal types. */ +/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 + +struct drm_mode_get_connector { + + uint64_t encoders_ptr; + uint64_t modes_ptr; + uint64_t props_ptr; + uint64_t prop_values_ptr; + + int count_modes; + int count_props; + int count_encoders; + + unsigned int encoder_id; /**< Current Encoder */ + unsigned int connector_id; /**< Id */ + unsigned int connector_type; + unsigned int connector_type_id; + + unsigned int connection; + unsigned int mm_width, mm_height; /**< HxW in millimeters */ + unsigned int subpixel; +}; + +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings +#define DRM_MODE_PROP_BLOB (1<<4) + +struct drm_mode_property_enum { + uint64_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { + uint64_t values_ptr; /* values and blob lengths */ + uint64_t enum_blob_ptr; /* enum and blob id ptrs */ + + unsigned int prop_id; + unsigned int flags; + unsigned char name[DRM_PROP_NAME_LEN]; + + int count_values; + int count_enum_blobs; +}; + +struct drm_mode_connector_set_property { + uint64_t value; + unsigned int prop_id; + unsigned int connector_id; +}; + +struct drm_mode_get_blob { + uint32_t blob_id; + uint32_t length; + uint64_t data; +}; + +struct drm_mode_fb_cmd { + unsigned int buffer_id; + unsigned int width, height; + unsigned int pitch; + unsigned int bpp; + unsigned int handle; + unsigned int depth; +}; + +struct drm_mode_mode_cmd { + unsigned int connector_id; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 + +/* + * depending on the value in flags diffrent members are used. + * + * CURSOR_BO uses + * crtc + * width + * height + * handle - if 0 turns the cursor of + * + * CURSOR_MOVE uses + * crtc + * x + * y + */ +struct drm_mode_cursor { + unsigned int flags; + unsigned int crtc; + int x; + int y; + uint32_t width; + uint32_t height; + unsigned int handle; +}; + +/* + * oh so ugly hotplug + */ +struct drm_mode_hotplug { + uint32_t counter; +}; + +struct drm_mode_crtc_lut { + + uint32_t crtc_id; + uint32_t gamma_size; + + uint64_t red; + uint64_t green; + uint64_t blue; +}; + /** * \name Ioctls Definitions */ @@ -978,7 +1281,11 @@ struct drm_mm_info_arg { #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) -#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) + +#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) +#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) +#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) @@ -997,6 +1304,9 @@ struct drm_mm_info_arg { #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) #define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) +#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) +#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) + #define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) #define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) @@ -1052,6 +1362,29 @@ struct drm_mm_info_arg { #define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) #define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) +#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA2, struct drm_mode_get_connector) +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) + +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xA7, struct drm_mode_connector_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) + +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) +#define DRM_IOCTL_WAIT_HOTPLUG DRM_IOWR(0xAE, union drm_wait_hotplug) + +#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xB0, struct drm_mode_get_encoder) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xB1, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xB2, struct drm_mode_crtc_lut) + /*@}*/ /** diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 205fc539..0c45b4c1 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -1,3 +1,7 @@ +[radeon_ms] +0x1002 0x4150 CHIP_RV350|RADEON_AGP "ATI Radeon RV350 9600" +0x1002 0x5b63 CHIP_RV370|RADEON_PCIE "ATI Radeon RV370 X550" + [radeon] 0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24" 0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X300 M24" diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 47f1f463..8d09828a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -38,13 +38,17 @@ */ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_ring_buffer *ring = &(dev_priv->ring); u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + u32 acthd_reg = IS_I965G(dev) ? I965REG_ACTHD : I915REG_ACTHD; + u32 last_acthd = I915_READ(acthd_reg); + u32 acthd; int i; for (i = 0; i < 10000; i++) { ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + acthd = I915_READ(acthd_reg); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -54,17 +58,50 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) if (ring->head != last_head) i = 0; + if (acthd != last_acthd) + i = 0; + last_head = ring->head; - DRM_UDELAY(1); + last_acthd = acthd; + msleep_interruptible (10); } return -EBUSY; } -void i915_kernel_lost_context(struct drm_device * dev) +#if I915_RING_VALIDATE +/** + * Validate the cached ring tail value + * + * If the X server writes to the ring and DRM doesn't + * reload the head and tail pointers, it will end up writing + * data to the wrong place in the ring, causing havoc. + */ +void i915_ring_validate(struct drm_device *dev, const char *func, int line) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 tail = I915_READ(LP_RING+RING_TAIL) & HEAD_ADDR; + u32 head = I915_READ(LP_RING+RING_HEAD) & HEAD_ADDR; + + if (tail != ring->tail) { + DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n", + func, line, + ring->head, head, ring->tail, tail); + BUG_ON(1); + } +} +#endif + +void i915_kernel_lost_context(struct drm_device * dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_ring_buffer *ring = &(dev_priv->ring); + + /* we should never lose context on the ring with modesetting + * as we don't expose it to userspace */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; @@ -73,40 +110,45 @@ void i915_kernel_lost_context(struct drm_device * dev) ring->space += ring->Size; } -static int i915_dma_cleanup(struct drm_device * dev) +int i915_dma_cleanup(struct drm_device * dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if (dev->irq) + if (dev->irq_enabled) drm_irq_uninstall(dev); - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - dev_priv->ring.virtual_start = 0; - dev_priv->ring.map.handle = 0; - dev_priv->ring.map.size = 0; - } - - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - dev_priv->status_page_dmah = NULL; - /* Need to rewrite hardware status page */ - I915_WRITE(0x02080, 0x1ffff000); - } - - if (dev_priv->status_gfx_addr) { - dev_priv->status_gfx_addr = 0; - drm_core_ioremapfree(&dev_priv->hws_map, dev); - I915_WRITE(0x02080, 0x1ffff000); - } + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = 0; + dev_priv->ring.map.handle = 0; + dev_priv->ring.map.size = 0; + dev_priv->ring.Size = 0; + } + + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); + } + + if (dev_priv->hws_agpoffset) { + dev_priv->hws_agpoffset = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(0x02080, 0x1ffff000); + } return 0; } -#if defined(I915_HAVE_BUFFER) +#if defined(I915_HAVE_BUFFER) && defined(DRI2) #define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) #define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) #define DRI2_SAREA_BLOCK_NEXT(p) \ @@ -122,7 +164,7 @@ setup_dri2_sarea(struct drm_device * dev, struct drm_file *file_priv, drm_i915_init_t * init) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; unsigned int *p, *end, *next; @@ -150,8 +192,8 @@ setup_dri2_sarea(struct drm_device * dev, while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) { switch (DRI2_SAREA_BLOCK_TYPE(*p)) { case DRI2_SAREA_BLOCK_LOCK: - dev->lock.hw_lock = (void *) (p + 1); - dev->sigdata.lock = dev->lock.hw_lock; + dev->primary->master->lock.hw_lock = (void *) (p + 1); + dev->sigdata.lock = dev->primary->master->lock.hw_lock; break; } next = DRI2_SAREA_BLOCK_NEXT(p); @@ -171,71 +213,50 @@ static int i915_initialize(struct drm_device * dev, struct drm_file *file_priv, drm_i915_init_t * init) { - drm_i915_private_t *dev_priv = dev->dev_private; -#if defined(I915_HAVE_BUFFER) - int ret; -#endif - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - i915_dma_cleanup(dev); - return -EINVAL; - } + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - if (init->mmio_offset != 0) - dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio_map) { - i915_dma_cleanup(dev); - DRM_ERROR("can not find mmio map!\n"); - return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + if (init->mmio_offset != 0) + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio_map) { + i915_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return -EINVAL; + } } #ifdef I915_HAVE_BUFFER - dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; -#endif - - if (init->sarea_priv_offset) - dev_priv->sarea_priv = (drm_i915_sarea_t *) - ((u8 *) dev_priv->sarea->handle + - init->sarea_priv_offset); - else { - /* No sarea_priv for you! */ - dev_priv->sarea_priv = NULL; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; } +#endif - dev_priv->ring.Start = init->ring_start; - dev_priv->ring.End = init->ring_end; - dev_priv->ring.Size = init->ring_size; - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - - dev_priv->ring.map.offset = init->ring_start; - dev_priv->ring.map.size = init->ring_size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; - - drm_core_ioremap(&dev_priv->ring.map, dev); - - if (dev_priv->ring.map.handle == NULL) { - i915_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return -ENOMEM; + if (init->ring_size != 0) { + dev_priv->ring.Size = init->ring_size; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + dev_priv->ring.map.offset = init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { + i915_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; } - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; - dev_priv->cpp = init->cpp; - - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->pf_current_page = 0; + master_priv->sarea_priv->pf_current_page = 0; /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. */ - dev_priv->use_mi_batchbuffer_start = 0; - if (IS_I965G(dev)) /* 965 doesn't support older method */ - dev_priv->use_mi_batchbuffer_start = 1; /* Allow hardware batchbuffers unless told otherwise. */ @@ -255,46 +276,42 @@ static int i915_initialize(struct drm_device * dev, DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->hws_vaddr = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); I915_WRITE(0x02080, dev_priv->dma_status_page); } DRM_DEBUG("Enabled hardware status page\n"); + #ifdef I915_HAVE_BUFFER - mutex_init(&dev_priv->cmdbuf_mutex); -#endif -#if defined(I915_HAVE_BUFFER) + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_init(&dev_priv->cmdbuf_mutex); + } +#ifdef DRI2 if (init->func == I915_INIT_DMA2) { - ret = setup_dri2_sarea(dev, file_priv, init); + int ret = setup_dri2_sarea(dev, file_priv, init); if (ret) { i915_dma_cleanup(dev); DRM_ERROR("could not set up dri2 sarea\n"); return ret; } } -#endif +#endif /* DRI2 */ +#endif /* I915_HAVE_BUFFER */ return 0; } static int i915_dma_resume(struct drm_device * dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; DRM_DEBUG("\n"); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - return -EINVAL; - } - - if (!dev_priv->mmio_map) { - DRM_ERROR("can not find mmio map!\n"); - return -EINVAL; - } + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; if (dev_priv->ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" @@ -303,16 +320,16 @@ static int i915_dma_resume(struct drm_device * dev) } /* Program Hardware Status Page */ - if (!dev_priv->hw_status_page) { + if (!dev_priv->hws_vaddr) { DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hws_vaddr); - if (dev_priv->status_gfx_addr != 0) - I915_WRITE(0x02080, dev_priv->status_gfx_addr); + if (dev_priv->hws_agpoffset != 0) + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); else - I915_WRITE(0x02080, dev_priv->dma_status_page); + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); return 0; @@ -321,7 +338,7 @@ static int i915_dma_resume(struct drm_device * dev) static int i915_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_init_t *init = data; + struct drm_i915_init *init = data; int retcode = 0; switch (init->func) { @@ -422,7 +439,7 @@ static int validate_cmd(int cmd) static int i915_emit_cmds(struct drm_device *dev, int __user *buffer, int dwords) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int i; RING_LOCALS; @@ -459,11 +476,11 @@ static int i915_emit_cmds(struct drm_device *dev, int __user *buffer, return 0; } -static int i915_emit_box(struct drm_device * dev, - struct drm_clip_rect __user * boxes, - int i, int DR1, int DR4) +int i915_emit_box(struct drm_device * dev, + struct drm_clip_rect __user * boxes, + int i, int DR1, int DR4) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_clip_rect box; RING_LOCALS; @@ -504,7 +521,8 @@ static int i915_emit_box(struct drm_device * dev, void i915_emit_breadcrumb(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; RING_LOCALS; if (++dev_priv->counter > BREADCRUMB_MASK) { @@ -512,12 +530,11 @@ void i915_emit_breadcrumb(struct drm_device *dev) DRM_DEBUG("Breadcrumb counter wrapped around\n"); } - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + master_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(20); + OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); @@ -526,7 +543,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; uint32_t flush_cmd = MI_FLUSH; RING_LOCALS; @@ -546,10 +563,10 @@ int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) static int i915_dispatch_cmdbuffer(struct drm_device * dev, - drm_i915_cmdbuffer_t * cmd) + struct drm_i915_cmdbuffer * cmd) { #ifdef I915_HAVE_FENCE - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; #endif int nbox = cmd->num_cliprects; int i = 0, count, ret; @@ -587,7 +604,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, int i915_dispatch_batchbuffer(struct drm_device * dev, drm_i915_batchbuffer_t * batch) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_clip_rect __user *boxes = batch->cliprects; int nbox = batch->num_cliprects; int i = 0, count; @@ -610,7 +627,14 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, return ret; } - if (dev_priv->use_mi_batchbuffer_start) { + if (IS_I830(dev) || IS_845G(dev)) { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + OUT_RING(batch->start + batch->used - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { BEGIN_LP_RING(2); if (IS_I965G(dev)) { OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); @@ -620,14 +644,6 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, OUT_RING(batch->start | MI_BATCH_NON_SECURE); } ADVANCE_LP_RING(); - - } else { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(batch->start | MI_BATCH_NON_SECURE); - OUT_RING(batch->start + batch->used - 4); - OUT_RING(0); - ADVANCE_LP_RING(); } } @@ -641,38 +657,39 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; u32 num_pages, current_page, next_page, dspbase; int shift = 2 * plane, x, y; RING_LOCALS; /* Calculate display base offset */ - num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; - current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; + num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; + current_page = (master_priv->sarea_priv->pf_current_page >> shift) & 0x3; next_page = (current_page + 1) % num_pages; switch (next_page) { default: case 0: - dspbase = dev_priv->sarea_priv->front_offset; + dspbase = master_priv->sarea_priv->front_offset; break; case 1: - dspbase = dev_priv->sarea_priv->back_offset; + dspbase = master_priv->sarea_priv->back_offset; break; case 2: - dspbase = dev_priv->sarea_priv->third_offset; + dspbase = master_priv->sarea_priv->third_offset; break; } if (plane == 0) { - x = dev_priv->sarea_priv->planeA_x; - y = dev_priv->sarea_priv->planeA_y; + x = master_priv->sarea_priv->planeA_x; + y = master_priv->sarea_priv->planeA_y; } else { - x = dev_priv->sarea_priv->planeB_x; - y = dev_priv->sarea_priv->planeB_y; + x = master_priv->sarea_priv->planeB_x; + y = master_priv->sarea_priv->planeB_y; } - dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; + dspbase += (y * master_priv->sarea_priv->pitch + x) * dev_priv->cpp; DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, dspbase); @@ -683,21 +700,22 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) MI_WAIT_FOR_PLANE_A_FLIP))); OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); - OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); + OUT_RING(master_priv->sarea_priv->pitch * dev_priv->cpp); OUT_RING(dspbase); ADVANCE_LP_RING(); - dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); - dev_priv->sarea_priv->pf_current_page |= next_page << shift; + master_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); + master_priv->sarea_priv->pf_current_page |= next_page << shift; } void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int i; DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", - planes, dev_priv->sarea_priv->pf_current_page); + planes, master_priv->sarea_priv->pf_current_page); i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); @@ -714,10 +732,20 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) int i915_quiescent(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + if (ret) + { + i915_kernel_lost_context (dev); + DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n", + dev_priv->ring.head, + dev_priv->ring.tail, + dev_priv->ring.space); + } + return ret; } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -732,9 +760,10 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data, static int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; + master_priv->sarea_priv; drm_i915_batchbuffer_t *batch = data; int ret; @@ -762,10 +791,11 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, static int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; - drm_i915_cmdbuffer_t *cmdbuf = data; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *) + master_priv->sarea_priv; + struct drm_i915_cmdbuffer *cmdbuf = data; int ret; DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", @@ -797,21 +827,22 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, #define DRM_DEBUG_RELOCATION 0 #endif -static int i915_do_cleanup_pageflip(struct drm_device * dev) +int i915_do_cleanup_pageflip(struct drm_device * dev) { - drm_i915_private_t *dev_priv = dev->dev_private; - int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + int i, planes, num_pages; DRM_DEBUG("\n"); - - for (i = 0, planes = 0; i < 2; i++) - if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { - dev_priv->sarea_priv->pf_current_page = - (dev_priv->sarea_priv->pf_current_page & + num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; + for (i = 0, planes = 0; i < 2; i++) { + if (master_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { + master_priv->sarea_priv->pf_current_page = + (master_priv->sarea_priv->pf_current_page & ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); planes |= 1 << i; } + } if (planes) i915_dispatch_flip(dev, planes, 0); @@ -821,7 +852,7 @@ static int i915_do_cleanup_pageflip(struct drm_device * dev) static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_flip_t *param = data; + struct drm_i915_flip *param = data; DRM_DEBUG("\n"); @@ -843,8 +874,8 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *f static int i915_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_getparam_t *param = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_getparam *param = data; int value; if (!dev_priv) { @@ -854,7 +885,7 @@ static int i915_getparam(struct drm_device *dev, void *data, switch (param->param) { case I915_PARAM_IRQ_ACTIVE: - value = dev->irq ? 1 : 0; + value = dev->irq_enabled ? 1 : 0; break; case I915_PARAM_ALLOW_BATCHBUFFER: value = dev_priv->allow_batchbuffer ? 1 : 0; @@ -881,7 +912,7 @@ static int i915_getparam(struct drm_device *dev, void *data, static int i915_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; drm_i915_setparam_t *param = data; if (!dev_priv) { @@ -891,8 +922,6 @@ static int i915_setparam(struct drm_device *dev, void *data, switch (param->param) { case I915_SETPARAM_USE_MI_BATCHBUFFER_START: - if (!IS_I965G(dev)) - dev_priv->use_mi_batchbuffer_start = param->value; break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: dev_priv->tex_lru_log_granularity = param->value; @@ -913,6 +942,26 @@ drm_i915_mmio_entry_t mmio_table[] = { I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, 0x2350, 8 + }, + [MMIO_REGS_DOVSTA] = { + I915_MMIO_MAY_READ, + 0x30008, + 1 + }, + [MMIO_REGS_GAMMA] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x30010, + 6 + }, + [MMIO_REGS_FENCE] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x2000, + 8 + }, + [MMIO_REGS_FENCE_NEW] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x3000, + 16 } }; @@ -922,8 +971,8 @@ static int i915_mmio(struct drm_device *dev, void *data, struct drm_file *file_priv) { uint32_t buf[8]; - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mmio_entry_t *e; + struct drm_i915_private *dev_priv = dev->dev_private; + drm_i915_mmio_entry_t *e; drm_i915_mmio_t *mmio = data; void __iomem *base; int i; @@ -968,7 +1017,7 @@ static int i915_mmio(struct drm_device *dev, void *data, static int i915_set_status_page(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; if (!I915_NEED_GFX_HWS(dev)) @@ -978,9 +1027,13 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_ERROR("called with no initialization\n"); return -EINVAL; } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr); - dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); + dev_priv->hws_agpoffset = hws->addr & (0x1ffff<<12); dev_priv->hws_map.offset = dev->agp->base + hws->addr; dev_priv->hws_map.size = 4*1024; @@ -991,181 +1044,30 @@ static int i915_set_status_page(struct drm_device *dev, void *data, drm_core_ioremap(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); - dev_priv->status_gfx_addr = 0; + dev_priv->hws_agpoffset = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->hws_map.handle; - - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); - DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); - return 0; -} - -int i915_driver_load(struct drm_device *dev, unsigned long flags) -{ - struct drm_i915_private *dev_priv; - unsigned long base, size; - int ret = 0, num_pipes = 2, mmio_bar = IS_I9XX(dev) ? 0 : 1; - - /* i915 has 4 more counters */ - dev->counters += 4; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - dev->types[9] = _DRM_STAT_DMA; - - dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) - return -ENOMEM; - - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - dev->dev_private = (void *)dev_priv; + dev_priv->hws_vaddr = dev_priv->hws_map.handle; - /* Add register map (needed for suspend/resume) */ - base = drm_get_resource_start(dev, mmio_bar); - size = drm_get_resource_len(dev, mmio_bar); + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); + DRM_DEBUG("load hws at %p\n", dev_priv->hws_vaddr); - ret = drm_addmap(dev, base, size, _DRM_REGISTERS, - _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map); - -#ifdef __linux__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - intel_init_chipset_flush_compat(dev); -#endif -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) - intel_opregion_init(dev); -#endif -#endif - - I915_WRITE16(HWSTAM, 0xeffe); - I915_WRITE16(IMR, 0x0); - I915_WRITE16(IER, 0x0); - - DRM_SPININIT(&dev_priv->swaps_lock, "swap"); - INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); - dev_priv->swaps_pending = 0; - - DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = 0; - - ret = drm_vblank_init(dev, num_pipes); - if (ret) - return ret; - - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - - i915_enable_interrupt(dev); - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); - - /* - * Initialize the hardware status page IRQ location. - */ - - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - - return ret; -} - -int i915_driver_unload(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp; - - if (dev_priv) { - dev_priv->vblank_pipe = 0; - - dev_priv->irq_enabled = 0; - I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(IMR, 0xffffffff); - I915_WRITE(IER, 0x0); - - temp = I915_READ(PIPEASTAT); - I915_WRITE(PIPEASTAT, temp); - temp = I915_READ(PIPEBSTAT); - I915_WRITE(PIPEBSTAT, temp); - temp = I915_READ(IIR); - I915_WRITE(IIR, temp); - } - - if (dev_priv->mmio_map) - drm_rmmap(dev, dev_priv->mmio_map); - -#ifdef __linux__ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) - intel_opregion_free(dev); -#endif -#endif - - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); -#ifdef __linux__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - intel_fini_chipset_flush_compat(dev); -#endif -#endif return 0; } -void i915_driver_lastclose(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - /* agp off can use this to get called before dev_priv */ - if (!dev_priv) - return; - -#ifdef I915_HAVE_BUFFER - if (dev_priv->val_bufs) { - vfree(dev_priv->val_bufs); - dev_priv->val_bufs = NULL; - } -#endif - - if (drm_getsarea(dev) && dev_priv->sarea_priv) - i915_do_cleanup_pageflip(dev); - if (dev_priv->agp_heap) - i915_mem_takedown(&(dev_priv->agp_heap)); -#if defined(I915_HAVE_BUFFER) - if (dev_priv->sarea_kmap.virtual) { - drm_bo_kunmap(&dev_priv->sarea_kmap); - dev_priv->sarea_kmap.virtual = NULL; - dev->lock.hw_lock = NULL; - dev->sigdata.lock = NULL; - } - - if (dev_priv->sarea_bo) { - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(&dev_priv->sarea_bo); - mutex_unlock(&dev->struct_mutex); - dev_priv->sarea_bo = NULL; - } -#endif - i915_dma_cleanup(dev); -} - -void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, file_priv, dev_priv->agp_heap); -} - struct drm_ioctl_desc i915_ioctls[] = { - DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -1179,6 +1081,20 @@ struct drm_ioctl_desc i915_ioctls[] = { #ifdef I915_HAVE_BUFFER DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH), #endif + DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); @@ -1199,10 +1115,3 @@ int i915_driver_device_is_agp(struct drm_device * dev) return 1; } -int i915_driver_firstopen(struct drm_device *dev) -{ -#ifdef I915_HAVE_BUFFER - drm_bo_driver_init(dev); -#endif - return 0; -} diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 97e77428..8ba71687 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -39,7 +39,7 @@ * of chars for next/prev indices */ #define I915_LOG_MIN_TEX_REGION_SIZE 14 -typedef struct _drm_i915_init { +typedef struct drm_i915_init { enum { I915_INIT_DMA = 0x01, I915_CLEANUP_DMA = 0x02, @@ -176,6 +176,20 @@ typedef struct drm_i915_sarea { #define DRM_I915_MMIO 0x10 #define DRM_I915_HWS_ADDR 0x11 #define DRM_I915_EXECBUFFER 0x12 +#define DRM_I915_GEM_INIT 0x13 +#define DRM_I915_GEM_EXECBUFFER 0x14 +#define DRM_I915_GEM_PIN 0x15 +#define DRM_I915_GEM_UNPIN 0x16 +#define DRM_I915_GEM_BUSY 0x17 +#define DRM_I915_GEM_THROTTLE 0x18 +#define DRM_I915_GEM_ENTERVT 0x19 +#define DRM_I915_GEM_LEAVEVT 0x1a +#define DRM_I915_GEM_CREATE 0x1b +#define DRM_I915_GEM_PREAD 0x1c +#define DRM_I915_GEM_PWRITE 0x1d +#define DRM_I915_GEM_MMAP 0x1e +#define DRM_I915_GEM_SET_DOMAIN 0x1f +#define DRM_I915_GEM_SW_FINISH 0x20 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -195,6 +209,20 @@ typedef struct drm_i915_sarea { #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) #define DRM_IOCTL_I915_MMIO DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_MMIO, drm_i915_mmio) #define DRM_IOCTL_I915_EXECBUFFER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_EXECBUFFER, struct drm_i915_execbuffer) +#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) +#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) +#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) +#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) +#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) +#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE) +#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) +#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) +#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) +#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) +#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) +#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) +#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) +#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) /* Asynchronous page flipping: */ @@ -223,7 +251,7 @@ typedef struct drm_i915_batchbuffer { /* As above, but pass a pointer to userspace buffer which can be * validated by the kernel prior to sending to hardware. */ -typedef struct _drm_i915_cmdbuffer { +typedef struct drm_i915_cmdbuffer { char __user *buf; /* pointer to userspace command buffer */ int sz; /* nr bytes in buf */ int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ @@ -326,6 +354,10 @@ typedef struct drm_i915_vblank_swap { #define MMIO_REGS_CL_INVOCATION_COUNT 6 #define MMIO_REGS_PS_INVOCATION_COUNT 7 #define MMIO_REGS_PS_DEPTH_COUNT 8 +#define MMIO_REGS_DOVSTA 9 +#define MMIO_REGS_GAMMA 10 +#define MMIO_REGS_FENCE 11 +#define MMIO_REGS_FENCE_NEW 12 typedef struct drm_i915_mmio_entry { unsigned int flag; @@ -395,4 +427,232 @@ struct drm_i915_execbuffer { struct drm_fence_arg fence_arg; }; +struct drm_i915_gem_init { + /** + * Beginning offset in the GTT to be managed by the DRM memory + * manager. + */ + uint64_t gtt_start; + /** + * Ending offset in the GTT to be managed by the DRM memory + * manager. + */ + uint64_t gtt_end; +}; + +struct drm_i915_gem_create { + /** + * Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + */ + uint64_t size; + /** + * Returned handle for the object. + * + * Object handles are nonzero. + */ + uint32_t handle; + uint32_t pad; +}; + +struct drm_i915_gem_pread { + /** Handle for the object being read. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to read from */ + uint64_t offset; + /** Length of data to read */ + uint64_t size; + /** Pointer to write the data into. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_pwrite { + /** Handle for the object being written to. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to write to */ + uint64_t offset; + /** Length of data to write */ + uint64_t size; + /** Pointer to read the data from. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_mmap { + /** Handle for the object being mapped. */ + uint32_t handle; + uint32_t pad; + /** Offset in the object to map. */ + uint64_t offset; + /** + * Length of data to map. + * + * The value will be page-aligned. + */ + uint64_t size; + /** Returned pointer the data was mapped at */ + uint64_t addr_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_i915_gem_set_domain { + /** Handle for the object */ + uint32_t handle; + + /** New read domains */ + uint32_t read_domains; + + /** New write domain */ + uint32_t write_domain; +}; + +struct drm_i915_gem_sw_finish { + /** Handle for the object */ + uint32_t handle; +}; + +struct drm_i915_gem_relocation_entry { + /** + * Handle of the buffer being pointed to by this relocation entry. + * + * It's appealing to make this be an index into the mm_validate_entry + * list to refer to the buffer, but this allows the driver to create + * a relocation list for state buffers and not re-write it per + * exec using the buffer. + */ + uint32_t target_handle; + + /** + * Value to be added to the offset of the target buffer to make up + * the relocation entry. + */ + uint32_t delta; + + /** Offset in the buffer the relocation entry will be written into */ + uint64_t offset; + + /** + * Offset value of the target buffer that the relocation entry was last + * written as. + * + * If the buffer has the same offset as last time, we can skip syncing + * and writing the relocation. This value is written back out by + * the execbuffer ioctl when the relocation is written. + */ + uint64_t presumed_offset; + + /** + * Target memory domains read by this operation. + */ + uint32_t read_domains; + + /** + * Target memory domains written by this operation. + * + * Note that only one domain may be written by the whole + * execbuffer operation, so that where there are conflicts, + * the application will get -EINVAL back. + */ + uint32_t write_domain; +}; + +/** @{ + * Intel memory domains + * + * Most of these just align with the various caches in + * the system and are used to flush and invalidate as + * objects end up cached in different domains. + */ +/** CPU cache */ +#define I915_GEM_DOMAIN_CPU 0x00000001 +/** Render cache, used by 2D and 3D drawing */ +#define I915_GEM_DOMAIN_RENDER 0x00000002 +/** Sampler cache, used by texture engine */ +#define I915_GEM_DOMAIN_SAMPLER 0x00000004 +/** Command queue, used to load batch buffers */ +#define I915_GEM_DOMAIN_COMMAND 0x00000008 +/** Instruction cache, used by shader programs */ +#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010 +/** Vertex address cache */ +#define I915_GEM_DOMAIN_VERTEX 0x00000020 +/** GTT domain - aperture and scanout */ +#define I915_GEM_DOMAIN_GTT 0x00000040 +/** @} */ + +struct drm_i915_gem_exec_object { + /** + * User's handle for a buffer to be bound into the GTT for this + * operation. + */ + uint32_t handle; + + /** Number of relocations to be performed on this buffer */ + uint32_t relocation_count; + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + uint64_t relocs_ptr; + + /** Required alignment in graphics aperture */ + uint64_t alignment; + + /** + * Returned value of the updated offset of the object, for future + * presumed_offset writes. + */ + uint64_t offset; +}; + +struct drm_i915_gem_execbuffer { + /** + * List of buffers to be validated with their relocations to be + * performend on them. + * + * This is a pointer to an array of struct drm_i915_gem_validate_entry. + * + * These buffers must be listed in an order such that all relocations + * a buffer is performing refer to buffers that have already appeared + * in the validate list. + */ + uint64_t buffers_ptr; + uint32_t buffer_count; + + /** Offset in the batchbuffer to start execution from. */ + uint32_t batch_start_offset; + /** Bytes used in batchbuffer from batch_start_offset */ + uint32_t batch_len; + uint32_t DR1; + uint32_t DR4; + uint32_t num_cliprects; + uint64_t cliprects_ptr; /* struct drm_clip_rect *cliprects */ +}; + +struct drm_i915_gem_pin { + /** Handle of the buffer to be pinned. */ + uint32_t handle; + uint32_t pad; + + /** alignment required within the aperture */ + uint64_t alignment; + + /** Returned GTT offset of the buffer. */ + uint64_t offset; +}; + +struct drm_i915_gem_unpin { + /** Handle of the buffer to be unpinned. */ + uint32_t handle; + uint32_t pad; +}; + +struct drm_i915_gem_busy { + /** Handle of the buffer to check for busy */ + uint32_t handle; + + /** Return busy status (1 if busy, 0 if idle) */ + uint32_t busy; +}; + #endif /* _I915_DRM_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a77fcf04..a0f73298 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -33,11 +33,13 @@ /* General customization: */ +#include "intel_bios.h" + #define DRIVER_AUTHOR "Tungsten Graphics, Inc." #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20080312" +#define DRIVER_DATE "20080611" #if defined(__linux__) #define I915_HAVE_FENCE @@ -61,7 +63,7 @@ */ #define DRIVER_MAJOR 1 #if defined(I915_HAVE_FENCE) && defined(I915_HAVE_BUFFER) -#define DRIVER_MINOR 13 +#define DRIVER_MINOR 14 #else #define DRIVER_MINOR 6 #endif @@ -77,17 +79,16 @@ enum pipe { struct drm_i915_validate_buffer; #endif -typedef struct _drm_i915_ring_buffer { +struct drm_i915_ring_buffer { int tail_mask; - unsigned long Start; - unsigned long End; unsigned long Size; u8 *virtual_start; int head; int tail; int space; drm_local_map_t map; -} drm_i915_ring_buffer_t; + struct drm_gem_object *ring_obj; +}; struct mem_block { struct mem_block *next; @@ -97,13 +98,15 @@ struct mem_block { struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ }; -typedef struct _drm_i915_vbl_swap { +struct drm_i915_vbl_swap { struct list_head head; drm_drawable_t drw_id; unsigned int plane; unsigned int sequence; int flip; -} drm_i915_vbl_swap_t; + struct drm_minor *minor; +}; + #ifdef __linux__ struct opregion_header; @@ -121,26 +124,33 @@ struct intel_opregion { }; #endif -typedef struct drm_i915_private { +struct drm_i915_master_private { drm_local_map_t *sarea; + struct drm_i915_sarea *sarea_priv; +}; + +struct drm_i915_private { + struct drm_device *dev; + drm_local_map_t *mmio_map; - drm_i915_sarea_t *sarea_priv; - drm_i915_ring_buffer_t ring; + unsigned long mmiobase; + unsigned long mmiolen; - drm_dma_handle_t *status_page_dmah; - void *hw_status_page; + struct drm_i915_ring_buffer ring; + + struct drm_dma_handle *status_page_dmah; dma_addr_t dma_status_page; uint32_t counter; - unsigned int status_gfx_addr; + uint32_t hws_agpoffset; drm_local_map_t hws_map; + void *hws_vaddr; + struct drm_memrange_node *hws; unsigned int cpp; - int use_mi_batchbuffer_start; wait_queue_head_t irq_queue; atomic_t irq_received; - atomic_t irq_emitted; int tex_lru_log_granularity; int allow_batchbuffer; @@ -150,8 +160,13 @@ typedef struct drm_i915_private { DRM_SPINTYPE user_irq_lock; int user_irq_refcount; int fence_irq_on; - uint32_t irq_enable_reg; + uint32_t irq_mask_reg; int irq_enabled; + struct workqueue_struct *wq; + + bool cursor_needs_physical; + + struct drm_memrange vram; #ifdef I915_HAVE_FENCE uint32_t flush_sequence; @@ -163,18 +178,111 @@ typedef struct drm_i915_private { void *agp_iomap; unsigned int max_validate_buffers; struct mutex cmdbuf_mutex; + u32 stolen_base; struct drm_i915_validate_buffer *val_bufs; #endif DRM_SPINTYPE swaps_lock; - drm_i915_vbl_swap_t vbl_swaps; + struct drm_i915_vbl_swap vbl_swaps; unsigned int swaps_pending; -#if defined(I915_HAVE_BUFFER) + + /* LVDS info */ + int backlight_duty_cycle; /* restore backlight to this value */ + bool panel_wants_dither; + struct drm_display_mode *panel_fixed_mode; + struct drm_display_mode *vbt_mode; /* if any */ + +#if defined(I915_HAVE_BUFFER) && defined(DRI2) /* DRI2 sarea */ - struct drm_buffer_object *sarea_bo; - struct drm_bo_kmap_obj sarea_kmap; + struct drm_gem_object *sarea_object; + struct drm_bo_kmap_obj sarea_kmap; #endif + /* Feature bits from the VBIOS */ + int int_tv_support:1; + int lvds_dither:1; + int lvds_vbt:1; + int int_crt_support:1; + + struct { + struct drm_memrange gtt_space; + + /** + * List of objects currently involved in rendering from the + * ringbuffer. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * List of objects which are not in the ringbuffer but which + * still have a write_domain which needs to be flushed before + * unbinding. + * + * A reference is held on the buffer while on this list. + */ + struct list_head flushing_list; + + /** + * LRU list of objects which are not in the ringbuffer and + * are ready to unbind, but are still in the GTT. + * + * A reference is not held on the buffer while on this list, + * as merely being GTT-bound shouldn't prevent its being + * freed, and we'll pull it off the list in the free path. + */ + struct list_head inactive_list; + + /** + * List of breadcrumbs associated with GPU requests currently + * outstanding. + */ + struct list_head request_list; + + /** + * We leave the user IRQ off as much as possible, + * but this means that requests will finish and never + * be retired once the system goes idle. Set a timer to + * fire periodically while the ring is running. When it + * fires, go retire requests. + */ + struct delayed_work retire_work; + + uint32_t next_gem_seqno; + + /** + * Waiting sequence number, if any + */ + uint32_t waiting_gem_seqno; + + /** + * Last seq seen at irq time + */ + uint32_t irq_gem_seqno; + + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int suspended; + + /** + * Flag if the hardware appears to be wedged. + * + * This is set when attempts to idle the device timeout. + * It prevents command submission from occuring and makes + * every pending request fail + */ + int wedged; + } mm; + + struct work_struct user_interrupt_task; + #ifdef __linux__ struct intel_opregion opregion; #endif @@ -267,7 +375,14 @@ typedef struct drm_i915_private { u8 saveDACMASK; u8 saveDACDATA[256*3]; /* 256 3-byte colors */ u8 saveCR[37]; -} drm_i915_private_t; +}; + +struct drm_i915_file_private { + struct { + uint32_t last_gem_seqno; + uint32_t last_gem_throttle_seqno; + } mm; +}; enum intel_chip_family { CHIP_I8XX = 0x01, @@ -276,16 +391,89 @@ enum intel_chip_family { CHIP_I965 = 0x08, }; +/** driver private structure attached to each drm_gem_object */ +struct drm_i915_gem_object { + struct drm_gem_object *obj; + + /** Current space allocated to this object in the GTT, if any. */ + struct drm_memrange_node *gtt_space; + + /** This object's place on the active/flushing/inactive lists */ + struct list_head list; + + /** + * This is set if the object is on the active or flushing lists + * (has pending rendering), and is not set if it's on inactive (ready + * to be unbound). + */ + int active; + + /** + * This is set if the object has been written to since last bound + * to the GTT + */ + int dirty; + + /** AGP memory structure for our GTT binding. */ + DRM_AGP_MEM *agp_mem; + + struct page **page_list; + + /** + * Current offset of the object in GTT space. + * + * This is the same as gtt_space->start + */ + uint32_t gtt_offset; + + /** Boolean whether this object has a valid gtt offset. */ + int gtt_bound; + + /** How many users have pinned this object in GTT space */ + int pin_count; + + /** Breadcrumb of last rendering to the buffer. */ + uint32_t last_rendering_seqno; +}; + +/** + * Request queue structure. + * + * The request queue allows us to note sequence numbers that have been emitted + * and may be associated with active buffers to be retired. + * + * By keeping this list, we can avoid having to do questionable + * sequence-number comparisons on buffer last_rendering_seqnos, and associate + * an emission time with seqnos for tracking how far ahead of the GPU we are. + */ +struct drm_i915_gem_request { + /** GEM sequence number associated with this request. */ + uint32_t seqno; + + /** Time at which this request was emitted, in jiffies. */ + unsigned long emitted_jiffies; + + /** Cache domains that were flushed at the start of the request. */ + uint32_t flush_domains; + + struct list_head list; +}; + extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; +extern int i915_master_create(struct drm_device *dev, struct drm_master *master); +extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); /* i915_dma.c */ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); -extern int i915_driver_unload(struct drm_device *); +extern int i915_driver_unload(struct drm_device *dev); extern void i915_driver_lastclose(struct drm_device * dev); +extern int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv); extern void i915_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); +extern void i915_driver_postclose(struct drm_device *dev, + struct drm_file *file_priv); extern int i915_driver_device_is_agp(struct drm_device * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -293,10 +481,16 @@ extern void i915_emit_breadcrumb(struct drm_device *dev); extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync); extern int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush); extern int i915_driver_firstopen(struct drm_device *dev); +extern int i915_do_cleanup_pageflip(struct drm_device *dev); +extern int i915_dma_cleanup(struct drm_device *dev); extern int i915_dispatch_batchbuffer(struct drm_device * dev, drm_i915_batchbuffer_t * batch); extern int i915_quiescent(struct drm_device *dev); +int i915_emit_box(struct drm_device * dev, + struct drm_clip_rect __user * boxes, + int i, int DR1, int DR4); + /* i915_irq.c */ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -313,13 +507,15 @@ extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_emit_irq(struct drm_device * dev); +extern void i915_enable_interrupt (struct drm_device *dev); +extern int i915_wait_irq(struct drm_device * dev, int irq_nr); extern int i915_enable_vblank(struct drm_device *dev, int crtc); extern void i915_disable_vblank(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void i915_user_irq_on(drm_i915_private_t *dev_priv); -extern void i915_user_irq_off(drm_i915_private_t *dev_priv); +extern void i915_user_irq_on(struct drm_device *dev); +extern void i915_user_irq_off(struct drm_device *dev); /* i915_mem.c */ extern int i915_mem_alloc(struct drm_device *dev, void *data, @@ -346,7 +542,7 @@ extern void i915_invalidate_reported_sequence(struct drm_device *dev); #endif -#ifdef I915_HAVE_BUFFER +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) /* i915_buffer.c */ extern struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev); extern int i915_fence_type(struct drm_buffer_object *bo, uint32_t *fclass, @@ -358,12 +554,58 @@ extern uint64_t i915_evict_flags(struct drm_buffer_object *bo); extern int i915_move(struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); void i915_flush_ttm(struct drm_ttm *ttm); +#endif /* ttm */ +#ifdef I915_HAVE_BUFFER /* i915_execbuf.c */ int i915_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); - +/* i915_gem.c */ +int i915_gem_init_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_busy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_throttle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_proc_init(struct drm_minor *minor); +void i915_gem_proc_cleanup(struct drm_minor *minor); +int i915_gem_init_object(struct drm_gem_object *obj); +void i915_gem_free_object(struct drm_gem_object *obj); +int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); +void i915_gem_object_unpin(struct drm_gem_object *obj); +void i915_gem_lastclose(struct drm_device *dev); +uint32_t i915_get_gem_seqno(struct drm_device *dev); +void i915_gem_retire_requests(struct drm_device *dev); +int i915_gem_init_ringbuffer(struct drm_device *dev); +void i915_gem_cleanup_ringbuffer(struct drm_device *dev); +int i915_gem_do_init(struct drm_device *dev, unsigned long start, + unsigned long end); +void i915_gem_retire_work_handler(struct work_struct *work); #endif +extern unsigned int i915_fbpercrtc; + #ifdef __linux__ /* i915_opregion.c */ extern int intel_opregion_init(struct drm_device *dev); @@ -379,6 +621,12 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev); #endif #endif + +/* modesetting */ +extern void intel_modeset_init(struct drm_device *dev); +extern void intel_modeset_cleanup(struct drm_device *dev); + + #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) @@ -391,16 +639,27 @@ typedef boolean_t bool; #endif #define I915_VERBOSE 0 +#define I915_RING_VALIDATE 0 + +#define PRIMARY_RINGBUFFER_SIZE (128*1024) #define PRIMARY_RINGBUFFER_SIZE (128*1024) #define RING_LOCALS unsigned int outring, ringmask, outcount; \ volatile char *virt; +#if I915_RING_VALIDATE +void i915_ring_validate(struct drm_device *dev, const char *func, int line); +#define I915_RING_DO_VALIDATE(dev) i915_ring_validate(dev, __FUNCTION__, __LINE__) +#else +#define I915_RING_DO_VALIDATE(dev) +#endif + #define BEGIN_LP_RING(n) do { \ if (I915_VERBOSE) \ DRM_DEBUG("BEGIN_LP_RING(%d)\n", \ (n)); \ + I915_RING_DO_VALIDATE(dev); \ if (dev_priv->ring.space < (n)*4) \ i915_wait_ring(dev, (n)*4, __FUNCTION__); \ outcount = 0; \ @@ -419,6 +678,7 @@ typedef boolean_t bool; #define ADVANCE_LP_RING() do { \ if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ + I915_RING_DO_VALIDATE(dev); \ dev_priv->ring.tail = outring; \ dev_priv->ring.space -= outcount * 4; \ I915_WRITE(PRB0_TAIL, outring); \ @@ -526,6 +786,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) +#define MI_STORE_DWORD_INDEX_SHIFT 2 #define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) @@ -535,7 +796,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define BREADCRUMB_BITS 31 #define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) -#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hws_vaddr))[5]) /** * Reads a dword out of the status page, which is written to from the command @@ -550,7 +811,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * * The area from dword 0x10 to 0x3ff is available for driver usage. */ -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hws_vaddr))[reg]) #define I915_GEM_HWS_INDEX 0x10 /* @@ -558,6 +819,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ #define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) #define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) #define SC_UPDATE_SCISSOR (0x1<<1) @@ -618,6 +880,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */ #define PRB1_CTL 0x0204c /* 915+ only */ +#define I965REG_ACTHD 0x02074 #define HWS_PGA 0x02080 #define IPEIR 0x02088 #define NOPID 0x02094 @@ -648,6 +911,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define EMR 0x020b4 #define ESR 0x020b8 #define INSTPM 0x020c0 +#define I915REG_ACTHD 0x020C8 #define FW_BLC 0x020d8 #define FW_BLC_SELF 0x020e0 /* 915+ only */ #define MI_ARB_STATE 0x020e4 /* 915+ only */ @@ -751,6 +1015,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ #define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +/* + * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register + * and is 24 bits wide. + */ +#define PIPE_PIXEL_MASK 0x00ffffff +#define PIPE_PIXEL_SHIFT 0 #define I915_FIFO_UNDERRUN_STATUS (1UL<<31) #define I915_CRC_ERROR_ENABLE (1UL<<29) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c new file mode 100644 index 00000000..009d447b --- /dev/null +++ b/shared-core/i915_init.c @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2007 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> + * 2004 Sylvain Meyer + * + * GPL/BSD dual license + */ +#include "drmP.h" +#include "drm.h" +#include "drm_sarea.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_bios.h" +#include "intel_drv.h" + +/** + * i915_probe_agp - get AGP bootup configuration + * @pdev: PCI device + * @aperture_size: returns AGP aperture configured size + * @preallocated_size: returns size of BIOS preallocated AGP space + * + * Since Intel integrated graphics are UMA, the BIOS has to set aside + * some RAM for the framebuffer at early boot. This code figures out + * how much was set aside so we can use it for our own purposes. + */ +int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, + unsigned long *preallocated_size) +{ + struct pci_dev *bridge_dev; + u16 tmp = 0; + unsigned long overhead; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_ERROR("bridge device not found\n"); + return -1; + } + + /* Get the fb aperture size and "stolen" memory amount. */ + pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); + pci_dev_put(bridge_dev); + + *aperture_size = 1024 * 1024; + *preallocated_size = 1024 * 1024; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_82830_CGC: + case PCI_DEVICE_ID_INTEL_82845G_IG: + case PCI_DEVICE_ID_INTEL_82855GM_IG: + case PCI_DEVICE_ID_INTEL_82865_IG: + if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) + *aperture_size *= 64; + else + *aperture_size *= 128; + break; + default: + /* 9xx supports large sizes, just look at the length */ + *aperture_size = pci_resource_len(pdev, 2); + break; + } + + /* + * Some of the preallocated space is taken by the GTT + * and popup. GTT is 1K per MB of aperture size, and popup is 4K. + */ + overhead = (*aperture_size / 1024) + 4096; + switch (tmp & INTEL_855_GMCH_GMS_MASK) { + case INTEL_855_GMCH_GMS_STOLEN_1M: + break; /* 1M already */ + case INTEL_855_GMCH_GMS_STOLEN_4M: + *preallocated_size *= 4; + break; + case INTEL_855_GMCH_GMS_STOLEN_8M: + *preallocated_size *= 8; + break; + case INTEL_855_GMCH_GMS_STOLEN_16M: + *preallocated_size *= 16; + break; + case INTEL_855_GMCH_GMS_STOLEN_32M: + *preallocated_size *= 32; + break; + case INTEL_915G_GMCH_GMS_STOLEN_48M: + *preallocated_size *= 48; + break; + case INTEL_915G_GMCH_GMS_STOLEN_64M: + *preallocated_size *= 64; + break; + case INTEL_855_GMCH_GMS_DISABLED: + DRM_ERROR("video memory is disabled\n"); + return -1; + default: + DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", + tmp & INTEL_855_GMCH_GMS_MASK); + return -1; + } + *preallocated_size -= overhead; + + return 0; +} + +static int i915_init_hwstatus(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_memrange_node *free_space; + int ret = 0; + + /* Program Hardware Status Page */ + if (!IS_G33(dev)) { + dev_priv->status_page_dmah = + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + + if (!dev_priv->status_page_dmah) { + DRM_ERROR("Can not allocate hardware status page\n"); + ret = -ENOMEM; + goto out; + } + dev_priv->hws_vaddr = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + } else { + free_space = drm_memrange_search_free(&dev_priv->vram, + PAGE_SIZE, + PAGE_SIZE, 0); + if (!free_space) { + DRM_ERROR("No free vram available, aborting\n"); + ret = -ENOMEM; + goto out; + } + + dev_priv->hws = drm_memrange_get_block(free_space, PAGE_SIZE, + PAGE_SIZE); + if (!dev_priv->hws) { + DRM_ERROR("Unable to allocate or pin hw status page\n"); + ret = -EINVAL; + goto out; + } + + dev_priv->hws_agpoffset = dev_priv->hws->start; + dev_priv->hws_map.offset = dev->agp->base + + dev_priv->hws->start; + dev_priv->hws_map.size = PAGE_SIZE; + dev_priv->hws_map.type= 0; + dev_priv->hws_map.flags= 0; + dev_priv->hws_map.mtrr = 0; + + drm_core_ioremap(&dev_priv->hws_map, dev); + if (dev_priv->hws_map.handle == NULL) { + dev_priv->hws_agpoffset = 0; + DRM_ERROR("can not ioremap virtual addr for" + "G33 hw status page\n"); + ret = -ENOMEM; + goto out_free; + } + dev_priv->hws_vaddr = dev_priv->hws_map.handle; + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); + } + + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); + + DRM_DEBUG("Enabled hardware status page\n"); + + return 0; + +out_free: + /* free hws */ +out: + return ret; +} + +static void i915_cleanup_hwstatus(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_G33(dev)) { + if (dev_priv->status_page_dmah) + drm_pci_free(dev, dev_priv->status_page_dmah); + } else { + if (dev_priv->hws_map.handle) + drm_core_ioremapfree(&dev_priv->hws_map, dev); + if (dev_priv->hws) + drm_memrange_put_block(dev_priv->hws); + } + I915_WRITE(HWS_PGA, 0x1ffff000); +} + +static int i915_load_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long agp_size, prealloc_size; + int ret = 0; + + i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + + /* Basic memrange allocator for stolen space (aka vram) */ + drm_memrange_init(&dev_priv->vram, 0, prealloc_size); + /* Let GEM Manage from end of prealloc space to end of aperture */ + i915_gem_do_init(dev, prealloc_size, agp_size); + + ret = i915_gem_init_ringbuffer(dev); + if (ret) + goto out; + + ret = i915_init_hwstatus(dev); + if (ret) + goto destroy_ringbuffer; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; + mutex_init(&dev_priv->cmdbuf_mutex); + + dev_priv->wq = create_singlethread_workqueue("i915"); + if (dev_priv->wq == 0) { + DRM_DEBUG("Error\n"); + ret = -EINVAL; + goto destroy_hws; + } + + ret = intel_init_bios(dev); + if (ret) { + DRM_ERROR("failed to find VBIOS tables\n"); + ret = -ENODEV; + goto destroy_wq; + } + + intel_modeset_init(dev); + drm_helper_initial_config(dev, false); + + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + if (!dev->devname) { + ret = -ENOMEM; + goto modeset_cleanup; + } + + ret = drm_irq_install(dev); + if (ret) { + kfree(dev->devname); + goto modeset_cleanup; + } + return 0; + +modeset_cleanup: + intel_modeset_cleanup(dev); +destroy_wq: + destroy_workqueue(dev_priv->wq); +destroy_hws: + i915_cleanup_hwstatus(dev); +destroy_ringbuffer: + i915_gem_cleanup_ringbuffer(dev); +out: + return ret; +} + +/** + * i915_driver_load - setup chip and create an initial config + * @dev: DRM device + * @flags: startup flags + * + * The driver load routine has to do several things: + * - drive output discovery via intel_modeset_init() + * - initialize the memory manager + * - allocate initial config memory + * - setup the DRM framebuffer with the allocated memory + */ +int i915_driver_load(struct drm_device *dev, unsigned long flags) +{ + struct drm_i915_private *dev_priv; + int ret = 0, num_pipes = 2; + u32 tmp; + + dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + + memset(dev_priv, 0, sizeof(struct drm_i915_private)); + dev->dev_private = (void *)dev_priv; + dev_priv->dev = dev; + + /* i915 has 4 more counters */ + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + if (IS_MOBILE(dev) || IS_I9XX(dev)) + dev_priv->cursor_needs_physical = true; + else + dev_priv->cursor_needs_physical = false; + + if (IS_I965G(dev) || IS_G33(dev)) + dev_priv->cursor_needs_physical = false; + + if (IS_I9XX(dev)) + pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base); + + if (IS_I9XX(dev)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 0); + dev_priv->mmiolen = drm_get_resource_len(dev, 0); + dev->mode_config.fb_base = + drm_get_resource_start(dev, 2) & 0xff000000; + } else if (drm_get_resource_start(dev, 1)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 1); + dev_priv->mmiolen = drm_get_resource_len(dev, 1); + dev->mode_config.fb_base = + drm_get_resource_start(dev, 0) & 0xff000000; + } else { + DRM_ERROR("Unable to find MMIO registers\n"); + ret = -ENODEV; + goto free_priv; + } + + DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base); + + ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, + _DRM_REGISTERS, _DRM_KERNEL|_DRM_READ_ONLY|_DRM_DRIVER, + &dev_priv->mmio_map); + if (ret != 0) { + DRM_ERROR("Cannot add mapping for MMIO registers\n"); + goto free_priv; + } + + INIT_LIST_HEAD(&dev_priv->mm.active_list); + INIT_LIST_HEAD(&dev_priv->mm.flushing_list); + INIT_LIST_HEAD(&dev_priv->mm.inactive_list); + INIT_LIST_HEAD(&dev_priv->mm.request_list); + INIT_DELAYED_WORK(&dev_priv->mm.retire_work, + i915_gem_retire_work_handler); + dev_priv->mm.next_gem_seqno = 1; + +#ifdef __linux__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + intel_init_chipset_flush_compat(dev); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + intel_opregion_init(dev); +#endif +#endif + + tmp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, tmp); + tmp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, tmp); + + atomic_set(&dev_priv->irq_received, 0); + I915_WRITE(HWSTAM, 0xeffe); + I915_WRITE(IMR, 0x0); + I915_WRITE(IER, 0x0); + + DRM_SPININIT(&dev_priv->swaps_lock, "swap"); + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + + DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); + dev_priv->user_irq_refcount = 0; + dev_priv->irq_mask_reg = ~0; + + ret = drm_vblank_init(dev, num_pipes); + if (ret) + goto out_rmmap; + + ret = drm_hotplug_init(dev); + if (ret) + goto out_rmmap; + + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + + i915_enable_interrupt(dev); + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = i915_load_modeset_init(dev); + if (ret < 0) { + DRM_ERROR("failed to init modeset\n"); + goto out_rmmap; + } + } + + return 0; + +out_rmmap: + drm_rmmap(dev, dev_priv->mmio_map); +free_priv: + drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + return ret; +} + +int i915_driver_unload(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + u32 temp; + + dev_priv->vblank_pipe = 0; + + dev_priv->irq_enabled = 0; + + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + + temp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, temp); + temp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, temp); + temp = I915_READ(IIR); + I915_WRITE(IIR, temp); + + I915_WRITE(PRB0_CTL, 0); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_irq_uninstall(dev); + intel_modeset_cleanup(dev); + destroy_workqueue(dev_priv->wq); + } + +#if 0 + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + } +#endif + +#ifdef DRI2 + if (dev_priv->sarea_kmap.virtual) { + drm_bo_kunmap(&dev_priv->sarea_kmap); + dev_priv->sarea_kmap.virtual = NULL; + dev->sigdata.lock = NULL; + } + + if (dev_priv->sarea_bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->sarea_bo); + mutex_unlock(&dev->struct_mutex); + dev_priv->sarea_bo = NULL; + } +#endif + i915_cleanup_hwstatus(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + mutex_unlock(&dev->struct_mutex); + drm_memrange_takedown(&dev_priv->vram); + i915_gem_lastclose(dev); + } + + drm_rmmap(dev, dev_priv->mmio_map); + +#ifdef __linux__ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + intel_opregion_free(dev); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + intel_fini_chipset_flush_compat(dev); +#endif +#endif + + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + + dev->dev_private = NULL; + return 0; +} + +int i915_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv; + unsigned long sareapage; + int ret; + + master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + if (!master_priv) + return -ENOMEM; + + /* prebuild the SAREA */ + sareapage = max(SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + &master_priv->sarea); + if (ret) { + DRM_ERROR("SAREA setup failed\n"); + return ret; + } + master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); + master_priv->sarea_priv->pf_current_page = 0; + + master->driver_priv = master_priv; + return 0; +} + +void i915_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv = master->driver_priv; + + if (!master_priv) + return; + + if (master_priv->sarea) + drm_rmmap(dev, master_priv->sarea); + + drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + + master->driver_priv = NULL; +} + +int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv; + + DRM_DEBUG("\n"); + i915_file_priv = (struct drm_i915_file_private *) + drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); + + if (!i915_file_priv) + return -ENOMEM; + + file_priv->driver_priv = i915_file_priv; + + i915_file_priv->mm.last_gem_seqno = 0; + i915_file_priv->mm.last_gem_throttle_seqno = 0; + + return 0; +} + +void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + + drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); +} + +void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_mem_release(dev, file_priv, dev_priv->agp_heap); +} + +void i915_driver_lastclose(struct drm_device * dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + +#ifdef I915_HAVE_BUFFER + if (dev_priv->val_bufs) { + vfree(dev_priv->val_bufs); + dev_priv->val_bufs = NULL; + } +#endif + + i915_gem_lastclose(dev); + + if (dev_priv->agp_heap) + i915_mem_takedown(&(dev_priv->agp_heap)); + +#if defined(DRI2) + if (dev_priv->sarea_kmap.virtual) { + drm_bo_kunmap(&dev_priv->sarea_kmap); + dev_priv->sarea_kmap.virtual = NULL; + dev->control->master->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; + } + + if (dev_priv->sarea_bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->sarea_bo); + mutex_unlock(&dev->struct_mutex); + dev_priv->sarea_bo = NULL; + } +#endif + + i915_dma_cleanup(dev); +} + +int i915_driver_firstopen(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) + drm_bo_driver_init(dev); +#endif + return 0; +} diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d507d76e..b4004a8f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -30,9 +30,38 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" +#include "drm_crtc_helper.h" #define MAX_NOPID ((u32)~0) +/* + * These are the interrupts used by the driver + */ +#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) + +static inline void +i915_enable_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + if ((dev_priv->irq_mask_reg & mask) != 0) { + dev_priv->irq_mask_reg &= ~mask; + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } +} + +static inline void +i915_disable_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + if ((dev_priv->irq_mask_reg & mask) != mask) { + dev_priv->irq_mask_reg |= mask; + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } +} + /** * i915_get_pipe - return the the pipe associated with a given plane * @dev: DRM device @@ -45,7 +74,7 @@ static int i915_get_pipe(struct drm_device *dev, int plane) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 dspcntr; dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); @@ -82,7 +111,7 @@ i915_get_plane(struct drm_device *dev, int pipe) static int i915_pipe_enabled(struct drm_device *dev, int pipe) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; if (I915_READ(pipeconf) & PIPEACONF_ENABLE) @@ -100,8 +129,8 @@ static void i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, int plane) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; u16 x1, y1, x2, y2; int pf_planes = 1 << plane; @@ -145,12 +174,13 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, */ static void i915_vblank_tasklet(struct drm_device *dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; struct list_head *list, *tmp, hits, *hit; int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; unsigned counter[2]; struct drm_drawable_info *drw; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; u32 cpp = dev_priv->cpp, offsets[3]; u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | @@ -189,13 +219,16 @@ static void i915_vblank_tasklet(struct drm_device *dev) /* Find buffer swaps scheduled for this vertical blank */ list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { - drm_i915_vbl_swap_t *vbl_swap = - list_entry(list, drm_i915_vbl_swap_t, head); + struct drm_i915_vbl_swap *vbl_swap = + list_entry(list, struct drm_i915_vbl_swap, head); int pipe = i915_get_pipe(dev, vbl_swap->plane); if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) continue; + master_priv = vbl_swap->minor->master->driver_priv; + sarea_priv = master_priv->sarea_priv; + list_del(list); dev_priv->swaps_pending--; drm_vblank_put(dev, pipe); @@ -213,8 +246,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) } list_for_each(hit, &hits) { - drm_i915_vbl_swap_t *swap_cmp = - list_entry(hit, drm_i915_vbl_swap_t, head); + struct drm_i915_vbl_swap *swap_cmp = + list_entry(hit, struct drm_i915_vbl_swap, head); struct drm_drawable_info *drw_cmp = drm_get_drawable_info(dev, swap_cmp->drw_id); @@ -271,8 +304,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) lower[0] = lower[1] = sarea_priv->height; list_for_each(hit, &hits) { - drm_i915_vbl_swap_t *swap_hit = - list_entry(hit, drm_i915_vbl_swap_t, head); + struct drm_i915_vbl_swap *swap_hit = + list_entry(hit, struct drm_i915_vbl_swap, head); struct drm_clip_rect *rect; int num_rects, plane, front, back; unsigned short top, bottom; @@ -323,7 +356,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) top = upper[plane]; bottom = lower[plane]; - front = (dev_priv->sarea_priv->pf_current_page >> + front = (master_priv->sarea_priv->pf_current_page >> (2 * plane)) & 0x3; back = (front + 1) % num_pages; @@ -353,8 +386,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) DRM_SPINUNLOCK(&dev->drw_lock); list_for_each_safe(hit, tmp, &hits) { - drm_i915_vbl_swap_t *swap_hit = - list_entry(hit, drm_i915_vbl_swap_t, head); + struct drm_i915_vbl_swap *swap_hit = + list_entry(hit, struct drm_i915_vbl_swap, head); list_del(hit); @@ -364,7 +397,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) u32 i915_get_vblank_counter(struct drm_device *dev, int plane) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; u32 high1, high2, low, count; @@ -398,17 +431,78 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) return count; } +static struct drm_device *hotplug_dev; + +/** + * Handler for user interrupts in process context (able to sleep, do VFS + * operations, etc. + * + * If another IRQ comes in while we're in this handler, it will still get put + * on the queue again to be rerun when we finish. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void i915_hotplug_work_func(void *work) +#else +static void i915_hotplug_work_func(struct work_struct *work) +#endif +{ + struct drm_device *dev = hotplug_dev; + + drm_helper_hotplug_stage_two(dev); + drm_handle_hotplug(dev); +} + +static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + static DECLARE_WORK(hotplug, i915_hotplug_work_func, NULL); +#else + static DECLARE_WORK(hotplug, i915_hotplug_work_func); +#endif + struct drm_i915_private *dev_priv = dev->dev_private; + + hotplug_dev = dev; + + if (stat & TV_HOTPLUG_INT_STATUS) { + DRM_DEBUG("TV event\n"); + } + + if (stat & CRT_HOTPLUG_INT_STATUS) { + DRM_DEBUG("CRT event\n"); + } + + if (stat & SDVOB_HOTPLUG_INT_STATUS) { + DRM_DEBUG("sDVOB event\n"); + } + + if (stat & SDVOC_HOTPLUG_INT_STATUS) { + DRM_DEBUG("sDVOC event\n"); + } + queue_work(dev_priv->wq, &hotplug); + + return 0; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_master_private *master_priv; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 iir; - u32 pipea_stats, pipeb_stats; + u32 pipea_stats = 0, pipeb_stats = 0, tvdac; + int hotplug = 0; int vblank = 0; + if (dev->pdev->msi_enabled) + I915_WRITE(IMR, ~0); iir = I915_READ(IIR); - if (iir == 0) - return IRQ_NONE; + atomic_inc(&dev_priv->irq_received); + if (iir == 0) { + if (dev->pdev->msi_enabled) { + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IMR); + } + } /* * Clear the PIPE(A|B)STAT regs before the IIR otherwise @@ -416,72 +510,101 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) */ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { pipea_stats = I915_READ(PIPEASTAT); - if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - } - I915_WRITE(PIPEASTAT, pipea_stats); } + if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { pipeb_stats = I915_READ(PIPEBSTAT); - /* Ack the event */ I915_WRITE(PIPEBSTAT, pipeb_stats); + } - /* The vblank interrupt gets enabled even if we didn't ask for - it, so make sure it's shut down again */ - if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) - pipeb_stats &= ~(I915_VBLANK_INTERRUPT_ENABLE); - - if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - } + I915_WRITE(IIR, iir); + if (dev->pdev->msi_enabled) + I915_WRITE(IMR, dev_priv->irq_mask_reg); + (void) I915_READ(IIR); /* Flush posted writes */ + + /* This is a global event, and not a pipe A event */ + if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) + hotplug = 1; + + if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) { + hotplug = 1; + /* Toggle hotplug detection to clear hotplug status */ + tvdac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN); + I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); + } -#ifdef __linux__ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) - if (pipeb_stats & I915_LEGACY_BLC_EVENT_ENABLE) - opregion_asle_intr(dev); -#endif -#endif - I915_WRITE(PIPEBSTAT, pipeb_stats); + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); } #ifdef __linux__ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + if ((iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) && + (pipeb_stats & I915_LEGACY_BLC_EVENT_ENABLE)) + opregion_asle_intr(dev); if (iir & I915_ASLE_INTERRUPT) opregion_asle_intr(dev); #endif #endif - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - - I915_WRITE(IIR, iir); - (void) I915_READ(IIR); - if (iir & I915_USER_INTERRUPT) { + dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE i915_fence_handler(dev); #endif } + if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 0)); + } + + /* The vblank interrupt gets enabled even if we didn't ask for + it, so make sure it's shut down again */ + if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) + pipeb_stats &= ~(I915_VBLANK_INTERRUPT_ENABLE); + + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 1)); + } + if (vblank) { if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); } + if ((iir & I915_DISPLAY_PORT_INTERRUPT) || hotplug) { + u32 temp2 = 0; + + DRM_INFO("Hotplug event received\n"); + + if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { + if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) + temp2 |= SDVOB_HOTPLUG_INT_STATUS | + SDVOC_HOTPLUG_INT_STATUS; + if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) + temp2 |= TV_HOTPLUG_INT_STATUS; + } else { + temp2 = I915_READ(PORT_HOTPLUG_STAT); + + I915_WRITE(PORT_HOTPLUG_STAT, temp2); + } + i915_run_hotplug_tasklet(dev, temp2); + } + return IRQ_HANDLED; } int i915_emit_irq(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; RING_LOCALS; i915_kernel_lost_context(dev); @@ -498,52 +621,67 @@ int i915_emit_irq(struct drm_device *dev) return dev_priv->counter; } -void i915_user_irq_on(drm_i915_private_t *dev_priv) +void i915_user_irq_on(struct drm_device *dev) { + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(IER, dev_priv->irq_enable_reg); - } + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)) + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); - } - -void i915_user_irq_off(drm_i915_private_t *dev_priv) + +void i915_user_irq_off(struct drm_device *dev) { + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; - // I915_WRITE(IER, dev_priv->irq_enable_reg); - } + BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0); + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } -static int i915_wait_irq(struct drm_device * dev, int irq_nr) +int i915_wait_irq(struct drm_device * dev, int irq_nr) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv; int ret = 0; + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); - if (READ_BREADCRUMB(dev_priv) >= irq_nr) + master_priv = dev->primary->master->driver_priv; + + if (!master_priv) { + DRM_ERROR("no master priv?\n"); + return -EINVAL; + } + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) { + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return 0; + } - i915_user_irq_on(dev_priv); + i915_user_irq_on(dev); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - i915_user_irq_off(dev_priv); + i915_user_irq_off(dev); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); return ret; } @@ -552,8 +690,8 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_emit_t *emit = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_irq_emit *emit = data; int result; LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -578,8 +716,8 @@ int i915_irq_emit(struct drm_device *dev, void *data, int i915_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_wait_t *irqwait = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_irq_wait *irqwait = data; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); @@ -591,19 +729,20 @@ int i915_irq_wait(struct drm_device *dev, void *data, int i915_enable_vblank(struct drm_device *dev, int plane) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; int pipe = i915_get_pipe(dev, plane); u32 pipestat_reg = 0; + u32 mask_reg = 0; u32 pipestat; switch (pipe) { case 0: pipestat_reg = PIPEASTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: pipestat_reg = PIPEBSTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", @@ -629,26 +768,30 @@ int i915_enable_vblank(struct drm_device *dev, int plane) PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); } - I915_WRITE(IER, dev_priv->irq_enable_reg); + + DRM_SPINLOCK(&dev_priv->user_irq_lock); + i915_enable_irq(dev_priv, mask_reg); + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); return 0; } void i915_disable_vblank(struct drm_device *dev, int plane) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; int pipe = i915_get_pipe(dev, plane); u32 pipestat_reg = 0; + u32 mask_reg = 0; u32 pipestat; switch (pipe) { case 0: pipestat_reg = PIPEASTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: pipestat_reg = PIPEBSTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", @@ -656,10 +799,11 @@ void i915_disable_vblank(struct drm_device *dev, int plane) break; } - I915_WRITE(IER, dev_priv->irq_enable_reg); + DRM_SPINLOCK(&dev_priv->user_irq_lock); + i915_disable_irq(dev_priv, mask_reg); + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); - if (pipestat_reg) - { + if (pipestat_reg) { pipestat = I915_READ (pipestat_reg); pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | PIPE_VBLANK_INTERRUPT_ENABLE); @@ -669,14 +813,76 @@ void i915_disable_vblank(struct drm_device *dev, int plane) pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); + (void) I915_READ(pipestat_reg); } } void i915_enable_interrupt (struct drm_device *dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_connector *o; - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; + dev_priv->irq_mask_reg &= ~0; + + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + if (dev->mode_config.num_connector) + dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT; + } else { + if (dev->mode_config.num_connector) + dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + + /* Enable global interrupts for hotplug - not a pipeA event */ + I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) | + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_STATUS | + PIPE_HOTPLUG_INTERRUPT_STATUS); + } + + if (!(dev_priv->irq_mask_reg & I915_DISPLAY_PORT_INTERRUPT) || + !(dev_priv->irq_mask_reg & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { + u32 temp = 0; + + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + temp = I915_READ(PORT_HOTPLUG_EN); + + /* Activate the CRT */ + temp |= CRT_HOTPLUG_INT_EN; + } + + if (IS_I9XX(dev)) { + /* SDVOB */ + o = intel_sdvo_find(dev, 1); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + temp |= SDVOB_HOTPLUG_INT_EN; + } + + /* SDVOC */ + o = intel_sdvo_find(dev, 0); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + temp |= SDVOC_HOTPLUG_INT_EN; + } + + I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE); + I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE); + + /* TV */ + I915_WRITE(TV_DAC, I915_READ(TV_DAC) | TVDAC_STATE_CHG_EN); + } else { + /* DVO ???? */ + } + + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, temp); + + DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); + DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } + } #ifdef __linux__ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) @@ -684,7 +890,10 @@ void i915_enable_interrupt (struct drm_device *dev) #endif #endif - I915_WRITE(IER, dev_priv->irq_enable_reg); + I915_WRITE(IMR, dev_priv->irq_mask_reg); + I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); + (void) I915_READ (IER); + dev_priv->irq_enabled = 1; } @@ -693,7 +902,7 @@ void i915_enable_interrupt (struct drm_device *dev) int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); @@ -706,15 +915,23 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, int i915_vblank_pipe_get(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_vblank_pipe *pipe = data; + u32 flag = 0; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } - pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + if (dev_priv->irq_enabled) + flag = ~dev_priv->irq_mask_reg; + + pipe->pipe = 0; + if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) + pipe->pipe |= DRM_I915_VBLANK_PIPE_A; + if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) + pipe->pipe |= DRM_I915_VBLANK_PIPE_B; return 0; } @@ -725,9 +942,10 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_swap_t *swap = data; - drm_i915_vbl_swap_t *vbl_swap; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; + struct drm_i915_vblank_swap *swap = data; + struct drm_i915_vbl_swap *vbl_swap; unsigned int pipe, seqtype, curseq, plane; unsigned long irqflags; struct list_head *list; @@ -738,7 +956,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } - if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { + if (!dev->primary->master) + return -EINVAL; + + master_priv = dev->primary->master->driver_priv; + + if (master_priv->sarea_priv->rotation) { DRM_DEBUG("Rotation not supported\n"); return -EINVAL; } @@ -830,7 +1053,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); list_for_each(list, &dev_priv->vbl_swaps.head) { - vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + vbl_swap = list_entry(list, struct drm_i915_vbl_swap, head); if (vbl_swap->drw_id == swap->drawable && vbl_swap->plane == plane && @@ -864,6 +1087,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, vbl_swap->plane = plane; vbl_swap->sequence = swap->sequence; vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); + vbl_swap->minor = file_priv->minor; if (vbl_swap->flip) swap->sequence++; diff --git a/shared-core/i915_mem.c b/shared-core/i915_mem.c index 6126a60d..15d63dec 100644 --- a/shared-core/i915_mem.c +++ b/shared-core/i915_mem.c @@ -45,8 +45,9 @@ */ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; struct drm_tex_region *list; unsigned shift, nr; unsigned start; @@ -256,7 +257,7 @@ void i915_mem_takedown(struct mem_block **heap) *heap = NULL; } -static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) +static struct mem_block **get_heap(struct drm_i915_private * dev_priv, int region) { switch (region) { case I915_MEM_REGION_AGP: @@ -271,8 +272,8 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) int i915_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_alloc_t *alloc = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_mem_alloc *alloc = data; struct mem_block *block, **heap; if (!dev_priv) { @@ -309,8 +310,8 @@ int i915_mem_alloc(struct drm_device *dev, void *data, int i915_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_free_t *memfree = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_mem_free *memfree = data; struct mem_block *block, **heap; if (!dev_priv) { @@ -337,8 +338,8 @@ int i915_mem_free(struct drm_device *dev, void *data, int i915_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_init_heap_t *initheap = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_mem_init_heap *initheap = data; struct mem_block **heap; if (!dev_priv) { @@ -361,8 +362,8 @@ int i915_mem_init_heap(struct drm_device *dev, void *data, int i915_mem_destroy_heap( struct drm_device *dev, void *data, struct drm_file *file_priv ) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_destroy_heap_t *destroyheap = data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_mem_destroy_heap *destroyheap = data; struct mem_block **heap; if ( !dev_priv ) { diff --git a/shared-core/nouveau_dma.h b/shared-core/nouveau_dma.h index ce3c58cb..07652c2b 100644 --- a/shared-core/nouveau_dma.h +++ b/shared-core/nouveau_dma.h @@ -93,4 +93,9 @@ typedef enum { } \ } while(0) +/* This should allow easy switching to a real fifo in the future. */ +#define OUT_MODE(mthd, val) do { \ + nv50_display_command(dev_priv, mthd, val); \ +} while(0) + #endif diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index cd5f9cf8..03fe2ba7 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -41,6 +41,9 @@ #include "nouveau_drm.h" #include "nouveau_reg.h" +#include "nouveau_bios.h" + +#define MAX_NUM_DCB_ENTRIES 16 struct mem_block { struct mem_block *next; @@ -310,6 +313,28 @@ struct drm_nouveau_private { struct nouveau_config config; struct list_head gpuobj_list; + + void *display_priv; /* internal modesetting */ + void *kms_priv; /* related to public interface */ + + /* Hook these up to the "public interface" to accomodate a certain allocation style. */ + /* This is to avoid polluting the internal interface. */ + void *(*alloc_crtc) (struct drm_device *dev); + void *(*alloc_output) (struct drm_device *dev); + void *(*alloc_connector) (struct drm_device *dev); + + void (*free_crtc) (void *crtc); + void (*free_output) (void *output); + void (*free_connector) (void *connector); + + struct bios bios; + + struct { + int entries; + struct dcb_entry entry[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_read[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_write[MAX_NUM_DCB_ENTRIES]; + } dcb_table; }; #define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ @@ -353,6 +378,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, struct drm_file *, int tail); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); +extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle); extern uint64_t nouveau_mem_fb_amount(struct drm_device *); extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 2a3d8a0b..4c46da8d 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -37,6 +37,11 @@ #include "nouveau_reg.h" #include "nouveau_swmthd.h" +/* needed for interrupt based vpll changes */ +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_output.h" + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -503,11 +508,82 @@ static void nouveau_nv50_display_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t val = NV_READ(NV50_DISPLAY_SUPERVISOR); + uint32_t val = NV_READ(NV50_PDISPLAY_SUPERVISOR); DRM_INFO("NV50_DISPLAY_INTR - 0x%08X\n", val); - NV_WRITE(NV50_DISPLAY_SUPERVISOR, val); + /* vblank interrupts */ + if (val & NV50_PDISPLAY_SUPERVISOR_CRTCn) { + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CRTCn); + val &= ~NV50_PDISPLAY_SUPERVISOR_CRTCn; + } + + /* clock setting amongst other things. */ + if (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) { + uint32_t state = (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) >> NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT; + + NV50_DEBUG("state %d\n", state); + + /* Set pll */ + if (state == 2) { + struct nv50_display *display = nv50_get_display(dev); + struct nv50_output *output = NULL; + struct nv50_crtc *crtc = NULL; + int crtc_index; + + uint32_t unk30 = NV_READ(NV50_PDISPLAY_UNK30_CTRL); + + for (crtc_index = 0; crtc_index < 2; crtc_index++) { + bool clock_change = false; + bool clock_ack = false; + + if (crtc_index == 0 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0)) + clock_change = true; + + if (crtc_index == 1 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1)) + clock_change = true; + + if (clock_change) + clock_ack = true; + + if (display->last_crtc == crtc_index) + clock_ack = true; + + list_for_each_entry(crtc, &display->crtcs, item) { + if (crtc->index == crtc_index) + break; + } + + if (clock_change) + crtc->set_clock(crtc); + + NV50_DEBUG("index %d clock_change %d clock_ack %d\n", crtc_index, clock_change, clock_ack); + + if (!clock_ack) + continue; + + crtc->set_clock_mode(crtc); + + list_for_each_entry(output, &display->outputs, item) { + if (!output->crtc) + continue; + + if (output->crtc == crtc) + output->set_clock_mode(output); + } + } + } + + NV_WRITE(NV50_PDISPLAY_UNK30_CTRL, NV50_PDISPLAY_UNK30_CTRL_PENDING); + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK); + + val &= ~NV50_PDISPLAY_SUPERVISOR_CLK_MASK; + } + + if (val) + DRM_ERROR("unsupported NV50_DISPLAY_INTR - 0x%08X\n", val); + + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val); } static void diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index d79c1a52..1078a9c5 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -34,6 +34,7 @@ #include "drm.h" #include "drm_sarea.h" #include "nouveau_drv.h" +#include "nv50_kms_wrapper.h" static struct mem_block * split_block(struct mem_block *p, uint64_t start, uint64_t size, @@ -120,6 +121,17 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start) return NULL; } +struct mem_block *find_block_by_handle(struct mem_block *heap, drm_handle_t handle) +{ + struct mem_block *p; + + list_for_each(p, heap) + if (p->map_handle == handle) + return p; + + return NULL; +} + void nouveau_mem_free_block(struct mem_block *p) { p->file_priv = NULL; @@ -734,6 +746,30 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags); + /* Check if the deallocations cause problems for our modesetting system. */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (dev_priv->card_type >= NV_50) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + + list_for_each_entry(crtc, &display->crtcs, item) { + if (crtc->fb->block == block) { + crtc->fb->block = NULL; + + if (!crtc->blanked) + crtc->blank(crtc, true); + } + + if (crtc->cursor->block == block) { + crtc->cursor->block = NULL; + + if (crtc->cursor->visible) + crtc->cursor->hide(crtc); + } + } + } + } + if (block->flags&NOUVEAU_MEM_MAPPED) drm_rmmap(dev, block->map); diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 1ae0177c..6ed23e26 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -116,6 +116,9 @@ #define NV04_PBUS_PCI_NV_1 0x00001804 #define NV04_PBUS_PCI_NV_19 0x0000184C +#define NV04_PBUS_PCI_NV_20 0x00001850 +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED (0 << 0) +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED (1 << 0) #define NV04_PTIMER_INTR_0 0x00009100 #define NV04_PTIMER_INTR_EN_0 0x00009140 @@ -542,6 +545,8 @@ /* This name is a partial guess. */ #define NV50_DISPLAY_SUPERVISOR 0x00610024 +#define NV04_PRAMIN 0x00700000 + /* Fifo commands. These are not regs, neither masks */ #define NV03_FIFO_CMD_JUMP 0x20000000 #define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc @@ -591,3 +596,236 @@ #define NV40_RAMFC_UNK_48 0x48 #define NV40_RAMFC_UNK_4C 0x4C #define NV40_RAMFC_UNK_50 0x50 + +/* This is a partial import from rules-ng, a few things may be duplicated. + * Eventually we should completely import everything from rules-ng. + * For the moment check rules-ng for docs. + */ + +#define NV50_PMC 0x00000000 +#define NV50_PMC__LEN 0x1 +#define NV50_PMC__ESIZE 0x2000 +# define NV50_PMC_BOOT_0 0x00000000 +# define NV50_PMC_BOOT_0_REVISION 0x000000ff +# define NV50_PMC_BOOT_0_REVISION__SHIFT 0 +# define NV50_PMC_BOOT_0_ARCH 0x0ff00000 +# define NV50_PMC_BOOT_0_ARCH__SHIFT 20 +# define NV50_PMC_INTR_0 0x00000100 +# define NV50_PMC_INTR_0_PFIFO (1<<8) +# define NV50_PMC_INTR_0_PGRAPH (1<<12) +# define NV50_PMC_INTR_0_PTIMER (1<<20) +# define NV50_PMC_INTR_0_HOTPLUG (1<<21) +# define NV50_PMC_INTR_0_DISPLAY (1<<26) +# define NV50_PMC_INTR_EN_0 0x00000140 +# define NV50_PMC_INTR_EN_0_MASTER (1<<0) +# define NV50_PMC_INTR_EN_0_MASTER_DISABLED (0<<0) +# define NV50_PMC_INTR_EN_0_MASTER_ENABLED (1<<0) +# define NV50_PMC_ENABLE 0x00000200 +# define NV50_PMC_ENABLE_PFIFO (1<<8) +# define NV50_PMC_ENABLE_PGRAPH (1<<12) + +#define NV50_PCONNECTOR 0x0000e000 +#define NV50_PCONNECTOR__LEN 0x1 +#define NV50_PCONNECTOR__ESIZE 0x1000 +# define NV50_PCONNECTOR_HOTPLUG_INTR 0x0000e050 +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054 +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_STATE 0x0000e104 +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C1 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C2 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C3 (1<<14) +# define NV50_PCONNECTOR_I2C_PORT_0 0x0000e138 +# define NV50_PCONNECTOR_I2C_PORT_1 0x0000e150 +# define NV50_PCONNECTOR_I2C_PORT_2 0x0000e168 +# define NV50_PCONNECTOR_I2C_PORT_3 0x0000e180 +# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240 +# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258 + +#define NV50_PBUS 0x00088000 +#define NV50_PBUS__LEN 0x1 +#define NV50_PBUS__ESIZE 0x1000 +# define NV50_PBUS_PCI_ID 0x00088000 +# define NV50_PBUS_PCI_ID_VENDOR_ID 0x0000ffff +# define NV50_PBUS_PCI_ID_VENDOR_ID__SHIFT 0 +# define NV50_PBUS_PCI_ID_DEVICE_ID 0xffff0000 +# define NV50_PBUS_PCI_ID_DEVICE_ID__SHIFT 16 + +#define NV50_PFB 0x00100000 +#define NV50_PFB__LEN 0x1 +#define NV50_PFB__ESIZE 0x1000 + +#define NV50_PEXTDEV 0x00101000 +#define NV50_PEXTDEV__LEN 0x1 +#define NV50_PEXTDEV__ESIZE 0x1000 + +#define NV50_PROM 0x00300000 +#define NV50_PROM__LEN 0x1 +#define NV50_PROM__ESIZE 0x10000 + +#define NV50_PGRAPH 0x00400000 +#define NV50_PGRAPH__LEN 0x1 +#define NV50_PGRAPH__ESIZE 0x10000 + +#define NV50_PDISPLAY 0x00610000 +#define NV50_PDISPLAY__LEN 0x1 +#define NV50_PDISPLAY__ESIZE 0x10000 +# define NV50_PDISPLAY_SUPERVISOR 0x00610024 +# define NV50_PDISPLAY_SUPERVISOR_CRTCn 0x0000000c +# define NV50_PDISPLAY_SUPERVISOR_CRTCn__SHIFT 2 +# define NV50_PDISPLAY_SUPERVISOR_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK 0x00000070 +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT 4 +# define NV50_PDISPLAY_SUPERVISOR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR 0x0061002c +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK1 (1<<4) +# define NV50_PDISPLAY_SUPERVISOR_INTR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK4 (1<<6) +# define NV50_PDISPLAY_UNK30_CTRL 0x00610030 +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 (1<<9) +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 (1<<10) +# define NV50_PDISPLAY_UNK30_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_UNK50_CTRL 0x00610050 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE (1<<1) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK 0x00000003 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK__SHIFT 0 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE (1<<9) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK 0x00000300 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK__SHIFT 8 +# define NV50_PDISPLAY_UNK200_CTRL 0x00610200 +# define NV50_PDISPLAY_CURSOR 0x00610270 +# define NV50_PDISPLAY_CURSOR__LEN 0x2 +# define NV50_PDISPLAY_CURSOR__ESIZE 0x10 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) (0x00610270+(i)*0x10) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON (1<<0) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK 0x00030000 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK__SHIFT 16 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE (1<<16) + +# define NV50_PDISPLAY_CTRL_STATE 0x00610300 +# define NV50_PDISPLAY_CTRL_STATE_ENABLE (1<<0) +# define NV50_PDISPLAY_CTRL_STATE_PENDING (1<<31) +# define NV50_PDISPLAY_CTRL_VAL 0x00610304 +# define NV50_PDISPLAY_UNK_380 0x00610380 +# define NV50_PDISPLAY_RAM_AMOUNT 0x00610384 +# define NV50_PDISPLAY_UNK_388 0x00610388 +# define NV50_PDISPLAY_UNK_38C 0x0061038c +# define NV50_PDISPLAY_CRTC_VAL 0x00610a00 +# define NV50_PDISPLAY_CRTC_VAL__LEN 0x2 +# define NV50_PDISPLAY_CRTC_VAL_UNK_900(i,j) (0x00610a18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLUT_MODE(i,j) (0x00610a24+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_INTERLACE(i,j) (0x00610a48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CTRL(i,j) (0x00610a50+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CURSOR_CTRL(i,j) (0x00610a58+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_904(i,j) (0x00610ab8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DEPTH(i,j) (0x00610ac8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLOCK(i,j) (0x00610ad0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_COLOR_CTRL(i,j) (0x00610ae0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_START_TO_BLANK_END(i,j) (0x00610ae8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK1(i,j) (0x00610af0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DISPLAY_TOTAL(i,j) (0x00610af8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_DURATION(i,j) (0x00610b00+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK2(i,j) (0x00610b08+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_828(i,j) (0x00610b10+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_SIZE(i,j) (0x00610b18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH(i,j) (0x00610b20+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH_LINEAR_FB (1<<20) +# define NV50_PDISPLAY_CRTC_VAL_FB_POS(i,j) (0x00610b28+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CENTER_OFFSET(i,j) (0x00610b38+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_REAL_RES(i,j) (0x00610b40+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES1(i,j) (0x00610b48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES2(i,j) (0x00610b50+(i)*0x540+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL(i,j) (0x00610b58+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_SOR_VAL_MODE_CTRL(i,j) (0x00610b70+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL2(i,j) (0x00610bdc+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_CRTC_CLK 0x00614000 +# define NV50_PDISPLAY_CRTC_CLK__LEN 0x2 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(i) (0x00614100+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i) (0x00614104+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i) (0x00614108+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(i) (0x00614200+(i)*0x800) + +# define NV50_PDISPLAY_DAC_CLK 0x00614000 +# define NV50_PDISPLAY_DAC_CLK__LEN 0x3 +# define NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(i) (0x00614280+(i)*0x800) + +# define NV50_PDISPLAY_SOR_CLK 0x00614000 +# define NV50_PDISPLAY_SOR_CLK__LEN 0x3 +# define NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(i) (0x00614300+(i)*0x800) + +# define NV50_PDISPLAY_DAC_REGS 0x0061a000 +# define NV50_PDISPLAY_DAC_REGS__LEN 0x3 +# define NV50_PDISPLAY_DAC_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i) (0x0061a004+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF (1<<0) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF (1<<2) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED (1<<4) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF (1<<6) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(i) (0x0061a00c+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE (1<<20) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT 0x38000000 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT__SHIFT 29 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_DONE (1<<31) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i) (0x0061a010+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 + +# define NV50_PDISPLAY_SOR_REGS 0x0061c000 +# define NV50_PDISPLAY_SOR_REGS__LEN 0x2 +# define NV50_PDISPLAY_SOR_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(i) (0x0061c004+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON (1<<0) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1(i) (0x0061c008+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_SOR_REGS_UNK_00C(i) (0x0061c00c+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_010(i) (0x0061c010+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_014(i) (0x0061c014+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_018(i) (0x0061c018+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i) (0x0061c030+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE 0x00030000 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE__SHIFT 16 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_BLANKED (1<<19) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT (1<<28) + + +#define NV50_UNK640000 0x00640000 +#define NV50_UNK640000__LEN 0x6 +#define NV50_UNK640000__ESIZE 0x1000 +# define NV50_UNK640000_UNK_000(i) (0x00640000+(i)*0x1000) + +#define NV50_HW_CURSOR 0x00647000 +#define NV50_HW_CURSOR__LEN 0x2 +#define NV50_HW_CURSOR__ESIZE 0x1000 +# define NV50_HW_CURSOR_POS_CTRL(i) (0x00647080+(i)*0x1000) +# define NV50_HW_CURSOR_POS(i) (0x00647084+(i)*0x1000) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index d9c6efe7..3baae6ad 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -27,6 +27,8 @@ #include "drm_sarea.h" #include "nouveau_drv.h" #include "nouveau_drm.h" +#include "nv50_kms_wrapper.h" +#include "nv50_fbcon.h" static int nouveau_init_card_mappings(struct drm_device *dev) { @@ -362,6 +364,14 @@ nouveau_card_init(struct drm_device *dev) if (ret) return ret; dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (dev_priv->card_type >= NV_50) { + nv50_kms_init(dev); + //nv50_kms_connector_detect_all(dev); + nv50_fbcon_init(dev); + } + return 0; } @@ -410,8 +420,7 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv) nouveau_mem_release(file_priv,dev_priv->pci_heap); } -/* first module load, setup the mmio/fb mapping */ -int nouveau_firstopen(struct drm_device *dev) +int nouveau_setup_mappings(struct drm_device *dev) { #if defined(__powerpc__) struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -457,6 +466,16 @@ int nouveau_firstopen(struct drm_device *dev) return 0; } +/* first module load, setup the mmio/fb mapping */ +/* KMS: we need mmio at load time, not when the first drm client opens. */ +int nouveau_firstopen(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + return nouveau_setup_mappings(dev); +} + #define NV40_CHIPSET_MASK 0x00000baf #define NV44_CHIPSET_MASK 0x00005450 @@ -540,6 +559,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) return -EINVAL; } + /* For those who think they want to be funny. */ + if (dev_priv->card_type < NV_50) + dev->driver->driver_features &= ~DRIVER_MODESET; + /* Special flags */ if (dev->pci_device == 0x01a0) { dev_priv->flags |= NV_NFORCE; @@ -549,10 +572,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; + /* init card now, otherwise bad things happen */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + int rval = 0; + + rval = nouveau_setup_mappings(dev); + if (rval != 0) + return rval; + + rval = nouveau_card_init(dev); + if (rval != 0) + return rval; + } + return 0; } -void nouveau_lastclose(struct drm_device *dev) +void nouveau_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -568,8 +604,23 @@ void nouveau_lastclose(struct drm_device *dev) } } +/* KMS: we need mmio at load time, not when the first drm client opens. */ +void nouveau_lastclose(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + nouveau_close(dev); +} + int nouveau_unload(struct drm_device *dev) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + nv50_kms_destroy(dev); + nv50_fbcon_destroy(dev); + nouveau_close(dev); + } + drm_free(dev->dev_private, sizeof(*dev->dev_private), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index 7546e839..05a76ef1 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -811,13 +811,13 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) RING_LOCALS; cache_z = R300_ZC_FLUSH; - cache_2d = R300_RB2D_DC_FLUSH; - cache_3d = R300_RB3D_DC_FLUSH; + cache_2d = R300_DC_FLUSH_2D; + cache_3d = R300_DC_FLUSH_3D; if (!(dev_priv->track_flush & RADEON_PURGE_EMITED)) { /* we can purge, primitive where draw since last purge */ cache_z |= R300_ZC_FREE; - cache_2d |= R300_RB2D_DC_FREE; - cache_3d |= R300_RB3D_DC_FREE; + cache_2d |= R300_DC_FREE_2D; + cache_3d |= R300_DC_FREE_3D; } /* flush & purge zbuffer */ @@ -861,12 +861,12 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must * be careful about how this function is called. */ -static void r300_discard_buffer(struct drm_device * dev, struct drm_buf * buf) +static void r300_discard_buffer(struct drm_device * dev, struct drm_master *master, struct drm_buf * buf) { - drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; - buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; + buf_priv->age = ++master_priv->sarea_priv->last_dispatch; buf->pending = 1; buf->used = 0; } @@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf = NULL; int emit_dispatch_age = 0; @@ -1133,7 +1134,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, } emit_dispatch_age = 1; - r300_discard_buffer(dev, buf); + r300_discard_buffer(dev, file_priv->master, buf); break; case R300_CMD_WAIT: @@ -1188,7 +1189,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, /* Emit the vertex buffer age */ BEGIN_RING(2); - RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch); + RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch); ADVANCE_RING(); } diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index ae31e969..6fbcfeab 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "drm.h" +#include "drm_sarea.h" #include "radeon_drm.h" #include "radeon_drv.h" #include "r300_reg.h" @@ -76,6 +77,23 @@ static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) return RS480_READ_MCIND(dev_priv, addr); } +u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr) +{ + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + return IGP_READ_MCIND(dev_priv, addr); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) + return R500_READ_MCIND(dev_priv, addr); + return 0; +} + +void radeon_write_mc_reg(drm_radeon_private_t *dev_priv, u32 addr, u32 val) +{ + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + IGP_WRITE_MCIND(addr, val); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) + R500_WRITE_MCIND(addr, val); +} + u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) { @@ -138,12 +156,57 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) } } -static int RADEON_READ_PLL(struct drm_device * dev, int addr) + +void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv) { - drm_radeon_private_t *dev_priv = dev->dev_private; + if (!(dev_priv->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) + return; - RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f); - return RADEON_READ(RADEON_CLOCK_CNTL_DATA); + (void)RADEON_READ(RADEON_CLOCK_CNTL_DATA); + (void)RADEON_READ(RADEON_CRTC_GEN_CNTL); +} + +void radeon_pll_errata_after_data(struct drm_radeon_private *dev_priv) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (dev_priv->pll_errata & CHIP_ERRATA_PLL_DELAY) + udelay(5000); + + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (dev_priv->pll_errata & CHIP_ERRATA_R300_CG) { + uint32_t save, tmp; + + save = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | RADEON_PLL_WR_EN); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, tmp); + tmp = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, save); + } +} + +int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr) +{ + uint32_t data; + + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); + radeon_pll_errata_after_index(dev_priv); + data = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + radeon_pll_errata_after_data(dev_priv); + return data; +} + +void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data) +{ + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f) | RADEON_PLL_WR_EN)); + radeon_pll_errata_after_index(dev_priv); + RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, data); + radeon_pll_errata_after_data(dev_priv); } static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) @@ -152,6 +215,39 @@ static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) return RADEON_READ(RADEON_PCIE_DATA); } +/* ATOM accessor methods */ +static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret = radeon_read_mc_reg(info->dev->dev_private, reg); + + // DRM_DEBUG("(%x) = %x\n", reg, ret); + return ret; +} + +static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + // DRM_DEBUG("(%x, %x)\n", reg, val); + radeon_write_mc_reg(info->dev->dev_private, reg, val); +} + +static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + // DRM_DEBUG("(%x, %x)\n", reg*4, val); + RADEON_WRITE(reg*4, val); +} + +static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret; + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + ret = RADEON_READ(reg*4); + // DRM_DEBUG("(%x) = %x\n", reg*4, ret); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -294,7 +390,7 @@ static void radeon_init_pipes(drm_radeon_private_t * dev_priv) } if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) { - RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); + RADEON_WRITE_PLL(dev_priv, R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1)); } RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config); @@ -494,15 +590,15 @@ static int radeon_do_engine_reset(struct drm_device * dev) if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { /* may need something similar for newer chips */ clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); - mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL); - - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl | - RADEON_FORCEON_MCLKA | - RADEON_FORCEON_MCLKB | - RADEON_FORCEON_YCLKA | - RADEON_FORCEON_YCLKB | - RADEON_FORCEON_MC | - RADEON_FORCEON_AIC)); + mclk_cntl = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, (mclk_cntl | + RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB | + RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC | + RADEON_FORCEON_AIC)); } rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET); @@ -527,7 +623,7 @@ static int radeon_do_engine_reset(struct drm_device * dev) RADEON_READ(RADEON_RBBM_SOFT_RESET); if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, mclk_cntl); RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index); RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset); } @@ -543,7 +639,8 @@ static int radeon_do_engine_reset(struct drm_device * dev) dev_priv->cp_running = 0; /* Reset any pending vertex, indirect buffers */ - radeon_freelist_reset(dev); + if (dev->dma) + radeon_freelist_reset(dev); return 0; } @@ -561,9 +658,13 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, */ if (!dev_priv->new_memmap) radeon_write_fb_location(dev_priv, - ((dev_priv->gart_vm_start - 1) & 0xffff0000) - | (dev_priv->fb_location >> 16)); - + ((dev_priv->gart_vm_start - 1) & 0xffff0000) + | (dev_priv->fb_location >> 16)); + + if (dev_priv->mm.ring) { + ring_start = dev_priv->mm.ring->offset + + dev_priv->gart_vm_start; + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { radeon_write_agp_base(dev_priv, dev->agp->base); @@ -593,6 +694,12 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, SET_RING_HEAD(dev_priv, cur_read_ptr); dev_priv->ring.tail = cur_read_ptr; + + if (dev_priv->mm.ring_read_ptr) { + RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, + dev_priv->mm.ring_read_ptr->offset + + dev_priv->gart_vm_start); + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, @@ -641,9 +748,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR) + RADEON_SCRATCH_REG_OFFSET); - dev_priv->scratch = ((__volatile__ u32 *) - dev_priv->ring_rptr->handle + - (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); + if (dev_priv->mm.ring_read_ptr) + dev_priv->scratch = ((__volatile__ u32 *) + dev_priv->mm.ring_read_ptr_map.virtual + + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); + else + dev_priv->scratch = ((__volatile__ u32 *) + dev_priv->ring_rptr->handle + + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); @@ -651,15 +763,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; RADEON_WRITE(RADEON_BUS_CNTL, tmp); - dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; - RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); + dev_priv->scratch[0] = 0; + RADEON_WRITE(RADEON_LAST_FRAME_REG, 0); - dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; - RADEON_WRITE(RADEON_LAST_DISPATCH_REG, - dev_priv->sarea_priv->last_dispatch); + dev_priv->scratch[1] = 0; + RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0); - dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; - RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); + dev_priv->scratch[2] = 0; + RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); radeon_do_wait_for_idle(dev_priv); @@ -675,15 +786,21 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, static void radeon_test_writeback(drm_radeon_private_t * dev_priv) { u32 tmp; + void *ring_read_ptr; + + if (dev_priv->mm.ring_read_ptr) + ring_read_ptr = dev_priv->mm.ring_read_ptr_map.virtual; + else + ring_read_ptr = dev_priv->ring_rptr->handle; /* Writeback doesn't seem to work everywhere, test it here and possibly * enable it if it appears to work */ - DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); + writel(0, ring_read_ptr + RADEON_SCRATCHOFF(1)); RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { - if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == + if (readl(ring_read_ptr + RADEON_SCRATCHOFF(1)) == 0xdeadbeef) break; DRM_UDELAY(1); @@ -809,7 +926,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) } /* Enable or disable PCI GART on the chip */ -static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) +void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; @@ -850,9 +967,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) } } -static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) +static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, + struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; DRM_DEBUG("\n"); @@ -968,8 +1087,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->buffers_offset = init->buffers_offset; dev_priv->gart_textures_offset = init->gart_textures_offset; - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { + master_priv->sarea = drm_getsarea(dev); + if (!master_priv->sarea) { DRM_ERROR("could not find sarea!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; @@ -1005,10 +1124,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) } } - dev_priv->sarea_priv = - (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle + - init->sarea_priv_offset); - #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { drm_core_ioremap(dev_priv->cp_ring, dev); @@ -1139,28 +1254,40 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); /* if we have an offset set from userspace */ if (dev_priv->pcigart_offset_set) { - dev_priv->gart_info.bus_addr = - dev_priv->pcigart_offset + dev_priv->fb_location; - dev_priv->gart_info.mapping.offset = - dev_priv->pcigart_offset + dev_priv->fb_aper_offset; - dev_priv->gart_info.mapping.size = - dev_priv->gart_info.table_size; - - drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = - dev_priv->gart_info.mapping.handle; - - if (dev_priv->flags & RADEON_IS_PCIE) - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; - else - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; - dev_priv->gart_info.gart_table_location = - DRM_ATI_GART_FB; - - DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", - dev_priv->gart_info.addr, - dev_priv->pcigart_offset); + /* if it came from userspace - remap it */ + if (dev_priv->pcigart_offset_set == 1) { + dev_priv->gart_info.bus_addr = + dev_priv->pcigart_offset + dev_priv->fb_location; + dev_priv->gart_info.mapping.offset = + dev_priv->pcigart_offset + dev_priv->fb_aper_offset; + dev_priv->gart_info.mapping.size = + dev_priv->gart_info.table_size; + + /* this is done by the mm now */ + drm_core_ioremap(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = + dev_priv->gart_info.mapping.handle; + + memset(dev_priv->gart_info.addr, 0, dev_priv->gart_info.table_size); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; + dev_priv->gart_info.gart_table_location = + DRM_ATI_GART_FB; + + DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", + dev_priv->gart_info.addr, + dev_priv->pcigart_offset); + } } else { + + if (dev_priv->flags & RADEON_IS_PCIE) { + DRM_ERROR + ("Cannot use PCI Express without GART in FB memory\n"); + radeon_do_cleanup_cp(dev); + return -EINVAL; + } if (dev_priv->flags & RADEON_IS_IGPGART) dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; else @@ -1169,12 +1296,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - if (dev_priv->flags & RADEON_IS_PCIE) { - DRM_ERROR - ("Cannot use PCI Express without GART in FB memory\n"); - radeon_do_cleanup_cp(dev); - return -EINVAL; - } + } if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { @@ -1237,8 +1359,10 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = 0; + if (dev_priv->pcigart_offset_set == 1) { + drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = NULL; + } } } /* only clear to the start of flags */ @@ -1290,6 +1414,10 @@ static int radeon_do_resume_cp(struct drm_device * dev) int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_init_t *init = data; + + /* on a modesetting driver ignore this stuff */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -1300,7 +1428,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri case RADEON_INIT_CP: case RADEON_INIT_R200_CP: case RADEON_INIT_R300_CP: - return radeon_do_init_cp(dev, init); + return radeon_do_init_cp(dev, init, file_priv); case RADEON_CLEANUP_CP: return radeon_do_cleanup_cp(dev); } @@ -1313,6 +1441,9 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cp_running) { @@ -1340,6 +1471,9 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri int ret; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->cp_running) @@ -1378,6 +1512,9 @@ void radeon_do_release(struct drm_device * dev) drm_radeon_private_t *dev_priv = dev->dev_private; int i, ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + if (dev_priv) { if (dev_priv->cp_running) { /* Stop the cp */ @@ -1416,6 +1553,9 @@ void radeon_do_release(struct drm_device * dev) radeon_mem_takedown(&(dev_priv->gart_heap)); radeon_mem_takedown(&(dev_priv->fb_heap)); + + radeon_gem_mm_fini(dev); + /* deallocate kernel resources */ radeon_do_cleanup_cp(dev); } @@ -1428,6 +1568,9 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { @@ -1448,7 +1591,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_cp_idle(dev_priv); } @@ -1458,6 +1603,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + return radeon_do_resume_cp(dev); } @@ -1465,6 +1613,9 @@ int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *fil { DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_engine_reset(dev); @@ -1687,6 +1838,541 @@ int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_ return ret; } +static void radeon_get_vram_type(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (dev_priv->flags & RADEON_IS_IGP || (dev_priv->chip_family >= CHIP_R300)) + dev_priv->is_ddr = true; + else if (RADEON_READ(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) + dev_priv->is_ddr = true; + else + dev_priv->is_ddr = false; + + if ((dev_priv->chip_family >= CHIP_R600) && + (dev_priv->chip_family <= CHIP_RV635)) { + int chansize; + + tmp = RADEON_READ(R600_RAMCFG); + if (tmp & R600_CHANSIZE_OVERRIDE) + chansize = 16; + else if (tmp & R600_CHANSIZE) + chansize = 64; + else + chansize = 32; + + if (dev_priv->chip_family == CHIP_R600) + dev_priv->ram_width = 8 * chansize; + else if (dev_priv->chip_family == CHIP_RV670) + dev_priv->ram_width = 4 * chansize; + else if ((dev_priv->chip_family == CHIP_RV610) || + (dev_priv->chip_family == CHIP_RV620)) + dev_priv->ram_width = chansize; + else if ((dev_priv->chip_family == CHIP_RV630) || + (dev_priv->chip_family == CHIP_RV635)) + dev_priv->ram_width = 2 * chansize; + } else if (dev_priv->chip_family == CHIP_RV515) { + tmp = radeon_read_mc_reg(dev_priv, RV515_MC_CNTL); + tmp &= RV515_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: dev_priv->ram_width = 64; break; + case 1: dev_priv->ram_width = 128; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family >= CHIP_R520) && + (dev_priv->chip_family <= CHIP_RV570)) { + tmp = radeon_read_mc_reg(dev_priv, R520_MC_CNTL0); + switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { + case 0: dev_priv->ram_width = 32; break; + case 1: dev_priv->ram_width = 64; break; + case 2: dev_priv->ram_width = 128; break; + case 3: dev_priv->ram_width = 256; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family == CHIP_RV100) || + (dev_priv->chip_family == CHIP_RS100) || + (dev_priv->chip_family == CHIP_RS200)) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RV100_HALF_MODE) + dev_priv->ram_width = 32; + else + dev_priv->ram_width = 64; + + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + dev_priv->ram_width /= 4; + dev_priv->is_ddr = true; + } + } else if (dev_priv->chip_family <= CHIP_RV280) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) + dev_priv->ram_width = 128; + else + dev_priv->ram_width = 64; + } else { + /* newer IGPs */ + dev_priv->ram_width = 128; + } + DRM_DEBUG("RAM width %d bits %cDR\n", dev_priv->ram_width, dev_priv->is_ddr ? 'D' : 'S'); +} + +static void radeon_force_some_clocks(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); +} + +static void radeon_set_dynamic_clock(struct drm_device *dev, int mode) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + switch(mode) { + case 0: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_RB); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if (dev_priv->chip_family == CHIP_RV350) { + /* for RV350/M10, no delays are required. */ + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= (R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2); + tmp |= RADEON_SCLK_FORCE_SE; + + if ( dev_priv->flags & RADEON_SINGLE_CRTC ) { + tmp |= ( RADEON_SCLK_FORCE_RB | + RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_HDP ); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp |= ( RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP); + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + udelay(16000); + + if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= ( R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + udelay(16000); + } + + if (dev_priv->flags & RADEON_IS_IGP) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp &= ~(RADEON_FORCEON_MCLKA | + RADEON_FORCEON_YCLKA); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + udelay(16000); + } + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(16000); + } + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(16000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + } + DRM_DEBUG("Dynamic Clock Scaling Disabled\n"); + break; + case 1: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + if ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) > + RADEON_CFG_ATI_REV_A13) { + tmp &= ~(RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_RB); + } + tmp &= ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_TDM); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350) || + (dev_priv->chip_family == CHIP_RV350)) { + if (dev_priv->chip_family == CHIP_RV350) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT | + R300_SCLK_GA_MAX_DYN_STOP_LAT | + R300_SCLK_CBA_MAX_DYN_STOP_LAT); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_MISC); + tmp |= (RADEON_MC_MCLK_DYN_ENABLE | + RADEON_IO_MCLK_DYN_ENABLE); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_MISC, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp |= (RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB); + + tmp &= ~(RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC); + + /* Some releases of vbios have set DISABLE_MC_MCLKA + and DISABLE_MC_MCLKB bits in the vbios table. Setting these + bits will cause H/W hang when reading video memory with dynamic clocking + enabled. */ + if ((tmp & R300_DISABLE_MC_MCLKA) && + (tmp & R300_DISABLE_MC_MCLKB)) { + /* If both bits are set, then check the active channels */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + if (dev_priv->ram_width == 64) { + if (RADEON_READ(RADEON_MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY) + tmp &= ~R300_DISABLE_MC_MCLKB; + else + tmp &= ~R300_DISABLE_MC_MCLKA; + } else { + tmp &= ~(R300_DISABLE_MC_MCLKA | + R300_DISABLE_MC_MCLKB); + } + } + + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(R300_SCLK_FORCE_VAP); + tmp |= RADEON_SCLK_FORCE_CP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + } + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL); + tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK | + RADEON_DISP_DYN_STOP_LAT_MASK | + RADEON_DYN_STOP_MODE_MASK); + + tmp |= (RADEON_ENGIN_DYNCLK_MODE | + (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PIN_CNTL); + tmp |= RADEON_SCLK_DYN_START_CNTL; + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PIN_CNTL, tmp); + udelay(15000); + + /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 + to lockup randomly, leave them as set by BIOS. + */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + /*tmp &= RADEON_SCLK_SRC_SEL_MASK;*/ + tmp &= ~RADEON_SCLK_FORCEON_MASK; + + /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/ + if (((dev_priv->chip_family == CHIP_RV250) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) || + ((dev_priv->chip_family == CHIP_RV100) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <= + RADEON_CFG_ATI_REV_A13))){ + tmp |= RADEON_SCLK_FORCE_CP; + tmp |= RADEON_SCLK_FORCE_VIP; + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + + /* RV200::A11 A12 RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp |= RADEON_SCLK_MORE_FORCEON; + } + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(15000); + } + + /* RV200::A11 A12, RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL); + tmp |= RADEON_TCL_BYPASS_DISABLE; + RADEON_WRITE_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL, tmp); + } + udelay(15000); + + /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK)*/ + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + udelay(15000); + } + DRM_DEBUG("Dynamic Clock Scaling Enabled\n"); + break; + default: + break; + } + +} + +int radeon_modeset_cp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + /* allocate a ring and ring rptr bits from GART space */ + /* these are allocated in GEM files */ + + dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; + dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; + dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; + + dev_priv->ring.start = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual; + dev_priv->ring.end = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual + + dev_priv->ring.size / sizeof(u32); + dev_priv->ring.size_l2qw = drm_order(dev_priv->ring.size / 8); + dev_priv->ring.rptr_update = 4096; + dev_priv->ring.rptr_update_l2qw = drm_order(4096 / 8); + dev_priv->ring.fetch_size = 32; + dev_priv->ring.fetch_size_l2ow = drm_order(32 / 16); + dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; + dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; + + dev_priv->new_memmap = 1; + + radeon_cp_load_microcode(dev_priv); + + DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring->offset, dev_priv->mm.ring_read_ptr->offset); + + radeon_cp_init_ring_buffer(dev, dev_priv); + + radeon_do_engine_reset(dev); + radeon_test_writeback(dev_priv); + + radeon_do_cp_start(dev_priv); + return 0; +} + +static bool radeon_get_bios(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u8 __iomem *bios; + size_t size; + uint16_t tmp; + + bios = pci_map_rom(dev->pdev, &size); + if (!bios) + return -1; + + dev_priv->bios = kmalloc(size, GFP_KERNEL); + if (!dev_priv->bios) { + pci_unmap_rom(dev->pdev, bios); + return -1; + } + + memcpy(dev_priv->bios, bios, size); + + pci_unmap_rom(dev->pdev, bios); + + if (dev_priv->bios[0] != 0x55 || dev_priv->bios[1] != 0xaa) + goto free_bios; + + dev_priv->bios_header_start = radeon_bios16(dev_priv, 0x48); + + if (!dev_priv->bios_header_start) + goto free_bios; + + tmp = dev_priv->bios_header_start + 4; + + if (!memcmp(dev_priv->bios + tmp, "ATOM", 4) || + !memcmp(dev_priv->bios + tmp, "MOTA", 4)) + dev_priv->is_atom_bios = true; + else + dev_priv->is_atom_bios = false; + + DRM_DEBUG("%sBIOS detected\n", dev_priv->is_atom_bios ? "ATOM" : "COM"); + return true; +free_bios: + kfree(dev_priv->bios); + dev_priv->bios = NULL; + return false; +} + +int radeon_modeset_preinit(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + static struct card_info card; + int ret; + + card.dev = dev; + card.reg_read = cail_reg_read; + card.reg_write = cail_reg_write; + card.mc_read = cail_mc_read; + card.mc_write = cail_mc_write; + + ret = radeon_get_bios(dev); + if (!ret) + return -1; + + if (dev_priv->is_atom_bios) { + dev_priv->mode_info.atom_context = atom_parse(&card, dev_priv->bios); + radeon_get_clock_info(dev); + } + return 0; +} + + int radeon_driver_load(struct drm_device *dev, unsigned long flags) { drm_radeon_private_t *dev_priv; @@ -1727,11 +2413,122 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; + + DRM_DEBUG("%s card detected\n", ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); + + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), + drm_get_resource_len(dev, 2), _DRM_REGISTERS, + _DRM_DRIVER | _DRM_READ_ONLY, &dev_priv->mmio); + if (ret != 0) + return ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_modeset_preinit(dev); + + + radeon_get_vram_type(dev); + + dev_priv->pll_errata = 0; + + if (dev_priv->chip_family == CHIP_R300 && + (RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) + dev_priv->pll_errata |= CHIP_ERRATA_R300_CG; + + if (dev_priv->chip_family == CHIP_RV200 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; + + + if (dev_priv->chip_family == CHIP_RV100 || + dev_priv->chip_family == CHIP_RS100 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DELAY; + + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { + radeon_set_dynamic_clock(dev, radeon_dynclks); + } else if (radeon_is_avivo(dev_priv)) { + if (radeon_dynclks) { + radeon_atom_static_pwrmgt_setup(dev, 1); + radeon_atom_dyn_clk_setup(dev, 1); + } + } + radeon_force_some_clocks(dev); + } + + /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ + dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); + + drm_bo_driver_init(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + + dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; + dev_priv->fb_size = + ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; + radeon_gem_mm_init(dev); + radeon_modeset_init(dev); + + radeon_modeset_cp_init(dev); + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + + drm_irq_install(dev); + } + + return ret; } + +int radeon_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv; + unsigned long sareapage; + int ret; + + master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + if (!master_priv) + return -ENOMEM; + + /* prebuild the SAREA */ + sareapage = max(SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + &master_priv->sarea); + if (ret) { + DRM_ERROR("SAREA setup failed\n"); + return ret; + } + master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); + master_priv->sarea_priv->pfCurrentPage = 0; + + master->driver_priv = master_priv; + return 0; +} + +void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv = master->driver_priv; + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (!master_priv) + return; + + if (master_priv->sarea_priv && + master_priv->sarea_priv->pfCurrentPage != 0) + radeon_cp_dispatch_flip(dev, master); + + master_priv->sarea_priv = NULL; + if (master_priv->sarea) + drm_rmmap(dev, master_priv->sarea); + + drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + + master->driver_priv = NULL; +} /* Create mappings for registers and framebuffer so userland doesn't necessarily * have to find them. */ @@ -1743,13 +2540,9 @@ int radeon_driver_firstopen(struct drm_device *dev) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; - ret = drm_addmap(dev, drm_get_resource_start(dev, 2), - drm_get_resource_len(dev, 2), _DRM_REGISTERS, - _DRM_READ_ONLY, &dev_priv->mmio); - if (ret != 0) - return ret; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_gem_mm_init(dev); - dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); ret = drm_addmap(dev, dev_priv->fb_aper_offset, drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map); @@ -1763,9 +2556,40 @@ int radeon_driver_unload(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_irq_uninstall(dev); + radeon_modeset_cleanup(dev); + radeon_gem_mm_fini(dev); + } + + drm_bo_driver_finish(dev); + drm_rmmap(dev, dev_priv->mmio); + DRM_DEBUG("\n"); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; } + +void radeon_gart_flush(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->flags & RADEON_IS_IGPGART) { + IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE); + IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0); + } else if (dev_priv->flags & RADEON_IS_PCIE) { + u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + } else { + + + } + +} diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index ffaa46e4..7fcf9305 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -453,8 +453,11 @@ typedef struct { int pfCurrentPage; /* which buffer is being displayed? */ int crtc2_base; /* CRTC2 frame offset */ int tiling_enabled; /* set by drm, read by 2d + 3d clients */ + + unsigned int last_fence; } drm_radeon_sarea_t; + /* WARNING: If you change any of these defines, make sure to change the * defines in the Xserver file (xf86drmRadeon.h) * @@ -493,6 +496,17 @@ typedef struct { #define DRM_RADEON_SURF_ALLOC 0x1a #define DRM_RADEON_SURF_FREE 0x1b +#define DRM_RADEON_GEM_INFO 0x1c +#define DRM_RADEON_GEM_CREATE 0x1d +#define DRM_RADEON_GEM_MMAP 0x1e +#define DRM_RADEON_GEM_PIN 0x1f +#define DRM_RADEON_GEM_UNPIN 0x20 +#define DRM_RADEON_GEM_PREAD 0x21 +#define DRM_RADEON_GEM_PWRITE 0x22 +#define DRM_RADEON_GEM_SET_DOMAIN 0x23 +#define DRM_RADEON_GEM_INDIRECT 0x24 // temporary for X server + + #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) #define DRM_IOCTL_RADEON_CP_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_STOP, drm_radeon_cp_stop_t) @@ -521,6 +535,18 @@ typedef struct { #define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t) #define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t) +#define DRM_IOCTL_RADEON_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INFO, struct drm_radeon_gem_info) +#define DRM_IOCTL_RADEON_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_CREATE, struct drm_radeon_gem_create) +#define DRM_IOCTL_RADEON_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_MMAP, struct drm_radeon_gem_mmap) +#define DRM_IOCTL_RADEON_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PIN, struct drm_radeon_gem_pin) +#define DRM_IOCTL_RADEON_GEM_UNPIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_UNPIN, struct drm_radeon_gem_unpin) +#define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) +#define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) +#define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) +#define DRM_IOCTL_RADEON_GEM_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INDIRECT, struct drm_radeon_gem_indirect) + + + typedef struct drm_radeon_init { enum { RADEON_INIT_CP = 0x01, @@ -747,4 +773,92 @@ typedef struct drm_radeon_surface_free { #define DRM_RADEON_VBLANK_CRTC1 1 #define DRM_RADEON_VBLANK_CRTC2 2 +#define RADEON_GEM_DOMAIN_CPU 0x1 +#define RADEON_GEM_DOMAIN_VRAM 0x2 +#define RADEON_GEM_DOMAIN_2D 0x4 +#define RADEON_GEM_DOMAIN_3D 0x8 +#define RADEON_GEM_DOMAIN_TEXTURE 0x10 +#define RADEON_GEM_DOMAIN_GPU 0x20 // for vertex buffers + +/* return to userspace start/size of gtt and vram apertures */ +struct drm_radeon_gem_info { + uint64_t gart_start; + uint64_t gart_size; + uint64_t vram_start; + uint64_t vram_size; + uint64_t vram_visible; +}; + +struct drm_radeon_gem_create { + uint64_t size; + uint64_t alignment; + uint32_t handle; + uint32_t initial_domain; // to allow VRAM to be created + uint32_t no_backing_store; // for VRAM objects - select whether they need backing store + // pretty much front/back/depth don't need it - other things do +}; + +struct drm_radeon_gem_mmap { + uint32_t handle; + uint32_t pad; + uint64_t offset; + uint64_t size; + uint64_t addr_ptr; +}; + +struct drm_radeon_gem_set_domain { + uint32_t handle; + uint32_t read_domains; + uint32_t write_domain; +}; + +struct drm_radeon_gem_exec_buffer { +}; + +struct drm_radeon_gem_pin { + uint32_t handle; + uint32_t pad; + uint64_t alignment; + uint64_t offset; +}; + +struct drm_radeon_gem_unpin { + uint32_t handle; + uint32_t pad; +}; + +struct drm_radeon_gem_busy { + uint32_t handle; + uint32_t busy; +}; + +struct drm_radeon_gem_pread { + /** Handle for the object being read. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to read from */ + uint64_t offset; + /** Length of data to read */ + uint64_t size; + /** Pointer to write the data into. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_radeon_gem_pwrite { + /** Handle for the object being written to. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to write to */ + uint64_t offset; + /** Length of data to write */ + uint64_t size; + /** Pointer to read the data from. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_radeon_gem_indirect { + uint32_t handle; + uint32_t used; +}; + #endif diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 65569db9..5ce97b64 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -31,6 +31,7 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ +#include "atom.h" /* General customization: */ @@ -96,13 +97,13 @@ * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, * new packet type) * 1.26- Add support for variable size PCI(E) gart aperture - * 1.27- Add support for IGP GART + * 1.27- Add support for IGPGART * 1.28- Add support for VBL on CRTC2 * 1.29- R500 3D cmd buffer support */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 29 +#define DRIVER_MINOR 30 #define DRIVER_PATCHLEVEL 0 /* @@ -126,13 +127,24 @@ enum radeon_family { CHIP_RV410, CHIP_RS400, CHIP_RS480, + CHIP_RS600, CHIP_RS690, + CHIP_RS740, CHIP_RV515, CHIP_R520, CHIP_RV530, CHIP_RV560, CHIP_RV570, CHIP_R580, + CHIP_R600, + CHIP_R630, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RV770, CHIP_LAST, }; @@ -153,9 +165,42 @@ enum radeon_chip_flags { RADEON_IS_IGPGART = 0x01000000UL, }; +/* + * Errata workarounds + */ +enum radeon_pll_errata { + CHIP_ERRATA_R300_CG = 0x00000001, + CHIP_ERRATA_PLL_DUMMYREADS = 0x00000002, + CHIP_ERRATA_PLL_DELAY = 0x00000004 +}; + +enum radeon_ext_tmds_chip { + RADEON_DVOCHIP_NONE, + RADEON_SIL_164, + RADEON_SIL_1178 +}; + +#if defined(__powerpc__) +enum radeon_mac_model { + RADEON_MAC_NONE, + RADEON_MAC_IBOOK, + RADEON_MAC_POWERBOOK_EXTERNAL, + RADEON_MAC_POWERBOOK_INTERNAL, + RADEON_MAC_POWERBOOK_VGA, + RADEON_MAC_MINI_EXTERNAL, + RADEON_MAC_MINI_INTERNAL, + RADEON_MAC_IMAC_G5_ISIGHT +}; +#endif + + #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ - DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) -#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) + (dev_priv->mm.ring_read_ptr ? readl(dev_priv->mm.ring_read_ptr_map.virtual + 0) : DRM_READ32((dev_priv)->ring_rptr, 0 )) : \ + RADEON_READ(RADEON_CP_RB_RPTR)) + +#define SET_RING_HEAD(dev_priv,val) (dev_priv->mm.ring_read_ptr ? \ + writel((val), dev_priv->mm.ring_read_ptr_map.virtual) : \ + DRM_WRITE32((dev_priv)->ring_rptr, 0, (val))) typedef struct drm_radeon_freelist { unsigned int age; @@ -216,16 +261,38 @@ struct radeon_virt_surface { struct drm_file *file_priv; }; +struct radeon_mm_info { + uint64_t vram_offset; // Offset into GPU space + uint64_t vram_size; + uint64_t vram_visible; + + uint64_t gart_start; + uint64_t gart_size; + + struct drm_buffer_object *pcie_table; + struct drm_bo_kmap_obj pcie_table_map; + + struct drm_buffer_object *ring; + struct drm_bo_kmap_obj ring_map; + + struct drm_buffer_object *ring_read_ptr; + struct drm_bo_kmap_obj ring_read_ptr_map; +}; + +#include "radeon_mode.h" + +struct drm_radeon_master_private { + drm_local_map_t *sarea; + drm_radeon_sarea_t *sarea_priv; +}; + #define RADEON_FLUSH_EMITED (1 < 0) #define RADEON_PURGE_EMITED (1 < 1) typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; - drm_radeon_sarea_t *sarea_priv; - u32 fb_location; - u32 fb_size; int new_memmap; int gart_size; @@ -278,8 +345,6 @@ typedef struct drm_radeon_private { unsigned long buffers_offset; unsigned long gart_textures_offset; - drm_local_map_t *sarea; - drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; drm_local_map_t *gart_textures; @@ -288,8 +353,8 @@ typedef struct drm_radeon_private { struct mem_block *fb_heap; /* SW interrupt */ + int counter; wait_queue_head_t swi_queue; - atomic_t swi_emitted; int vblank_crtc; uint32_t irq_enable_reg; int irq_enabled; @@ -298,10 +363,6 @@ typedef struct drm_radeon_private { struct radeon_surface surfaces[RADEON_MAX_SURFACES]; struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; - unsigned long pcigart_offset; - unsigned int pcigart_offset_set; - struct drm_ati_pcigart_info gart_info; - u32 scratch_ages[5]; unsigned int crtc_last_cnt; @@ -311,6 +372,26 @@ typedef struct drm_radeon_private { uint32_t flags; /* see radeon_chip_flags */ unsigned long fb_aper_offset; + struct radeon_mm_info mm; + drm_local_map_t *mmio; + + + unsigned long pcigart_offset; + unsigned int pcigart_offset_set; + struct drm_ati_pcigart_info gart_info; + + struct radeon_mode_info mode_info; + + uint8_t *bios; /* copy of the BIOS image */ + bool is_atom_bios; + uint16_t bios_header_start; + u32 fb_location; + u32 fb_size; + bool is_ddr; + u32 ram_width; + + enum radeon_pll_errata pll_errata; + int num_gb_pipes; int track_flush; uint32_t chip_family; /* extract from flags */ @@ -328,6 +409,7 @@ typedef struct drm_radeon_kcmd_buffer { } drm_radeon_kcmd_buffer_t; extern int radeon_no_wb; +extern int radeon_dynclks; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; @@ -416,9 +498,14 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_BOX_WAIT_IDLE 0x8 #define RADEON_BOX_TEXTURE_LOAD 0x10 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_APER_SIZE 0x5430 /* Register definitions, register access macros and drmAddMap constants * for Radeon kernel driver. */ + +#include "radeon_reg.h" + #define RADEON_AGP_COMMAND 0x0f60 #define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */ # define RADEON_AGP_ENABLE (1<<8) @@ -521,16 +608,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define R520_MC_IND_WR_EN (1 << 24) #define R520_MC_IND_DATA 0x74 -#define RV515_MC_FB_LOCATION 0x01 -#define RV515_MC_AGP_LOCATION 0x02 -#define RV515_MC_AGP_BASE 0x03 -#define RV515_MC_AGP_BASE_2 0x04 - -#define R520_MC_FB_LOCATION 0x04 -#define R520_MC_AGP_LOCATION 0x05 -#define R520_MC_AGP_BASE 0x06 -#define R520_MC_AGP_BASE_2 0x07 - #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -600,9 +677,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) -#define GET_SCRATCH( x ) (dev_priv->writeback_works \ - ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ - : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) +#define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ + (dev_priv->mm.ring_read_ptr ? \ + readl(dev_priv->mm.ring_read_ptr_map.virtual + RADEON_SCRATCHOFF(0)) : \ + DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ + RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) #define RADEON_CRTC_CRNT_FRAME 0x0214 #define RADEON_CRTC2_CRNT_FRAME 0x0314 @@ -627,11 +706,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, # define RADEON_SW_INT_FIRE (1 << 26) # define R500_DISPLAY_INT_STATUS (1 << 0) +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_APER_CNTL (1 << 23) -#define RADEON_HOST_PATH_CNTL 0x0130 -# define RADEON_HDP_SOFT_RESET (1 << 26) -# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) -# define RADEON_HDP_WC_TIMEOUT_28BCLK (7 << 28) +#define RADEON_NB_TOM 0x15c #define RADEON_ISYNC_CNTL 0x1724 # define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0) @@ -670,12 +749,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 -#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */ -#define R300_DSTCACHE_CTLSTAT 0x1714 -# define R300_RB2D_DC_FLUSH (3 << 0) -# define R300_RB2D_DC_FREE (3 << 2) -# define R300_RB2D_DC_FLUSH_ALL 0xf -# define R300_RB2D_DC_BUSY (1 << 31) #define RADEON_RB3D_CNTL 0x1c3c # define RADEON_ALPHA_BLEND_ENABLE (1 << 0) # define RADEON_PLANE_MASK_ENABLE (1 << 1) @@ -702,11 +775,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, # define R300_ZC_FLUSH (1 << 0) # define R300_ZC_FREE (1 << 1) # define R300_ZC_BUSY (1 << 31) -#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c -# define RADEON_RB3D_DC_FLUSH (3 << 0) -# define RADEON_RB3D_DC_FREE (3 << 2) -# define RADEON_RB3D_DC_FLUSH_ALL 0xf -# define RADEON_RB3D_DC_BUSY (1 << 31) #define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c # define R300_RB3D_DC_FLUSH (2 << 0) # define R300_RB3D_DC_FREE (2 << 2) @@ -982,27 +1050,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_NUM_VERTICES_SHIFT 16 #define RADEON_COLOR_FORMAT_CI8 2 -#define RADEON_COLOR_FORMAT_ARGB1555 3 -#define RADEON_COLOR_FORMAT_RGB565 4 -#define RADEON_COLOR_FORMAT_ARGB8888 6 -#define RADEON_COLOR_FORMAT_RGB332 7 -#define RADEON_COLOR_FORMAT_RGB8 9 -#define RADEON_COLOR_FORMAT_ARGB4444 15 - -#define RADEON_TXFORMAT_I8 0 -#define RADEON_TXFORMAT_AI88 1 -#define RADEON_TXFORMAT_RGB332 2 -#define RADEON_TXFORMAT_ARGB1555 3 -#define RADEON_TXFORMAT_RGB565 4 -#define RADEON_TXFORMAT_ARGB4444 5 -#define RADEON_TXFORMAT_ARGB8888 6 -#define RADEON_TXFORMAT_RGBA8888 7 -#define RADEON_TXFORMAT_Y8 8 -#define RADEON_TXFORMAT_VYUY422 10 -#define RADEON_TXFORMAT_YVYU422 11 -#define RADEON_TXFORMAT_DXT1 12 -#define RADEON_TXFORMAT_DXT23 14 -#define RADEON_TXFORMAT_DXT45 15 #define R200_PP_TXCBLEND_0 0x2f00 #define R200_PP_TXCBLEND_1 0x2f10 @@ -1188,18 +1235,16 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_RING_HIGH_MARK 128 #define RADEON_PCIGART_TABLE_SIZE (32*1024) +#define RADEON_DEFAULT_RING_SIZE (1024*1024) +#define RADEON_DEFAULT_CP_TIMEOUT 100000 /* usecs */ #define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) -#define RADEON_WRITE_PLL( addr, val ) \ -do { \ - RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX, \ - ((addr) & 0x1f) | RADEON_PLL_WR_EN ); \ - RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ -} while (0) +extern int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); +extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); #define RADEON_WRITE_PCIE( addr, val ) \ do { \ @@ -1334,7 +1379,8 @@ do { \ #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ do { \ - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \ + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ int __ret = radeon_do_cp_idle( dev_priv ); \ if ( __ret ) return __ret; \ @@ -1440,4 +1486,110 @@ do { \ write &= mask; \ } while (0) +/* radeon GEM->TTM munger */ +struct drm_radeon_gem_object { + /* wrap a TTM bo */ + struct drm_buffer_object *bo; + struct drm_fence_object *fence; + struct drm_gem_object *obj; + +}; + +extern int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern void radeon_fence_handler(struct drm_device *dev); +extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type); +extern void radeon_poke_flush(struct drm_device *dev, uint32_t class); +extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); + +/* radeon_buffer.c */ +extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev); +extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); +extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); +extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man); +extern int radeon_move(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem); + +extern void radeon_gart_flush(struct drm_device *dev); +extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); + +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +/* Breadcrumb - swi irq */ +#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) + +static inline int radeon_update_breadcrumb(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv; + + ++dev_priv->counter; + if (dev_priv->counter > BREADCRUMB_MASK) + dev_priv->counter = 1; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_fence = dev_priv->counter; + } + return dev_priv->counter; +} + +#define radeon_is_avivo(dev_priv) ((dev_priv->chip_family >= CHIP_RS600)) + +#define radeon_is_dce3(dev_priv) ((dev_priv->chip_family >= CHIP_RV620)) + +#define radeon_bios8(dev_priv, v) (dev_priv->bios[v]) +#define radeon_bios16(dev_priv, v) (dev_priv->bios[v] | (dev_priv->bios[(v) + 1] << 8)) +#define radeon_bios32(dev_priv, v) ((dev_priv->bios[v]) | \ + (dev_priv->bios[(v) + 1] << 8) | \ + (dev_priv->bios[(v) + 2] << 16) | \ + (dev_priv->bios[(v) + 3] << 24)) + +extern int radeon_emit_irq(struct drm_device * dev); + +extern void radeon_gem_free_object(struct drm_gem_object *obj); +extern int radeon_gem_init_object(struct drm_gem_object *obj); +extern int radeon_gem_mm_init(struct drm_device *dev); +extern void radeon_gem_mm_fini(struct drm_device *dev); +extern int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_object_pin(struct drm_gem_object *obj, + uint32_t alignment); +int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, + int initial_domain); +int radeon_modeset_init(struct drm_device *dev); +void radeon_modeset_cleanup(struct drm_device *dev); +extern u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr); +extern void radeon_write_mc_reg(drm_radeon_private_t *dev_priv, u32 addr, u32 val); + +extern void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on); +#define RADEONFB_CONN_LIMIT 4 + +extern int radeon_master_create(struct drm_device *dev, struct drm_master *master); +extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); +extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); #endif /* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 69569961..dcf58e43 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -198,8 +198,10 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) stat &= dev_priv->irq_enable_reg; /* SW interrupt */ - if (stat & RADEON_SW_INT_TEST) + if (stat & RADEON_SW_INT_TEST) { DRM_WAKEUP(&dev_priv->swi_queue); + radeon_fence_handler(dev); + } /* VBLANK interrupt */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { @@ -216,14 +218,13 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -static int radeon_emit_irq(struct drm_device * dev) +int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; RING_LOCALS; - atomic_inc(&dev_priv->swi_emitted); - ret = atomic_read(&dev_priv->swi_emitted); + ret = radeon_update_breadcrumb(dev); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -240,13 +241,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) (drm_radeon_private_t *) dev->dev_private; int ret = 0; - if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) + if (READ_BREADCRUMB(dev_priv) >= swi_nr) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, - RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); + READ_BREADCRUMB(dev_priv) >= swi_nr); return ret; } @@ -341,7 +342,6 @@ int radeon_driver_irq_postinstall(struct drm_device * dev) (drm_radeon_private_t *) dev->dev_private; int ret; - atomic_set(&dev_priv->swi_emitted, 0); DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); ret = drm_vblank_init(dev, 2); diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h new file mode 100644 index 00000000..f3bbc9a3 --- /dev/null +++ b/shared-core/radeon_ms.h @@ -0,0 +1,591 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * 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: + * Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_H__ +#define __RADEON_MS_H__ + +#include "radeon_ms_drv.h" +#include "radeon_ms_reg.h" +#include "radeon_ms_drm.h" +#include "radeon_ms_rom.h" +#include "radeon_ms_properties.h" +#include "amd.h" +#include "amd_legacy.h" + +#define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ + "Keith Whitwell, others." +#define DRIVER_NAME "radeon_ms" +#define DRIVER_DESC "radeon kernel modesetting" +#define DRIVER_DATE "20071108" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +enum radeon_bus_type { + RADEON_PCI = 0x10000, + RADEON_AGP = 0x20000, + RADEON_PCIE = 0x30000, +}; + +enum radeon_family { + CHIP_R100, + CHIP_RV100, + CHIP_RS100, + CHIP_RV200, + CHIP_RS200, + CHIP_R200, + CHIP_RV250, + CHIP_RS300, + CHIP_RV280, + CHIP_R300, + CHIP_R350, + CHIP_R360, + CHIP_RV350, + CHIP_RV370, + CHIP_RV380, + CHIP_RS400, + CHIP_RV410, + CHIP_R420, + CHIP_R430, + CHIP_R480, + CHIP_LAST, +}; + +enum radeon_monitor_type { + MT_UNKNOWN = -1, + MT_NONE = 0, + MT_CRT = 1, + MT_LCD = 2, + MT_DFP = 3, + MT_CTV = 4, + MT_STV = 5 +}; + +enum radeon_connector_type { + CONNECTOR_NONE, + CONNECTOR_PROPRIETARY, + CONNECTOR_VGA, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_CTV, + CONNECTOR_STV, + CONNECTOR_UNSUPPORTED +}; + +enum radeon_output_type { + OUTPUT_NONE, + OUTPUT_DAC1, + OUTPUT_DAC2, + OUTPUT_TMDS, + OUTPUT_LVDS +}; + +struct radeon_state; + +struct radeon_ms_crtc { + int crtc; + uint16_t lut_r[256]; + uint16_t lut_g[256]; + uint16_t lut_b[256]; +}; + +struct radeon_ms_i2c { + struct drm_device *drm_dev; + uint32_t reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +struct radeon_ms_connector { + struct radeon_ms_i2c *i2c; + struct edid *edid; + struct drm_output *output; + int type; + int monitor_type; + int crtc; + uint32_t i2c_reg; + char outputs[RADEON_MAX_OUTPUTS]; + char name[32]; +}; + +struct radeon_ms_output { + int type; + struct drm_device *dev; + struct radeon_ms_connector *connector; + int (*initialize)(struct radeon_ms_output *output); + enum drm_output_status (*detect)(struct radeon_ms_output *output); + void (*dpms)(struct radeon_ms_output *output, int mode); + int (*get_modes)(struct radeon_ms_output *output); + bool (*mode_fixup)(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + int (*mode_set)(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*restore)(struct radeon_ms_output *output, + struct radeon_state *state); + void (*save)(struct radeon_ms_output *output, + struct radeon_state *state); +}; + +struct radeon_state { + /* memory */ + uint32_t config_aper_0_base; + uint32_t config_aper_1_base; + uint32_t config_aper_size; + uint32_t mc_fb_location; + uint32_t display_base_addr; + /* irq */ + uint32_t gen_int_cntl; + /* pci */ + uint32_t aic_ctrl; + uint32_t aic_pt_base; + uint32_t aic_pt_base_lo; + uint32_t aic_pt_base_hi; + uint32_t aic_lo_addr; + uint32_t aic_hi_addr; + /* agp */ + uint32_t agp_cntl; + uint32_t agp_command; + uint32_t agp_base; + uint32_t agp_base_2; + uint32_t bus_cntl; + uint32_t mc_agp_location; + /* cp */ + uint32_t cp_rb_cntl; + uint32_t cp_rb_base; + uint32_t cp_rb_rptr_addr; + uint32_t cp_rb_wptr; + uint32_t cp_rb_wptr_delay; + uint32_t scratch_umsk; + uint32_t scratch_addr; + /* pcie */ + uint32_t pcie_tx_gart_cntl; + uint32_t pcie_tx_gart_discard_rd_addr_lo; + uint32_t pcie_tx_gart_discard_rd_addr_hi; + uint32_t pcie_tx_gart_base; + uint32_t pcie_tx_gart_start_lo; + uint32_t pcie_tx_gart_start_hi; + uint32_t pcie_tx_gart_end_lo; + uint32_t pcie_tx_gart_end_hi; + /* surface */ + uint32_t surface_cntl; + uint32_t surface0_info; + uint32_t surface0_lower_bound; + uint32_t surface0_upper_bound; + uint32_t surface1_info; + uint32_t surface1_lower_bound; + uint32_t surface1_upper_bound; + uint32_t surface2_info; + uint32_t surface2_lower_bound; + uint32_t surface2_upper_bound; + uint32_t surface3_info; + uint32_t surface3_lower_bound; + uint32_t surface3_upper_bound; + uint32_t surface4_info; + uint32_t surface4_lower_bound; + uint32_t surface4_upper_bound; + uint32_t surface5_info; + uint32_t surface5_lower_bound; + uint32_t surface5_upper_bound; + uint32_t surface6_info; + uint32_t surface6_lower_bound; + uint32_t surface6_upper_bound; + uint32_t surface7_info; + uint32_t surface7_lower_bound; + uint32_t surface7_upper_bound; + /* crtc */ + uint32_t crtc_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_h_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_offset; + uint32_t crtc_offset_cntl; + uint32_t crtc_pitch; + uint32_t crtc_more_cntl; + uint32_t crtc_tile_x0_y0; + uint32_t fp_h_sync_strt_wid; + uint32_t fp_v_sync_strt_wid; + uint32_t fp_crtc_h_total_disp; + uint32_t fp_crtc_v_total_disp; + /* pll */ + uint32_t clock_cntl_index; + uint32_t ppll_cntl; + uint32_t ppll_ref_div; + uint32_t ppll_div_0; + uint32_t ppll_div_1; + uint32_t ppll_div_2; + uint32_t ppll_div_3; + uint32_t vclk_ecp_cntl; + uint32_t htotal_cntl; + /* dac */ + uint32_t dac_cntl; + uint32_t dac_cntl2; + uint32_t dac_ext_cntl; + uint32_t disp_misc_cntl; + uint32_t dac_macro_cntl; + uint32_t disp_pwr_man; + uint32_t disp_merge_cntl; + uint32_t disp_output_cntl; + uint32_t disp2_merge_cntl; + uint32_t dac_embedded_sync_cntl; + uint32_t dac_broad_pulse; + uint32_t dac_skew_clks; + uint32_t dac_incr; + uint32_t dac_neg_sync_level; + uint32_t dac_pos_sync_level; + uint32_t dac_blank_level; + uint32_t dac_sync_equalization; + uint32_t tv_dac_cntl; + uint32_t tv_master_cntl; +}; + +struct drm_radeon_private { + /* driver family specific functions */ + int (*bus_finish)(struct drm_device *dev); + int (*bus_init)(struct drm_device *dev); + void (*bus_restore)(struct drm_device *dev, struct radeon_state *state); + void (*bus_save)(struct drm_device *dev, struct radeon_state *state); + struct drm_ttm_backend *(*create_ttm)(struct drm_device *dev); + void (*irq_emit)(struct drm_device *dev); + void (*flush_cache)(struct drm_device *dev); + /* bus informations */ + void *bus; + uint32_t bus_type; + /* cp */ + uint32_t ring_buffer_size; + uint32_t ring_rptr; + uint32_t ring_wptr; + uint32_t ring_mask; + int ring_free; + uint32_t ring_tail_mask; + uint32_t write_back_area_size; + struct drm_buffer_object *ring_buffer_object; + struct drm_bo_kmap_obj ring_buffer_map; + 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; + struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; + struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; + /* drm map (MMIO, FB) */ + struct drm_map mmio; + struct drm_map vram; + /* gpu address space */ + uint32_t gpu_vram_size; + uint32_t gpu_vram_start; + uint32_t gpu_vram_end; + uint32_t gpu_gart_size; + uint32_t gpu_gart_start; + uint32_t gpu_gart_end; + /* state of the card when module was loaded */ + struct radeon_state load_state; + /* state the driver wants */ + struct radeon_state driver_state; + /* last emitted fence */ + uint32_t fence_id_last; + uint32_t fence_reg; + /* when doing gpu stop we save here current state */ + uint32_t crtc_ext_cntl; + uint32_t crtc_gen_cntl; + uint32_t crtc2_gen_cntl; + uint32_t ov0_scale_cntl; + /* bool & type on the hw */ + uint8_t crtc1_dpms; + uint8_t crtc2_dpms; + uint8_t restore_state; + uint8_t cp_ready; + uint8_t bus_ready; + uint8_t write_back; + /* command buffer informations */ + struct amd_cmd_module cmd_module; + /* abstract asic specific structures */ + struct radeon_ms_rom rom; + struct radeon_ms_properties properties; + void *fence; +}; + + +/* radeon_ms_bo.c */ +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + uint32_t *gpu_addr); +int radeon_ms_bo_move(struct drm_buffer_object * bo, int evict, + int no_wait, struct drm_bo_mem_reg * new_mem); +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev); +uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo); +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man); +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags); +void radeon_ms_ttm_flush(struct drm_ttm *ttm); + +/* radeon_ms_bus.c */ +int radeon_ms_agp_finish(struct drm_device *dev); +int radeon_ms_agp_init(struct drm_device *dev); +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state); +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev); +int radeon_ms_pcie_finish(struct drm_device *dev); +int radeon_ms_pcie_init(struct drm_device *dev); +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_combios.c */ +int radeon_ms_combios_get_properties(struct drm_device *dev); +int radeon_ms_connectors_from_combios(struct drm_device *dev); +int radeon_ms_outputs_from_combios(struct drm_device *dev); + +/* radeon_ms_compat.c */ +long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); + +/* radeon_ms_cp.c */ +int radeon_ms_cp_finish(struct drm_device *dev); +int radeon_ms_cp_init(struct drm_device *dev); +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_stop(struct drm_device *dev); +int radeon_ms_cp_wait(struct drm_device *dev, int n); +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count); +int radeon_ms_resetcp(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +/* radeon_ms_crtc.c */ +int radeon_ms_crtc_create(struct drm_device *dev, int crtc); +void radeon_ms_crtc1_restore(struct drm_device *dev, + struct radeon_state *state); +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_dac.c */ +int radeon_ms_dac1_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output); +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_ms_dac1_restore(struct radeon_ms_output *output, + struct radeon_state *state); +void radeon_ms_dac1_save(struct radeon_ms_output *output, + struct radeon_state *state); +int radeon_ms_dac2_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output); +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_ms_dac2_restore(struct radeon_ms_output *output, + struct radeon_state *state); +void radeon_ms_dac2_save(struct radeon_ms_output *output, + struct radeon_state *state); + +/* radeon_ms_drm.c */ +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +void radeon_ms_driver_lastclose(struct drm_device * dev); +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags); +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv); +int radeon_ms_driver_unload(struct drm_device *dev); + +/* radeon_ms_family.c */ +int radeon_ms_family_init(struct drm_device *dev); + +/* radeon_ms_fence.c */ +void r3xx_fence_handler(struct drm_device * dev); +int r3xx_fence_types(struct drm_buffer_object *bo, + uint32_t * class, uint32_t * type); + +/* radeon_ms_fb.c */ +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); + +/* radeon_ms_gpu.c */ +int radeon_ms_gpu_initialize(struct drm_device *dev); +void radeon_ms_gpu_dpms(struct drm_device *dev); +void radeon_ms_gpu_flush(struct drm_device *dev); +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state); +int radeon_ms_wait_for_idle(struct drm_device *dev); + +/* radeon_ms_i2c.c */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c); +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, + const uint32_t reg, + const char *name); + +/* radeon_ms_irq.c */ +void radeon_ms_irq_emit(struct drm_device *dev); +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS); +void radeon_ms_irq_preinstall(struct drm_device * dev); +int radeon_ms_irq_postinstall(struct drm_device * dev); +int radeon_ms_irq_init(struct drm_device *dev); +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_uninstall(struct drm_device * dev); + +/* radeon_ms_output.c */ +void radeon_ms_connectors_destroy(struct drm_device *dev); +int radeon_ms_connectors_from_properties(struct drm_device *dev); +int radeon_ms_connectors_from_rom(struct drm_device *dev); +void radeon_ms_outputs_destroy(struct drm_device *dev); +int radeon_ms_outputs_from_properties(struct drm_device *dev); +int radeon_ms_outputs_from_rom(struct drm_device *dev); +void radeon_ms_outputs_restore(struct drm_device *dev, + struct radeon_state *state); +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_properties.c */ +int radeon_ms_properties_init(struct drm_device *dev); + +/* radeon_ms_rom.c */ +int radeon_ms_rom_get_properties(struct drm_device *dev); +int radeon_ms_rom_init(struct drm_device *dev); + +/* radeon_ms_state.c */ +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_state_restore(struct drm_device *dev, + struct radeon_state *state); + +/* helper macro & functions ***************************************************/ +#define REG_S(rn, bn, v) (((v) << rn##__##bn##__SHIFT) & rn##__##bn##__MASK) +#define REG_G(rn, bn, v) (((v) & rn##__##bn##__MASK) >> rn##__##bn##__SHIFT) +#define MMIO_R(rid) mmio_read(dev_priv, rid) +#define MMIO_W(rid, v) mmio_write(dev_priv, rid, v) +#define PCIE_R(rid) pcie_read(dev_priv, rid) +#define PCIE_W(rid, v) pcie_write(dev_priv, rid, v) +#define PPLL_R(rid) pll_read(dev_priv, rid) +#define PPLL_W(rid, v) pll_write(dev_priv, rid, v) + +static __inline__ uint32_t mmio_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + return DRM_READ32(&dev_priv->mmio, offset); +} + + +static __inline__ void mmio_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t v) +{ + DRM_WRITE32(&dev_priv->mmio, offset, v); +} + +static __inline__ uint32_t pcie_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); + return MMIO_R(PCIE_DATA); +} + +static __inline__ void pcie_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t v) +{ + MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); + MMIO_W(PCIE_DATA, v); +} + +static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv) +{ + uint32_t tmp, save; + + /* This workaround is necessary on rv200 and RS200 or PLL + * reads may return garbage (among others...) + */ + if (dev_priv->properties.pll_dummy_reads) { + tmp = MMIO_R(CLOCK_CNTL_DATA); + tmp = MMIO_R(CRTC_GEN_CNTL); + } + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (dev_priv->properties.pll_r300_errata) { + tmp = save = MMIO_R(CLOCK_CNTL_INDEX); + tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_WR_EN; + MMIO_W(CLOCK_CNTL_INDEX, tmp); + tmp = MMIO_R(CLOCK_CNTL_DATA); + MMIO_W(CLOCK_CNTL_INDEX, save); + } +} + +static __inline__ void pll_data_errata(struct drm_radeon_private *dev_priv) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (dev_priv->properties.pll_delay) { + /* we can't deal with posted writes here ... */ + udelay(5000); + } +} + +static __inline__ uint32_t pll_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; + uint32_t data; + + clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + data = MMIO_R(CLOCK_CNTL_DATA); + pll_data_errata(dev_priv); + return data; +} + +static __inline__ void pll_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t value) +{ + uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; + + clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); + clock_cntl_index |= CLOCK_CNTL_INDEX__PLL_WR_EN; + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + MMIO_W(CLOCK_CNTL_DATA, value); + pll_data_errata(dev_priv); +} + +#endif diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c new file mode 100644 index 00000000..b366ae5a --- /dev/null +++ b/shared-core/radeon_ms_bo.c @@ -0,0 +1,321 @@ +/* + * Copyright 2007 Dave Airlie + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie <airlied@linux.ie> + * Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" + +#include "radeon_ms.h" + +#define GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +#define GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +#define GMC_BRUSH_NONE (15 << 4) +#define GMC_SRC_DATATYPE_COLOR (3 << 12) +#define ROP3_S 0x00cc0000 +#define DP_SRC_SOURCE_MEMORY (2 << 24) +#define GMC_CLR_CMP_CNTL_DIS (1 << 28) +#define GMC_WR_MSK_DIS (1 << 30) + +void radeon_ms_bo_copy_blit(struct drm_device *dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t num_pages, stride, c; + uint32_t offset_inc = 0; + uint32_t cmd[7]; + + if (!dev_priv) { + return; + } + + /* radeon limited to 16320=255*64 bytes per row so copy at + * most 2 pages */ + num_pages = 2; + stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; + while(pages > 0) { + if (num_pages > pages) { + num_pages = pages; + stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; + } + c = pages / num_pages; + if (c >= 8192) { + c = 8191; + } + cmd[0] = CP_PACKET3(PACKET3_OPCODE_BITBLT, 5); + cmd[1] = GMC_SRC_PITCH_OFFSET_CNTL | + GMC_DST_PITCH_OFFSET_CNTL | + GMC_BRUSH_NONE | + (0x6 << 8) | + GMC_SRC_DATATYPE_COLOR | + ROP3_S | + DP_SRC_SOURCE_MEMORY | + GMC_CLR_CMP_CNTL_DIS | + GMC_WR_MSK_DIS; + cmd[2] = (stride << 22) | (src_offset >> 10); + cmd[3] = (stride << 22) | (dst_offset >> 10); + cmd[4] = (0 << 16) | 0; + cmd[5] = (0 << 16) | 0; + cmd[6] = ((stride * 16) << 16) | c; + radeon_ms_ring_emit(dev, cmd, 7); + offset_inc = num_pages * c * PAGE_SIZE; + src_offset += offset_inc; + dst_offset += offset_inc; + pages -= num_pages * c; + } + /* wait for 2d engine to go busy so wait_until stall */ + for (c = 0; c < dev_priv->usec_timeout; c++) { + uint32_t status = MMIO_R(RBBM_STATUS); + if ((RBBM_STATUS__E2_BUSY & status) || + (RBBM_STATUS__CBA2D_BUSY & status)) { + DRM_INFO("[radeon_ms] RBBM_STATUS 0x%08X\n", status); + break; + } + DRM_UDELAY(1); + } + /* Sync everything up */ + cmd[0] = CP_PACKET0(WAIT_UNTIL, 0); + cmd[1] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + radeon_ms_ring_emit(dev, cmd, 2); + return; +} + +static int radeon_ms_bo_move_blit(struct drm_buffer_object *bo, + int evict, int no_wait, + struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg *old_mem = &bo->mem; + uint32_t gpu_src_addr; + uint32_t gpu_dst_addr; + int ret; + + ret = radeon_ms_bo_get_gpu_addr(dev, old_mem, &gpu_src_addr); + if (ret) { + return ret; + } + ret = radeon_ms_bo_get_gpu_addr(dev, new_mem, &gpu_dst_addr); + if (ret) { + return ret; + } + + radeon_ms_bo_copy_blit(bo->dev, + gpu_src_addr, + gpu_dst_addr, + new_mem->num_pages); + + ret = drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, + DRM_FENCE_TYPE_EXE | + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W, + DRM_AMD_FENCE_FLAG_FLUSH, + new_mem); + return ret; +} + +static int radeon_ms_bo_move_flip(struct drm_buffer_object *bo, + int evict, int no_wait, + struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg tmp_mem; + int ret; + + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + tmp_mem.flags = DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_FORCE_CACHING; + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) { + return ret; + } + + ret = drm_ttm_bind(bo->ttm, &tmp_mem); + if (ret) { + goto out_cleanup; + } + ret = radeon_ms_bo_move_blit(bo, 1, no_wait, &tmp_mem); + if (ret) { + goto out_cleanup; + } + ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: + if (tmp_mem.mm_node) { + mutex_lock(&dev->struct_mutex); + if (tmp_mem.mm_node != bo->pinned_node) + drm_mm_put_block(tmp_mem.mm_node); + tmp_mem.mm_node = NULL; + mutex_unlock(&dev->struct_mutex); + } + return ret; +} + +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + uint32_t *gpu_addr) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + *gpu_addr = mem->mm_node->start << PAGE_SHIFT; + switch (mem->flags & DRM_BO_MASK_MEM) { + case DRM_BO_FLAG_MEM_TT: + *gpu_addr += dev_priv->gpu_gart_start; + DRM_INFO("[radeon_ms] GPU TT: 0x%08X\n", *gpu_addr); + break; + case DRM_BO_FLAG_MEM_VRAM: + *gpu_addr += dev_priv->gpu_vram_start; + DRM_INFO("[radeon_ms] GPU VRAM: 0x%08X\n", *gpu_addr); + break; + default: + DRM_ERROR("[radeon_ms] memory not accessible by GPU\n"); + return -EINVAL; + } + return 0; +} + +int radeon_ms_bo_move(struct drm_buffer_object *bo, int evict, + int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (radeon_ms_bo_move_flip(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else { + if (radeon_ms_bo_move_blit(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + return 0; +} + +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (dev_priv && dev_priv->create_ttm) + return dev_priv->create_ttm(dev); + return NULL; +} + +uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo) +{ + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + case DRM_BO_MEM_VRAM: + if (bo->mem.num_pages > 128) + return DRM_BO_MEM_TT; + else + return DRM_BO_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + } +} + +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (type) { + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_FIXED | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = dev_priv->vram.offset; + man->io_size = dev_priv->vram.size; + break; + case DRM_BO_MEM_TT: + if (!dev_priv->bus_ready) { + DRM_ERROR("Bus isn't initialized while " + "intializing TT memory type\n"); + return -EINVAL; + } + switch(dev_priv->bus_type) { + case RADEON_AGP: + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory " + "type %u\n", (unsigned)type); + return -EINVAL; + } + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * + 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + man->gpu_offset = 0; + break; + default: + man->io_offset = dev_priv->gpu_gart_start; + man->io_size = dev_priv->gpu_gart_size; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CMA; + man->drm_bus_maptype = _DRM_SCATTER_GATHER; + break; + } + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->flush_cache(dev); + return 0; +} + +void radeon_ms_ttm_flush(struct drm_ttm *ttm) +{ + if (!ttm) + return; + + DRM_MEMORYBARRIER(); +} diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c new file mode 100644 index 00000000..333fd558 --- /dev/null +++ b/shared-core/radeon_ms_bus.c @@ -0,0 +1,461 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie <airlied@linux.ie> + * Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_pcie { + uint32_t gart_table_size; + struct drm_buffer_object *gart_table_object; + volatile uint32_t *gart_table; + struct drm_device *dev; + unsigned long page_last; +}; + +struct radeon_pcie_gart { + struct drm_ttm_backend backend; + struct radeon_pcie *pcie; + unsigned long page_first; + struct page **pages; + struct page *dummy_read_page; + unsigned long num_pages; + int populated; + int bound; +}; + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem); +static void pcie_ttm_clear(struct drm_ttm_backend *backend); +static void pcie_ttm_destroy(struct drm_ttm_backend *backend); +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend); +static int pcie_ttm_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page); +static int pcie_ttm_unbind(struct drm_ttm_backend *backend); + +static struct drm_ttm_backend_func radeon_pcie_gart_ttm_backend = +{ + .needs_ub_cache_adjust = pcie_ttm_needs_ub_cache_adjust, + .populate = pcie_ttm_populate, + .clear = pcie_ttm_clear, + .bind = pcie_ttm_bind, + .unbind = pcie_ttm_unbind, + .destroy = pcie_ttm_destroy, +}; + +static void pcie_gart_flush(struct radeon_pcie *pcie) +{ + struct drm_device *dev; + struct drm_radeon_private *dev_priv; + uint32_t flush; + + if (pcie == NULL) { + return; + } + dev = pcie->dev; + dev_priv = dev->dev_private; + flush = dev_priv->driver_state.pcie_tx_gart_cntl; + flush |= PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB; + PCIE_W(PCIE_TX_GART_CNTL, flush); + PCIE_W(PCIE_TX_GART_CNTL, dev_priv->driver_state.pcie_tx_gart_cntl); +} + +static __inline__ uint32_t pcie_gart_get_page_base(struct radeon_pcie *pcie, + unsigned long page) +{ + if (pcie == NULL || pcie->gart_table == NULL) { + return 0; + } + return ((pcie->gart_table[page] & (~0xC)) << 8); +} + +static __inline__ void pcie_gart_set_page_base(struct radeon_pcie *pcie, + unsigned long page, + uint32_t page_base) +{ + if (pcie == NULL || pcie->gart_table == NULL) { + return; + } + pcie->gart_table[page] = cpu_to_le32((page_base >> 8) | 0xC); +} + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem) +{ + struct radeon_pcie_gart *pcie_gart; + unsigned long page_first; + unsigned long page_last; + unsigned long page, i; + uint32_t page_base; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + page = page_first = bo_mem->mm_node->start; + page_last = page_first + pcie_gart->num_pages; + if (page_first >= pcie_gart->pcie->page_last || + page_last >= pcie_gart->pcie->page_last) + return -EINVAL; + while (page < page_last) { + if (pcie_gart_get_page_base(pcie_gart->pcie, page)) { + return -EBUSY; + } + page++; + } + + for (i = 0, page = page_first; i < pcie_gart->num_pages; i++, page++) { + struct page *cur_page = pcie_gart->pages[i]; + + if (!page) { + cur_page = pcie_gart->dummy_read_page; + } + /* write value */ + page_base = page_to_phys(cur_page); + pcie_gart_set_page_base(pcie_gart->pcie, page, page_base); + } + DRM_MEMORYBARRIER(); + pcie_gart_flush(pcie_gart->pcie); + pcie_gart->bound = 1; + pcie_gart->page_first = page_first; + return 0; +} + +static void pcie_ttm_clear(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->pages) { + backend->func->unbind(backend); + pcie_gart->pages = NULL; + } + pcie_gart->num_pages = 0; +} + +static void pcie_ttm_destroy(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + + if (backend == NULL) { + return; + } + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->pages) { + backend->func->clear(backend); + } + drm_ctl_free(pcie_gart, sizeof(*pcie_gart), DRM_MEM_TTM); +} + +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend) +{ + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int pcie_ttm_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page) +{ + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + pcie_gart->pages = pages; + pcie_gart->num_pages = num_pages; + pcie_gart->populated = 1; + return 0; +} + +static int pcie_ttm_unbind(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + unsigned long page, i; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->bound != 1 || pcie_gart->pcie->gart_table == NULL) { + return -EINVAL; + } + for (i = 0, page = pcie_gart->page_first; i < pcie_gart->num_pages; + i++, page++) { + pcie_gart->pcie->gart_table[page] = 0; + } + pcie_gart_flush(pcie_gart->pcie); + pcie_gart->bound = 0; + pcie_gart->page_first = 0; + return 0; +} + +int radeon_ms_agp_finish(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (!dev_priv->bus_ready) { + return 0; + } + dev_priv->bus_ready = 0; + DRM_INFO("[radeon_ms] release agp\n"); + drm_agp_release(dev); + return 0; +} + +int radeon_ms_agp_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + struct drm_agp_mode mode; + uint32_t agp_status; + int ret; + + dev_priv->bus_ready = -1; + if (dev->agp == NULL) { + DRM_ERROR("[radeon_ms] can't initialize AGP\n"); + return -EINVAL; + } + ret = drm_agp_acquire(dev); + if (ret) { + DRM_ERROR("[radeon_ms] error failed to acquire agp %d\n", ret); + return ret; + } + agp_status = MMIO_R(AGP_STATUS); + if ((AGP_STATUS__MODE_AGP30 & agp_status)) { + mode.mode = AGP_STATUS__RATE4X; + } else { + mode.mode = AGP_STATUS__RATE2X_8X; + } + ret = drm_agp_enable(dev, mode); + if (ret) { + DRM_ERROR("[radeon_ms] error failed to enable agp\n"); + return ret; + } + state->agp_command = MMIO_R(AGP_COMMAND) | AGP_COMMAND__AGP_EN; + state->agp_command &= ~AGP_COMMAND__FW_EN; + state->agp_command &= ~AGP_COMMAND__MODE_4G_EN; + state->aic_ctrl = 0; + state->agp_base = REG_S(AGP_BASE, AGP_BASE_ADDR, dev->agp->base); + state->agp_base_2 = 0; + state->bus_cntl = MMIO_R(BUS_CNTL); + state->bus_cntl &= ~BUS_CNTL__BUS_MASTER_DIS; + state->mc_agp_location = + REG_S(MC_AGP_LOCATION, MC_AGP_START, + dev_priv->gpu_gart_start >> 16) | + REG_S(MC_AGP_LOCATION, MC_AGP_TOP, + dev_priv->gpu_gart_end >> 16); + DRM_INFO("[radeon_ms] gpu agp base 0x%08X\n", MMIO_R(AGP_BASE)); + DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", + MMIO_R(MC_AGP_LOCATION)); + DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", + state->mc_agp_location); + DRM_INFO("[radeon_ms] bus ready\n"); + dev_priv->bus_ready = 1; + return 0; +} + +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(MC_AGP_LOCATION, state->mc_agp_location); + MMIO_W(AGP_BASE, state->agp_base); + MMIO_W(AGP_BASE_2, state->agp_base_2); + MMIO_W(AGP_COMMAND, state->agp_command); +} + +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->agp_command = MMIO_R(AGP_COMMAND); + state->agp_base = MMIO_R(AGP_BASE); + state->agp_base_2 = MMIO_R(AGP_BASE_2); + state->mc_agp_location = MMIO_R(MC_AGP_LOCATION); +} + +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = drm_ctl_calloc(1, sizeof (*pcie_gart), DRM_MEM_TTM); + if (pcie_gart == NULL) { + return NULL; + } + memset(pcie_gart, 0, sizeof(struct radeon_pcie_gart)); + pcie_gart->populated = 0; + pcie_gart->pcie = dev_priv->bus; + pcie_gart->backend.func = &radeon_pcie_gart_ttm_backend; + + return &pcie_gart->backend; +} + +int radeon_ms_pcie_finish(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_pcie *pcie = dev_priv->bus; + + if (!dev_priv->bus_ready || pcie == NULL) { + dev_priv->bus_ready = 0; + return 0; + } + dev_priv->bus_ready = 0; + if (pcie->gart_table) { + drm_mem_reg_iounmap(dev, &pcie->gart_table_object->mem, + (void *)pcie->gart_table); + } + pcie->gart_table = NULL; + if (pcie->gart_table_object) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&pcie->gart_table_object); + mutex_unlock(&dev->struct_mutex); + } + dev_priv->bus = NULL; + drm_free(pcie, sizeof(*pcie), DRM_MEM_DRIVER); + return 0; +} + +int radeon_ms_pcie_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + struct radeon_pcie *pcie; + int ret = 0; + + dev_priv->bus_ready = -1; + /* allocate and clear device private structure */ + pcie = drm_alloc(sizeof(struct radeon_pcie), DRM_MEM_DRIVER); + if (pcie == NULL) { + return -ENOMEM; + } + memset(pcie, 0, sizeof(struct radeon_pcie)); + pcie->dev = dev; + dev_priv->bus = (void *)pcie; + pcie->gart_table_size = (dev_priv->gpu_gart_size / RADEON_PAGE_SIZE) * + 4; + /* gart table start must be aligned on 16bytes, align it on one page */ + ret = drm_buffer_object_create(dev, + pcie->gart_table_size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 1, + 0, + &pcie->gart_table_object); + if (ret) { + return ret; + } + ret = drm_mem_reg_ioremap(dev, &pcie->gart_table_object->mem, + (void **) &pcie->gart_table); + if (ret) { + DRM_ERROR("[radeon_ms] error mapping gart table: %d\n", ret); + return ret; + } + DRM_INFO("[radeon_ms] gart table in vram at 0x%08lX\n", + pcie->gart_table_object->offset); + memset((void *)pcie->gart_table, 0, pcie->gart_table_size); + pcie->page_last = pcie->gart_table_size >> 2; + state->pcie_tx_gart_discard_rd_addr_lo = + REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_LO, + GART_DISCARD_RD_ADDR_LO, + dev_priv->gpu_gart_start); + state->pcie_tx_gart_discard_rd_addr_hi = + REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_HI, + GART_DISCARD_RD_ADDR_HI, 0); + state->pcie_tx_gart_base = + REG_S(PCIE_TX_GART_BASE, GART_BASE, + pcie->gart_table_object->offset); + state->pcie_tx_gart_start_lo = + REG_S(PCIE_TX_GART_START_LO, GART_START_LO, + dev_priv->gpu_gart_start); + state->pcie_tx_gart_start_hi = + REG_S(PCIE_TX_GART_START_HI, GART_START_HI, 0); + state->pcie_tx_gart_end_lo = + REG_S(PCIE_TX_GART_END_LO, GART_END_LO, dev_priv->gpu_gart_end); + state->pcie_tx_gart_end_hi = + REG_S(PCIE_TX_GART_END_HI, GART_END_HI, 0); + /* FIXME: why this ? */ + state->aic_ctrl = 0; + state->agp_base = 0; + state->agp_base_2 = 0; + state->bus_cntl = MMIO_R(BUS_CNTL); + state->mc_agp_location = REG_S(MC_AGP_LOCATION, MC_AGP_START, 0xffc0) | + REG_S(MC_AGP_LOCATION, MC_AGP_TOP, 0xffff); + state->pcie_tx_gart_cntl = + PCIE_TX_GART_CNTL__GART_EN | + REG_S(PCIE_TX_GART_CNTL, GART_UNMAPPED_ACCESS, + GART_UNMAPPED_ACCESS__DISCARD) | + REG_S(PCIE_TX_GART_CNTL, GART_MODE, GART_MODE__CACHE_32x128) | + REG_S(PCIE_TX_GART_CNTL, GART_RDREQPATH_SEL, + GART_RDREQPATH_SEL__HDP); + DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", + PCIE_R(PCIE_TX_GART_START_LO)); + DRM_INFO("[radeon_ms] gpu gart end 0x%08X\n", + PCIE_R(PCIE_TX_GART_END_LO)); + DRM_INFO("[radeon_ms] bus ready\n"); + dev_priv->bus_ready = 1; + return 0; +} + +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* disable gart before programing other registers */ + radeon_ms_agp_restore(dev, state); + PCIE_W(PCIE_TX_GART_CNTL, 0); + PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); + PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); + PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_HI, + state->pcie_tx_gart_discard_rd_addr_hi); + PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_LO, + state->pcie_tx_gart_discard_rd_addr_lo); + PCIE_W(PCIE_TX_GART_START_HI, state->pcie_tx_gart_start_hi); + PCIE_W(PCIE_TX_GART_START_LO, state->pcie_tx_gart_start_lo); + PCIE_W(PCIE_TX_GART_END_HI, state->pcie_tx_gart_end_hi); + PCIE_W(PCIE_TX_GART_END_LO, state->pcie_tx_gart_end_lo); + PCIE_W(PCIE_TX_GART_CNTL, state->pcie_tx_gart_cntl); +} + +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + radeon_ms_agp_save(dev, state); + state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); + state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); + state->pcie_tx_gart_discard_rd_addr_hi = + PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_HI); + state->pcie_tx_gart_discard_rd_addr_lo = + PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_LO); + state->pcie_tx_gart_start_hi = PCIE_R(PCIE_TX_GART_START_HI); + state->pcie_tx_gart_start_lo = PCIE_R(PCIE_TX_GART_START_LO); + state->pcie_tx_gart_end_hi = PCIE_R(PCIE_TX_GART_END_HI); + state->pcie_tx_gart_end_lo = PCIE_R(PCIE_TX_GART_END_LO); + state->pcie_tx_gart_cntl = PCIE_R(PCIE_TX_GART_CNTL); +} diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c new file mode 100644 index 00000000..65609af9 --- /dev/null +++ b/shared-core/radeon_ms_combios.c @@ -0,0 +1,411 @@ +/* + * 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: + * Jérôme Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +extern struct radeon_ms_output radeon_ms_dac1; +extern struct radeon_ms_output radeon_ms_dac2; +extern const struct drm_output_funcs radeon_ms_output_funcs; + +static struct combios_connector_chip_info * +radeon_ms_combios_get_connector_chip_info(struct drm_device *dev, int chip_num) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + struct combios_header *header; + struct combios_connector_table *connector_table; + struct combios_connector_chip_info *connector_chip_info; + uint32_t offset; + int numof_chips, i; + + if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { + return NULL; + } + header = rom->rom.combios_header; + offset = header->usPointerToExtendedInitTable2; + if ((offset + sizeof(struct combios_connector_table)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS connector offset\n"); + return NULL; + } + if (!offset) { + return NULL; + } + connector_table = (struct combios_connector_table *) + &rom->rom_image[offset]; + numof_chips = (connector_table->ucConnectorHeader & + BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK) >> + BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of chip: %d (table rev: %d)\n", + numof_chips, + (connector_table->ucConnectorHeader & + BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK) >> + BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT); + for (i = 0; i < numof_chips; i++) { + int chip; + + connector_chip_info = &connector_table->sChipConnectorInfo[i]; + chip = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK) >> + BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS chip: %d (asked for: %d)\n", + chip, chip_num); + if (chip == chip_num) { + return connector_chip_info; + } + } + return NULL; +} + +static int radeon_combios_get_connector_infos(struct drm_device *dev, + int connector_info, + int *connector_type, + int *ddc_line, + int *tmds_type, + int *dac_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + *connector_type = (connector_info & BIOS_CONNECTOR_INFO__TYPE__MASK) >> + BIOS_CONNECTOR_INFO__TYPE__SHIFT; + *ddc_line = (connector_info & BIOS_CONNECTOR_INFO__DDC_LINE__MASK) >> + BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT; + *tmds_type = (connector_info & BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK) >> + BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT; + *dac_type = (connector_info & BIOS_CONNECTOR_INFO__DAC_TYPE__MASK) >> + BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT; + + /* most XPRESS chips seem to specify DDC_CRT2 for their + * VGA DDC port, however DDC never seems to work on that + * port. Some have reported success on DDC_MONID, so + * lets see what happens with that. + */ + if (dev_priv->family == CHIP_RS400 && + *connector_type == BIOS_CONNECTOR_TYPE__CRT && + *ddc_line == BIOS_DDC_LINE__CRT2) { + *ddc_line = BIOS_DDC_LINE__MONID01; + } + /* XPRESS desktop chips seem to have a proprietary + * connector listed for DVI-D, try and do the right + * thing here. + */ + if (dev_priv->family == CHIP_RS400 && + *connector_type == BIOS_CONNECTOR_TYPE__PROPRIETARY) { + DRM_INFO("[radeon_ms] COMBIOS Proprietary connector " + "found, assuming DVI-D\n"); + *dac_type = 2; + *tmds_type = BIOS_TMDS_TYPE__EXTERNAL; + *connector_type = BIOS_CONNECTOR_TYPE__DVI_D; + } + return 0; +} + +static int radeon_ms_combios_connector_add(struct drm_device *dev, + int connector_number, + int connector_type, + uint32_t i2c_reg) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + struct drm_output *output = NULL; + + connector = drm_alloc(sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + if (connector == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + memset(connector, 0, sizeof(struct radeon_ms_connector)); + connector->monitor_type = MT_NONE; + connector->type = connector_type; + connector->i2c_reg = i2c_reg; + + switch (connector->type) { + case CONNECTOR_VGA: + sprintf(connector->name, "VGA"); + break; + case CONNECTOR_DVI_I: + sprintf(connector->name, "DVI-I"); + break; + case CONNECTOR_DVI_D: + sprintf(connector->name, "DVI-D"); + break; + default: + sprintf(connector->name, "UNKNOWN-CONNECTOR"); + break; + } + + if (i2c_reg) { + connector->i2c = radeon_ms_i2c_create(dev, + connector->i2c_reg, + connector->name); + if (connector->i2c == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + } else { + connector->i2c = NULL; + } + + output = drm_output_create(dev, &radeon_ms_output_funcs, + connector->type); + if (output == NULL) { + radeon_ms_connectors_destroy(dev); + return -EINVAL; + } + connector->output = output; + output->driver_private = connector; + output->possible_crtcs = 0x3; + dev_priv->connectors[connector_number] = connector; + return 0; +} + +int radeon_ms_combios_get_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + struct combios_pll_block *pll_block; + struct combios_header *header; + uint32_t offset; + + if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { + return 0; + } + header = rom->rom.combios_header; + offset = header->usPointerToPllInfoBlock; + if ((offset + sizeof(struct combios_pll_block)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS pll block offset\n"); + return 0; + } + if (!offset) { + return 0; + } + pll_block = (struct combios_pll_block *)&rom->rom_image[offset]; + dev_priv->properties.pll_reference_freq = pll_block->usDotClockRefFreq; + dev_priv->properties.pll_reference_div = pll_block->usDotClockRefDiv; + dev_priv->properties.pll_min_pll_freq = pll_block->ulDotClockMinFreq; + dev_priv->properties.pll_max_pll_freq = pll_block->ulDotClockMaxFreq; + dev_priv->properties.pll_reference_freq *= 10; + dev_priv->properties.pll_min_pll_freq *= 10; + dev_priv->properties.pll_max_pll_freq *= 10; + DRM_INFO("[radeon_ms] COMBIOS pll reference frequency : %d\n", + dev_priv->properties.pll_reference_freq); + DRM_INFO("[radeon_ms] COMBIOS pll reference divider : %d\n", + dev_priv->properties.pll_reference_div); + DRM_INFO("[radeon_ms] COMBIOS pll minimum frequency : %d\n", + dev_priv->properties.pll_min_pll_freq); + DRM_INFO("[radeon_ms] COMBIOS pll maximum frequency : %d\n", + dev_priv->properties.pll_max_pll_freq); + return 1; +} + +int radeon_ms_connectors_from_combios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct combios_connector_chip_info *connector_chip_info; + int connector_type, ddc_line, tmds_type, dac_type; + int dac1, dac2, tmdsint, tmdsext; + int numof_connector, i, c = 0, added, j; + uint32_t i2c_reg; + int ret; + + dac1 = dac2 = tmdsint = tmdsext = -1; + connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); + if (connector_chip_info == NULL) { + return -1; + } + numof_connector = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", + numof_connector); + for (i = 0; i < numof_connector; i++) { + int connector_info = connector_chip_info->sConnectorInfo[i]; + + ret = radeon_combios_get_connector_infos(dev, + connector_info, + &connector_type, + &ddc_line, + &tmds_type, + &dac_type); + + switch (ddc_line) { + case BIOS_DDC_LINE__MONID01: + i2c_reg = GPIO_MONID; + break; + case BIOS_DDC_LINE__DVI: + i2c_reg = GPIO_DVI_DDC; + break; + case BIOS_DDC_LINE__VGA: + i2c_reg = GPIO_DDC1; + break; + case BIOS_DDC_LINE__CRT2: + i2c_reg = GPIO_CRT2_DDC; + break; + case BIOS_DDC_LINE__GPIOPAD: + i2c_reg = VIPPAD_EN; + break; + case BIOS_DDC_LINE__ZV_LCDPAD: + i2c_reg = VIPPAD1_EN; + break; + default: + i2c_reg = 0; + break; + } + added = 0; + switch (connector_type) { + case BIOS_CONNECTOR_TYPE__CRT: + ret = radeon_ms_combios_connector_add(dev, c, + CONNECTOR_VGA, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + case BIOS_CONNECTOR_TYPE__DVI_I: + ret = radeon_ms_combios_connector_add(dev, c, + CONNECTOR_DVI_I, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + case BIOS_CONNECTOR_TYPE__DVI_D: + ret = radeon_ms_combios_connector_add(dev, c, + CONNECTOR_DVI_D, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + default: + break; + } + if (added) { + j = 0; + /* find to which output this connector is associated + * by following same algo as in: + * radeon_ms_outputs_from_combios*/ + switch (dac_type) { + case BIOS_DAC_TYPE__CRT: + if (dac1 == -1) { + dac1 = c; + } + dev_priv->connectors[c]->outputs[j++] = dac1; + break; + case BIOS_DAC_TYPE__NON_CRT: + if (dac2 == -1) { + dac2 = c; + } + dev_priv->connectors[c]->outputs[j++] = dac2; + break; + } +#if 0 + switch (tmds_type) { + case BIOS_TMDS_TYPE__INTERNAL: + if (tmdsint == -1) { + tmdsint = c; + } + dev_priv->connectors[c]->outputs[j++] = tmdsint; + break; + case BIOS_TMDS_TYPE__EXTERNAL: + if (tmdsext == -1) { + tmdsext = c; + } + dev_priv->connectors[c]->outputs[j++] = tmdsext; + break; + } +#endif + c++; + } + } + return c; +} + +int radeon_ms_outputs_from_combios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct combios_connector_chip_info *connector_chip_info; + int connector_type, ddc_line, tmds_type, dac_type; + int numof_connector, i, dac1_present, dac2_present, c = 0; + int ret; + + dac1_present = dac2_present = 0; + connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); + if (connector_chip_info == NULL) { + return -1; + } + numof_connector = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", + numof_connector); + for (i = 0; i < numof_connector; i++) { + int connector_info = connector_chip_info->sConnectorInfo[i]; + + ret = radeon_combios_get_connector_infos(dev, + connector_info, + &connector_type, + &ddc_line, + &tmds_type, + &dac_type); + + if (!dac1_present && dac_type == BIOS_DAC_TYPE__CRT) { + dev_priv->outputs[c] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[c] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[c], &radeon_ms_dac1, + sizeof(struct radeon_ms_output)); + dev_priv->outputs[c]->dev = dev; + dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); + dac1_present = 1; + c++; + } + if (!dac2_present && dac_type == BIOS_DAC_TYPE__NON_CRT) { + dev_priv->outputs[c] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[c] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[c], &radeon_ms_dac2, + sizeof(struct radeon_ms_output)); + dev_priv->outputs[c]->dev = dev; + dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); + dac1_present = 1; + c++; + } + } + return c; +} diff --git a/shared-core/radeon_ms_combios.h b/shared-core/radeon_ms_combios.h new file mode 100644 index 00000000..fbceadf2 --- /dev/null +++ b/shared-core/radeon_ms_combios.h @@ -0,0 +1,385 @@ +/* + * Copyright 2006-2007 Advanced Micro Devices, Inc. + * Copyright 2007 Jérôme Glisse + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: + * Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_COMBIOS_H__ +#define __RADEON_MS_COMBIOS_H__ + +#pragma pack(1) + +#define ROM_HEADER 0x48 + +struct combios_header +{ + uint8_t ucTypeDefinition; + uint8_t ucExtFunctionCode; + uint8_t ucOemID1; + uint8_t ucOemID2; + uint8_t ucBiosMajorRev; + uint8_t ucBiosMinorRev; + uint16_t usStructureSize; + uint16_t usPointerToSmi; + uint16_t usPointerToPmid; + uint16_t usPointerToInitTable; + uint16_t usPointerToCrcChecksumBlock; + uint16_t usPointerToConfigFilename; + uint16_t usPointerToLogonMessage; + uint16_t usPointerToMiscInfo; + uint16_t usPciBusDevInitCode; + uint16_t usBiosRuntimeSegmentAddress; + uint16_t usIoBaseAddress; + uint16_t usSubsystemVendorID; + uint16_t usSubsystemID; + uint16_t usPostVendorID; + uint16_t usInt10Offset; + uint16_t usInt10Segment; + uint16_t usMonitorInfo; + uint16_t usPointerToConfigBlock; + uint16_t usPointerToDacDelayInfo; + uint16_t usPointerToCapDataStruct; + uint16_t usPointerToInternalCrtTables; + uint16_t usPointerToPllInfoBlock; + uint16_t usPointerToTVInfoTable; + uint16_t usPointerToDFPInfoTable; + uint16_t usPointerToHWConfigTable; + uint16_t usPointerToMMConfigTable; + uint32_t ulTVStdPatchTableSignature; + uint16_t usPointerToTVStdPatchTable; + uint16_t usPointerToPanelInfoTable; + uint16_t usPointerToAsicInfoTable; + uint16_t usPointerToAuroraInfoTable; + uint16_t usPointerToPllInitTable; + uint16_t usPointerToMemoryConfigTable; + uint16_t usPointerToSaveMaskTable; + uint16_t usPointerHardCodedEdid; + uint16_t usPointerToExtendedInitTable1; + uint16_t usPointerToExtendedInitTable2; + uint16_t usPointerToDynamicClkTable; + uint16_t usPointerToReservedMemoryTable; + uint16_t usPointerToBridgetInitTable; + uint16_t usPointerToExtTMDSInitTable; + uint16_t usPointerToMemClkInfoTable; + uint16_t usPointerToExtDACTable; + uint16_t usPointerToMiscInfoTable; +}; + +struct combios_pll_block +{ + /* Usually 6 */ + uint8_t ucPLLBiosVersion; + /* Size in bytes */ + uint8_t ucStructureSize; + /* Dot clock entry used for accelerated modes */ + uint8_t ucDotClockEntry; + /* Dot clock entry used for extended VGA modes */ + uint8_t ucDotClockEntryVga; + /* Offset into internal clock table used for by VGA parameter table */ + uint16_t usPointerToInternalClock; + /* Offset into actual programmed frequency table at POST */ + uint16_t usPointerToFreqTable; + /* XCLK setting, (memory clock in 10 KHz units) */ + uint16_t usXclkSetting; + /* MCLK setting, (engine clock in 10 KHz units) */ + uint16_t usMclkSetting; + /* Number of PLL information block to follow, currently value is 3 */ + uint8_t ucPllInfoBlockNumber; + /* Size of each PLL information block */ + uint8_t ucPllInfoBlockSize; + /* Reference frequency of the dot clock */ + uint16_t usDotClockRefFreq; + /* Reference Divider of the dot clock */ + uint16_t usDotClockRefDiv; + /* Min Frequency supported before post divider for the dot clock */ + uint32_t ulDotClockMinFreq; + /* Max Frequency can be supported for the dot clock */ + uint32_t ulDotClockMaxFreq; + /* Reference frequency of the MCLK, engine clock */ + uint16_t usMclkRefFreq; + /* Reference Divider of the MCLK, engine clock */ + uint16_t usMclkRefDiv; + /* Min Frequency supported before post divider for MCLK, engine clock */ + uint32_t ulMclkMinFreq; + /* Max Frequency can be supported for the MCLK, engine clock */ + uint32_t ulMclkMaxFreq; + /* Reference frequency of the XCLK, memory clock */ + uint16_t usXclkRefFreq; + /* Reference Divider of the XCLK, memory clock */ + uint16_t usXclkRefDiv; + /* Min Frequency supported before post divider for XCLK, memory clock */ + uint32_t ulXclkMinFreq; + /* Max Frequency can be supported for the XCLK, memory clock */ + uint32_t ulXclkMaxFreq; + + /*this is the PLL Information Table Extended structure version 10 */ + uint8_t ucNumberOfExtendedPllBlocks; + uint8_t ucSizePLLDefinition; + uint16_t ulCrystalFrequencyPixelClock_pll; + uint32_t ulMinInputPixelClockPLLFrequency; + uint32_t ulMaxInputPixelClockPLLFrequency; + uint32_t ulMinOutputPixelClockPLLFrequency; + uint32_t ulMaxOutputPixelClockPLLFrequency; + + /*version 11 */ + uint16_t ulCrystalFrequencyEngineClock_pll; + uint32_t ulMinInputFrequencyEngineClock_pll; + uint32_t ulMaxInputFrequencyEngineClock_pll; + uint32_t ulMinOutputFrequencyEngineClock_pll; + uint32_t ulMaxOutputFrequencyEngineClock_pll; + uint16_t ulCrystalFrequencyMemoryClock_pll; + uint32_t ulMinInputFrequencyMemoryClock_pll; + uint32_t ulMaxInputFrequencyMemoryClock_pll; + uint32_t ulMinOutputFrequencyMemoryClock_pll; + uint32_t ulMaxOutputFrequencyMemoryClock_pll; + uint32_t ulMaximumDACOutputFrequency; +}; + +#define MAX_NO_OF_LCD_RES_TIMING 25 + +struct panel_information_table +{ + uint8_t ucPanelIdentification; + uint8_t ucPanelIDString[24]; + uint16_t usHorizontalSize; + uint16_t usVerticalSize; + uint16_t usFlatPanelType; + uint8_t ucRedBitsPerPrimary; + uint8_t ucGreenBitsPerPrimary; + uint8_t ucBlueBitsPerPrimary; + uint8_t ucReservedBitsPerPrimary; + uint8_t ucPanelCaps; + uint8_t ucPowerSequenceDelayStepsInMS; + uint8_t ucSupportedRefreshRateExtended; + uint16_t usExtendedPanelInfoTable; + uint16_t usPtrToHalfFrameBufferInformationTable; + uint16_t usVccOntoBlOn; + uint16_t usOffDelay; + uint16_t usRefDiv; + uint8_t ucPostDiv; + uint16_t usFeedBackDiv; + uint8_t ucSpreadSpectrumType; + uint16_t usSpreadSpectrumPercentage; + uint8_t ucBackLightLevel; + uint8_t ucBiasLevel; + uint8_t ucPowerSequenceDelay; + uint32_t ulPanelData; + uint8_t ucPanelRefreshRateData; + uint16_t usSupportedRefreshRate; + uint16_t usModeTableOffset[MAX_NO_OF_LCD_RES_TIMING]; +}; + +struct extended_panel_info_table +{ + uint8_t ucExtendedPanelInfoTableVer; + uint8_t ucSSDelay; + uint8_t ucSSStepSizeIndex; +}; + +struct lcd_mode_table_center +{ + uint16_t usHorizontalRes; + uint16_t usVerticalRes; + uint8_t ucModeType; + uint16_t usOffset2ExpParamTable; + uint16_t usOffset2TvParamTable; + uint16_t usPixelClock; + uint16_t usPixelClockAdjustment; + uint16_t usFpPos; + uint8_t ucReserved; + uint8_t ucMiscBits; + uint16_t usCrtcHTotal; + uint16_t usCrtcHDisp; + uint16_t usCrtcHSyncStrt; + uint8_t ucCrtcHSyncWid; + uint16_t usCrtcVTotal; + uint16_t usCrtcVDisp; + uint16_t usCrtcVSyncStrt; + uint8_t ucOvrWidTop; +}; + +struct lcd_mode_table_exp +{ + uint16_t usPixelClock; + uint16_t usPixelClockAdjustment; + uint16_t usFpPos; + uint8_t ucReserved; + uint8_t ucMiscBits; + uint16_t usCrtcHTotal; + uint16_t usCrtcHDisp; + uint16_t usCrtcHSyncStrt; + uint8_t ucCrtcHSyncWid; + uint16_t usCrtcVTotal; + uint16_t usCrtcVDisp; + uint16_t usCrtcVSyncStrt; + uint8_t ucOvrWidTop; + uint16_t usHorizontalBlendRatio; + uint32_t ulVgaVertStretching; + uint16_t usCopVertStretching; + uint16_t usVgaExtVertStretching; +}; + +struct tmds_pll_cntl_block +{ + uint16_t usClockUpperRange; + uint32_t ulPllSetting; +}; + +#define MAX_PLL_CNTL_ENTRIES 8 + +struct combios_dfp_info_table +{ + uint8_t ucDFPInfoTableRev; + uint8_t ucDFPInfoTableSize; + uint16_t usOffsetDetailedTimingTable; + uint8_t ucReserved; + uint8_t ucNumberOfClockRanges; + uint16_t usMaxPixelClock; + uint32_t ulInitValueTmdsPllCntl; + uint32_t ulFinalValueTmdsPllCntl; + struct tmds_pll_cntl_block sTmdsPllCntlBlock[MAX_PLL_CNTL_ENTRIES]; +}; + +struct combios_exttmds_table_header +{ + uint8_t ucTableRev; + uint16_t usTableSize; + uint8_t ucNoBlocks; +}; + +struct combios_exttmds_block_header +{ + uint16_t usMaxFreq; + uint8_t ucI2CSlaveAddr; + uint8_t ucI2CLine; + uint8_t ucConnectorId; + uint8_t ucFlags; +}; + +/* Connector table - applicable from Piglet and later ASICs + byte 0 (embedded revision) + [7:4] = number of chips (valid number 1 - 15) + [3:0] = revision number of table (valid number 1 - 15) + + byte 1 (Chip info) + [7:4] = chip number, max. 15 (valid number 1 - 15) + [3:0] = number of connectors for that chip, (valid number 1 - 15) + (number of connectors = number of 'Connector info' entries + for that chip) + + byte 2,3 (Connector info) + [15:12] - connector type + = 0 - no connector + = 1 - proprietary + = 2 - CRT + = 3 - DVI-I + = 4 - DVI-D + = 5-15 - reserved for future expansion + [11:8] - DDC line pair used for that connector + = 0 - no DDC + = 1 - MONID 0/1 + = 2 - DVI_DDC + = 3 - VGA_DDC + = 4 - CRT2_DDC + = 5-15 - reserved for future expansion + [5] - bit indicating presence of multiplexer for TV,CRT2 + [7:6] - reserved for future expansion + [4] - TMDS type + = 0 - internal TMDS + = 1 - external TMDS + [3:1] - reserved for future expansion + [0] - DAC associated with that connector + = 0 - CRT DAC + = 1 - non-CRT DAC (e.g. TV DAC, external DAC ..) + + byte 4,5,6... - byte 4,5 can be another "Connector info" word + describing another connector + - or byte 5 is a "Chip info" byte for anther chip, + then start with byte 5,6 to describe connectors + for that chip + - or byte 5 = 0 if all connectors for all chips on + board have been described, no more connector left + to describe. +*/ +#define BIOS_CONNECTOR_INFO__TYPE__MASK 0xF000 +#define BIOS_CONNECTOR_INFO__TYPE__SHIFT 0x0000000C +#define BIOS_CONNECTOR_TYPE__NONE 0x00000000 +#define BIOS_CONNECTOR_TYPE__PROPRIETARY 0x00000001 +#define BIOS_CONNECTOR_TYPE__CRT 0x00000002 +#define BIOS_CONNECTOR_TYPE__DVI_I 0x00000003 +#define BIOS_CONNECTOR_TYPE__DVI_D 0x00000004 + +#define BIOS_CONNECTOR_INFO__DDC_LINE__MASK 0x0F00 +#define BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT 0x00000008 +#define BIOS_DDC_LINE__NONE 0x00000000 +#define BIOS_DDC_LINE__MONID01 0x00000001 +#define BIOS_DDC_LINE__DVI 0x00000002 +#define BIOS_DDC_LINE__VGA 0x00000003 +#define BIOS_DDC_LINE__CRT2 0x00000004 +#define BIOS_DDC_LINE__GPIOPAD 0x00000005 +#define BIOS_DDC_LINE__ZV_LCDPAD 0x00000006 + +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK 0x0010 +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT 0x00000004 +#define BIOS_TMDS_TYPE__INTERNAL 0x00000000 +#define BIOS_TMDS_TYPE__EXTERNAL 0x00000001 + +#define BIOS_CONNECTOR_INFO__DAC_TYPE__MASK 0x0001 +#define BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT 0x00000000 +#define BIOS_DAC_TYPE__CRT 0x00000000 +#define BIOS_DAC_TYPE__NON_CRT 0x00000001 + +#define BIOS_CONNECTOR_INFO__MUX_MASK 0x00000020 +#define BIOS_CONNECTOR_INFO__MUX_SHIFT 0x00000005 + +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK 0xF0 +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT 0x00000004 + +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK 0x0F +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT 0x00000000 + +#define BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS 0x00000010 + +struct combios_connector_chip_info +{ + uint8_t ucChipHeader; + uint16_t sConnectorInfo[BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS]; +}; + +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK 0xF0 +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT 0x00000004 + +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK 0x0F +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT 0x00000000 + +struct combios_connector_table +{ + uint8_t ucConnectorHeader; + struct combios_connector_chip_info sChipConnectorInfo[0x10]; +}; + +#pragma pack() + +int combios_parse(unsigned char *rom, struct combios_header *header); + +#endif diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c new file mode 100644 index 00000000..3ddeea47 --- /dev/null +++ b/shared-core/radeon_ms_cp.c @@ -0,0 +1,371 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * 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 <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +static int radeon_ms_test_ring_buffer(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, ret; + uint32_t cmd[4]; + + MMIO_W(SCRATCH_REG4, 0); + cmd[0] = CP_PACKET0(SCRATCH_REG4, 0); + cmd[1] = 0xdeadbeef; + cmd[2] = CP_PACKET0(WAIT_UNTIL, 0); + cmd[3] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + DRM_MEMORYBARRIER(); + ret = radeon_ms_ring_emit(dev, cmd, 4); + if (ret) { + return 0; + } + DRM_UDELAY(100); + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (MMIO_R(SCRATCH_REG4) == 0xdeadbeef) { + DRM_INFO("[radeon_ms] cp test succeeded in %d usecs\n", + i); + return 1; + } + DRM_UDELAY(1); + } + DRM_INFO("[radeon_ms] cp test failed\n"); + return 0; +} + +static int radeon_ms_test_write_back(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (dev_priv->ring_buffer_object == NULL || + dev_priv->ring_buffer == NULL) + return 0; + dev_priv->write_back_area[0] = 0x0; + MMIO_W(SCRATCH_REG0, 0xdeadbeef); + for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { + if (dev_priv->write_back_area[0] == 0xdeadbeef) + break; + DRM_UDELAY(1); + } + if (tmp < dev_priv->usec_timeout) { + DRM_INFO("[radeon_ms] writeback test succeeded in %d usecs\n", + tmp); + return 1; + } + MMIO_W(SCRATCH_UMSK, 0x0); + DRM_INFO("[radeon_ms] writeback test failed\n"); + return 0; +} + +static __inline__ void radeon_ms_load_mc(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + MMIO_W(CP_ME_RAM_ADDR, 0); + for (i = 0; i < 256; i++) { + MMIO_W(CP_ME_RAM_DATAH, dev_priv->microcode[(i * 2) + 1]); + MMIO_W(CP_ME_RAM_DATAL, dev_priv->microcode[(i * 2) + 0]); + } +} + +int radeon_ms_cp_finish(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (!dev_priv->cp_ready) { + return 0; + } + dev_priv->cp_ready = 0; + radeon_ms_wait_for_idle(dev); + DRM_INFO("[radeon_ms] cp idle\n"); + radeon_ms_cp_stop(dev); + + DRM_INFO("[radeon_ms] ring buffer %p\n", dev_priv->ring_buffer); + if (dev_priv->ring_buffer) { + drm_bo_kunmap(&dev_priv->ring_buffer_map); + } + dev_priv->ring_buffer = NULL; + DRM_INFO("[radeon_ms] ring buffer object %p\n", dev_priv->ring_buffer_object); + if (dev_priv->ring_buffer_object) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->ring_buffer_object); + mutex_unlock(&dev->struct_mutex); + } + return 0; +} + +int radeon_ms_cp_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int ret = 0; + + dev_priv->cp_ready = -1; + if (dev_priv->microcode == NULL) { + DRM_INFO("[radeon_ms] no microcode not starting cp"); + return 0; + } + /* we allocate an extra page for all write back stuff */ + ret = drm_buffer_object_create(dev, + dev_priv->ring_buffer_size + + dev_priv->write_back_area_size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 1, + 0, + &dev_priv->ring_buffer_object); + if (ret) { + return ret; + } + memset(&dev_priv->ring_buffer_map, 0, sizeof(struct drm_bo_kmap_obj)); + ret = drm_bo_kmap(dev_priv->ring_buffer_object, + dev_priv->ring_buffer_object->mem.mm_node->start, + dev_priv->ring_buffer_object->mem.num_pages, + &dev_priv->ring_buffer_map); + if (ret) { + DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); + return ret; + } + dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual; + dev_priv->write_back_area = + &dev_priv->ring_buffer[dev_priv->ring_buffer_size >> 2]; + /* setup write back offset */ + state->scratch_umsk = 0x7; + state->scratch_addr = + REG_S(SCRATCH_ADDR, SCRATCH_ADDR, + (dev_priv->ring_buffer_object->offset + + dev_priv->ring_buffer_size + + dev_priv->gpu_gart_start) >> 5); + MMIO_W(SCRATCH_ADDR, state->scratch_addr); + MMIO_W(SCRATCH_UMSK, REG_S(SCRATCH_UMSK, SCRATCH_UMSK, 0x7)); + DRM_INFO("[radeon_ms] write back at 0x%08X in gpu space\n", + MMIO_R(SCRATCH_ADDR)); + dev_priv->write_back = radeon_ms_test_write_back(dev); + + /* stop cp so it's in know state */ + radeon_ms_cp_stop(dev); + if (dev_priv->ring_rptr) { + DRM_INFO("[radeon_ms] failed to set cp read ptr to 0\n"); + } else { + DRM_INFO("[radeon_ms] set cp read ptr to 0\n"); + } + dev_priv->ring_mask = (dev_priv->ring_buffer_size / 4) - 1; + + /* load microcode */ + DRM_INFO("[radeon_ms] load microcode\n"); + radeon_ms_load_mc(dev); + /* initialize CP registers */ + state->cp_rb_cntl = + REG_S(CP_RB_CNTL, RB_BUFSZ, + drm_order(dev_priv->ring_buffer_size / 8)) | + REG_S(CP_RB_CNTL, RB_BLKSZ, drm_order(4096 / 8)) | + REG_S(CP_RB_CNTL, MAX_FETCH, 2); + if (!dev_priv->write_back) { + state->cp_rb_cntl |= CP_RB_CNTL__RB_NO_UPDATE; + } + state->cp_rb_base = + REG_S(CP_RB_BASE, RB_BASE, + (dev_priv->ring_buffer_object->offset + + dev_priv->gpu_gart_start) >> 2); + /* read ptr writeback just after the + * 8 scratch registers 32 = 8*4 */ + state->cp_rb_rptr_addr = + REG_S(CP_RB_RPTR_ADDR, RB_RPTR_ADDR, + (dev_priv->ring_buffer_object->offset + + dev_priv->ring_buffer_size + 32 + + dev_priv->gpu_gart_start) >> 2); + state->cp_rb_wptr = dev_priv->ring_wptr; + state->cp_rb_wptr_delay = + REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_TIMER, 64) | + REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_LIMIT, 8); + state->cp_rb_wptr_delay = 0; + + radeon_ms_cp_restore(dev, state); + DRM_INFO("[radeon_ms] ring buffer at 0x%08X in gpu space\n", + MMIO_R(CP_RB_BASE)); + + /* compute free space */ + dev_priv->ring_free = 0; + ret = radeon_ms_cp_wait(dev, 64); + if (ret) { + /* we shouldn't fail here */ + DRM_INFO("[radeon_ms] failed to get ring free space\n"); + return ret; + } + DRM_INFO("[radeon_ms] free ring size: %d\n", dev_priv->ring_free * 4); + + MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, + CSQ_MODE__CSQ_PRIBM_INDBM)); + if (!radeon_ms_test_ring_buffer(dev)) { + DRM_INFO("[radeon_ms] cp doesn't work\n"); + /* disable ring should wait idle before */ + radeon_ms_cp_stop(dev); + return -EBUSY; + } + /* waaooo the cp is ready & working */ + DRM_INFO("[radeon_ms] cp ready, enjoy\n"); + dev_priv->cp_ready = 1; + return 0; +} + +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + radeon_ms_wait_for_idle(dev); + MMIO_W(SCRATCH_ADDR, state->scratch_addr); + MMIO_W(SCRATCH_UMSK, state->scratch_umsk); + MMIO_W(CP_RB_BASE, state->cp_rb_base); + MMIO_W(CP_RB_RPTR_ADDR, state->cp_rb_rptr_addr); + MMIO_W(CP_RB_WPTR_DELAY, state->cp_rb_wptr_delay); + MMIO_W(CP_RB_CNTL, state->cp_rb_cntl); + /* Sync everything up */ + MMIO_W(ISYNC_CNTL, ISYNC_CNTL__ISYNC_ANY2D_IDLE3D | + ISYNC_CNTL__ISYNC_ANY3D_IDLE2D | + ISYNC_CNTL__ISYNC_WAIT_IDLEGUI | + ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI); +} + +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->scratch_addr = MMIO_R(SCRATCH_ADDR); + state->scratch_umsk = MMIO_R(SCRATCH_UMSK); + state->cp_rb_base = MMIO_R(CP_RB_BASE); + state->cp_rb_rptr_addr = MMIO_R(CP_RB_RPTR_ADDR); + state->cp_rb_wptr_delay = MMIO_R(CP_RB_WPTR_DELAY); + state->cp_rb_wptr = MMIO_R(CP_RB_WPTR); + state->cp_rb_cntl = MMIO_R(CP_RB_CNTL); +} + +void radeon_ms_cp_stop(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, + CSQ_MODE__CSQ_PRIDIS_INDDIS)); + MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA); + MMIO_W(CP_RB_RPTR_WR, 0); + MMIO_W(CP_RB_WPTR, 0); + DRM_UDELAY(5); + dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); + MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr); +} + +int radeon_ms_cp_wait(struct drm_device *dev, int n) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i, last_rptr, p = 0; + + last_rptr = MMIO_R(CP_RB_RPTR); + for (i = 0; i < dev_priv->usec_timeout; i++) { + dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); + if (last_rptr != dev_priv->ring_rptr) { + /* the ring is progressing no lockup */ + p = 1; + } + dev_priv->ring_free = (((int)dev_priv->ring_rptr) - + ((int)dev_priv->ring_wptr)); + if (dev_priv->ring_free <= 0) + dev_priv->ring_free += (dev_priv->ring_buffer_size / 4); + if (dev_priv->ring_free > n) + return 0; + last_rptr = dev_priv->ring_rptr; + DRM_UDELAY(1); + } + if (p) { + DRM_INFO("[radeon_ms] timed out waiting free slot\n"); + } else { + DRM_INFO("[radeon_ms] cp have lickely locked up\n"); + } + return -EBUSY; +} + +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) +{ + static spinlock_t ring_lock = SPIN_LOCK_UNLOCKED; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i = 0; + + if (!count) + return -EINVAL; + + spin_lock(&ring_lock); + if (dev_priv->ring_free <= (count)) { + spin_unlock(&ring_lock); + return -EBUSY; + } + dev_priv->ring_free -= count; + for (i = 0; i < count; i++) { + dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; + DRM_DEBUG("ring[%d]=0x%08X\n", dev_priv->ring_wptr, cmd[i]); + dev_priv->ring_wptr++; + dev_priv->ring_wptr &= dev_priv->ring_mask; + } + /* commit ring */ + DRM_MEMORYBARRIER(); + MMIO_W(CP_RB_WPTR, REG_S(CP_RB_WPTR, RB_WPTR, dev_priv->ring_wptr)); + /* read from PCI bus to ensure correct posting */ + MMIO_R(CP_RB_WPTR); + spin_unlock(&ring_lock); + return 0; +} + +int radeon_ms_resetcp(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + DRM_INFO("[radeon_ms]--------------------------------------------\n"); + + /* reset VAP */ + DRM_INFO("[radeon_ms] status before VAP : RBBM_STATUS: 0x%08X\n", + MMIO_R(RBBM_STATUS)); + MMIO_W(RBBM_SOFT_RESET, RBBM_SOFT_RESET__SOFT_RESET_VAP); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + MMIO_R(RBBM_SOFT_RESET); + for (i = 0; i < 100; i++) { + DRM_UDELAY(100); + } + DRM_INFO("[radeon_ms] status after VAP : RBBM_STATUS: 0x%08X\n", + MMIO_R(RBBM_STATUS)); + + DRM_INFO("[radeon_ms]--------------------------------------------\n"); + return 0; +} diff --git a/shared-core/radeon_ms_cp_mc.c b/shared-core/radeon_ms_cp_mc.c new file mode 100644 index 00000000..f0397d87 --- /dev/null +++ b/shared-core/radeon_ms_cp_mc.c @@ -0,0 +1,801 @@ +/* + * Copyright 2007 Advanced Micro Devices, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "radeon_ms.h" + +/* CP microcode (from ATI) */ + +const uint32_t radeon_cp_microcode[] = { + 0x21007000, 0000000000, + 0x20007000, 0000000000, + 0x000000b4, 0x00000004, + 0x000000b8, 0x00000004, + 0x6f5b4d4c, 0000000000, + 0x4c4c427f, 0000000000, + 0x5b568a92, 0000000000, + 0x4ca09c6d, 0000000000, + 0xad4c4c4c, 0000000000, + 0x4ce1af3d, 0000000000, + 0xd8afafaf, 0000000000, + 0xd64c4cdc, 0000000000, + 0x4cd10d10, 0000000000, + 0x000f0000, 0x00000016, + 0x362f242d, 0000000000, + 0x00000012, 0x00000004, + 0x000f0000, 0x00000016, + 0x362f282d, 0000000000, + 0x000380e7, 0x00000002, + 0x04002c97, 0x00000002, + 0x000f0001, 0x00000016, + 0x333a3730, 0000000000, + 0x000077ef, 0x00000002, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00000017, 0x00000004, + 0x0003802b, 0x00000002, + 0x040067e0, 0x00000002, + 0x00000017, 0x00000004, + 0x000077e0, 0x00000002, + 0x00065000, 0x00000002, + 0x000037e1, 0x00000002, + 0x040067e1, 0x00000006, + 0x000077e0, 0x00000002, + 0x000077e1, 0x00000002, + 0x000077e1, 0x00000006, + 0xffffffff, 0000000000, + 0x10000000, 0000000000, + 0x0003802b, 0x00000002, + 0x040067e0, 0x00000006, + 0x00007675, 0x00000002, + 0x00007676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0003802c, 0x00000002, + 0x04002676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0000002f, 0x00000018, + 0x0000002f, 0x00000018, + 0000000000, 0x00000006, + 0x00000030, 0x00000018, + 0x00000030, 0x00000018, + 0000000000, 0x00000006, + 0x01605000, 0x00000002, + 0x00065000, 0x00000002, + 0x00098000, 0x00000002, + 0x00061000, 0x00000002, + 0x64c0603e, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00080000, 0x00000016, + 0000000000, 0000000000, + 0x0400251d, 0x00000002, + 0x00007580, 0x00000002, + 0x00067581, 0x00000002, + 0x04002580, 0x00000002, + 0x00067581, 0x00000002, + 0x00000049, 0x00000004, + 0x00005000, 0000000000, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00061000, 0x00000002, + 0x0000750e, 0x00000002, + 0x00019000, 0x00000002, + 0x00011055, 0x00000014, + 0x00000055, 0x00000012, + 0x0400250f, 0x00000002, + 0x0000504f, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007565, 0x00000002, + 0x00007566, 0x00000002, + 0x00000058, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x01e655b4, 0x00000002, + 0x4401b0e4, 0x00000002, + 0x01c110e4, 0x00000002, + 0x26667066, 0x00000018, + 0x040c2565, 0x00000002, + 0x00000066, 0x00000018, + 0x04002564, 0x00000002, + 0x00007566, 0x00000002, + 0x0000005d, 0x00000004, + 0x00401069, 0x00000008, + 0x00101000, 0x00000002, + 0x000d80ff, 0x00000002, + 0x0080006c, 0x00000008, + 0x000f9000, 0x00000002, + 0x000e00ff, 0x00000002, + 0000000000, 0x00000006, + 0x0000008f, 0x00000018, + 0x0000005b, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007576, 0x00000002, + 0x00065000, 0x00000002, + 0x00009000, 0x00000002, + 0x00041000, 0x00000002, + 0x0c00350e, 0x00000002, + 0x00049000, 0x00000002, + 0x00051000, 0x00000002, + 0x01e785f8, 0x00000002, + 0x00200000, 0x00000002, + 0x0060007e, 0x0000000c, + 0x00007563, 0x00000002, + 0x006075f0, 0x00000021, + 0x20007073, 0x00000004, + 0x00005073, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007576, 0x00000002, + 0x00007577, 0x00000002, + 0x0000750e, 0x00000002, + 0x0000750f, 0x00000002, + 0x00a05000, 0x00000002, + 0x00600083, 0x0000000c, + 0x006075f0, 0x00000021, + 0x000075f8, 0x00000002, + 0x00000083, 0x00000004, + 0x000a750e, 0x00000002, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x0020750f, 0x00000002, + 0x00600086, 0x00000004, + 0x00007570, 0x00000002, + 0x00007571, 0x00000002, + 0x00007572, 0x00000006, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00005000, 0x00000002, + 0x00a05000, 0x00000002, + 0x00007568, 0x00000002, + 0x00061000, 0x00000002, + 0x00000095, 0x0000000c, + 0x00058000, 0x00000002, + 0x0c607562, 0x00000002, + 0x00000097, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00600096, 0x00000004, + 0x400070e5, 0000000000, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x000380e5, 0x00000002, + 0x000000a8, 0x0000001c, + 0x000650aa, 0x00000018, + 0x040025bb, 0x00000002, + 0x000610ab, 0x00000018, + 0x040075bc, 0000000000, + 0x000075bb, 0x00000002, + 0x000075bc, 0000000000, + 0x00090000, 0x00000006, + 0x00090000, 0x00000002, + 0x000d8002, 0x00000006, + 0x00007832, 0x00000002, + 0x00005000, 0x00000002, + 0x000380e7, 0x00000002, + 0x04002c97, 0x00000002, + 0x00007820, 0x00000002, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x01200000, 0x00000002, + 0x20077000, 0x00000002, + 0x01200000, 0x00000002, + 0x20007000, 0x00000002, + 0x00061000, 0x00000002, + 0x0120751b, 0x00000002, + 0x8040750a, 0x00000002, + 0x8040750b, 0x00000002, + 0x00110000, 0x00000002, + 0x000380e5, 0x00000002, + 0x000000c6, 0x0000001c, + 0x000610ab, 0x00000018, + 0x844075bd, 0x00000002, + 0x000610aa, 0x00000018, + 0x840075bb, 0x00000002, + 0x000610ab, 0x00000018, + 0x844075bc, 0x00000002, + 0x000000c9, 0x00000004, + 0x804075bd, 0x00000002, + 0x800075bb, 0x00000002, + 0x804075bc, 0x00000002, + 0x00108000, 0x00000002, + 0x01400000, 0x00000002, + 0x006000cd, 0x0000000c, + 0x20c07000, 0x00000020, + 0x000000cf, 0x00000012, + 0x00800000, 0x00000006, + 0x0080751d, 0x00000006, + 0000000000, 0000000000, + 0x0000775c, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460275d, 0x00000020, + 0x00004000, 0000000000, + 0x01e00830, 0x00000002, + 0x21007000, 0000000000, + 0x6464614d, 0000000000, + 0x69687420, 0000000000, + 0x00000073, 0000000000, + 0000000000, 0000000000, + 0x00005000, 0x00000002, + 0x000380d0, 0x00000002, + 0x040025e0, 0x00000002, + 0x000075e1, 0000000000, + 0x00000001, 0000000000, + 0x000380e0, 0x00000002, + 0x04002394, 0x00000002, + 0x00005000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0x00000008, 0000000000, + 0x00000004, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; + +const uint32_t r200_cp_microcode[] = { + 0x21007000, 0000000000, + 0x20007000, 0000000000, + 0x000000ab, 0x00000004, + 0x000000af, 0x00000004, + 0x66544a49, 0000000000, + 0x49494174, 0000000000, + 0x54517d83, 0000000000, + 0x498d8b64, 0000000000, + 0x49494949, 0000000000, + 0x49da493c, 0000000000, + 0x49989898, 0000000000, + 0xd34949d5, 0000000000, + 0x9dc90e11, 0000000000, + 0xce9b9b9b, 0000000000, + 0x000f0000, 0x00000016, + 0x352e232c, 0000000000, + 0x00000013, 0x00000004, + 0x000f0000, 0x00000016, + 0x352e272c, 0000000000, + 0x000f0001, 0x00000016, + 0x3239362f, 0000000000, + 0x000077ef, 0x00000002, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00000016, 0x00000004, + 0x0003802a, 0x00000002, + 0x040067e0, 0x00000002, + 0x00000016, 0x00000004, + 0x000077e0, 0x00000002, + 0x00065000, 0x00000002, + 0x000037e1, 0x00000002, + 0x040067e1, 0x00000006, + 0x000077e0, 0x00000002, + 0x000077e1, 0x00000002, + 0x000077e1, 0x00000006, + 0xffffffff, 0000000000, + 0x10000000, 0000000000, + 0x0003802a, 0x00000002, + 0x040067e0, 0x00000006, + 0x00007675, 0x00000002, + 0x00007676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0003802b, 0x00000002, + 0x04002676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0000002e, 0x00000018, + 0x0000002e, 0x00000018, + 0000000000, 0x00000006, + 0x0000002f, 0x00000018, + 0x0000002f, 0x00000018, + 0000000000, 0x00000006, + 0x01605000, 0x00000002, + 0x00065000, 0x00000002, + 0x00098000, 0x00000002, + 0x00061000, 0x00000002, + 0x64c0603d, 0x00000004, + 0x00080000, 0x00000016, + 0000000000, 0000000000, + 0x0400251d, 0x00000002, + 0x00007580, 0x00000002, + 0x00067581, 0x00000002, + 0x04002580, 0x00000002, + 0x00067581, 0x00000002, + 0x00000046, 0x00000004, + 0x00005000, 0000000000, + 0x00061000, 0x00000002, + 0x0000750e, 0x00000002, + 0x00019000, 0x00000002, + 0x00011055, 0x00000014, + 0x00000055, 0x00000012, + 0x0400250f, 0x00000002, + 0x0000504a, 0x00000004, + 0x00007565, 0x00000002, + 0x00007566, 0x00000002, + 0x00000051, 0x00000004, + 0x01e655b4, 0x00000002, + 0x4401b0dc, 0x00000002, + 0x01c110dc, 0x00000002, + 0x2666705d, 0x00000018, + 0x040c2565, 0x00000002, + 0x0000005d, 0x00000018, + 0x04002564, 0x00000002, + 0x00007566, 0x00000002, + 0x00000054, 0x00000004, + 0x00401060, 0x00000008, + 0x00101000, 0x00000002, + 0x000d80ff, 0x00000002, + 0x00800063, 0x00000008, + 0x000f9000, 0x00000002, + 0x000e00ff, 0x00000002, + 0000000000, 0x00000006, + 0x00000080, 0x00000018, + 0x00000054, 0x00000004, + 0x00007576, 0x00000002, + 0x00065000, 0x00000002, + 0x00009000, 0x00000002, + 0x00041000, 0x00000002, + 0x0c00350e, 0x00000002, + 0x00049000, 0x00000002, + 0x00051000, 0x00000002, + 0x01e785f8, 0x00000002, + 0x00200000, 0x00000002, + 0x00600073, 0x0000000c, + 0x00007563, 0x00000002, + 0x006075f0, 0x00000021, + 0x20007068, 0x00000004, + 0x00005068, 0x00000004, + 0x00007576, 0x00000002, + 0x00007577, 0x00000002, + 0x0000750e, 0x00000002, + 0x0000750f, 0x00000002, + 0x00a05000, 0x00000002, + 0x00600076, 0x0000000c, + 0x006075f0, 0x00000021, + 0x000075f8, 0x00000002, + 0x00000076, 0x00000004, + 0x000a750e, 0x00000002, + 0x0020750f, 0x00000002, + 0x00600079, 0x00000004, + 0x00007570, 0x00000002, + 0x00007571, 0x00000002, + 0x00007572, 0x00000006, + 0x00005000, 0x00000002, + 0x00a05000, 0x00000002, + 0x00007568, 0x00000002, + 0x00061000, 0x00000002, + 0x00000084, 0x0000000c, + 0x00058000, 0x00000002, + 0x0c607562, 0x00000002, + 0x00000086, 0x00000004, + 0x00600085, 0x00000004, + 0x400070dd, 0000000000, + 0x000380dd, 0x00000002, + 0x00000093, 0x0000001c, + 0x00065095, 0x00000018, + 0x040025bb, 0x00000002, + 0x00061096, 0x00000018, + 0x040075bc, 0000000000, + 0x000075bb, 0x00000002, + 0x000075bc, 0000000000, + 0x00090000, 0x00000006, + 0x00090000, 0x00000002, + 0x000d8002, 0x00000006, + 0x00005000, 0x00000002, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x01665000, 0x00000002, + 0x000a0000, 0x00000002, + 0x000671cc, 0x00000002, + 0x0286f1cd, 0x00000002, + 0x000000a3, 0x00000010, + 0x21007000, 0000000000, + 0x000000aa, 0x0000001c, + 0x00065000, 0x00000002, + 0x000a0000, 0x00000002, + 0x00061000, 0x00000002, + 0x000b0000, 0x00000002, + 0x38067000, 0x00000002, + 0x000a00a6, 0x00000004, + 0x20007000, 0000000000, + 0x01200000, 0x00000002, + 0x20077000, 0x00000002, + 0x01200000, 0x00000002, + 0x20007000, 0000000000, + 0x00061000, 0x00000002, + 0x0120751b, 0x00000002, + 0x8040750a, 0x00000002, + 0x8040750b, 0x00000002, + 0x00110000, 0x00000002, + 0x000380dd, 0x00000002, + 0x000000bd, 0x0000001c, + 0x00061096, 0x00000018, + 0x844075bd, 0x00000002, + 0x00061095, 0x00000018, + 0x840075bb, 0x00000002, + 0x00061096, 0x00000018, + 0x844075bc, 0x00000002, + 0x000000c0, 0x00000004, + 0x804075bd, 0x00000002, + 0x800075bb, 0x00000002, + 0x804075bc, 0x00000002, + 0x00108000, 0x00000002, + 0x01400000, 0x00000002, + 0x006000c4, 0x0000000c, + 0x20c07000, 0x00000020, + 0x000000c6, 0x00000012, + 0x00800000, 0x00000006, + 0x0080751d, 0x00000006, + 0x000025bb, 0x00000002, + 0x000040c0, 0x00000004, + 0x0000775c, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460275d, 0x00000020, + 0x00004000, 0000000000, + 0x00007999, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460299b, 0x00000020, + 0x00004000, 0000000000, + 0x01e00830, 0x00000002, + 0x21007000, 0000000000, + 0x00005000, 0x00000002, + 0x00038042, 0x00000002, + 0x040025e0, 0x00000002, + 0x000075e1, 0000000000, + 0x00000001, 0000000000, + 0x000380d9, 0x00000002, + 0x04007394, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; + +const uint32_t r300_cp_microcode[] = { + 0x4200e000, 0000000000, + 0x4000e000, 0000000000, + 0x000000af, 0x00000008, + 0x000000b3, 0x00000008, + 0x6c5a504f, 0000000000, + 0x4f4f497a, 0000000000, + 0x5a578288, 0000000000, + 0x4f91906a, 0000000000, + 0x4f4f4f4f, 0000000000, + 0x4fe24f44, 0000000000, + 0x4f9c9c9c, 0000000000, + 0xdc4f4fde, 0000000000, + 0xa1cd4f4f, 0000000000, + 0xd29d9d9d, 0000000000, + 0x4f0f9fd7, 0000000000, + 0x000ca000, 0x00000004, + 0x000d0012, 0x00000038, + 0x0000e8b4, 0x00000004, + 0x000d0014, 0x00000038, + 0x0000e8b6, 0x00000004, + 0x000d0016, 0x00000038, + 0x0000e854, 0x00000004, + 0x000d0018, 0x00000038, + 0x0000e855, 0x00000004, + 0x000d001a, 0x00000038, + 0x0000e856, 0x00000004, + 0x000d001c, 0x00000038, + 0x0000e857, 0x00000004, + 0x000d001e, 0x00000038, + 0x0000e824, 0x00000004, + 0x000d0020, 0x00000038, + 0x0000e825, 0x00000004, + 0x000d0022, 0x00000038, + 0x0000e830, 0x00000004, + 0x000d0024, 0x00000038, + 0x0000f0c0, 0x00000004, + 0x000d0026, 0x00000038, + 0x0000f0c1, 0x00000004, + 0x000d0028, 0x00000038, + 0x0000f041, 0x00000004, + 0x000d002a, 0x00000038, + 0x0000f184, 0x00000004, + 0x000d002c, 0x00000038, + 0x0000f185, 0x00000004, + 0x000d002e, 0x00000038, + 0x0000f186, 0x00000004, + 0x000d0030, 0x00000038, + 0x0000f187, 0x00000004, + 0x000d0032, 0x00000038, + 0x0000f180, 0x00000004, + 0x000d0034, 0x00000038, + 0x0000f393, 0x00000004, + 0x000d0036, 0x00000038, + 0x0000f38a, 0x00000004, + 0x000d0038, 0x00000038, + 0x0000f38e, 0x00000004, + 0x0000e821, 0x00000004, + 0x0140a000, 0x00000004, + 0x00000043, 0x00000018, + 0x00cce800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x0000003a, 0x00000008, + 0x0000a000, 0000000000, + 0x02c0a000, 0x00000004, + 0x000ca000, 0x00000004, + 0x00130000, 0x00000004, + 0x000c2000, 0x00000004, + 0xc980c045, 0x00000008, + 0x2000451d, 0x00000004, + 0x0000e580, 0x00000004, + 0x000ce581, 0x00000004, + 0x08004580, 0x00000004, + 0x000ce581, 0x00000004, + 0x0000004c, 0x00000008, + 0x0000a000, 0000000000, + 0x000c2000, 0x00000004, + 0x0000e50e, 0x00000004, + 0x00032000, 0x00000004, + 0x00022056, 0x00000028, + 0x00000056, 0x00000024, + 0x0800450f, 0x00000004, + 0x0000a050, 0x00000008, + 0x0000e565, 0x00000004, + 0x0000e566, 0x00000004, + 0x00000057, 0x00000008, + 0x03cca5b4, 0x00000004, + 0x05432000, 0x00000004, + 0x00022000, 0x00000004, + 0x4ccce063, 0x00000030, + 0x08274565, 0x00000004, + 0x00000063, 0x00000030, + 0x08004564, 0x00000004, + 0x0000e566, 0x00000004, + 0x0000005a, 0x00000008, + 0x00802066, 0x00000010, + 0x00202000, 0x00000004, + 0x001b00ff, 0x00000004, + 0x01000069, 0x00000010, + 0x001f2000, 0x00000004, + 0x001c00ff, 0x00000004, + 0000000000, 0x0000000c, + 0x00000085, 0x00000030, + 0x0000005a, 0x00000008, + 0x0000e576, 0x00000004, + 0x000ca000, 0x00000004, + 0x00012000, 0x00000004, + 0x00082000, 0x00000004, + 0x1800650e, 0x00000004, + 0x00092000, 0x00000004, + 0x000a2000, 0x00000004, + 0x000f0000, 0x00000004, + 0x00400000, 0x00000004, + 0x00000079, 0x00000018, + 0x0000e563, 0x00000004, + 0x00c0e5f9, 0x000000c2, + 0x0000006e, 0x00000008, + 0x0000a06e, 0x00000008, + 0x0000e576, 0x00000004, + 0x0000e577, 0x00000004, + 0x0000e50e, 0x00000004, + 0x0000e50f, 0x00000004, + 0x0140a000, 0x00000004, + 0x0000007c, 0x00000018, + 0x00c0e5f9, 0x000000c2, + 0x0000007c, 0x00000008, + 0x0014e50e, 0x00000004, + 0x0040e50f, 0x00000004, + 0x00c0007f, 0x00000008, + 0x0000e570, 0x00000004, + 0x0000e571, 0x00000004, + 0x0000e572, 0x0000000c, + 0x0000a000, 0x00000004, + 0x0140a000, 0x00000004, + 0x0000e568, 0x00000004, + 0x000c2000, 0x00000004, + 0x00000089, 0x00000018, + 0x000b0000, 0x00000004, + 0x18c0e562, 0x00000004, + 0x0000008b, 0x00000008, + 0x00c0008a, 0x00000008, + 0x000700e4, 0x00000004, + 0x00000097, 0x00000038, + 0x000ca099, 0x00000030, + 0x080045bb, 0x00000004, + 0x000c209a, 0x00000030, + 0x0800e5bc, 0000000000, + 0x0000e5bb, 0x00000004, + 0x0000e5bc, 0000000000, + 0x00120000, 0x0000000c, + 0x00120000, 0x00000004, + 0x001b0002, 0x0000000c, + 0x0000a000, 0x00000004, + 0x0000e821, 0x00000004, + 0x0000e800, 0000000000, + 0x0000e821, 0x00000004, + 0x0000e82e, 0000000000, + 0x02cca000, 0x00000004, + 0x00140000, 0x00000004, + 0x000ce1cc, 0x00000004, + 0x050de1cd, 0x00000004, + 0x000000a7, 0x00000020, + 0x4200e000, 0000000000, + 0x000000ae, 0x00000038, + 0x000ca000, 0x00000004, + 0x00140000, 0x00000004, + 0x000c2000, 0x00000004, + 0x00160000, 0x00000004, + 0x700ce000, 0x00000004, + 0x001400aa, 0x00000008, + 0x4000e000, 0000000000, + 0x02400000, 0x00000004, + 0x400ee000, 0x00000004, + 0x02400000, 0x00000004, + 0x4000e000, 0000000000, + 0x000c2000, 0x00000004, + 0x0240e51b, 0x00000004, + 0x0080e50a, 0x00000005, + 0x0080e50b, 0x00000005, + 0x00220000, 0x00000004, + 0x000700e4, 0x00000004, + 0x000000c1, 0x00000038, + 0x000c209a, 0x00000030, + 0x0880e5bd, 0x00000005, + 0x000c2099, 0x00000030, + 0x0800e5bb, 0x00000005, + 0x000c209a, 0x00000030, + 0x0880e5bc, 0x00000005, + 0x000000c4, 0x00000008, + 0x0080e5bd, 0x00000005, + 0x0000e5bb, 0x00000005, + 0x0080e5bc, 0x00000005, + 0x00210000, 0x00000004, + 0x02800000, 0x00000004, + 0x00c000c8, 0x00000018, + 0x4180e000, 0x00000040, + 0x000000ca, 0x00000024, + 0x01000000, 0x0000000c, + 0x0100e51d, 0x0000000c, + 0x000045bb, 0x00000004, + 0x000080c4, 0x00000008, + 0x0000f3ce, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c053cf, 0x00000040, + 0x00008000, 0000000000, + 0x0000f3d2, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c053d3, 0x00000040, + 0x00008000, 0000000000, + 0x0000f39d, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c0539e, 0x00000040, + 0x00008000, 0000000000, + 0x03c00830, 0x00000004, + 0x4200e000, 0000000000, + 0x0000a000, 0x00000004, + 0x200045e0, 0x00000004, + 0x0000e5e1, 0000000000, + 0x00000001, 0000000000, + 0x000700e1, 0x00000004, + 0x0800e394, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c new file mode 100644 index 00000000..d73275bb --- /dev/null +++ b/shared-core/radeon_ms_crtc.c @@ -0,0 +1,765 @@ +/* + * Copyright © 2007 Alex Deucher + * Copyright © 2007 Dave Airlie + * Copyright © 2007 Michel Dänzer + * Copyright © 2007 Jerome 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "radeon_ms.h" + +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc); + +/** + * radeon_ms_crtc1_init - initialize CRTC state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize CRTC state to default values + */ +static void radeon_ms_crtc1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->surface_cntl = SURFACE_CNTL__SURF_TRANSLATION_DIS; + state->surface0_info = 0; + state->surface0_lower_bound = 0; + state->surface0_upper_bound = 0; + state->surface1_info = 0; + state->surface1_lower_bound = 0; + state->surface1_upper_bound = 0; + state->surface2_info = 0; + state->surface2_lower_bound = 0; + state->surface2_upper_bound = 0; + state->surface3_info = 0; + state->surface3_lower_bound = 0; + state->surface3_upper_bound = 0; + state->surface4_info = 0; + state->surface4_lower_bound = 0; + state->surface4_upper_bound = 0; + state->surface5_info = 0; + state->surface5_lower_bound = 0; + state->surface5_upper_bound = 0; + state->surface6_info = 0; + state->surface6_lower_bound = 0; + state->surface6_upper_bound = 0; + state->surface7_info = 0; + state->surface7_lower_bound = 0; + state->surface7_upper_bound = 0; + state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | + CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + state->crtc_ext_cntl = CRTC_EXT_CNTL__VGA_ATI_LINEAR | + CRTC_EXT_CNTL__VGA_XCRT_CNT_EN | + CRTC_EXT_CNTL__CRT_ON; + state->crtc_h_total_disp = 0; + state->crtc_h_sync_strt_wid = 0; + state->crtc_v_total_disp = 0; + state->crtc_v_sync_strt_wid = 0; + state->crtc_offset = 0; + state->crtc_pitch = 0; + state->crtc_more_cntl = 0; + state->crtc_tile_x0_y0 = 0; + state->crtc_offset_cntl = 0; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->crtc_offset_cntl |= REG_S(CRTC_OFFSET_CNTL, + CRTC_MICRO_TILE_BUFFER_MODE, + CRTC_MICRO_TILE_BUFFER_MODE__DIS); + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return; + } + radeon_pll1_init(dev_priv, state); +} + +/** + * radeon_pll1_init - initialize PLL1 state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize PLL1 state to default values + */ +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->clock_cntl_index = 0; + state->ppll_cntl = PPLL_R(PPLL_CNTL); + state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | + PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC | + PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TST_EN; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TCPOFF; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TVCOMAX; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_DISABLE_AUTO_RESET; + state->ppll_ref_div = 0; + state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, 12) | + REG_S(PPLL_REF_DIV, PPLL_REF_DIV_SRC, PPLL_REF_DIV_SRC__XTALIN); + state->ppll_div_0 = 0; + state->ppll_div_1 = 0; + state->ppll_div_2 = 0; + state->ppll_div_3 = 0; + state->vclk_ecp_cntl = 0; + state->htotal_cntl = 0; +} + +/** + * radeon_ms_crtc1_restore - restore CRTC state + * @dev_priv: radeon private structure + * @state: CRTC state to restore + */ +void radeon_ms_crtc1_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + MMIO_W(CRTC_GEN_CNTL, ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B & + state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, CRTC_EXT_CNTL__CRTC_VSYNC_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS | + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + state->crtc_ext_cntl); + MMIO_W(SURFACE_CNTL, state->surface_cntl); + MMIO_W(SURFACE0_INFO, state->surface0_info); + MMIO_W(SURFACE0_LOWER_BOUND, state->surface0_lower_bound); + MMIO_W(SURFACE0_UPPER_BOUND, state->surface0_upper_bound); + MMIO_W(SURFACE1_INFO, state->surface1_info); + MMIO_W(SURFACE1_LOWER_BOUND, state->surface1_lower_bound); + MMIO_W(SURFACE1_UPPER_BOUND, state->surface1_upper_bound); + MMIO_W(SURFACE2_INFO, state->surface2_info); + MMIO_W(SURFACE2_LOWER_BOUND, state->surface2_lower_bound); + MMIO_W(SURFACE2_UPPER_BOUND, state->surface2_upper_bound); + MMIO_W(SURFACE3_INFO, state->surface3_info); + MMIO_W(SURFACE3_LOWER_BOUND, state->surface3_lower_bound); + MMIO_W(SURFACE3_UPPER_BOUND, state->surface3_upper_bound); + MMIO_W(SURFACE4_INFO, state->surface4_info); + MMIO_W(SURFACE4_LOWER_BOUND, state->surface4_lower_bound); + MMIO_W(SURFACE4_UPPER_BOUND, state->surface4_upper_bound); + MMIO_W(SURFACE5_INFO, state->surface5_info); + MMIO_W(SURFACE5_LOWER_BOUND, state->surface5_lower_bound); + MMIO_W(SURFACE5_UPPER_BOUND, state->surface5_upper_bound); + MMIO_W(SURFACE6_INFO, state->surface6_info); + MMIO_W(SURFACE6_LOWER_BOUND, state->surface6_lower_bound); + MMIO_W(SURFACE6_UPPER_BOUND, state->surface6_upper_bound); + MMIO_W(SURFACE7_INFO, state->surface7_info); + MMIO_W(SURFACE7_LOWER_BOUND, state->surface7_lower_bound); + MMIO_W(SURFACE7_UPPER_BOUND, state->surface7_upper_bound); + MMIO_W(CRTC_H_TOTAL_DISP, state->crtc_h_total_disp); + MMIO_W(CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid); + MMIO_W(CRTC_V_TOTAL_DISP, state->crtc_v_total_disp); + MMIO_W(CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid); + MMIO_W(FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid); + MMIO_W(FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid); + MMIO_W(FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp); + MMIO_W(FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp); + MMIO_W(CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0); + MMIO_W(CRTC_OFFSET_CNTL, state->crtc_offset_cntl); + MMIO_W(CRTC_OFFSET, state->crtc_offset); + MMIO_W(CRTC_PITCH, state->crtc_pitch); + radeon_pll1_restore(dev_priv, state); + MMIO_W(CRTC_MORE_CNTL, state->crtc_more_cntl); + MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); +} + +/** + * radeon_pll1_restore - restore PLL1 state + * @dev_priv: radeon private structure + * @state: PLL1 state to restore + */ +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + uint32_t tmp; + + /* switch to gpu clock while programing new clock */ + MMIO_W(CLOCK_CNTL_INDEX, state->clock_cntl_index); + tmp = state->vclk_ecp_cntl; + tmp = REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, VCLK_SRC_SEL__CPUCLK); + PPLL_W(VCLK_ECP_CNTL, tmp); + /* reset PLL and update atomicly */ + state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | + PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC; + + PPLL_W(PPLL_CNTL, state->ppll_cntl | PPLL_CNTL__PPLL_RESET); + PPLL_W(PPLL_REF_DIV, state->ppll_ref_div); + PPLL_W(PPLL_DIV_0, state->ppll_div_0); + PPLL_W(PPLL_DIV_1, state->ppll_div_1); + PPLL_W(PPLL_DIV_2, state->ppll_div_2); + PPLL_W(PPLL_DIV_3, state->ppll_div_3); + PPLL_W(HTOTAL_CNTL, state->htotal_cntl); + + /* update */ + PPLL_W(PPLL_REF_DIV, state->ppll_ref_div | + PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W); + for (tmp = 0; tmp < 100; tmp++) { + if (!(PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R & + PPLL_R(PPLL_REF_DIV))) { + break; + } + DRM_UDELAY(10); + } + state->ppll_cntl &= ~PPLL_CNTL__PPLL_RESET; + PPLL_W(PPLL_CNTL, state->ppll_cntl); + PPLL_W(VCLK_ECP_CNTL, state->vclk_ecp_cntl); +} + +/** + * radeon_ms_crtc1_save - save CRTC state + * @dev_priv: radeon private structure + * @state: state where saving current CRTC state + */ +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->surface_cntl = MMIO_R(SURFACE_CNTL); + state->surface0_info = MMIO_R(SURFACE0_INFO); + state->surface0_lower_bound = MMIO_R(SURFACE0_LOWER_BOUND); + state->surface0_upper_bound = MMIO_R(SURFACE0_UPPER_BOUND); + state->surface1_info = MMIO_R(SURFACE1_INFO); + state->surface1_lower_bound = MMIO_R(SURFACE1_LOWER_BOUND); + state->surface1_upper_bound = MMIO_R(SURFACE1_UPPER_BOUND); + state->surface2_info = MMIO_R(SURFACE2_INFO); + state->surface2_lower_bound = MMIO_R(SURFACE2_LOWER_BOUND); + state->surface2_upper_bound = MMIO_R(SURFACE2_UPPER_BOUND); + state->surface3_info = MMIO_R(SURFACE3_INFO); + state->surface3_lower_bound = MMIO_R(SURFACE3_LOWER_BOUND); + state->surface3_upper_bound = MMIO_R(SURFACE3_UPPER_BOUND); + state->surface4_info = MMIO_R(SURFACE4_INFO); + state->surface4_lower_bound = MMIO_R(SURFACE4_LOWER_BOUND); + state->surface4_upper_bound = MMIO_R(SURFACE4_UPPER_BOUND); + state->surface5_info = MMIO_R(SURFACE5_INFO); + state->surface5_lower_bound = MMIO_R(SURFACE5_LOWER_BOUND); + state->surface5_upper_bound = MMIO_R(SURFACE5_UPPER_BOUND); + state->surface6_info = MMIO_R(SURFACE6_INFO); + state->surface6_lower_bound = MMIO_R(SURFACE6_LOWER_BOUND); + state->surface6_upper_bound = MMIO_R(SURFACE6_UPPER_BOUND); + state->surface7_info = MMIO_R(SURFACE7_INFO); + state->surface7_lower_bound = MMIO_R(SURFACE7_LOWER_BOUND); + state->surface7_upper_bound = MMIO_R(SURFACE7_UPPER_BOUND); + state->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); + state->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); + state->crtc_h_total_disp = MMIO_R(CRTC_H_TOTAL_DISP); + state->crtc_h_sync_strt_wid = MMIO_R(CRTC_H_SYNC_STRT_WID); + state->crtc_v_total_disp = MMIO_R(CRTC_V_TOTAL_DISP); + state->crtc_v_sync_strt_wid = MMIO_R(CRTC_V_SYNC_STRT_WID); + state->fp_h_sync_strt_wid = MMIO_R(FP_H_SYNC_STRT_WID); + state->fp_v_sync_strt_wid = MMIO_R(FP_V_SYNC_STRT_WID); + state->fp_crtc_h_total_disp = MMIO_R(FP_CRTC_H_TOTAL_DISP); + state->fp_crtc_v_total_disp = MMIO_R(FP_CRTC_V_TOTAL_DISP); + state->crtc_offset = MMIO_R(CRTC_OFFSET); + state->crtc_offset_cntl = MMIO_R(CRTC_OFFSET_CNTL); + state->crtc_pitch = MMIO_R(CRTC_PITCH); + state->crtc_more_cntl = MMIO_R(CRTC_MORE_CNTL); + state->crtc_tile_x0_y0 = MMIO_R(CRTC_TILE_X0_Y0); + radeon_pll1_save(dev_priv,state); +} + +/** + * radeon_pll1_save - save PLL1 state + * @dev_priv: radeon private structure + * @state: state where saving current PLL1 state + */ +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); + state->ppll_cntl = PPLL_R(PPLL_CNTL); + state->ppll_ref_div = PPLL_R(PPLL_REF_DIV); + state->ppll_div_0 = PPLL_R(PPLL_DIV_0); + state->ppll_div_1 = PPLL_R(PPLL_DIV_1); + state->ppll_div_2 = PPLL_R(PPLL_DIV_2); + state->ppll_div_3 = PPLL_R(PPLL_DIV_3); + state->vclk_ecp_cntl = PPLL_R(VCLK_ECP_CNTL); + state->htotal_cntl = PPLL_R(HTOTAL_CNTL); +} + +static void radeon_ms_crtc1_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_HSYNC_DIS; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + switch(mode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS; + break; + case DPMSModeSuspend: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + break; + case DPMSModeOff: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS | + CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + state->crtc_gen_cntl |= + CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + break; + } + MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); + + dev_priv->crtc1_dpms = mode; + /* FIXME: once adding crtc2 remove this */ + dev_priv->crtc2_dpms = mode; + radeon_ms_gpu_dpms(crtc->dev); + + if (mode != DPMSModeOff) { + radeon_ms_crtc_load_lut(crtc); + } +} + +static bool radeon_ms_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc) +{ + crtc->funcs->dpms(crtc, DPMSModeOff); +} + +/* compute PLL registers values for requested video mode */ +static int radeon_pll1_constraint(struct drm_device *dev, + int clock, int rdiv, + int fdiv, int pdiv, + int rfrq, int pfrq) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int dfrq; + + if (rdiv < 2 || fdiv < 4) { + return 0; + } + dfrq = rfrq / rdiv; + if (dfrq < 2000 || dfrq > 3300) { + return 0; + } + if (pfrq < dev_priv->properties.pll_min_pll_freq || + pfrq > dev_priv->properties.pll_max_pll_freq) { + return 0; + } + return 1; +} + +static void radeon_pll1_compute(struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct { + int divider; + int divider_id; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int clock = mode->clock; + int rfrq = dev_priv->properties.pll_reference_freq; + int pdiv = 1; + int pdiv_id = 0; + int rdiv_best = 2; + int fdiv_best = 4; + int tfrq_best = 0; + int pfrq_best = 0; + int diff_cpfrq_best = 350000; + int vco_freq; + int vco_gain; + int rdiv = 0; + int fdiv = 0; + int tfrq = 35000; + int pfrq = 35000; + int diff_cpfrq = 350000; + + /* clamp frequency into pll [min; max] frequency range */ + if (clock > dev_priv->properties.pll_max_pll_freq) { + clock = dev_priv->properties.pll_max_pll_freq; + } + if ((clock * 12) < dev_priv->properties.pll_min_pll_freq) { + clock = dev_priv->properties.pll_min_pll_freq / 12; + } + + /* maximize pll_ref_div while staying in boundary and minimizing + * the difference btw target frequency and programmed frequency */ + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == 0) { + break; + } + tfrq = clock * post_div->divider; + for (fdiv = 1023; fdiv >= 4; fdiv--) { + rdiv = (fdiv * rfrq) / tfrq; + if (radeon_pll1_constraint(crtc->dev, clock, rdiv, + fdiv, pdiv, rfrq, tfrq)) { + pfrq = (fdiv * rfrq) / rdiv; + diff_cpfrq = pfrq - tfrq; + if ((diff_cpfrq >= 0 && + diff_cpfrq < diff_cpfrq_best) || + (diff_cpfrq == diff_cpfrq_best && + rdiv > rdiv_best)) { + rdiv_best = rdiv; + fdiv_best = fdiv; + tfrq_best = tfrq; + pfrq_best = pfrq; + pdiv = post_div->divider; + pdiv_id = post_div->divider_id; + diff_cpfrq_best = diff_cpfrq; + } + } + } + } + state->ppll_ref_div = + REG_S(PPLL_REF_DIV, PPLL_REF_DIV, rdiv_best) | + REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, rdiv_best); + state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fdiv_best) | + REG_S(PPLL_DIV_0, PPLL_POST0_DIV, pdiv_id); + + vco_freq = (fdiv_best * rfrq) / rdiv_best; + /* This is horribly crude: the VCO frequency range is divided into + * 3 parts, each part having a fixed PLL gain value. + */ + if (vco_freq >= 300000) { + /* [300..max] MHz : 7 */ + vco_gain = 7; + } else if (vco_freq >= 180000) { + /* [180..300) MHz : 4 */ + vco_gain = 4; + } else { + /* [0..180) MHz : 1 */ + vco_gain = 1; + } + state->ppll_cntl |= REG_S(PPLL_CNTL, PPLL_PVG, vco_gain); + state->vclk_ecp_cntl |= REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, + VCLK_SRC_SEL__PPLLCLK); + state->htotal_cntl = 0; + DRM_INFO("rdiv: %d\n", rdiv_best); + DRM_INFO("fdiv: %d\n", fdiv_best); + DRM_INFO("pdiv: %d\n", pdiv); + DRM_INFO("pdiv: %d\n", pdiv_id); + DRM_INFO("tfrq: %d\n", tfrq_best); + DRM_INFO("pfrq: %d\n", pfrq_best); + DRM_INFO("PPLL_REF_DIV: 0x%08X\n", state->ppll_ref_div); + DRM_INFO("PPLL_DIV_0: 0x%08X\n", state->ppll_div_0); + DRM_INFO("PPLL_CNTL: 0x%08X\n", state->ppll_cntl); + DRM_INFO("VCLK_ECP_CNTL: 0x%08X\n", state->vclk_ecp_cntl); +} + +static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + 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; + int format, hsync_wid, vsync_wid, pitch; + + DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", + mode->mode_id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type); + DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x (adjusted)\n", + adjusted_mode->mode_id, adjusted_mode->name, adjusted_mode->vrefresh, adjusted_mode->clock, + adjusted_mode->hdisplay, adjusted_mode->hsync_start, + 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) { + case 16: + if (crtc->fb->depth == 15) { + format = 3; + } else { + format = 4; + } + break; + case 24: + case 32: + format = 6; + break; + default: + DRM_ERROR("Unknown color depth %d\n", crtc->fb->bits_per_pixel); + return; + } + radeon_pll1_compute(crtc, adjusted_mode); + + state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset); + state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | + CRTC_GEN_CNTL__CRTC_EN | + REG_S(CRTC_GEN_CNTL, CRTC_PIX_WIDTH, format); + if (adjusted_mode->flags & V_DBLSCAN) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN; + } + if (adjusted_mode->flags & V_CSYNC) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_C_SYNC_EN; + } + if (adjusted_mode->flags & V_INTERLACE) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_INTERLACE_EN; + } + state->crtc_more_cntl = 0; + state->crtc_h_total_disp = + REG_S(CRTC_H_TOTAL_DISP, + CRTC_H_TOTAL, + (adjusted_mode->crtc_htotal/8) - 1) | + REG_S(CRTC_H_TOTAL_DISP, + CRTC_H_DISP, + (adjusted_mode->crtc_hdisplay/8) - 1); + hsync_wid = (adjusted_mode->crtc_hsync_end - + adjusted_mode->crtc_hsync_start) / 8; + if (!hsync_wid) { + hsync_wid = 1; + } + if (hsync_wid > 0x3f) { + hsync_wid = 0x3f; + } + state->crtc_h_sync_strt_wid = + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_WID, hsync_wid) | + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_STRT_PIX, + adjusted_mode->crtc_hsync_start) | + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_STRT_CHAR, + adjusted_mode->crtc_hsync_start/8); + if (adjusted_mode->flags & V_NHSYNC) { + state->crtc_h_sync_strt_wid |= + CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL; + } + + state->crtc_v_total_disp = + REG_S(CRTC_V_TOTAL_DISP, CRTC_V_TOTAL, + adjusted_mode->crtc_vtotal - 1) | + REG_S(CRTC_V_TOTAL_DISP, CRTC_V_DISP, + adjusted_mode->crtc_vdisplay - 1); + vsync_wid = adjusted_mode->crtc_vsync_end - + adjusted_mode->crtc_vsync_start; + if (!vsync_wid) { + vsync_wid = 1; + } + if (vsync_wid > 0x1f) { + vsync_wid = 0x1f; + } + state->crtc_v_sync_strt_wid = + REG_S(CRTC_V_SYNC_STRT_WID, + CRTC_V_SYNC_WID, + vsync_wid) | + REG_S(CRTC_V_SYNC_STRT_WID, + CRTC_V_SYNC_STRT, + adjusted_mode->crtc_vsync_start); + if (adjusted_mode->flags & V_NVSYNC) { + state->crtc_v_sync_strt_wid |= + CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL; + } + + pitch = (crtc->fb->width * crtc->fb->bits_per_pixel + + ((crtc->fb->bits_per_pixel * 8)- 1)) / + (crtc->fb->bits_per_pixel * 8); + state->crtc_pitch = REG_S(CRTC_PITCH, CRTC_PITCH, pitch) | + REG_S(CRTC_PITCH, CRTC_PITCH_RIGHT, pitch); + + state->fp_h_sync_strt_wid = state->crtc_h_sync_strt_wid; + state->fp_v_sync_strt_wid = state->crtc_v_sync_strt_wid; + state->fp_crtc_h_total_disp = state->crtc_h_total_disp; + state->fp_crtc_v_total_disp = state->crtc_v_total_disp; + + 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("mode_set_base 0x%lX\n", crtc->fb->bo->offset); + 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); +} + +static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, + u16 g, u16 b, int regno) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; + 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; + break; + case 2: + state->dac_cntl2 |= DAC_CNTL2__PALETTE_ACCESS_CNTL; + break; + } + MMIO_W(DAC_CNTL2, state->dac_cntl2); + 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) +{ + struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; + int i; + + if (!crtc->enabled) + return; + + for (i = 0; i < 256; i++) { + radeon_ms_crtc_gamma_set(crtc, + radeon_ms_crtc->lut_r[i], + radeon_ms_crtc->lut_g[i], + radeon_ms_crtc->lut_b[i], + i); + } +} + +static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { + .dpms = radeon_ms_crtc1_dpms, + .save = NULL, /* XXX */ + .restore = NULL, /* XXX */ + .prepare = radeon_ms_crtc_mode_prepare, + .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 */ +}; + +int radeon_ms_crtc_create(struct drm_device *dev, int crtc) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_crtc *drm_crtc; + struct radeon_ms_crtc *radeon_ms_crtc; + int i; + + switch (crtc) { + case 1: + radeon_ms_crtc1_init(dev_priv, &dev_priv->driver_state); + drm_crtc = drm_crtc_create(dev, &radeon_ms_crtc1_funcs); + break; + case 2: + default: + return -EINVAL; + } + if (drm_crtc == NULL) { + return -ENOMEM; + } + + radeon_ms_crtc = drm_alloc(sizeof(struct radeon_ms_crtc), DRM_MEM_DRIVER); + if (radeon_ms_crtc == NULL) { + kfree(drm_crtc); + return -ENOMEM; + } + + radeon_ms_crtc->crtc = crtc; + for (i = 0; i < 256; i++) { + radeon_ms_crtc->lut_r[i] = i << 8; + radeon_ms_crtc->lut_g[i] = i << 8; + radeon_ms_crtc->lut_b[i] = i << 8; + } + drm_crtc->driver_private = radeon_ms_crtc; + return 0; +} diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c new file mode 100644 index 00000000..e6312942 --- /dev/null +++ b/shared-core/radeon_ms_dac.c @@ -0,0 +1,400 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ +#include "radeon_ms.h" + +int radeon_ms_dac1_initialize(struct radeon_ms_output *output) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->dac_cntl = + REG_S(DAC_CNTL, DAC_RANGE_CNTL, DAC_RANGE_CNTL__PS2) | + DAC_CNTL__DAC_8BIT_EN | + DAC_CNTL__DAC_VGA_ADR_EN | + DAC_CNTL__DAC_PDWN | + REG_S(DAC_CNTL, DAC, 0xff); + state->dac_ext_cntl = 0; + state->dac_macro_cntl = + DAC_MACRO_CNTL__DAC_PDWN_R | + DAC_MACRO_CNTL__DAC_PDWN_G | + DAC_MACRO_CNTL__DAC_PDWN_B | + REG_S(DAC_MACRO_CNTL, DAC_WHITE_CNTL, 7) | + REG_S(DAC_MACRO_CNTL, DAC_BG_ADJ, 7); + state->dac_embedded_sync_cntl = + DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G; + state->dac_broad_pulse = 0; + state->dac_skew_clks = 0; + state->dac_incr = 0; + state->dac_neg_sync_level = 0; + state->dac_pos_sync_level = 0; + state->dac_blank_level = 0; + state->dac_sync_equalization = 0; + state->disp_output_cntl = 0; + radeon_ms_dac1_restore(output, state); + return 0; +} + +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output) +{ + return output_status_unknown; +} + +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t dac_cntl; + uint32_t dac_macro_cntl; + + dac_cntl = DAC_CNTL__DAC_PDWN; + dac_macro_cntl = DAC_MACRO_CNTL__DAC_PDWN_R | + DAC_MACRO_CNTL__DAC_PDWN_G | + DAC_MACRO_CNTL__DAC_PDWN_B; + switch(mode) { + case DPMSModeOn: + state->dac_cntl &= ~dac_cntl; + state->dac_macro_cntl &= ~dac_macro_cntl; + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + state->dac_cntl |= dac_cntl; + state->dac_macro_cntl |= dac_macro_cntl; + break; + default: + /* error */ + break; + } + MMIO_W(DAC_CNTL, state->dac_cntl); + MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); +} + +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output) +{ + return 0; +} + +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->connector; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t v = 0; + + if (connector == NULL) { + /* output not associated with a connector */ + return -EINVAL; + } + state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK; + state->dac_cntl2 &= ~DAC_CNTL2__DAC_CLK_SEL; + switch (connector->crtc) { + case 1: + v = DISP_DAC_SOURCE__PRIMARYCRTC; + break; + case 2: + v = DISP_DAC_SOURCE__SECONDARYCRTC; + state->dac_cntl2 |= DAC_CNTL2__DAC_CLK_SEL; + break; + } + state->disp_output_cntl |= REG_S(DISP_OUTPUT_CNTL, DISP_DAC_SOURCE, v); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + MMIO_W(DAC_CNTL2, state->dac_cntl2); + return 0; +} + +void radeon_ms_dac1_restore(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + MMIO_W(DAC_CNTL, state->dac_cntl); + MMIO_W(DAC_EXT_CNTL, state->dac_ext_cntl); + MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); + MMIO_W(DAC_EMBEDDED_SYNC_CNTL, state->dac_embedded_sync_cntl); + MMIO_W(DAC_BROAD_PULSE, state->dac_broad_pulse); + MMIO_W(DAC_SKEW_CLKS, state->dac_skew_clks); + MMIO_W(DAC_INCR, state->dac_incr); + MMIO_W(DAC_NEG_SYNC_LEVEL, state->dac_neg_sync_level); + MMIO_W(DAC_POS_SYNC_LEVEL, state->dac_pos_sync_level); + MMIO_W(DAC_BLANK_LEVEL, state->dac_blank_level); + MMIO_W(DAC_SYNC_EQUALIZATION, state->dac_sync_equalization); +} + +void radeon_ms_dac1_save(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + state->dac_cntl = MMIO_R(DAC_CNTL); + state->dac_ext_cntl = MMIO_R(DAC_EXT_CNTL); + state->dac_macro_cntl = MMIO_R(DAC_MACRO_CNTL); + state->dac_embedded_sync_cntl = MMIO_R(DAC_EMBEDDED_SYNC_CNTL); + state->dac_broad_pulse = MMIO_R(DAC_BROAD_PULSE); + state->dac_skew_clks = MMIO_R(DAC_SKEW_CLKS); + state->dac_incr = MMIO_R(DAC_INCR); + state->dac_neg_sync_level = MMIO_R(DAC_NEG_SYNC_LEVEL); + state->dac_pos_sync_level = MMIO_R(DAC_POS_SYNC_LEVEL); + state->dac_blank_level = MMIO_R(DAC_BLANK_LEVEL); + state->dac_sync_equalization = MMIO_R(DAC_SYNC_EQUALIZATION); +} + +int radeon_ms_dac2_initialize(struct radeon_ms_output *output) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->tv_dac_cntl = TV_DAC_CNTL__BGSLEEP | + REG_S(TV_DAC_CNTL, STD, STD__PS2) | + REG_S(TV_DAC_CNTL, BGADJ, 0); + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD | + TV_DAC_CNTL__GDACPD | + TV_DAC_CNTL__BDACPD | + REG_S(TV_DAC_CNTL, DACADJ, 0); + break; + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD_R4 | + TV_DAC_CNTL__GDACPD_R4 | + TV_DAC_CNTL__BDACPD_R4 | + REG_S(TV_DAC_CNTL, DACADJ_R4, 0); + break; + } + state->tv_master_cntl = TV_MASTER_CNTL__TV_ASYNC_RST | + TV_MASTER_CNTL__CRT_ASYNC_RST | + TV_MASTER_CNTL__RESTART_PHASE_FIX | + TV_MASTER_CNTL__CRT_FIFO_CE_EN | + TV_MASTER_CNTL__TV_FIFO_CE_EN; + state->dac_cntl2 = 0; + state->disp_output_cntl = 0; + radeon_ms_dac2_restore(output, state); + return 0; +} + +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output) +{ + return output_status_unknown; +} + +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t tv_dac_cntl_on, tv_dac_cntl_off; + + tv_dac_cntl_off = TV_DAC_CNTL__BGSLEEP; + tv_dac_cntl_on = TV_DAC_CNTL__NBLANK | + TV_DAC_CNTL__NHOLD; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD | + TV_DAC_CNTL__GDACPD | + TV_DAC_CNTL__BDACPD; + break; + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD_R4 | + TV_DAC_CNTL__GDACPD_R4 | + TV_DAC_CNTL__BDACPD_R4; + break; + } + switch(mode) { + case DPMSModeOn: + state->tv_dac_cntl &= ~tv_dac_cntl_off; + state->tv_dac_cntl |= tv_dac_cntl_on; + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + state->tv_dac_cntl &= ~tv_dac_cntl_on; + state->tv_dac_cntl |= tv_dac_cntl_off; + break; + default: + /* error */ + break; + } + MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); +} + +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output) +{ + return 0; +} + +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->connector; + struct radeon_state *state = &dev_priv->driver_state; + + if (connector == NULL) { + /* output not associated with a connector */ + return -EINVAL; + } + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_TV_SOURCE; + switch (connector->crtc) { + case 1: + break; + case 2: + state->disp_output_cntl |= + DISP_OUTPUT_CNTL__DISP_TV_SOURCE; + break; + } + break; + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->disp_output_cntl &= + ~DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK; + switch (connector->crtc) { + case 1: + state->disp_output_cntl |= + REG_S(DISP_OUTPUT_CNTL, + DISP_TVDAC_SOURCE, + DISP_TVDAC_SOURCE__PRIMARYCRTC); + break; + case 2: + state->disp_output_cntl |= + REG_S(DISP_OUTPUT_CNTL, + DISP_TVDAC_SOURCE, + DISP_TVDAC_SOURCE__SECONDARYCRTC); + break; + } + break; + } + switch (dev_priv->family) { + case CHIP_R200: + break; + case CHIP_R100: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + if (connector->type != CONNECTOR_CTV && + connector->type != CONNECTOR_STV) { + state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; + } + } + MMIO_W(DAC_CNTL2, state->dac_cntl2); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + return 0; +} + +void radeon_ms_dac2_restore(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + MMIO_W(DAC_CNTL2, state->dac_cntl2); + MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); + MMIO_W(TV_MASTER_CNTL, state->tv_master_cntl); +} + +void radeon_ms_dac2_save(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + state->dac_cntl2 = MMIO_R(DAC_CNTL2); + state->tv_dac_cntl = MMIO_R(TV_DAC_CNTL); + state->tv_master_cntl = MMIO_R(TV_MASTER_CNTL); +} diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c new file mode 100644 index 00000000..9238de24 --- /dev/null +++ b/shared-core/radeon_ms_drm.c @@ -0,0 +1,341 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 <glisse@freedesktop.org> + */ +#include "drm_pciids.h" +#include "radeon_ms.h" +#include "amd_legacy_fence.h" + + +static uint32_t radeon_ms_mem_prios[] = { + DRM_BO_MEM_VRAM, + DRM_BO_MEM_TT, + DRM_BO_MEM_LOCAL, +}; + +static uint32_t radeon_ms_busy_prios[] = { + DRM_BO_MEM_TT, + DRM_BO_MEM_VRAM, + DRM_BO_MEM_LOCAL, +}; + +struct drm_bo_driver radeon_ms_bo_driver = { + .mem_type_prio = radeon_ms_mem_prios, + .mem_busy_prio = radeon_ms_busy_prios, + .num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = radeon_ms_create_ttm_backend, + .fence_type = r3xx_fence_types, + .invalidate_caches = radeon_ms_invalidate_caches, + .init_mem_type = radeon_ms_init_mem_type, + .evict_flags = radeon_ms_evict_flags, + .move = radeon_ms_bo_move, + .ttm_cache_flush = radeon_ms_ttm_flush, +}; + +struct drm_ioctl_desc radeon_ms_ioctls[] = { + DRM_IOCTL_DEF(DRM_AMD_CMD, amd_ioctl_cmd, DRM_AUTH), + DRM_IOCTL_DEF(DRM_AMD_RESETCP, radeon_ms_resetcp, DRM_AUTH), +}; +int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls); + +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_device_dma *dma = dev->dma; + struct drm_dma *d = data; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + /* Please don't send us buffers. + */ + if (d->send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + DRM_CURRENTPID, d->send_count); + return -EINVAL; + } + + /* Don't ask us buffer neither :) + */ + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; +} + +void radeon_ms_driver_lastclose(struct drm_device * dev) +{ +} + +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) +{ + struct drm_radeon_private *dev_priv; + int ret = 0; + + DRM_INFO("[radeon_ms] loading\n"); + /* allocate and clear device private structure */ + dev_priv = drm_alloc(sizeof(struct drm_radeon_private), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + memset(dev_priv, 0, sizeof(struct drm_radeon_private)); + dev->dev_private = (void *)dev_priv; + + /* initialize modesetting structure (must be done here) */ + drm_mode_config_init(dev); + + /* flags correspond to chipset family */ + dev_priv->usec_timeout = 100; + dev_priv->family = flags & 0xffffU; + dev_priv->bus_type = flags & 0xff0000U; + /* initialize family functions */ + ret = radeon_ms_family_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + dev_priv->fence = drm_alloc(sizeof(struct legacy_fence), DRM_MEM_DRIVER); + if (dev_priv->fence == NULL) { + radeon_ms_driver_unload(dev); + return -ENOMEM; + } + memset(dev_priv->fence, 0, sizeof(struct legacy_fence)); + + /* we don't want userspace to be able to map this so don't use + * drm_addmap */ + dev_priv->mmio.offset = drm_get_resource_start(dev, 2); + dev_priv->mmio.size = drm_get_resource_len(dev, 2); + dev_priv->mmio.type = _DRM_REGISTERS; + dev_priv->mmio.flags = _DRM_RESTRICTED; + drm_core_ioremap(&dev_priv->mmio, dev); + /* map vram FIXME: IGP likely don't have any of this */ + dev_priv->vram.offset = drm_get_resource_start(dev, 0); + dev_priv->vram.size = drm_get_resource_len(dev, 0); + dev_priv->vram.type = _DRM_FRAME_BUFFER; + dev_priv->vram.flags = _DRM_RESTRICTED; + drm_core_ioremap(&dev_priv->vram, dev); + + /* save radeon initial state which will be restored upon module + * exit */ + radeon_ms_state_save(dev, &dev_priv->load_state); + dev_priv->restore_state = 1; + memcpy(&dev_priv->driver_state, &dev_priv->load_state, + sizeof(struct radeon_state)); + + /* initialize irq */ + ret = radeon_ms_irq_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* init bo driver */ + dev_priv->fence_id_last = 1; + dev_priv->fence_reg = SCRATCH_REG2; + ret = drm_bo_driver_init(dev); + if (ret != 0) { + DRM_INFO("[radeon_ms] failed to init bo driver %d.\n", ret); + radeon_ms_driver_unload(dev); + return ret; + } + DRM_INFO("[radeon_ms] bo driver succesfull %d.\n", dev->bm.initialized); + /* initialize vram */ + ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize gpu address space (only after) VRAM initialization */ + ret = radeon_ms_gpu_initialize(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + radeon_ms_gpu_restore(dev, &dev_priv->driver_state); + + /* initialize ttm */ + ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, + dev_priv->gpu_gart_size / RADEON_PAGE_SIZE, 1); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize ring buffer */ + /* set ring size to 4Mo FIXME: should make a parameter for this */ + dev_priv->write_back_area_size = 4 * 1024; + dev_priv->ring_buffer_size = 4 * 1024 * 1024; + ret = radeon_ms_cp_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize modesetting */ + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + dev->mode_config.fb_base = dev_priv->vram.offset; + ret = radeon_ms_crtc_create(dev, 1); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + ret = radeon_ms_outputs_from_rom(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (!ret) { + ret = radeon_ms_outputs_from_properties(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (ret == 0) { + DRM_INFO("[radeon_ms] no outputs !\n"); + } + } else { + DRM_INFO("[radeon_ms] added %d outputs from rom.\n", ret); + } + ret = radeon_ms_connectors_from_rom(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (!ret) { + ret = radeon_ms_connectors_from_properties(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (!ret) { + DRM_INFO("[radeon_ms] no connectors !\n"); + } + } else { + DRM_INFO("[radeon_ms] added %d connectors from rom.\n", ret); + } + radeon_ms_outputs_save(dev, &dev_priv->load_state); + drm_initial_config(dev, false); + + ret = drm_irq_install(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialze driver specific */ + ret = amd_legacy_cmd_module_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); + } else { + DRM_INFO("[radeon_ms] error control 0x%lx, render 0x%lx\n", + (long)dev->primary, (long)dev->control); + } + DRM_INFO("[radeon_ms] successfull initialization\n"); + return 0; +} + +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv) +{ + return 0; +} + + +int radeon_ms_driver_unload(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (dev_priv == NULL) { + return 0; + } + + /* cleanup modesetting */ + drm_mode_config_cleanup(dev); + DRM_INFO("[radeon_ms] modesetting clean\n"); + radeon_ms_outputs_restore(dev, &dev_priv->load_state); + radeon_ms_connectors_destroy(dev); + radeon_ms_outputs_destroy(dev); + + /* shutdown specific driver */ + amd_legacy_cmd_module_destroy(dev); + + /* shutdown cp engine */ + radeon_ms_cp_finish(dev); + DRM_INFO("[radeon_ms] cp clean\n"); + + drm_irq_uninstall(dev); + DRM_INFO("[radeon_ms] irq uninstalled\n"); + + DRM_INFO("[radeon_ms] unloading\n"); + /* clean ttm memory manager */ + mutex_lock(&dev->struct_mutex); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { + DRM_ERROR("TT memory manager not clean. Delaying takedown\n"); + } + mutex_unlock(&dev->struct_mutex); + DRM_INFO("[radeon_ms] TT memory clean\n"); + /* finish */ + if (dev_priv->bus_finish) { + dev_priv->bus_finish(dev); + } + DRM_INFO("[radeon_ms] bus down\n"); + /* clean vram memory manager */ + mutex_lock(&dev->struct_mutex); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { + DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n"); + } + mutex_unlock(&dev->struct_mutex); + DRM_INFO("[radeon_ms] VRAM memory clean\n"); + /* clean memory manager */ + drm_bo_driver_finish(dev); + DRM_INFO("[radeon_ms] memory manager clean\n"); + /* restore card state */ + if (dev_priv->restore_state) { + radeon_ms_state_restore(dev, &dev_priv->load_state); + } + DRM_INFO("[radeon_ms] state restored\n"); + if (dev_priv->mmio.handle) { + drm_core_ioremapfree(&dev_priv->mmio, dev); + } + if (dev_priv->vram.handle) { + drm_core_ioremapfree(&dev_priv->vram, dev); + } + DRM_INFO("[radeon_ms] map released\n"); + drm_free(dev_priv->fence, sizeof(struct legacy_fence), DRM_MEM_DRIVER); + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + + + DRM_INFO("[radeon_ms] that's all the folks\n"); + return 0; +} + diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h new file mode 100644 index 00000000..d7fe6fab --- /dev/null +++ b/shared-core/radeon_ms_drm.h @@ -0,0 +1,80 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * 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: + * Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __AMD_DRM_H__ +#define __AMD_DRM_H__ + +/* Fence + * + * Set DRM_AND_FENCE_FLAG_FLUSH if you want a flush with + * emission of the fence + * + * For fence type we have the native DRM EXE type and the amd R & W type. + */ +#define DRM_AMD_FENCE_CLASS_2D 0 +#define DRM_AMD_FENCE_TYPE_R (1 << 1) +#define DRM_AMD_FENCE_TYPE_W (1 << 2) +#define DRM_AMD_FENCE_FLAG_FLUSH 0x01000000 + +/* ioctl */ +#define DRM_AMD_CMD 0x00 +#define DRM_AMD_RESETCP 0x01 + +/* cmd ioctl */ + +#define DRM_AMD_CMD_BO_TYPE_INVALID 0 +#define DRM_AMD_CMD_BO_TYPE_CMD_RING (1 << 0) +#define DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT (1 << 1) +#define DRM_AMD_CMD_BO_TYPE_DATA (1 << 2) + +struct drm_amd_cmd_bo_offset +{ + uint64_t next; + uint64_t offset; + uint32_t cs_id; +}; + +struct drm_amd_cmd_bo +{ + uint32_t type; + uint64_t next; + uint64_t offset; + struct drm_bo_op_req op_req; + struct drm_bo_arg_rep op_rep; +}; + +struct drm_amd_cmd +{ + uint32_t cdw_count; + uint32_t bo_count; + uint64_t bo; + struct drm_fence_arg fence_arg; +}; + +#endif diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c new file mode 100644 index 00000000..bda9a846 --- /dev/null +++ b/shared-core/radeon_ms_exec.c @@ -0,0 +1,404 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#include "radeon_ms.h" +#include "amd.h" + +static inline void amd_cmd_bo_cleanup(struct drm_device *dev, + struct amd_cmd *cmd) +{ + struct amd_cmd_bo *bo; + + mutex_lock(&dev->struct_mutex); + list_for_each_entry(bo, &cmd->bo_unused.list, list) { + drm_bo_usage_deref_locked(&bo->bo); + } + list_for_each_entry(bo, &cmd->bo_used.list, list) { + drm_bo_usage_deref_locked(&bo->bo); + } + mutex_unlock(&dev->struct_mutex); +} + +static inline int amd_cmd_bo_validate(struct drm_device *dev, + struct drm_file *file, + struct amd_cmd_bo *cmd_bo, + struct drm_amd_cmd_bo *bo, + uint64_t data) +{ + int ret; + + /* validate only cmd indirect or data bo */ + switch (bo->type) { + case DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT: + case DRM_AMD_CMD_BO_TYPE_DATA: + case DRM_AMD_CMD_BO_TYPE_CMD_RING: + /* FIXME: make sure userspace can no longer map the bo */ + break; + default: + return 0; + } + /* check that buffer operation is validate */ + if (bo->op_req.op != drm_bo_validate) { + DRM_ERROR("buffer 0x%x object operation is not validate.\n", + cmd_bo->handle); + return -EINVAL; + } + /* validate buffer */ + memset(&bo->op_rep, 0, sizeof(struct drm_bo_arg_rep)); + ret = drm_bo_handle_validate(file, + bo->op_req.bo_req.handle, + bo->op_req.bo_req.flags, + bo->op_req.bo_req.mask, + bo->op_req.bo_req.hint, + bo->op_req.bo_req.fence_class, + &bo->op_rep.bo_info, + &cmd_bo->bo); + if (ret) { + DRM_ERROR("validate error %d for 0x%08x\n", + ret, cmd_bo->handle); + return ret; + } + if (copy_to_user((void __user *)((unsigned)data), bo, + sizeof(struct drm_amd_cmd_bo))) { + DRM_ERROR("failed to copy to user validate result of 0x%08x\n", + cmd_bo->handle); + return -EFAULT; + } + return 0; +} + +static int amd_cmd_parse_cmd_bo(struct drm_device *dev, + struct drm_file *file, + struct drm_amd_cmd *drm_amd_cmd, + struct amd_cmd *cmd) +{ + struct drm_amd_cmd_bo drm_amd_cmd_bo; + struct amd_cmd_bo *cmd_bo; + uint32_t bo_count = 0; + uint64_t data = drm_amd_cmd->bo; + int ret = 0; + + do { + /* check we don't have more buffer than announced */ + if (bo_count >= drm_amd_cmd->bo_count) { + DRM_ERROR("cmd bo count exceeded got %d waited %d\n.", + bo_count, drm_amd_cmd->bo_count); + return -EINVAL; + } + /* initialize amd_cmd_bo */ + cmd_bo = &cmd->bo[bo_count]; + INIT_LIST_HEAD(&cmd_bo->list); + cmd_bo->bo = NULL; + /* copy from userspace */ + if (copy_from_user(&drm_amd_cmd_bo, + (void __user *)((unsigned)data), + sizeof(struct drm_amd_cmd_bo))) { + return -EFAULT; + } + /* collect informations */ + cmd_bo->type = drm_amd_cmd_bo.type; + cmd_bo->mask = drm_amd_cmd_bo.op_req.bo_req.mask; + cmd_bo->flags = drm_amd_cmd_bo.op_req.bo_req.flags; + cmd_bo->handle = drm_amd_cmd_bo.op_req.arg_handle; + /* get bo objects */ + mutex_lock(&dev->struct_mutex); + cmd_bo->bo = drm_lookup_buffer_object(file, cmd_bo->handle, 1); + mutex_unlock(&dev->struct_mutex); + if (cmd_bo->bo == NULL) { + DRM_ERROR("unknown bo handle 0x%x\n", cmd_bo->handle); + return -EINVAL; + } + /* validate buffer if necessary */ + ret = amd_cmd_bo_validate(dev, file, cmd_bo, + &drm_amd_cmd_bo, data); + if (ret) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&cmd_bo->bo); + mutex_unlock(&dev->struct_mutex); + return ret; + } + /* inspect bo type */ + switch (cmd_bo->type) { + case DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT: + /* add it so we properly unreference in case of error */ + list_add_tail(&cmd_bo->list, &cmd->bo_used.list); + return -EINVAL; + case DRM_AMD_CMD_BO_TYPE_DATA: + /* add to unused list */ + list_add_tail(&cmd_bo->list, &cmd->bo_unused.list); + break; + case DRM_AMD_CMD_BO_TYPE_CMD_RING: + /* set cdw_bo */ + list_add_tail(&cmd_bo->list, &cmd->bo_used.list); + cmd->cdw_bo = cmd_bo; + break; + default: + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&cmd_bo->bo); + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("unknow bo 0x%x unknown type 0x%x in cmd\n", + cmd_bo->handle, cmd_bo->type); + return -EINVAL; + } + /* ok next bo */ + data = drm_amd_cmd_bo.next; + bo_count++; + } while (data != 0); + if (bo_count != drm_amd_cmd->bo_count) { + DRM_ERROR("not enought buffer got %d expected %d\n.", + bo_count, drm_amd_cmd->bo_count); + return -EINVAL; + } + return 0; +} + +static int amd_cmd_packet0_check(struct drm_device *dev, + struct amd_cmd *cmd, + int *cdw_id) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t reg, count, r, i; + int ret; + + reg = cmd->cdw[*cdw_id] & PACKET0_REG_MASK; + count = (cmd->cdw[*cdw_id] & PACKET0_COUNT_MASK) >> PACKET0_COUNT_SHIFT; + if (reg + count > dev_priv->cmd_module.numof_p0_checkers) { + DRM_ERROR("0x%08X registers is above last accepted registers\n", + reg << 2); + return -EINVAL; + } + for (r = reg, i = 0; i <= count; i++, r++) { + if (dev_priv->cmd_module.check_p0[r] == NULL) { + continue; + } + if (dev_priv->cmd_module.check_p0[r] == (void *)-1) { + DRM_ERROR("register 0x%08X (at %d) is forbidden\n", + r << 2, (*cdw_id) + i + 1); + return -EINVAL; + } + ret = dev_priv->cmd_module.check_p0[r](dev, cmd, + (*cdw_id) + i + 1, r); + if (ret) { + return ret; + } + } + /* header + N + 1 dword passed test */ + (*cdw_id) += count + 2; + return 0; +} + +static int amd_cmd_packet3_check(struct drm_device *dev, + struct amd_cmd *cmd, + int *cdw_id) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t opcode, count; + int ret; + + opcode = (cmd->cdw[*cdw_id] & PACKET3_OPCODE_MASK) >> + PACKET3_OPCODE_SHIFT; + if (opcode > dev_priv->cmd_module.numof_p3_checkers) { + DRM_ERROR("0x%08X opcode is above last accepted opcodes\n", + opcode); + return -EINVAL; + } + count = (cmd->cdw[*cdw_id] & PACKET3_COUNT_MASK) >> PACKET3_COUNT_SHIFT; + if (dev_priv->cmd_module.check_p3[opcode] == NULL) { + DRM_ERROR("0x%08X opcode is forbidden\n", opcode); + return -EINVAL; + } + ret = dev_priv->cmd_module.check_p3[opcode](dev, cmd, + (*cdw_id) + 1, opcode, + count); + if (ret) { + return ret; + } + /* header + N + 1 dword passed test */ + (*cdw_id) += count + 2; + return 0; +} + +int amd_cmd_check(struct drm_device *dev, struct amd_cmd *cmd) +{ + uint32_t i; + int ret; + + for (i = 0; i < cmd->cdw_count;) { + switch (PACKET_HEADER_GET(cmd->cdw[i])) { + case 0: + ret = amd_cmd_packet0_check(dev, cmd, &i); + if (ret) { + return ret; + } + break; + case 1: + /* we don't accept packet 1 */ + return -EINVAL; + case 2: + /* FIXME: accept packet 2 */ + return -EINVAL; + case 3: + ret = amd_cmd_packet3_check(dev, cmd, &i); + if (ret) { + return ret; + } + break; + } + } + return 0; +} + +static int amd_ioctl_cmd_cleanup(struct drm_device *dev, + struct drm_file *file, + struct amd_cmd *cmd, + int r) +{ + /* check if we need to unfence object */ + if (r && (!list_empty(&cmd->bo_unused.list) || + !list_empty(&cmd->bo_unused.list))) { + drm_putback_buffer_objects(dev); + } + if (cmd->cdw) { + drm_bo_kunmap(&cmd->cdw_kmap); + cmd->cdw = NULL; + } + /* derefence buffer as lookup reference them */ + amd_cmd_bo_cleanup(dev, cmd); + if (cmd->bo) { + drm_free(cmd->bo, + cmd->bo_count * sizeof(struct amd_cmd_bo), + DRM_MEM_DRIVER); + cmd->bo = NULL; + } + drm_bo_read_unlock(&dev->bm.bm_lock); + return r; +} + +int amd_ioctl_cmd(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_amd_cmd *drm_amd_cmd = data; + struct drm_fence_arg *fence_arg = &drm_amd_cmd->fence_arg; + struct drm_fence_object *fence; + struct amd_cmd cmd; + int tmp; + int ret; + + /* check that we have a command checker */ + if (dev_priv->cmd_module.check == NULL) { + DRM_ERROR("invalid command checker module.\n"); + return -EFAULT; + } + /* command dword count must be >= 0 */ + if (drm_amd_cmd->cdw_count == 0) { + DRM_ERROR("command dword count is 0.\n"); + return -EINVAL; + } + + /* FIXME: Lock buffer manager. This is needed so the X server can + * block DRI clients while VT switched. The X server will then + * take the lock in write mode + */ + + ret = drm_bo_read_lock(&dev->bm.bm_lock, 1); + if (ret) { + + /* FIXME: ret can be -EAGAIN here, + * which really isn't an error. + */ + + DRM_ERROR("bo read locking failed.\n"); + return ret; + } + /* cleanup & initialize amd cmd structure */ + memset(&cmd, 0, sizeof(struct amd_cmd)); + cmd.bo_count = drm_amd_cmd->bo_count; + INIT_LIST_HEAD(&cmd.bo_unused.list); + INIT_LIST_HEAD(&cmd.bo_used.list); + /* allocate structure for bo parsing */ + cmd.bo = drm_calloc(cmd.bo_count, sizeof(struct amd_cmd_bo), + DRM_MEM_DRIVER); + if (cmd.bo == NULL) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -ENOMEM); + } + /* parse cmd bo */ + ret = amd_cmd_parse_cmd_bo(dev, file, drm_amd_cmd, &cmd); + if (ret) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + /* check that a command buffer have been found */ + if (cmd.cdw_bo == NULL) { + DRM_ERROR("no command buffer submited in cmd ioctl\n"); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -EINVAL); + } + /* map command buffer */ + cmd.cdw_count = drm_amd_cmd->cdw_count; + cmd.cdw_size = (cmd.cdw_bo->bo->mem.num_pages * PAGE_SIZE) >> 2; + if (cmd.cdw_size < cmd.cdw_count) { + DRM_ERROR("command buffer (%d) is smaller than expected (%d)\n", + cmd.cdw_size, cmd.cdw_count); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -EINVAL); + } + memset(&cmd.cdw_kmap, 0, sizeof(struct drm_bo_kmap_obj)); + ret = drm_bo_kmap(cmd.cdw_bo->bo, 0, + cmd.cdw_bo->bo->mem.num_pages, &cmd.cdw_kmap); + if (ret) { + DRM_ERROR("error mapping command buffer\n"); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + cmd.cdw = drm_bmo_virtual(&cmd.cdw_kmap, &tmp); + /* do command checking */ + ret = dev_priv->cmd_module.check(dev, &cmd); + if (ret) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + /* copy command to ring */ + ret = radeon_ms_ring_emit(dev, cmd.cdw, cmd.cdw_count); + if (ret) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + /* fence */ + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + if (ret) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { + ret = drm_fence_add_user_object(file, fence, + fence_arg->flags & + DRM_FENCE_FLAG_SHAREABLE); + if (!ret) { + fence_arg->handle = fence->base.hash.key; + fence_arg->fence_class = fence->fence_class; + fence_arg->type = fence->type; + fence_arg->signaled = fence->signaled_types; + fence_arg->sequence = fence->sequence; + } else { + DRM_ERROR("error add object fence, expect oddity !\n"); + } + } + drm_fence_usage_deref_unlocked(&fence); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, 0); +} diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c new file mode 100644 index 00000000..5e83766a --- /dev/null +++ b/shared-core/radeon_ms_family.c @@ -0,0 +1,142 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +extern const uint32_t radeon_cp_microcode[]; +extern const uint32_t r200_cp_microcode[]; +extern const uint32_t r300_cp_microcode[]; + +static void radeon_flush_cache(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[6]; + int i, ret; + + cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); + cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT, 0); + cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT, 0); + cmd[5] = RB3D_ZCACHE_CTLSTAT__ZC_FLUSH; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 6); + if (!ret) { + break; + } + } +} + +static void r300_flush_cache(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[6]; + int i, ret; + + cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); + cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT_R3, 0); + cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3); + cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT_R3, 0); + cmd[5] = RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 6); + if (!ret) { + break; + } + } +} + +int radeon_ms_family_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int ret; + + dev_priv->microcode = radeon_cp_microcode; + dev_priv->irq_emit = radeon_ms_irq_emit; + + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + dev_priv->microcode = radeon_cp_microcode; + dev_priv->flush_cache = radeon_flush_cache; + break; + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + dev_priv->microcode = r200_cp_microcode; + dev_priv->flush_cache = radeon_flush_cache; + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + dev_priv->microcode = r300_cp_microcode; + dev_priv->flush_cache = r300_flush_cache; + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return -EINVAL; + } + switch (dev_priv->bus_type) { + case RADEON_AGP: + dev_priv->create_ttm = drm_agp_init_ttm; + dev_priv->bus_finish = radeon_ms_agp_finish; + dev_priv->bus_init = radeon_ms_agp_init; + dev_priv->bus_restore = radeon_ms_agp_restore; + dev_priv->bus_save = radeon_ms_agp_save; + break; + case RADEON_PCIE: + dev_priv->create_ttm = radeon_ms_pcie_create_ttm; + dev_priv->bus_finish = radeon_ms_pcie_finish; + dev_priv->bus_init = radeon_ms_pcie_init; + dev_priv->bus_restore = radeon_ms_pcie_restore; + dev_priv->bus_save = radeon_ms_pcie_save; + break; + default: + DRM_ERROR("Unknown radeon bus type, aborting\n"); + return -EINVAL; + } + ret = radeon_ms_rom_init(dev); + if (ret) { + return ret; + } + ret = radeon_ms_properties_init(dev); + return ret; +} diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c new file mode 100644 index 00000000..08e53bd2 --- /dev/null +++ b/shared-core/radeon_ms_fence.c @@ -0,0 +1,275 @@ +/* + * Copyright 2007 Dave Airlie. + * 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: + * Dave Airlie + * Jerome Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" +#include "amd_legacy_fence.h" + +#define R3XX_FENCE_SEQUENCE_RW_FLUSH 0x80000000u + +static inline int r3xx_fence_emit_sequence(struct drm_device *dev, + struct drm_radeon_private *dev_priv, + uint32_t sequence) +{ + struct legacy_fence *r3xx_fence = dev_priv->fence; + uint32_t cmd[2]; + int i, r; + + if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) { + r3xx_fence->sequence_last_flush = + sequence & ~R3XX_FENCE_SEQUENCE_RW_FLUSH; + /* Ask flush for VERTEX & FRAGPROG pipeline + * have 3D idle */ + /* FIXME: proper flush */ +#if 0 + dev_priv->flush_cache(dev); +#endif + } + cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); + cmd[1] = sequence; + for (i = 0; i < dev_priv->usec_timeout; i++) { + r = radeon_ms_ring_emit(dev, cmd, 2); + if (!r) { + dev_priv->irq_emit(dev); + return 0; + } + } + return -EBUSY; +} + +static inline uint32_t r3xx_fence_sequence(struct legacy_fence *r3xx_fence) +{ + r3xx_fence->sequence += 1; + if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) { + r3xx_fence->sequence = 1; + } + return r3xx_fence->sequence; +} + +static inline void r3xx_fence_report(struct drm_device *dev, + struct drm_radeon_private *dev_priv, + struct legacy_fence *r3xx_fence) +{ + uint32_t fence_types = DRM_FENCE_TYPE_EXE; + uint32_t sequence; + + if (dev_priv == NULL) { + return; + } + sequence = mmio_read(dev_priv, dev_priv->fence_reg); +DRM_INFO("%s pass fence 0x%08x\n", __func__, sequence); + if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) { + sequence &= ~R3XX_FENCE_SEQUENCE_RW_FLUSH; + fence_types |= DRM_AMD_FENCE_TYPE_R; + fence_types |= DRM_AMD_FENCE_TYPE_W; + if (sequence == r3xx_fence->sequence_last_flush) { + r3xx_fence->sequence_last_flush = 0; + } + } + drm_fence_handler(dev, 0, sequence, fence_types, 0); + r3xx_fence->sequence_last_reported = sequence; +} + +static void r3xx_fence_flush(struct drm_device *dev, uint32_t class) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct legacy_fence *r3xx_fence = dev_priv->fence; + uint32_t sequence; + + sequence = r3xx_fence_sequence(r3xx_fence); + sequence |= R3XX_FENCE_SEQUENCE_RW_FLUSH; + r3xx_fence_emit_sequence(dev, dev_priv, sequence); +} + +static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class, + uint32_t waiting_types) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; + struct legacy_fence *r3xx_fence = dev_priv->fence; + + if (unlikely(!dev_priv)) { + return; + } + /* if there is a RW flush pending then submit new sequence + * preceded by flush cmds */ + if (fc->pending_flush & (DRM_AMD_FENCE_TYPE_R | DRM_AMD_FENCE_TYPE_W)) { + r3xx_fence_flush(dev, 0); + fc->pending_flush &= ~DRM_AMD_FENCE_TYPE_R; + fc->pending_flush &= ~DRM_AMD_FENCE_TYPE_W; + } + r3xx_fence_report(dev, dev_priv, r3xx_fence); + return; +} + +static int r3xx_fence_emit(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct legacy_fence *r3xx_fence = dev_priv->fence; + uint32_t tmp; + + if (!dev_priv || dev_priv->cp_ready != 1) { + return -EINVAL; + } + *sequence = tmp = r3xx_fence_sequence(r3xx_fence); + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_AMD_FENCE_FLAG_FLUSH) { + *native_type |= DRM_AMD_FENCE_TYPE_R; + *native_type |= DRM_AMD_FENCE_TYPE_W; + tmp |= R3XX_FENCE_SEQUENCE_RW_FLUSH; + } +DRM_INFO("%s emit fence 0x%08x\n", __func__, tmp); + return r3xx_fence_emit_sequence(dev, dev_priv, tmp); +} + +static int r3xx_fence_has_irq(struct drm_device *dev, + uint32_t class, uint32_t type) +{ + const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE | + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W; + /* + * We have an irq for EXE & RW fence. + */ + if (class == 0 && (type & type_irq_mask)) { + return 1; + } + return 0; +} + +static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence) +{ + struct drm_device *dev = fence->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct legacy_fence *r3xx_fence = dev_priv->fence; + struct drm_fence_driver *driver = dev->driver->fence_driver; + uint32_t flush_types, diff; + + flush_types = fence->waiting_types & + ~(DRM_FENCE_TYPE_EXE | fence->signaled_types); + + if (flush_types == 0 || ((flush_types & ~fence->native_types) == 0)) { + return 0; + } + if (unlikely(dev_priv == NULL)) { + return 0; + } + if (r3xx_fence->sequence_last_flush) { + diff = (r3xx_fence->sequence_last_flush - fence->sequence) & + driver->sequence_mask; + if (diff < driver->wrap_diff) { + return 0; + } + } + return flush_types; +} + +static int r3xx_fence_wait(struct drm_fence_object *fence, + int lazy, int interruptible, uint32_t mask) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + int r; + + drm_fence_object_flush(fence, mask); + if (likely(interruptible)) { + r = wait_event_interruptible_timeout( + fc->fence_queue, + drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + } else { + r = wait_event_timeout( + fc->fence_queue, + drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + } + if (unlikely(r == -ERESTARTSYS)) { + return -EAGAIN; + } + if (unlikely(r == 0)) { + return -EBUSY; + } + + if (likely(mask == DRM_FENCE_TYPE_EXE || + drm_fence_object_signaled(fence, mask))) { + return 0; + } + + /* + * Poll for sync flush completion. + */ + return drm_fence_wait_polling(fence, lazy, interruptible, + mask, 3 * DRM_HZ); +} + +struct drm_fence_driver r3xx_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 29), + .flush_diff = (1 << 28), + .sequence_mask = 0x7fffffffU, + .has_irq = r3xx_fence_has_irq, + .emit = r3xx_fence_emit, + .flush = r3xx_fence_flush, + .poll = r3xx_fence_poll, + .needed_flush = r3xx_fence_needed_flush, + .wait = r3xx_fence_wait, +}; + +/* this are used by the buffer object code */ +int r3xx_fence_types(struct drm_buffer_object *bo, + uint32_t *class, uint32_t *type) +{ + *class = 0; + if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) { + *type = DRM_FENCE_TYPE_EXE | + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W; + } else { + *type = DRM_FENCE_TYPE_EXE; + } + return 0; +} + +/* this are used by the irq code */ +void r3xx_fence_handler(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + + if (unlikely(dev_priv == NULL)) { + return; + } + + write_lock(&fm->lock); + r3xx_fence_poll(dev, 0, fc->waiting_types); + write_unlock(&fm->lock); +} diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c new file mode 100644 index 00000000..5b03dc35 --- /dev/null +++ b/shared-core/radeon_ms_gpu.c @@ -0,0 +1,599 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ +#include "radeon_ms.h" + +static int radeon_ms_gpu_address_space_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + /* initialize gpu mapping */ + dev_priv->gpu_vram_start = dev_priv->vram.offset; + dev_priv->gpu_vram_end = dev_priv->gpu_vram_start + dev_priv->vram.size; + /* align it on 16Mo boundary (clamp memory which is then + * unreachable but not manufacturer should use strange + * memory size */ + dev_priv->gpu_vram_end = dev_priv->gpu_vram_end & (~0xFFFFFF); + dev_priv->gpu_vram_end -= 1; + dev_priv->gpu_vram_size = dev_priv->gpu_vram_end - + dev_priv->gpu_vram_start + 1; + /* set gart size to 32Mo FIXME: should make a parameter for this */ + dev_priv->gpu_gart_size = 1024 * 1024 * 32; + if (dev_priv->gpu_gart_size > (0xffffffffU - dev_priv->gpu_vram_end)) { + /* align gart start to next 4Ko in gpu address space */ + dev_priv->gpu_gart_start = (dev_priv->gpu_vram_end + 1) + 0xfff; + dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); + dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - + 0x1000; + } else { + /* align gart start to next 4Ko in gpu address space */ + dev_priv->gpu_gart_start = (dev_priv->gpu_vram_start & ~0xfff) - + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); + dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - + 0x1000; + } + state->mc_fb_location = + REG_S(MC_FB_LOCATION, MC_FB_START, + dev_priv->gpu_vram_start >> 16) | + REG_S(MC_FB_LOCATION, MC_FB_TOP, dev_priv->gpu_vram_end >> 16); + state->display_base_addr = + REG_S(DISPLAY_BASE_ADDR, DISPLAY_BASE_ADDR, + dev_priv->gpu_vram_start); + state->config_aper_0_base = dev_priv->gpu_vram_start; + state->config_aper_1_base = dev_priv->gpu_vram_start; + state->config_aper_size = dev_priv->gpu_vram_size; + DRM_INFO("[radeon_ms] gpu vram start 0x%08X\n", + dev_priv->gpu_vram_start); + DRM_INFO("[radeon_ms] gpu vram end 0x%08X\n", + dev_priv->gpu_vram_end); + DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", + dev_priv->gpu_gart_start); + DRM_INFO("[radeon_ms] gpu gart end 0x%08X\n", + dev_priv->gpu_gart_end); + return 0; +} + +static void radeon_ms_gpu_reset(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t clock_cntl_index, mclk_cntl, rbbm_soft_reset; + uint32_t reset_mask, host_path_cntl, cache_mode; + + radeon_ms_cp_stop(dev); + radeon_ms_gpu_flush(dev); + + /* reset clock */ + clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); + pll_index_errata(dev_priv); + mclk_cntl = PPLL_R(MCLK_CNTL); + PPLL_W(MCLK_CNTL, + mclk_cntl | + MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC | + MCLK_CNTL__FORCE_AIC); + PPLL_W(SCLK_CNTL, + PPLL_R(SCLK_CNTL) | + SCLK_CNTL__FORCE_CP | + SCLK_CNTL__FORCE_VIP); + + /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some + * unexpected behaviour on some machines. Here we use + * RADEON_HOST_PATH_CNTL to reset it. + */ + host_path_cntl = MMIO_R(HOST_PATH_CNTL); + rbbm_soft_reset = MMIO_R(RBBM_SOFT_RESET); + reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP | + RBBM_SOFT_RESET__SOFT_RESET_HI | + RBBM_SOFT_RESET__SOFT_RESET_VAP | + RBBM_SOFT_RESET__SOFT_RESET_SE | + RBBM_SOFT_RESET__SOFT_RESET_RE | + RBBM_SOFT_RESET__SOFT_RESET_PP | + RBBM_SOFT_RESET__SOFT_RESET_E2 | + RBBM_SOFT_RESET__SOFT_RESET_RB; + MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + MMIO_R(RBBM_SOFT_RESET); + +#if 1 + cache_mode = MMIO_R(RB2D_DSTCACHE_MODE); + MMIO_W(RB2D_DSTCACHE_MODE, + cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE); +#else + reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP | + RBBM_SOFT_RESET__SOFT_RESET_HI | + RBBM_SOFT_RESET__SOFT_RESET_E2; + MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + cache_mode = MMIO_R(RB3D_DSTCACHE_CTLSTAT); + MMIO_W(RB3D_DSTCACHE_CTLSTAT, cache_mode | (0xf)); +#endif + + MMIO_W(HOST_PATH_CNTL, host_path_cntl | HOST_PATH_CNTL__HDP_SOFT_RESET); + MMIO_R(HOST_PATH_CNTL); + MMIO_W(HOST_PATH_CNTL, host_path_cntl); + MMIO_R(HOST_PATH_CNTL); + + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + PPLL_W(MCLK_CNTL, mclk_cntl); +} + +static void radeon_ms_gpu_resume(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t a; + uint32_t i; + + /* make sure we have sane offset before restoring crtc */ + a = (MMIO_R(MC_FB_LOCATION) & MC_FB_LOCATION__MC_FB_START__MASK) << 16; + MMIO_W(DISPLAY_BASE_ADDR, a); + MMIO_W(CRTC2_DISPLAY_BASE_ADDR, a); + MMIO_W(CRTC_OFFSET, 0); + MMIO_W(CUR_OFFSET, 0); + MMIO_W(CRTC_OFFSET_CNTL, CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL); + MMIO_W(CRTC2_OFFSET, 0); + MMIO_W(CUR2_OFFSET, 0); + MMIO_W(CRTC2_OFFSET_CNTL, CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL); + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET & + MMIO_R(CRTC_OFFSET))) { + break; + } + DRM_UDELAY(1); + } + if (i >= dev_priv->usec_timeout) { + DRM_INFO("[radeon_ms] timeout waiting for crtc...\n"); + } + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET & + MMIO_R(CRTC2_OFFSET))) { + break; + } + DRM_UDELAY(1); + } + if (i >= dev_priv->usec_timeout) { + DRM_INFO("[radeon_ms] timeout waiting for crtc...\n"); + } + DRM_UDELAY(10000); +} + +static void radeon_ms_gpu_stop(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl; + uint32_t crtc2_gen_cntl, i; + + /* Capture MC_STATUS in case things go wrong ... */ + ov0_scale_cntl = dev_priv->ov0_scale_cntl = MMIO_R(OV0_SCALE_CNTL); + crtc_ext_cntl = dev_priv->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); + crtc_gen_cntl = dev_priv->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); + crtc2_gen_cntl = dev_priv->crtc2_gen_cntl = MMIO_R(CRTC2_GEN_CNTL); + ov0_scale_cntl &= ~OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK; + crtc_ext_cntl |= CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; + crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_CUR_EN; + crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_ICON_EN; + crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_EXT_DISP_EN; + crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_CUR_EN; + crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_ICON_EN; + crtc2_gen_cntl |= CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B; + MMIO_W(OV0_SCALE_CNTL, ov0_scale_cntl); + MMIO_W(CRTC_EXT_CNTL, crtc_ext_cntl); + MMIO_W(CRTC_GEN_CNTL, crtc_gen_cntl); + MMIO_W(CRTC2_GEN_CNTL, crtc2_gen_cntl); + DRM_UDELAY(10000); + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + for (i = 0; i < dev_priv->usec_timeout; i++) { + if ((MC_STATUS__MC_IDLE & MMIO_R(MC_STATUS))) { + DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", + i); + return; + } + DRM_UDELAY(1); + } + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + for (i = 0; i < dev_priv->usec_timeout; i++) { + if ((MC_STATUS__MC_IDLE_R3 & MMIO_R(MC_STATUS))) { + DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", + i); + return; + } + DRM_UDELAY(1); + } + break; + default: + DRM_INFO("Unknown radeon family, aborting\n"); + return; + } + DRM_INFO("[radeon_ms] failed to stop gpu...will proceed anyway\n"); + DRM_UDELAY(20000); +} + +static int radeon_ms_wait_for_fifo(struct drm_device *dev, int num_fifo) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int t; + t = RBBM_STATUS__CMDFIFO_AVAIL__MASK & MMIO_R(RBBM_STATUS); + t = t >> RBBM_STATUS__CMDFIFO_AVAIL__SHIFT; + if (t >= num_fifo) + return 0; + DRM_UDELAY(1); + } + DRM_INFO("[radeon_ms] failed to wait for fifo\n"); + return -EBUSY; +} + +int radeon_ms_gpu_initialize(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int ret; + + state->disp_misc_cntl = DISP_MISC_CNTL__SYNC_PAD_FLOP_EN | + REG_S(DISP_MISC_CNTL, SYNC_STRENGTH, 2) | + REG_S(DISP_MISC_CNTL, PALETTE_MEM_RD_MARGIN, 0xb) | + REG_S(DISP_MISC_CNTL, PALETTE2_MEM_RD_MARGIN, 0xb) | + REG_S(DISP_MISC_CNTL, RMX_BUF_MEM_RD_MARGIN, 0x5); + state->disp_merge_cntl = REG_S(DISP_MERGE_CNTL, DISP_GRPH_ALPHA, 0xff) | + REG_S(DISP_MERGE_CNTL, DISP_OV0_ALPHA, 0xff); + state->disp_pwr_man = DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN | + DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN | + REG_S(DISP_PWR_MAN, DISP_PWR_MAN_DPMS, DISP_PWR_MAN_DPMS__OFF) | + DISP_PWR_MAN__DISP_D3_RST | + DISP_PWR_MAN__DISP_D3_REG_RST | + DISP_PWR_MAN__DISP_D3_GRPH_RST | + DISP_PWR_MAN__DISP_D3_SUBPIC_RST | + DISP_PWR_MAN__DISP_D3_OV0_RST | + DISP_PWR_MAN__DISP_D1D2_GRPH_RST | + DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST | + DISP_PWR_MAN__DISP_D1D2_OV0_RST | + DISP_PWR_MAN__DISP_DVO_ENABLE_RST | + DISP_PWR_MAN__TV_ENABLE_RST; + state->disp2_merge_cntl = 0; + ret = radeon_ms_gpu_address_space_init(dev); + if (ret) { + return ret; + } + + /* initialize bus */ + ret = dev_priv->bus_init(dev); + if (ret != 0) { + return ret; + } + return 0; +} + +void radeon_ms_gpu_dpms(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + if (dev_priv->crtc1_dpms == dev_priv->crtc2_dpms) { + /* both crtc are in same state so use global display pwr */ + state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; + switch(dev_priv->crtc1_dpms) { + case DPMSModeOn: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__ON); + break; + case DPMSModeStandby: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__STANDBY); + break; + case DPMSModeSuspend: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__SUSPEND); + break; + case DPMSModeOff: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__OFF); + break; + default: + /* error */ + break; + } + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + } else { + state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__ON); + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + } +} + +void radeon_ms_gpu_flush(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i; + uint32_t purge2d; + uint32_t purge3d; + + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); + purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FREE, 3); + MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); + MMIO_W(RB3D_DSTCACHE_CTLSTAT, purge3d); + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); + purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3) | + REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FREE, 3); + MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); + MMIO_W(RB3D_DSTCACHE_CTLSTAT_R3, purge3d); + break; + default: + DRM_INFO("Unknown radeon family, aborting\n"); + return; + } + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(RB2D_DSTCACHE_CTLSTAT__DC_BUSY & + MMIO_R(RB2D_DSTCACHE_CTLSTAT))) { + return; + } + DRM_UDELAY(1); + } + DRM_INFO("[radeon_ms] gpu flush timeout\n"); +} + +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t wait_until; + uint32_t fbstart; + int ret, ok = 1; + + radeon_ms_gpu_reset(dev); + radeon_ms_wait_for_idle(dev); + radeon_ms_gpu_stop(dev); + + MMIO_W(AIC_CTRL, state->aic_ctrl); + MMIO_W(MC_FB_LOCATION, state->mc_fb_location); + MMIO_R(MC_FB_LOCATION); + MMIO_W(CONFIG_APER_0_BASE, state->config_aper_0_base); + MMIO_W(CONFIG_APER_1_BASE, state->config_aper_1_base); + MMIO_W(CONFIG_APER_SIZE, state->config_aper_size); + MMIO_W(DISPLAY_BASE_ADDR, state->display_base_addr); + if (dev_priv->bus_restore) { + dev_priv->bus_restore(dev, state); + } + + radeon_ms_gpu_reset(dev); + radeon_ms_gpu_resume(dev); + + MMIO_W(BUS_CNTL, state->bus_cntl); + wait_until = WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE | + WAIT_UNTIL__WAIT_DMA_VID_IDLE | + WAIT_UNTIL__WAIT_DMA_GUI_IDLE | + WAIT_UNTIL__WAIT_2D_IDLE | + WAIT_UNTIL__WAIT_3D_IDLE | + WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_3D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + wait_until |= WAIT_UNTIL__WAIT_VAP_IDLE; + break; + } + MMIO_W(WAIT_UNTIL, wait_until); + MMIO_W(DISP_MISC_CNTL, state->disp_misc_cntl); + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + MMIO_W(DISP_MERGE_CNTL, state->disp_merge_cntl); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + MMIO_W(DISP2_MERGE_CNTL, state->disp2_merge_cntl); + + /* Setup engine location. This shouldn't be necessary since we + * set them appropriately before any accel ops, but let's avoid + * random bogus DMA in case we inadvertently trigger the engine + * in the wrong place (happened). + */ + ret = radeon_ms_wait_for_fifo(dev, 2); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting up dst & src gui\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } + fbstart = (MC_FB_LOCATION__MC_FB_START__MASK & + MMIO_R(MC_FB_LOCATION)) << 16; + MMIO_W(DST_PITCH_OFFSET, + REG_S(DST_PITCH_OFFSET, DST_OFFSET, fbstart >> 10)); + MMIO_W(SRC_PITCH_OFFSET, + REG_S(SRC_PITCH_OFFSET, SRC_OFFSET, fbstart >> 10)); + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting up dp data type\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } +#ifdef __BIG_ENDIAN + MMIO_W(DP_DATATYPE, DP_DATATYPE__DP_BYTE_PIX_ORDER); +#else + MMIO_W(DP_DATATYPE, 0); +#endif + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting up surface cntl\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } + MMIO_W(SURFACE_CNTL, SURFACE_CNTL__SURF_TRANSLATION_DIS); + + ret = radeon_ms_wait_for_fifo(dev, 2); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting scissor\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff); + MMIO_W(DEFAULT2_SC_BOTTOM_RIGHT, 0x1fff1fff); + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting up gui cntl\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DP_GUI_MASTER_CNTL, 0); + + ret = radeon_ms_wait_for_fifo(dev, 5); + if (ret) { + ok = 0; + DRM_INFO("[radeon_ms] no fifo for setting up clear color\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DP_BRUSH_BKGD_CLR, 0x00000000); + MMIO_W(DP_BRUSH_FRGD_CLR, 0xffffffff); + MMIO_W(DP_SRC_BKGD_CLR, 0x00000000); + MMIO_W(DP_SRC_FRGD_CLR, 0xffffffff); + MMIO_W(DP_WRITE_MSK, 0xffffffff); + + if (!ok) { + DRM_INFO("[radeon_ms] engine restore not enough fifo\n"); + } +} + +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->aic_ctrl = MMIO_R(AIC_CTRL); + state->bus_cntl = MMIO_R(BUS_CNTL); + state->mc_fb_location = MMIO_R(MC_FB_LOCATION); + state->display_base_addr = MMIO_R(DISPLAY_BASE_ADDR); + state->config_aper_0_base = MMIO_R(CONFIG_APER_0_BASE); + state->config_aper_1_base = MMIO_R(CONFIG_APER_1_BASE); + state->config_aper_size = MMIO_R(CONFIG_APER_SIZE); + state->disp_misc_cntl = MMIO_R(DISP_MISC_CNTL); + state->disp_pwr_man = MMIO_R(DISP_PWR_MAN); + state->disp_merge_cntl = MMIO_R(DISP_MERGE_CNTL); + state->disp_output_cntl = MMIO_R(DISP_OUTPUT_CNTL); + state->disp2_merge_cntl = MMIO_R(DISP2_MERGE_CNTL); + if (dev_priv->bus_save) { + dev_priv->bus_save(dev, state); + } +} + +int radeon_ms_wait_for_idle(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, j, ret; + + for (i = 0; i < 2; i++) { + ret = radeon_ms_wait_for_fifo(dev, 64); + if (ret) { + DRM_INFO("[radeon_ms] fifo not empty\n"); + } + for (j = 0; j < dev_priv->usec_timeout; j++) { + if (!(RBBM_STATUS__GUI_ACTIVE & MMIO_R(RBBM_STATUS))) { + radeon_ms_gpu_flush(dev); + return 0; + } + DRM_UDELAY(1); + } + DRM_INFO("[radeon_ms] idle timed out: status=0x%08x\n", + MMIO_R(RBBM_STATUS)); + radeon_ms_gpu_reset(dev); + radeon_ms_gpu_resume(dev); + } + return -EBUSY; +} diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c new file mode 100644 index 00000000..f4468c1e --- /dev/null +++ b/shared-core/radeon_ms_i2c.c @@ -0,0 +1,336 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ +#include "radeon_ms.h" + +static int get_clock(void *data) +{ + struct radeon_ms_i2c *i2c = data; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v; + + switch (i2c->reg) { + case VIPPAD_EN: + v = MMIO_R(VIPPAD_Y); + if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 2)) { + v = 1; + } else { + v = 0; + } + break; + case VIPPAD1_EN: + v = MMIO_R(VIPPAD1_Y); + if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 8)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC1: + v = MMIO_R(GPIO_DDC1); + if ((GPIO_DDC1__DDC1_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC2: + v = MMIO_R(GPIO_DDC2); + if ((GPIO_DDC2__DDC2_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_MONID: + v = MMIO_R(GPIO_MONID); + if ((GPIO_MONID__GPIO_MONID_1_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_CRT2_DDC: + v = MMIO_R(GPIO_CRT2_DDC); + if ((GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + default: + v = 0; + break; + } + return v; +} + +static int get_data(void *data) +{ + struct radeon_ms_i2c *i2c = data; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v; + + switch (i2c->reg) { + case VIPPAD_EN: + v = MMIO_R(VIPPAD_Y); + if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 1)) { + v = 1; + } else { + v = 0; + } + break; + case VIPPAD1_EN: + v = MMIO_R(VIPPAD1_Y); + if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 4)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC1: + v = MMIO_R(GPIO_DDC1); + if ((GPIO_DDC1__DDC1_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC2: + v = MMIO_R(GPIO_DDC2); + if ((GPIO_DDC2__DDC2_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_MONID: + v = MMIO_R(GPIO_MONID); + if ((GPIO_MONID__GPIO_MONID_0_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_CRT2_DDC: + v = MMIO_R(GPIO_CRT2_DDC); + if ((GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + default: + v = 0; + break; + } + return v; +} + +static void set_clock(void *i2c_priv, int clock) +{ + struct radeon_ms_i2c *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v, line; + + v = MMIO_R(i2c->reg); + switch (i2c->reg) { + case VIPPAD_EN: + line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~2; + v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; + if (!clock) { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 2); + } else { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); + } + break; + case VIPPAD1_EN: + line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~8; + v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; + if (!clock) { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 8); + } else { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); + } + break; + case GPIO_DDC1: + v &= ~GPIO_DDC1__DDC1_CLK_OUT_EN; + if (!clock) { + v |= GPIO_DDC1__DDC1_CLK_OUT_EN; + } + break; + case GPIO_DDC2: + v &= ~GPIO_DDC2__DDC2_CLK_OUT_EN; + if (!clock) { + v |= GPIO_DDC2__DDC2_CLK_OUT_EN; + } + break; + case GPIO_MONID: + v &= ~GPIO_MONID__GPIO_MONID_1_OUT_EN; + if (!clock) { + v |= GPIO_MONID__GPIO_MONID_1_OUT_EN; + } + break; + case GPIO_CRT2_DDC: + v &= ~GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; + if (!clock) { + v |= GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; + } + break; + default: + return; + } + MMIO_W(i2c->reg, v); +} + +static void set_data(void *i2c_priv, int data) +{ + struct radeon_ms_i2c *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v, line; + + v = MMIO_R(i2c->reg); + switch (i2c->reg) { + case VIPPAD_EN: + line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~1; + v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; + if (!data) { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 1); + } else { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); + } + break; + case VIPPAD1_EN: + line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~4; + v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; + if (!data) { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 4); + } else { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); + } + break; + case GPIO_DDC1: + v &= ~GPIO_DDC1__DDC1_DATA_OUT_EN; + if (!data) { + v |= GPIO_DDC1__DDC1_DATA_OUT_EN; + } + break; + case GPIO_DDC2: + v &= ~GPIO_DDC2__DDC2_DATA_OUT_EN; + if (!data) { + v |= GPIO_DDC2__DDC2_DATA_OUT_EN; + } + break; + case GPIO_MONID: + v &= ~GPIO_MONID__GPIO_MONID_0_OUT_EN; + if (!data) { + v |= GPIO_MONID__GPIO_MONID_0_OUT_EN; + } + break; + case GPIO_CRT2_DDC: + v &= ~GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; + if (!data) { + v |= GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; + } + break; + default: + return; + } + MMIO_W(i2c->reg, v); +} + +/** + * radeon_ms_i2c_create - instantiate an radeon i2c bus on specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + */ +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, + const uint32_t reg, + const char *name) +{ + struct radeon_ms_i2c *i2c; + int ret; + + i2c = drm_alloc(sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); + if (i2c == NULL) { + return NULL; + } + memset(i2c, 0, sizeof(struct radeon_ms_i2c)); + + i2c->drm_dev = dev; + i2c->reg = reg; + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name); + i2c->adapter.owner = THIS_MODULE; + /* fixme need to take a look at what its needed for */ + i2c->adapter.id = I2C_HW_B_RADEON; + i2c->adapter.algo_data = &i2c->algo; + i2c->adapter.dev.parent = &dev->pdev->dev; + i2c->algo.setsda = set_data; + i2c->algo.setscl = set_clock; + i2c->algo.getsda = get_data; + i2c->algo.getscl = get_clock; + i2c->algo.udelay = 20; + i2c->algo.timeout = usecs_to_jiffies(2200); + i2c->algo.data = i2c; + + i2c_set_adapdata(&i2c->adapter, i2c); + + ret = i2c_bit_add_bus(&i2c->adapter); + if(ret) { + DRM_INFO("[radeon_ms] failed to register I2C '%s' bus (0x%X)\n", + i2c->adapter.name, reg); + goto out_free; + } + DRM_INFO("[radeon_ms] registered I2C '%s' bus (0x%X)\n", + i2c->adapter.name, reg); + return i2c; + +out_free: + drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); + return NULL; +} + +/** + * radeon_ms_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c) +{ + if (i2c == NULL) { + return; + } + i2c_del_adapter(&i2c->adapter); + drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); +} diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c new file mode 100644 index 00000000..5c68c902 --- /dev/null +++ b/shared-core/radeon_ms_irq.c @@ -0,0 +1,161 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +static uint32_t radeon_ack_irqs(struct drm_radeon_private *dev_priv, + uint32_t mask) +{ + uint32_t irqs; + + irqs = MMIO_R(GEN_INT_STATUS); + if (irqs) { + MMIO_W(GEN_INT_STATUS, irqs); + } + if (irqs & (~mask)) { + /* reprogram irq */ + MMIO_W(GEN_INT_CNTL, dev_priv->driver_state.gen_int_cntl); + } + return irqs; +} + +void radeon_ms_irq_emit(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[4]; + int i, ret; + + cmd[0] = CP_PACKET0(GEN_INT_CNTL, 1); + cmd[1] = dev_priv->driver_state.gen_int_cntl | GEN_INT_CNTL__SW_INT_EN; + cmd[2] = GEN_INT_STATUS__SW_INT_SET; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 3); + if (!ret) { + break; + } + } +} + +static void radeon_ms_irq_enable(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->gen_int_cntl = GEN_INT_CNTL__SW_INT_EN; + radeon_ms_irq_restore(dev, state); +} + +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS) +{ + struct drm_device *dev = (struct drm_device *)arg; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t status, mask; + + /* Only consider the bits we're interested in - others could be used + * outside the DRM + */ + mask = GEN_INT_STATUS__SW_INT | + GEN_INT_STATUS__CRTC_VBLANK_STAT | + GEN_INT_STATUS__CRTC2_VBLANK_STAT; + status = radeon_ack_irqs(dev_priv, mask); + if (!status) { + return IRQ_NONE; + } + + /* SW interrupt */ + if (GEN_INT_STATUS__SW_INT & status) { + r3xx_fence_handler(dev); + } + r3xx_fence_handler(dev); + return IRQ_HANDLED; +} + +void radeon_ms_irq_preinstall(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t mask; + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); + + /* Clear bits if they're already high */ + mask = GEN_INT_STATUS__SW_INT | + GEN_INT_STATUS__CRTC_VBLANK_STAT | + GEN_INT_STATUS__CRTC2_VBLANK_STAT; + radeon_ack_irqs(dev_priv, mask); +} + +int radeon_ms_irq_postinstall(struct drm_device * dev) +{ + radeon_ms_irq_enable(dev); + return 0; +} + +int radeon_ms_irq_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); + return 0; +} + +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(GEN_INT_CNTL, state->gen_int_cntl); +} + +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->gen_int_cntl = MMIO_R(GEN_INT_CNTL); +} + +void radeon_ms_irq_uninstall(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + if (dev_priv == NULL) { + return; + } + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); +} diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c new file mode 100644 index 00000000..bc174371 --- /dev/null +++ b/shared-core/radeon_ms_output.c @@ -0,0 +1,361 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ +#include "radeon_ms.h" + +static struct radeon_ms_output *radeon_ms_connector_get_output( + struct drm_radeon_private *dev_priv, + struct radeon_ms_connector *connector, int i) +{ + if (connector->outputs[i] < 0) { + return NULL; + } + if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) { + return NULL; + } + i = connector->outputs[i]; + if (dev_priv->outputs[i] == NULL) { + return NULL; + } + if (dev_priv->outputs[i]->connector == NULL) { + return dev_priv->outputs[i]; + } + if (dev_priv->outputs[i]->connector == connector) { + return dev_priv->outputs[i]; + } + return NULL; +} + +static void radeon_ms_output_dpms(struct drm_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->driver_private; + struct radeon_ms_output *routput = NULL; + int i; + + if (connector == NULL) { + return; + } + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + routput = radeon_ms_connector_get_output(dev_priv, + connector, i); + + if (routput) { + routput->connector = connector; + routput->dpms(routput, mode); + } + } + radeon_ms_gpu_dpms(output->dev); +} + +static int radeon_ms_output_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL) { + return MODE_ERROR; + } + return MODE_OK; +} + +static bool radeon_ms_output_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_ms_output_prepare(struct drm_output *output) +{ + if (output->funcs->dpms) { + output->funcs->dpms(output, DPMSModeOff); + } +} + +static void radeon_ms_output_commit(struct drm_output *output) +{ + if (output->funcs->dpms) { + output->funcs->dpms(output, DPMSModeOn); + } +} + +static void radeon_ms_output_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->driver_private; + struct radeon_ms_crtc *crtc; + struct radeon_ms_output *routput = NULL; + int i; + + if (connector == NULL) { + return; + } + if (output->crtc == NULL) { + return; + } + crtc = output->crtc->driver_private; + connector->crtc = crtc->crtc; + /* catch unknown crtc */ + switch (connector->crtc) { + case 1: + case 2: + break; + default: + /* error */ + return; + } + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + routput = radeon_ms_connector_get_output(dev_priv, + connector, i); + if (routput) { + routput->connector = connector; + routput->mode_set(routput, mode, adjusted_mode); + } + } +} + +static enum drm_output_status radeon_ms_output_detect(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL || connector->i2c == NULL) { + return output_status_unknown; + } + kfree(connector->edid); + connector->edid = drm_get_edid(output, &connector->i2c->adapter); + if (connector->edid == NULL) { + return output_status_unknown; + } + return output_status_connected; +} + +static int radeon_ms_output_get_modes(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + int ret = 0; + + if (connector == NULL || connector->i2c == NULL) { + return 0; + } + if (connector->edid == NULL) { + return 0; + } + drm_mode_output_update_edid_property(output, connector->edid); + ret = drm_add_edid_modes(output, connector->edid); + kfree(connector->edid); + connector->edid = NULL; + return ret; +} + +static void radeon_ms_output_cleanup(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL) { + return; + } + if (connector->edid) { + kfree(connector->edid); + } + connector->edid = NULL; + connector->output = NULL; + output->driver_private = NULL; +} + +const struct drm_output_funcs radeon_ms_output_funcs = { + .dpms = radeon_ms_output_dpms, + .save = NULL, + .restore = NULL, + .mode_valid = radeon_ms_output_mode_valid, + .mode_fixup = radeon_ms_output_mode_fixup, + .prepare = radeon_ms_output_prepare, + .mode_set = radeon_ms_output_mode_set, + .commit = radeon_ms_output_commit, + .detect = radeon_ms_output_detect, + .get_modes = radeon_ms_output_get_modes, + .cleanup = radeon_ms_output_cleanup, +}; + +void radeon_ms_connectors_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + int i = 0; + + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (dev_priv->connectors[i]) { + connector = dev_priv->connectors[i]; + dev_priv->connectors[i] = NULL; + if (connector->output) { + drm_output_destroy(connector->output); + connector->output = NULL; + } + if (connector->i2c) { + radeon_ms_i2c_destroy(connector->i2c); + connector->i2c = NULL; + } + drm_free(connector, + sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + } + } +} + +int radeon_ms_connectors_from_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + struct drm_output *output = NULL; + int i = 0, c = 0; + + radeon_ms_connectors_destroy(dev); + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (dev_priv->properties.connectors[i]) { + connector = + drm_alloc(sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + if (connector == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + memcpy(connector, dev_priv->properties.connectors[i], + sizeof(struct radeon_ms_connector)); + connector->i2c = + radeon_ms_i2c_create(dev, connector->i2c_reg, + connector->name); + if (connector->i2c == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + output = drm_output_create(dev, + &radeon_ms_output_funcs, + connector->type); + if (output == NULL) { + radeon_ms_connectors_destroy(dev); + return -EINVAL; + } + connector->output = output; + output->driver_private = connector; + output->possible_crtcs = 0x3; + dev_priv->connectors[c++] = connector; + } + } + return c; +} + +int radeon_ms_connectors_from_rom(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_connectors_from_combios(dev); + } + return 0; +} + +void radeon_ms_outputs_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + drm_free(dev_priv->outputs[i], + sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + dev_priv->outputs[i] = NULL; + } + } +} + +int radeon_ms_outputs_from_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + int c = 0; + + radeon_ms_outputs_destroy(dev); + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->properties.outputs[i]) { + dev_priv->outputs[i] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[i] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[i], + dev_priv->properties.outputs[i], + sizeof(struct radeon_ms_output)); + dev_priv->outputs[i]->dev = dev; + dev_priv->outputs[i]->initialize(dev_priv->outputs[i]); + c++; + } + } + return c; +} + +int radeon_ms_outputs_from_rom(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_outputs_from_combios(dev); + } + return 0; +} + +void radeon_ms_outputs_restore(struct drm_device *dev, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + dev_priv->outputs[i]->restore(dev_priv->outputs[i], + state); + } + } +} + +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + dev_priv->outputs[i]->save(dev_priv->outputs[i], state); + } + } +} diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c new file mode 100644 index 00000000..baf2a7f2 --- /dev/null +++ b/shared-core/radeon_ms_properties.c @@ -0,0 +1,123 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_ms_output radeon_ms_dac1 = { + OUTPUT_DAC1, + NULL, + NULL, + radeon_ms_dac1_initialize, + radeon_ms_dac1_detect, + radeon_ms_dac1_dpms, + radeon_ms_dac1_get_modes, + radeon_ms_dac1_mode_fixup, + radeon_ms_dac1_mode_set, + radeon_ms_dac1_restore, + radeon_ms_dac1_save +}; + +struct radeon_ms_output radeon_ms_dac2 = { + OUTPUT_DAC2, + NULL, + NULL, + radeon_ms_dac2_initialize, + radeon_ms_dac2_detect, + radeon_ms_dac2_dpms, + radeon_ms_dac2_get_modes, + radeon_ms_dac2_mode_fixup, + radeon_ms_dac2_mode_set, + radeon_ms_dac2_restore, + radeon_ms_dac2_save +}; + +struct radeon_ms_connector radeon_ms_vga = { + NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, + { + 0, -1, -1, -1, -1, -1, -1, -1 + }, + "VGA" +}; + +struct radeon_ms_connector radeon_ms_dvi_i_2 = { + NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, + { + 1, -1, -1, -1, -1, -1, -1, -1 + }, + "DVI-I" +}; + +struct radeon_ms_properties properties[] = { + /* default only one VGA connector */ + { + 0, 0, 27000, 12, 25000, 200000, 1, 1, 1, 1, + { + &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + }, + { + &radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + } + } +}; + +int radeon_ms_properties_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, ret; + + for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) { + if (dev->pdev->subsystem_vendor == properties[i].subvendor && + dev->pdev->subsystem_device == properties[i].subdevice) { + DRM_INFO("[radeon_ms] found properties for " + "0x%04X:0x%04X\n", properties[i].subvendor, + properties[i].subdevice); + memcpy(&dev_priv->properties, &properties[i], + sizeof(struct radeon_ms_properties)); + } + } + if (dev_priv->properties.subvendor == 0) { + ret = radeon_ms_rom_get_properties(dev); + if (ret < 0) { + return ret; + } + if (!ret) { + memcpy(&dev_priv->properties, &properties[0], + sizeof(struct radeon_ms_properties)); + } else { + dev_priv->properties.pll_dummy_reads = 1; + dev_priv->properties.pll_delay = 1; + dev_priv->properties.pll_r300_errata = 1; + } + dev_priv->properties.subvendor = dev->pdev->subsystem_vendor; + dev_priv->properties.subdevice = dev->pdev->subsystem_device; + } + return 0; +} diff --git a/shared-core/radeon_ms_properties.h b/shared-core/radeon_ms_properties.h new file mode 100644 index 00000000..a02a84d5 --- /dev/null +++ b/shared-core/radeon_ms_properties.h @@ -0,0 +1,50 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_PROPERTIES_H__ +#define __RADEON_MS_PROPERTIES_H__ + +#define RADEON_PAGE_SIZE 4096 +#define RADEON_MAX_CONNECTORS 8 +#define RADEON_MAX_OUTPUTS 8 + +struct radeon_ms_properties { + uint16_t subvendor; + uint16_t subdevice; + int16_t pll_reference_freq; + int16_t pll_reference_div; + int32_t pll_min_pll_freq; + int32_t pll_max_pll_freq; + char pll_use_bios; + char pll_dummy_reads; + char pll_delay; + char pll_r300_errata; + struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; + struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; +}; + +#endif diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h new file mode 100644 index 00000000..25063990 --- /dev/null +++ b/shared-core/radeon_ms_reg.h @@ -0,0 +1,1787 @@ +/* + * Copyright 2007 Advanced Micro Devices, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#ifndef __RADEON_REG_H__ +#define __RADEON_REG_H__ + +#define MC_FB_LOCATION 0x00000148 +#define MC_FB_LOCATION__MC_FB_START__MASK 0x0000FFFF +#define MC_FB_LOCATION__MC_FB_START__SHIFT 0 +#define MC_FB_LOCATION__MC_FB_TOP__MASK 0xFFFF0000 +#define MC_FB_LOCATION__MC_FB_TOP__SHIFT 16 +#define MC_AGP_LOCATION 0x0000014C +#define MC_AGP_LOCATION__MC_AGP_START__MASK 0x0000FFFF +#define MC_AGP_LOCATION__MC_AGP_START__SHIFT 0 +#define MC_AGP_LOCATION__MC_AGP_TOP__MASK 0xFFFF0000 +#define MC_AGP_LOCATION__MC_AGP_TOP__SHIFT 16 +#define AGP_COMMAND 0x00000F60 +#define AGP_COMMAND__DATA_RATE__MASK 0x00000007 +#define AGP_COMMAND__DATA_RATE__SHIFT 0 +#define DATA_RATE__v2_1X 0x1 +#define DATA_RATE__v2_2X 0x2 +#define DATA_RATE__v2_4X 0x4 +#define DATA_RATE__v3_4X 0x1 +#define DATA_RATE__v3_8X 0x2 +#define AGP_COMMAND__AGP_EN 0x00000100 +#define AGP_COMMAND__SBA_EN 0x00000200 +#define AGP_COMMAND__RQ_DEPTH__MASK 0xFF000000 +#define AGP_COMMAND__RQ_DEPTH__SHIFT 24 +#define AGP_COMMAND__FW_EN 0x00000010 +#define AGP_COMMAND__MODE_4G_EN 0x00000020 +#define AGP_COMMAND__PARQSZ__MASK 0x0000E000 +#define AGP_COMMAND__PARQSZ__SHIFT 13 +#define AGP_STATUS 0x00000F5C +#define AGP_STATUS__RATE1X 0x00000001 +#define AGP_STATUS__RATE2X 0x00000002 +#define AGP_STATUS__RATE4X 0x00000004 +#define AGP_STATUS__SBA 0x00000200 +#define AGP_STATUS__RQ__MASK 0xFF000000 +#define AGP_STATUS__RQ__SHIFT 24 +#define AGP_STATUS__FW 0x00000010 +#define AGP_STATUS__MODE_4G 0x00000020 +#define AGP_STATUS__RATE1X_4X 0x00000001 +#define AGP_STATUS__RATE2X_8X 0x00000002 +#define AGP_STATUS__MODE_AGP30 0x00000008 +#define AGP_STATUS__CAL_CYCLE__MASK 0x00001C00 +#define AGP_STATUS__CAL_CYCLE__SHIFT 10 +#define AGP_STATUS__ISOCH_SUPPORT 0x00020000 +#define AGP_BASE 0x00000170 +#define AGP_BASE__AGP_BASE_ADDR__MASK 0xFFFFFFFF +#define AGP_BASE__AGP_BASE_ADDR__SHIFT 0 +#define AGP_BASE_2 0x0000015C +#define AGP_BASE_2__AGP_BASE_ADDR_2__MASK 0x0000000F +#define AGP_BASE_2__AGP_BASE_ADDR_2__SHIFT 0 +#define CONFIG_MEMSIZE 0x000000F8 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE__MASK 0x1F000000 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE__SHIFT 24 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__MASK 0x1FF00000 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__SHIFT 20 +#define CONFIG_APER_0_BASE 0x00000100 +#define CONFIG_APER_0_BASE__APER_0_BASE__MASK 0xFE000000 +#define CONFIG_APER_0_BASE__APER_0_BASE__SHIFT 25 +#define CONFIG_APER_1_BASE 0x00000104 +#define CONFIG_APER_1_BASE__APER_1_BASE__MASK 0xFF000000 +#define CONFIG_APER_1_BASE__APER_1_BASE__SHIFT 24 +#define CONFIG_APER_SIZE 0x00000108 +#define CONFIG_APER_SIZE__APER_SIZE__MASK 0x0F000000 +#define CONFIG_APER_SIZE__APER_SIZE__SHIFT 24 +#define GEN_INT_CNTL 0x00000040 +#define GEN_INT_CNTL__CRTC_VBLANK 0x00000001 +#define GEN_INT_CNTL__CRTC_VLINE 0x00000002 +#define GEN_INT_CNTL__CRTC_VSYNC 0x00000004 +#define GEN_INT_CNTL__SNAPSHOT 0x00000008 +#define GEN_INT_CNTL__FP_DETECT 0x00000010 +#define GEN_INT_CNTL__CRTC2_VLINE 0x00000020 +#define GEN_INT_CNTL__DMA_VIPH0_INT_EN 0x00001000 +#define GEN_INT_CNTL__CRTC2_VSYNC 0x00000040 +#define GEN_INT_CNTL__SNAPSHOT2 0x00000080 +#define GEN_INT_CNTL__CRTC2_VBLANK 0x00000200 +#define GEN_INT_CNTL__FP2_DETECT 0x00000400 +#define GEN_INT_CNTL__VSYNC_DIFF_OVER_LIMIT 0x00000800 +#define GEN_INT_CNTL__DMA_VIPH1_INT_EN 0x00002000 +#define GEN_INT_CNTL__DMA_VIPH2_INT_EN 0x00004000 +#define GEN_INT_CNTL__DMA_VIPH3_INT_EN 0x00008000 +#define GEN_INT_CNTL__I2C_INT_EN 0x00020000 +#define GEN_INT_CNTL__GUI_IDLE 0x00080000 +#define GEN_INT_CNTL__VIPH_INT_EN 0x01000000 +#define GEN_INT_CNTL__SW_INT_EN 0x02000000 +#define GEN_INT_CNTL__GEYSERVILLE 0x08000000 +#define GEN_INT_CNTL__DVI_I2C_INT 0x20000000 +#define GEN_INT_CNTL__GUIDMA 0x40000000 +#define GEN_INT_CNTL__VIDDMA 0x80000000 +#define GEN_INT_CNTL__TIMER_INT 0x00010000 +#define GEN_INT_CNTL__IDCT_INT_EN 0x08000000 +#define GEN_INT_STATUS 0x00000044 +#define GEN_INT_STATUS__CRTC_VBLANK_STAT 0x00000001 +#define GEN_INT_STATUS__CRTC_VBLANK_STAT_AK 0x00000001 +#define GEN_INT_STATUS__CRTC_VLINE_STAT 0x00000002 +#define GEN_INT_STATUS__CRTC_VLINE_STAT_AK 0x00000002 +#define GEN_INT_STATUS__CRTC_VSYNC_STAT 0x00000004 +#define GEN_INT_STATUS__CRTC_VSYNC_STAT_AK 0x00000004 +#define GEN_INT_STATUS__SNAPSHOT_STAT 0x00000008 +#define GEN_INT_STATUS__SNAPSHOT_STAT_AK 0x00000008 +#define GEN_INT_STATUS__FP_DETECT_STAT 0x00000010 +#define GEN_INT_STATUS__FP_DETECT_STAT_AK 0x00000010 +#define GEN_INT_STATUS__CRTC2_VLINE_STAT 0x00000020 +#define GEN_INT_STATUS__CRTC2_VLINE_STAT_AK 0x00000020 +#define GEN_INT_STATUS__CRTC2_VSYNC_STAT 0x00000040 +#define GEN_INT_STATUS__CRTC2_VSYNC_STAT_AK 0x00000040 +#define GEN_INT_STATUS__SNAPSHOT2_STAT 0x00000080 +#define GEN_INT_STATUS__SNAPSHOT2_STAT_AK 0x00000080 +#define GEN_INT_STATUS__CAP0_INT_ACTIVE 0x00000100 +#define GEN_INT_STATUS__CRTC2_VBLANK_STAT 0x00000200 +#define GEN_INT_STATUS__CRTC2_VBLANK_STAT_AK 0x00000200 +#define GEN_INT_STATUS__FP2_DETECT_STAT 0x00000400 +#define GEN_INT_STATUS__FP2_DETECT_STAT_AK 0x00000400 +#define GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT 0x00000800 +#define GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT_AK 0x00000800 +#define GEN_INT_STATUS__DMA_VIPH0_INT 0x00001000 +#define GEN_INT_STATUS__DMA_VIPH0_INT_AK 0x00001000 +#define GEN_INT_STATUS__DMA_VIPH1_INT 0x00002000 +#define GEN_INT_STATUS__DMA_VIPH1_INT_AK 0x00002000 +#define GEN_INT_STATUS__DMA_VIPH2_INT 0x00004000 +#define GEN_INT_STATUS__DMA_VIPH2_INT_AK 0x00004000 +#define GEN_INT_STATUS__DMA_VIPH3_INT 0x00008000 +#define GEN_INT_STATUS__DMA_VIPH3_INT_AK 0x00008000 +#define GEN_INT_STATUS__I2C_INT 0x00020000 +#define GEN_INT_STATUS__I2C_INT_AK 0x00020000 +#define GEN_INT_STATUS__GUI_IDLE_STAT 0x00080000 +#define GEN_INT_STATUS__GUI_IDLE_STAT_AK 0x00080000 +#define GEN_INT_STATUS__VIPH_INT 0x01000000 +#define GEN_INT_STATUS__SW_INT 0x02000000 +#define GEN_INT_STATUS__SW_INT_AK 0x02000000 +#define GEN_INT_STATUS__SW_INT_SET 0x04000000 +#define GEN_INT_STATUS__GEYSERVILLE_STAT 0x08000000 +#define GEN_INT_STATUS__GEYSERVILLE_STAT_AK 0x08000000 +#define GEN_INT_STATUS__DVI_I2C_INT_STAT 0x20000000 +#define GEN_INT_STATUS__DVI_I2C_INT_AK 0x20000000 +#define GEN_INT_STATUS__GUIDMA_STAT 0x40000000 +#define GEN_INT_STATUS__GUIDMA_AK 0x40000000 +#define GEN_INT_STATUS__VIDDMA_STAT 0x80000000 +#define GEN_INT_STATUS__VIDDMA_AK 0x80000000 +#define GEN_INT_STATUS__TIMER_INT_STAT 0x00010000 +#define GEN_INT_STATUS__TIMER_INT_STAT_AK 0x00010000 +#define GEN_INT_STATUS__IDCT_INT_STAT 0x08000000 +#define GEN_INT_STATUS__IDCT_INT_STAT_AK 0x08000000 +#define RB2D_DSTCACHE_MODE 0x00003428 +#define RB2D_DSTCACHE_MODE__DC_BYPASS__MASK 0x00000003 +#define RB2D_DSTCACHE_MODE__DC_BYPASS__SHIFT 0 +#define RB2D_DSTCACHE_MODE__DC_LINE_SIZE__MASK 0x0000000C +#define RB2D_DSTCACHE_MODE__DC_LINE_SIZE__SHIFT 2 +#define RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__MASK 0x00000300 +#define RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__SHIFT 8 +#define RB2D_DSTCACHE_MODE__DC_FORCE_RMW 0x00010000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_RI_FILL 0x01000000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_RI_READ 0x02000000 +#define RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__MASK 0x00000C00 +#define RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__SHIFT 10 +#define RB2D_DSTCACHE_MODE__DC_DISABLE 0x04000000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE 0x00020000 +#define RB2D_DSTCACHE_CTLSTAT 0x0000342C +#define RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK 0x00000003 +#define RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT 0 +#define RB2D_DSTCACHE_CTLSTAT__DC_FREE__MASK 0x0000000C +#define RB2D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT 2 +#define RB2D_DSTCACHE_CTLSTAT__DC_BUSY 0x80000000 +#define RB3D_DSTCACHE_CTLSTAT 0x0000325C +#define RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK 0x00000003 +#define RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT 0 +#define RB3D_DSTCACHE_CTLSTAT__DC_FREE__MASK 0x0000000C +#define RB3D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT 2 +#define RB3D_DSTCACHE_CTLSTAT__DC_BUSY 0x80000000 +#define RB3D_DSTCACHE_CTLSTAT_R3 0x00004E4C +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__MASK 0x00000003 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__SHIFT 0 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__MASK 0x0000000C +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__SHIFT 2 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FINISH 0x00000010 +#define RB3D_ZCACHE_CTLSTAT 0x00003254 +#define RB3D_ZCACHE_CTLSTAT__ZC_FLUSH 0x00000001 +#define RB3D_ZCACHE_CTLSTAT__ZC_FREE 0x00000004 +#define RB3D_ZCACHE_CTLSTAT__ZC_DIRTY 0x40000000 +#define RB3D_ZCACHE_CTLSTAT__ZC_BUSY 0x80000000 +#define RB3D_ZCACHE_CTLSTAT_R3 0x00004F18 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH 0x00000001 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_FREE 0x00000002 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_BUSY 0x80000000 +#define SCRATCH_REG0 0x000015E0 +#define SCRATCH_REG0__SCRATCH_REG0__MASK 0xFFFFFFFF +#define SCRATCH_REG0__SCRATCH_REG0__SHIFT 0 +#define SCRATCH_REG1 0x000015E4 +#define SCRATCH_REG1__SCRATCH_REG1__MASK 0xFFFFFFFF +#define SCRATCH_REG1__SCRATCH_REG1__SHIFT 0 +#define SCRATCH_REG2 0x000015E8 +#define SCRATCH_REG2__SCRATCH_REG2__MASK 0xFFFFFFFF +#define SCRATCH_REG2__SCRATCH_REG2__SHIFT 0 +#define SCRATCH_REG3 0x000015EC +#define SCRATCH_REG3__SCRATCH_REG3__MASK 0xFFFFFFFF +#define SCRATCH_REG3__SCRATCH_REG3__SHIFT 0 +#define SCRATCH_REG4 0x000015F0 +#define SCRATCH_REG4__SCRATCH_REG4__MASK 0xFFFFFFFF +#define SCRATCH_REG4__SCRATCH_REG4__SHIFT 0 +#define SCRATCH_REG5 0x000015F4 +#define SCRATCH_REG5__SCRATCH_REG5__MASK 0xFFFFFFFF +#define SCRATCH_REG5__SCRATCH_REG5__SHIFT 0 +#define SCRATCH_REG6 0x000015F8 +#define SCRATCH_REG6__SCRATCH_REG6__MASK 0xFFFFFFFF +#define SCRATCH_REG6__SCRATCH_REG6__SHIFT 0 +#define SCRATCH_REG7 0x000015FC +#define SCRATCH_REG7__SCRATCH_REG7__MASK 0xFFFFFFFF +#define SCRATCH_REG7__SCRATCH_REG7__SHIFT 0 +#define SC_SCISSOR0 0x000043E0 +#define SC_SCISSOR0__XS0__MASK 0x00001FFF +#define SC_SCISSOR0__XS0__SHIFT 0 +#define SC_SCISSOR0__YS0__MASK 0x03FFE000 +#define SC_SCISSOR0__YS0__SHIFT 13 +#define SC_SCISSOR1 0x000043E4 +#define SC_SCISSOR1__XS1__MASK 0x00001FFF +#define SC_SCISSOR1__XS1__SHIFT 0 +#define SC_SCISSOR1__YS1__MASK 0x03FFE000 +#define SC_SCISSOR1__YS1__SHIFT 13 +#define PCIE_INDEX 0x00000030 +#define PCIE_INDEX__PCIE_INDEX__MASK 0x000007FF +#define PCIE_INDEX__PCIE_INDEX__SHIFT 0 +#define PCIE_DATA 0x00000034 +#define PCIE_DATA__PCIE_DATA__MASK 0xFFFFFFFF +#define PCIE_DATA__PCIE_DATA__SHIFT 0 +#define PCIE_TX_GART_CNTL 0x00000010 +#define PCIE_TX_GART_CNTL__GART_EN 0x00000001 +#define PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__MASK 0x00000006 +#define PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__SHIFT 1 +#define GART_UNMAPPED_ACCESS__PTHRU 0x0 +#define GART_UNMAPPED_ACCESS__CLAMP 0x1 +#define GART_UNMAPPED_ACCESS__DISCARD 0x3 +#define PCIE_TX_GART_CNTL__GART_MODE__MASK 0x00000018 +#define PCIE_TX_GART_CNTL__GART_MODE__SHIFT 3 +#define GART_MODE__CACHE_32x128 0x0 +#define GART_MODE__CACHE_8x4x128 0x1 +#define PCIE_TX_GART_CNTL__GART_CHK_RW_VALID_EN 0x00000020 +#define PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__MASK 0x00000040 +#define PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__SHIFT 6 +#define GART_RDREQPATH_SEL__HDP 0x0 +#define GART_RDREQPATH_SEL__DRQMC 0x1 +#define PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB 0x00000100 +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO 0x00000011 +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__SHIFT 0 +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI 0x00000012 +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__MASK 0x000000FF +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__SHIFT 0 +#define PCIE_TX_GART_BASE 0x00000013 +#define PCIE_TX_GART_BASE__GART_BASE__MASK 0xFFFFFFFF +#define PCIE_TX_GART_BASE__GART_BASE__SHIFT 0 +#define PCIE_TX_GART_START_LO 0x00000014 +#define PCIE_TX_GART_START_LO__GART_START_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_START_LO__GART_START_LO__SHIFT 0 +#define PCIE_TX_GART_START_HI 0x00000015 +#define PCIE_TX_GART_START_HI__GART_START_HI__MASK 0x000000FF +#define PCIE_TX_GART_START_HI__GART_START_HI__SHIFT 0 +#define PCIE_TX_GART_END_LO 0x00000016 +#define PCIE_TX_GART_END_LO__GART_END_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_END_LO__GART_END_LO__SHIFT 0 +#define PCIE_TX_GART_END_HI 0x00000017 +#define PCIE_TX_GART_END_HI__GART_END_HI__MASK 0x000000FF +#define PCIE_TX_GART_END_HI__GART_END_HI__SHIFT 0 +#define PCIE_TX_GART_ERROR 0x00000018 +#define PCIE_TX_GART_ERROR__GART_UNMAPPED 0x00000002 +#define PCIE_TX_GART_ERROR__GART_INVALID_READ 0x00000004 +#define PCIE_TX_GART_ERROR__GART_INVALID_WRITE 0x00000008 +#define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__MASK 0xFFFFFFF0 +#define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__SHIFT 4 +#define CP_CSQ_MODE 0x00000744 +#define CP_CSQ_MODE__INDIRECT2_START__MASK 0x0000007F +#define CP_CSQ_MODE__INDIRECT2_START__SHIFT 0 +#define CP_CSQ_MODE__INDIRECT1_START__MASK 0x00007F00 +#define CP_CSQ_MODE__INDIRECT1_START__SHIFT 8 +#define CP_CSQ_MODE__CSQ_INDIRECT2_MODE 0x04000000 +#define CP_CSQ_MODE__CSQ_INDIRECT2_ENABLE 0x08000000 +#define CP_CSQ_MODE__CSQ_INDIRECT1_MODE 0x10000000 +#define CP_CSQ_MODE__CSQ_INDIRECT1_ENABLE 0x20000000 +#define CP_CSQ_MODE__CSQ_PRIMARY_MODE 0x40000000 +#define CP_CSQ_MODE__CSQ_PRIMARY_ENABLE 0x80000000 +#define CP_RB_CNTL 0x00000704 +#define CP_RB_CNTL__RB_BUFSZ__MASK 0x0000003F +#define CP_RB_CNTL__RB_BUFSZ__SHIFT 0 +#define CP_RB_CNTL__RB_BLKSZ__MASK 0x00003F00 +#define CP_RB_CNTL__RB_BLKSZ__SHIFT 8 +#define CP_RB_CNTL__BUF_SWAP__MASK 0x00030000 +#define CP_RB_CNTL__BUF_SWAP__SHIFT 16 +#define CP_RB_CNTL__MAX_FETCH__MASK 0x000C0000 +#define CP_RB_CNTL__MAX_FETCH__SHIFT 18 +#define CP_RB_CNTL__RB_NO_UPDATE 0x08000000 +#define CP_RB_CNTL__RB_RPTR_WR_ENA 0x80000000 +#define CP_RB_BASE 0x00000700 +#define CP_RB_BASE__RB_BASE__MASK 0xFFFFFFFC +#define CP_RB_BASE__RB_BASE__SHIFT 2 +#define CP_RB_RPTR_ADDR 0x0000070C +#define CP_RB_RPTR_ADDR__RB_RPTR_SWAP__MASK 0x00000003 +#define CP_RB_RPTR_ADDR__RB_RPTR_SWAP__SHIFT 0 +#define CP_RB_RPTR_ADDR__RB_RPTR_ADDR__MASK 0xFFFFFFFC +#define CP_RB_RPTR_ADDR__RB_RPTR_ADDR__SHIFT 2 +#define CP_RB_RPTR 0x00000710 +#define CP_RB_RPTR__RB_RPTR__MASK 0x007FFFFF +#define CP_RB_RPTR__RB_RPTR__SHIFT 0 +#define CP_RB_RPTR_WR 0x0000071C +#define CP_RB_RPTR_WR__RB_RPTR_WR__MASK 0x007FFFFF +#define CP_RB_RPTR_WR__RB_RPTR_WR__SHIFT 0 +#define CP_RB_WPTR 0x00000714 +#define CP_RB_WPTR__RB_WPTR__MASK 0x007FFFFF +#define CP_RB_WPTR__RB_WPTR__SHIFT 0 +#define CP_RB_WPTR_DELAY 0x00000718 +#define CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__MASK 0x0FFFFFFF +#define CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__SHIFT 0 +#define CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__MASK 0xF0000000 +#define CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__SHIFT 28 +#define SCRATCH_UMSK 0x00000770 +#define SCRATCH_UMSK__SCRATCH_UMSK__MASK 0x0000003F +#define SCRATCH_UMSK__SCRATCH_UMSK__SHIFT 0 +#define SCRATCH_UMSK__SCRATCH_SWAP__MASK 0x00030000 +#define SCRATCH_UMSK__SCRATCH_SWAP__SHIFT 16 +#define SCRATCH_UMSK__SCRATCH_UMSK_R2__MASK 0x000000FF +#define SCRATCH_UMSK__SCRATCH_UMSK_R2__SHIFT 0 +#define SCRATCH_ADDR 0x00000774 +#define SCRATCH_ADDR__SCRATCH_ADDR__MASK 0xFFFFFFE0 +#define SCRATCH_ADDR__SCRATCH_ADDR__SHIFT 5 +#define CP_ME_RAM_ADDR 0x000007D4 +#define CP_ME_RAM_ADDR__ME_RAM_ADDR__MASK 0x000000FF +#define CP_ME_RAM_ADDR__ME_RAM_ADDR__SHIFT 0 +#define CP_ME_RAM_DATAH 0x000007DC +#define CP_ME_RAM_DATAH__ME_RAM_DATAH__MASK 0x0000003F +#define CP_ME_RAM_DATAH__ME_RAM_DATAH__SHIFT 0 +#define CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__MASK 0x000000FF +#define CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__SHIFT 0 +#define CP_ME_RAM_DATAL 0x000007E0 +#define CP_ME_RAM_DATAL__ME_RAM_DATAL__MASK 0xFFFFFFFF +#define CP_ME_RAM_DATAL__ME_RAM_DATAL__SHIFT 0 +#define CP_CSQ_CNTL 0x00000740 +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY__MASK 0x000000FF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY__SHIFT 0 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT__MASK 0x0000FF00 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT__SHIFT 8 +#define CP_CSQ_CNTL__CSQ_MODE__MASK 0xF0000000 +#define CP_CSQ_CNTL__CSQ_MODE__SHIFT 28 +#define CSQ_MODE__CSQ_PRIDIS_INDDIS 0x0 +#define CSQ_MODE__CSQ_PRIPIO_INDDIS 0x1 +#define CSQ_MODE__CSQ_PRIBM_INDDIS 0x2 +#define CSQ_MODE__CSQ_PRIPIO_INDBM 0x3 +#define CSQ_MODE__CSQ_PRIBM_INDBM 0x4 +#define CSQ_MODE__CSQ_PRIPIO_INDPIO 0xF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__MASK 0x000001FF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__SHIFT 0 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__MASK 0x0003FE00 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__SHIFT 9 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__MASK 0x07FC0000 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__SHIFT 18 +#define CRTC_GEN_CNTL 0x00000050 +#define CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN 0x00000001 +#define CRTC_GEN_CNTL__CRTC_INTERLACE_EN 0x00000002 +#define CRTC_GEN_CNTL__CRTC_C_SYNC_EN 0x00000010 +#define CRTC_GEN_CNTL__CRTC_PIX_WIDTH__MASK 0x00000F00 +#define CRTC_GEN_CNTL__CRTC_PIX_WIDTH__SHIFT 8 +#define CRTC_PIX_WIDTH__4BPP 0x100 +#define CRTC_PIX_WIDTH__8BPP 0x200 +#define CRTC_PIX_WIDTH__15BPP 0x300 +#define CRTC_PIX_WIDTH__16BPP 0x400 +#define CRTC_PIX_WIDTH__24BPP 0x500 +#define CRTC_PIX_WIDTH__34BPP 0x600 +#define CRTC_PIX_WIDTH__16BPP_4444 0x700 +#define CRTC_PIX_WIDTH__16BPP_88 0x800 +#define CRTC_GEN_CNTL__CRTC_ICON_EN 0x00008000 +#define CRTC_GEN_CNTL__CRTC_CUR_EN 0x00010000 +#define CRTC_GEN_CNTL__CRTC_VSTAT_MODE__MASK 0x00060000 +#define CRTC_GEN_CNTL__CRTC_VSTAT_MODE__SHIFT 17 +#define CRTC_GEN_CNTL__CRTC_CUR_MODE__MASK 0x00700000 +#define CRTC_GEN_CNTL__CRTC_CUR_MODE__SHIFT 20 +#define CRTC_CUR_MODE__PREMULTI_ALPHA 0x2 +#define CRTC_CUR_MODE__COLOR24BPP 0x1 +#define CRTC_GEN_CNTL__CRTC_EXT_DISP_EN 0x01000000 +#define CRTC_GEN_CNTL__CRTC_EN 0x02000000 +#define CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B 0x04000000 +#define CRTC_GEN_CNTL__CRTC_MODE9_COLOR_ORDER 0x00001000 +#define CRTC_EXT_CNTL 0x00000054 +#define CRTC_EXT_CNTL__CRTC_VGA_XOVERSCAN 0x00000001 +#define CRTC_EXT_CNTL__VGA_BLINK_RATE__MASK 0x00000006 +#define CRTC_EXT_CNTL__VGA_BLINK_RATE__SHIFT 1 +#define CRTC_EXT_CNTL__VGA_ATI_LINEAR 0x00000008 +#define CRTC_EXT_CNTL__VGA_128KAP_PAGING 0x00000010 +#define CRTC_EXT_CNTL__VGA_TEXT_132 0x00000020 +#define CRTC_EXT_CNTL__VGA_XCRT_CNT_EN 0x00000040 +#define CRTC_EXT_CNTL__CRTC_HSYNC_DIS 0x00000100 +#define CRTC_EXT_CNTL__CRTC_VSYNC_DIS 0x00000200 +#define CRTC_EXT_CNTL__CRTC_DISPLAY_DIS 0x00000400 +#define CRTC_EXT_CNTL__CRTC_SYNC_TRISTATE 0x00000800 +#define CRTC_EXT_CNTL__CRTC_HSYNC_TRISTATE 0x00001000 +#define CRTC_EXT_CNTL__CRTC_VSYNC_TRISTATE 0x00002000 +#define CRTC_EXT_CNTL__CRT_ON 0x00008000 +#define CRTC_EXT_CNTL__VGA_CUR_B_TEST 0x00020000 +#define CRTC_EXT_CNTL__VGA_PACK_DIS 0x00040000 +#define CRTC_EXT_CNTL__VGA_MEM_PS_EN 0x00080000 +#define CRTC_EXT_CNTL__VCRTC_IDX_MASTER__MASK 0x7F000000 +#define CRTC_EXT_CNTL__VCRTC_IDX_MASTER__SHIFT 24 +#define CRTC_H_TOTAL_DISP 0x00000200 +#define CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__MASK 0x000003FF +#define CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__SHIFT 0 +#define CRTC_H_TOTAL_DISP__CRTC_H_DISP__MASK 0x01FF0000 +#define CRTC_H_TOTAL_DISP__CRTC_H_DISP__SHIFT 16 +#define CRTC_H_SYNC_STRT_WID 0x00000204 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__MASK 0x00000007 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__SHIFT 0 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__MASK 0x00001FF8 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__SHIFT 3 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__MASK 0x003F0000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__SHIFT 16 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL 0x00800000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__MASK 0x07000000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__SHIFT 24 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE_MODE 0x10000000 +#define CRTC_V_TOTAL_DISP 0x00000208 +#define CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__MASK 0x00000FFF +#define CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__SHIFT 0 +#define CRTC_V_TOTAL_DISP__CRTC_V_DISP__MASK 0x0FFF0000 +#define CRTC_V_TOTAL_DISP__CRTC_V_DISP__SHIFT 16 +#define CRTC_V_SYNC_STRT_WID 0x0000020C +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__MASK 0x00000FFF +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__SHIFT 0 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__MASK 0x001F0000 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__SHIFT 16 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL 0x00800000 +#define CRTC_OFFSET 0x00000224 +#define CRTC_OFFSET__CRTC_OFFSET__MASK 0x07FFFFFF +#define CRTC_OFFSET__CRTC_OFFSET__SHIFT 0 +#define CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_OFFSET__CRTC_OFFSET_LOCK 0x80000000 +#define CRTC_OFFSET__CRTC_OFFSET_R3__MASK 0x0FFFFFFF +#define CRTC_OFFSET__CRTC_OFFSET_R3__SHIFT 0 +#define CRTC_OFFSET_CNTL 0x00000228 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE__MASK 0x0000000F +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE__SHIFT 0 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__MASK 0x000000F0 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__SHIFT 4 +#define CRTC_OFFSET_CNTL__CRTC_TILE_EN_RIGHT 0x00004000 +#define CRTC_OFFSET_CNTL__CRTC_TILE_EN 0x00008000 +#define CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL 0x00010000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_OFFSET_EN 0x00020000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__MASK 0x000C0000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__SHIFT 18 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN 0x00100000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC 0x00200000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_LEFT_EN 0x10000000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_RIGHT_EN 0x20000000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_OFFSET_CNTL__CRTC_OFFSET_LOCK 0x80000000 +#define CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN_RIGHT 0x00000040 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__MASK 0x00000180 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__SHIFT 7 +#define CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN 0x00000200 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__MASK 0x00000C00 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__SHIFT 10 +#define CRTC_MICRO_TILE_BUFFER_MODE__AUTO 0x0 +#define CRTC_MICRO_TILE_BUFFER_MODE__SLINE 0x1 +#define CRTC_MICRO_TILE_BUFFER_MODE__DLINE 0x2 +#define CRTC_MICRO_TILE_BUFFER_MODE__DIS 0x3 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN_RIGHT 0x00001000 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN 0x00002000 +#define CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN_RIGHT 0x00004000 +#define CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN 0x00008000 +#define CRTC_PITCH 0x0000022C +#define CRTC_PITCH__CRTC_PITCH__MASK 0x000007FF +#define CRTC_PITCH__CRTC_PITCH__SHIFT 0 +#define CRTC_PITCH__CRTC_PITCH_RIGHT__MASK 0x07FF0000 +#define CRTC_PITCH__CRTC_PITCH_RIGHT__SHIFT 16 +#define CRTC_MORE_CNTL 0x0000027C +#define CRTC_MORE_CNTL__CRTC_HORZ_BLANK_MODE_SEL 0x00000001 +#define CRTC_MORE_CNTL__CRTC_VERT_BLANK_MODE_SEL 0x00000002 +#define CRTC_MORE_CNTL__CRTC_AUTO_HORZ_CENTER_EN 0x00000004 +#define CRTC_MORE_CNTL__CRTC_AUTO_VERT_CENTER_EN 0x00000008 +#define CRTC_MORE_CNTL__CRTC_H_CUTOFF_ACTIVE_EN 0x00000010 +#define CRTC_MORE_CNTL__CRTC_V_CUTOFF_ACTIVE_EN 0x00000020 +#define CRTC_MORE_CNTL__FORCE_H_EVEN_PIXEL_COUNT 0x00000040 +#define CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__MASK 0x07000000 +#define CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__SHIFT 24 +#define CRTC_MORE_CNTL__RMX_H_FILTER_EN 0x08000000 +#define CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__MASK 0x70000000 +#define CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__SHIFT 28 +#define CRTC_MORE_CNTL__RMX_V_FILTER_EN 0x80000000 +#define CRTC_MORE_CNTL__DSP_RST_HCOUNT 0x00000100 +#define CRTC_MORE_CNTL__DSP_RST_VCOUNT 0x00000200 +#define CRTC_MORE_CNTL__HCOUNT_RST_POS 0x00000400 +#define CRTC_MORE_CNTL__VCOUNT_RST_POS 0x00000800 +#define CRTC_MORE_CNTL__CRTC_FIX_VSYNC_EDGE_POSITION_EN 0x00001000 +#define CRTC_TILE_X0_Y0 0x00000350 +#define CRTC_TILE_X0_Y0__CRTC_TILE_X0__MASK 0x00000FFF +#define CRTC_TILE_X0_Y0__CRTC_TILE_X0__SHIFT 0 +#define CRTC_TILE_X0_Y0__CRTC_TILE_Y0__MASK 0x0FFF0000 +#define CRTC_TILE_X0_Y0__CRTC_TILE_Y0__SHIFT 16 +#define CRTC_TILE_X0_Y0__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_TILE_X0_Y0__CRTC_OFFSET_LOCK 0x80000000 +#define DAC_CNTL 0x00000058 +#define DAC_CNTL__DAC_RANGE_CNTL__MASK 0x00000003 +#define DAC_CNTL__DAC_RANGE_CNTL__SHIFT 0 +#define DAC_RANGE_CNTL__PS2 0x2 +#define DAC_RANGE_CNTL__YPbPr 0x3 +#define DAC_CNTL__DAC_BLANKING 0x00000004 +#define DAC_CNTL__DAC_CMP_EN 0x00000008 +#define DAC_CNTL__DAC_CMP_OUT_R 0x00000010 +#define DAC_CNTL__DAC_CMP_OUT_G 0x00000020 +#define DAC_CNTL__DAC_CMP_OUT_B 0x00000040 +#define DAC_CNTL__DAC_CMP_OUTPUT 0x00000080 +#define DAC_CNTL__DAC_8BIT_EN 0x00000100 +#define DAC_CNTL__DAC_4BPP_PIX_ORDER 0x00000200 +#define DAC_CNTL__DAC_TVO_EN 0x00000400 +#define DAC_CNTL__DAC_VGA_ADR_EN 0x00002000 +#define DAC_CNTL__DAC_EXPAND_MODE 0x00004000 +#define DAC_CNTL__DAC_PDWN 0x00008000 +#define DAC_CNTL__CRT_SENSE 0x00010000 +#define DAC_CNTL__CRT_DETECTION_ON 0x00020000 +#define DAC_CNTL__DAC_CRC_CONT_EN 0x00040000 +#define DAC_CNTL__DAC_CRC_EN 0x00080000 +#define DAC_CNTL__DAC_CRC_FIELD 0x00100000 +#define DAC_CNTL__DAC_LUT_COUNTER_LIMIT__MASK 0x00600000 +#define DAC_CNTL__DAC_LUT_COUNTER_LIMIT__SHIFT 21 +#define DAC_CNTL__DAC_LUT_READ_SEL 0x00800000 +#define DAC_CNTL__DAC__MASK 0xFF000000 +#define DAC_CNTL__DAC__SHIFT 24 +#define DAC_CNTL__DAC_CRC_BLANKb_ONLY 0x00000800 +#define DAC_CNTL2 0x0000007C +#define DAC_CNTL2__DAC_CLK_SEL 0x00000001 +#define DAC_CNTL2__DAC2_CLK_SEL 0x00000002 +#define DAC_CNTL2__PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_CNTL2__DAC2_CMP_EN 0x00000080 +#define DAC_CNTL2__DAC2_CMP_OUT_R 0x00000100 +#define DAC_CNTL2__DAC2_CMP_OUT_G 0x00000200 +#define DAC_CNTL2__DAC2_CMP_OUT_B 0x00000400 +#define DAC_CNTL2__DAC2_CMP_OUTPUT 0x00000800 +#define DAC_CNTL2__DAC2_EXPAND_MODE 0x00004000 +#define DAC_CNTL2__CRT2_SENSE 0x00010000 +#define DAC_CNTL2__CRT2_DETECTION_ON 0x00020000 +#define DAC_CNTL2__DAC_CRC2_CONT_EN 0x00040000 +#define DAC_CNTL2__DAC_CRC2_EN 0x00080000 +#define DAC_CNTL2__DAC_CRC2_FIELD 0x00100000 +#define DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__MASK 0x00600000 +#define DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__SHIFT 21 +#define DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_W 0x00000800 +#define DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_R 0x00000800 +#define DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_W 0x00001000 +#define DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_R 0x00001000 +#define DAC_CNTL2__DAC2_CMP_EN_R3 0x00000040 +#define DAC_CNTL2__DAC2_CMP_OUT_R_R3 0x00000080 +#define DAC_CNTL2__DAC2_CMP_OUT_G_R3 0x00000100 +#define DAC_CNTL2__DAC2_CMP_OUT_B_R3 0x00000200 +#define DAC_CNTL2__DAC2_CMP_OUTPUT_R3 0x00000400 +#define DAC_CNTL2__DAC_CRC2_BLANKb_ONLY 0x00020000 +#define DAC_EXT_CNTL 0x00000280 +#define DAC_EXT_CNTL__DAC2_FORCE_BLANK_OFF_EN 0x00000001 +#define DAC_EXT_CNTL__DAC2_FORCE_DATA_EN 0x00000002 +#define DAC_EXT_CNTL__DAC_FORCE_BLANK_OFF_EN 0x00000010 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_EN 0x00000020 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__MASK 0x000000C0 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__SHIFT 6 +#define DAC_EXT_CNTL__DAC_FORCE_DATA__MASK 0x0003FF00 +#define DAC_EXT_CNTL__DAC_FORCE_DATA__SHIFT 8 +#define DISP_MISC_CNTL 0x00000D00 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH_PP 0x00000001 +#define DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP 0x00000002 +#define DISP_MISC_CNTL__SOFT_RESET_OV0_PP 0x00000004 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK 0x00000010 +#define DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK 0x00000020 +#define DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK 0x00000040 +#define DISP_MISC_CNTL__SYNC_STRENGTH__MASK 0x00000300 +#define DISP_MISC_CNTL__SYNC_STRENGTH__SHIFT 8 +#define DISP_MISC_CNTL__SYNC_PAD_FLOP_EN 0x00000400 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP 0x00001000 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK 0x00008000 +#define DISP_MISC_CNTL__SOFT_RESET_LVDS 0x00010000 +#define DISP_MISC_CNTL__SOFT_RESET_TMDS 0x00020000 +#define DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS 0x00040000 +#define DISP_MISC_CNTL__SOFT_RESET_TV 0x00080000 +#define DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__MASK 0x00F00000 +#define DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__SHIFT 20 +#define DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__MASK 0x0F000000 +#define DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__SHIFT 24 +#define DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__MASK 0xF0000000 +#define DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__SHIFT 28 +#define DISP_MISC_CNTL__SOFT_RESET_DVO 0x00040000 +#define DISP_MISC_CNTL__SOFT_RESET_TV_R2 0x00000800 +#define DAC_MACRO_CNTL 0x00000D04 +#define DAC_MACRO_CNTL__DAC_WHITE_CNTL__MASK 0x0000000F +#define DAC_MACRO_CNTL__DAC_WHITE_CNTL__SHIFT 0 +#define DAC_MACRO_CNTL__DAC_BG_ADJ__MASK 0x00000F00 +#define DAC_MACRO_CNTL__DAC_BG_ADJ__SHIFT 8 +#define DAC_MACRO_CNTL__DAC_PDWN_R 0x00010000 +#define DAC_MACRO_CNTL__DAC_PDWN_G 0x00020000 +#define DAC_MACRO_CNTL__DAC_PDWN_B 0x00040000 +#define DISP_PWR_MAN 0x00000D08 +#define DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN 0x00000001 +#define DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN 0x00000010 +#define DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK 0x00000300 +#define DISP_PWR_MAN__DISP_PWR_MAN_DPMS__SHIFT 8 +#define DISP_PWR_MAN_DPMS__ON 0x0 +#define DISP_PWR_MAN_DPMS__STANDBY 0x1 +#define DISP_PWR_MAN_DPMS__SUSPEND 0x2 +#define DISP_PWR_MAN_DPMS__OFF 0x3 +#define DISP_PWR_MAN__DISP_D3_RST 0x00010000 +#define DISP_PWR_MAN__DISP_D3_REG_RST 0x00020000 +#define DISP_PWR_MAN__DISP_D3_GRPH_RST 0x00040000 +#define DISP_PWR_MAN__DISP_D3_SUBPIC_RST 0x00080000 +#define DISP_PWR_MAN__DISP_D3_OV0_RST 0x00100000 +#define DISP_PWR_MAN__DISP_D1D2_GRPH_RST 0x00200000 +#define DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST 0x00400000 +#define DISP_PWR_MAN__DISP_D1D2_OV0_RST 0x00800000 +#define DISP_PWR_MAN__DIG_TMDS_ENABLE_RST 0x01000000 +#define DISP_PWR_MAN__TV_ENABLE_RST 0x02000000 +#define DISP_PWR_MAN__AUTO_PWRUP_EN 0x04000000 +#define DISP_PWR_MAN__DISP_DVO_ENABLE_RST 0x01000000 +#define DISP_MERGE_CNTL 0x00000D60 +#define DISP_MERGE_CNTL__DISP_ALPHA_MODE__MASK 0x00000003 +#define DISP_MERGE_CNTL__DISP_ALPHA_MODE__SHIFT 0 +#define DISP_MERGE_CNTL__DISP_ALPHA_INV 0x00000004 +#define DISP_MERGE_CNTL__DISP_ALPHA_PREMULT 0x00000008 +#define DISP_MERGE_CNTL__DISP_RGB_OFFSET_EN 0x00000100 +#define DISP_MERGE_CNTL__DISP_LIN_TRANS_BYPASS 0x00000200 +#define DISP_MERGE_CNTL__DISP_GRPH_ALPHA__MASK 0x00FF0000 +#define DISP_MERGE_CNTL__DISP_GRPH_ALPHA__SHIFT 16 +#define DISP_MERGE_CNTL__DISP_OV0_ALPHA__MASK 0xFF000000 +#define DISP_MERGE_CNTL__DISP_OV0_ALPHA__SHIFT 24 +#define DISP_OUTPUT_CNTL 0x00000D64 +#define DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK 0x00000003 +#define DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__SHIFT 0 +#define DISP_DAC_SOURCE__YPbPr 0x3 +#define DISP_DAC_SOURCE__PRIMARYCRTC 0x0 +#define DISP_DAC_SOURCE__SECONDARYCRTC 0x1 +#define DISP_DAC_SOURCE__RMX 0x2 +#define DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__MASK 0x00000030 +#define DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__SHIFT 4 +#define DISP_OUTPUT_CNTL__DISP_RMX_SOURCE 0x00000100 +#define DISP_OUTPUT_CNTL__DISP_RMX_HTAP_SEL 0x00000200 +#define DISP_OUTPUT_CNTL__DISP_RMX_DITH_EN 0x00000400 +#define DISP_OUTPUT_CNTL__DISP_TV_SOURCE 0x00010000 +#define DISP_OUTPUT_CNTL__DISP_TV_MODE__MASK 0x00060000 +#define DISP_OUTPUT_CNTL__DISP_TV_MODE__SHIFT 17 +#define DISP_OUTPUT_CNTL__DISP_TV_YG_DITH_EN 0x00080000 +#define DISP_OUTPUT_CNTL__DISP_TV_CbB_CrR_DITH_EN 0x00100000 +#define DISP_OUTPUT_CNTL__DISP_TV_BIT_WIDTH 0x00200000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__MASK 0x00C00000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__SHIFT 22 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_FORCE 0x01000000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__MASK 0x06000000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__SHIFT 25 +#define DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__MASK 0x18000000 +#define DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__SHIFT 27 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_STATUS 0x20000000 +#define DISP_OUTPUT_CNTL__DISP_TV_H_DOWNSCALE 0x40000000 +#define DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__MASK 0x00003000 +#define DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__SHIFT 12 +#define DISP_TRANS_SOURCE__PRIMARYCRTC 0x0 +#define DISP_TRANS_SOURCE__SECONDARYCRTC 0x1 +#define DISP_TRANS_SOURCE__RMX 0x2 +#define DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK 0x0000000C +#define DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__SHIFT 2 +#define DISP_TVDAC_SOURCE__PRIMARYCRTC 0x0 +#define DISP_TVDAC_SOURCE__SECONDARYCRTC 0x1 +#define DISP_TVDAC_SOURCE__RMX 0x2 +#define DISP_TVDAC_SOURCE__YPbPr 0x3 +#define DISP2_MERGE_CNTL 0x00000D68 +#define DISP2_MERGE_CNTL__DISP2_RGB_OFFSET_EN 0x00000100 +#define DAC_EMBEDDED_SYNC_CNTL 0x00000DC0 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Y_G 0x00000001 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cb_B 0x00000002 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cr_R 0x00000004 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_TRILEVEL_SYNC_EN 0x00000008 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G 0x00000010 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_CbCr_BR 0x00000020 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__MASK 0x00070000 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__SHIFT 16 +#define DAC_BROAD_PULSE 0x00000DC4 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__MASK 0x00001FFF +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__SHIFT 0 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__MASK 0x1FFF0000 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__SHIFT 16 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__MASK 0x00000FFF +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__SHIFT 0 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__MASK 0x0FFF0000 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__SHIFT 16 +#define DAC_SKEW_CLKS 0x00000DC8 +#define DAC_SKEW_CLKS__DAC_SKEW_CLKS__MASK 0x000000FF +#define DAC_SKEW_CLKS__DAC_SKEW_CLKS__SHIFT 0 +#define DAC_INCR 0x00000DCC +#define DAC_INCR__DAC_INCR_Y_G__MASK 0x000003FF +#define DAC_INCR__DAC_INCR_Y_G__SHIFT 0 +#define DAC_INCR__DAC_INCR_CrCb_RB__MASK 0x03FF0000 +#define DAC_INCR__DAC_INCR_CrCb_RB__SHIFT 16 +#define DAC_NEG_SYNC_LEVEL 0x00000DD0 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__MASK 0x000003FF +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__SHIFT 0 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_POS_SYNC_LEVEL 0x00000DD4 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__MASK 0x000003FF +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__SHIFT 0 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_BLANK_LEVEL 0x00000DD8 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__MASK 0x000003FF +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__SHIFT 0 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_SYNC_EQUALIZATION 0x00000DDC +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__MASK 0x000007FF +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__SHIFT 0 +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__MASK 0x07FF0000 +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__SHIFT 16 +#define TV_MASTER_CNTL 0x00000800 +#define TV_MASTER_CNTL__TV_ASYNC_RST 0x00000001 +#define TV_MASTER_CNTL__CRT_ASYNC_RST 0x00000002 +#define TV_MASTER_CNTL__RESTART_PHASE_FIX 0x00000008 +#define TV_MASTER_CNTL__TV_FIFO_ASYNC_RST 0x00000010 +#define TV_MASTER_CNTL__MV_BP_LEVEL_FIX_EN 0x00000020 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_0 0x00000040 +#define TV_MASTER_CNTL__CRT_FIFO_CE_EN 0x00000200 +#define TV_MASTER_CNTL__TV_FIFO_CE_EN 0x00000400 +#define TV_MASTER_CNTL__RE_SYNC_NOW_SEL__MASK 0x0000C000 +#define TV_MASTER_CNTL__RE_SYNC_NOW_SEL__SHIFT 14 +#define TV_MASTER_CNTL__EXTRA_BIT_ZERO_1 0x00010000 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_1 0x00020000 +#define TV_MASTER_CNTL__EXTRA_BIT_ZERO_2 0x00040000 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_2 0x00080000 +#define TV_MASTER_CNTL__TVCLK_ALWAYS_ONb 0x40000000 +#define TV_MASTER_CNTL__TV_ON 0x80000000 +#define TV_DAC_CNTL 0x0000088C +#define TV_DAC_CNTL__NBLANK 0x00000001 +#define TV_DAC_CNTL__NHOLD 0x00000002 +#define TV_DAC_CNTL__PEDESTAL 0x00000004 +#define TV_DAC_CNTL__DETECT 0x00000010 +#define TV_DAC_CNTL__CMPOUT 0x00000020 +#define TV_DAC_CNTL__BGSLEEP 0x00000040 +#define TV_DAC_CNTL__STD__MASK 0x00000300 +#define TV_DAC_CNTL__STD__SHIFT 8 +#define STD__PAL 0x0 +#define STD__NTSC 0x1 +#define STD__PS2 0x2 +#define STD__RS343 0x3 +#define TV_DAC_CNTL__MON__MASK 0x0000F000 +#define TV_DAC_CNTL__MON__SHIFT 12 +#define TV_DAC_CNTL__BGADJ__MASK 0x000F0000 +#define TV_DAC_CNTL__BGADJ__SHIFT 16 +#define TV_DAC_CNTL__DACADJ__MASK 0x00F00000 +#define TV_DAC_CNTL__DACADJ__SHIFT 20 +#define TV_DAC_CNTL__RDACPD 0x01000000 +#define TV_DAC_CNTL__GDACPD 0x02000000 +#define TV_DAC_CNTL__BDACPD 0x04000000 +#define TV_DAC_CNTL__RDACDET 0x20000000 +#define TV_DAC_CNTL__GDACDET 0x40000000 +#define TV_DAC_CNTL__BDACDET 0x80000000 +#define TV_DAC_CNTL__DACADJ_R4__MASK 0x01F00000 +#define TV_DAC_CNTL__DACADJ_R4__SHIFT 20 +#define TV_DAC_CNTL__RDACPD_R4 0x02000000 +#define TV_DAC_CNTL__GDACPD_R4 0x04000000 +#define TV_DAC_CNTL__BDACPD_R4 0x08000000 +#define TV_DAC_CNTL__TVENABLE_R4 0x10000000 +#define VIPPAD_EN 0x000001A0 +#define VIPPAD_EN__VIPPAD_EN__MASK 0x0007FFFF +#define VIPPAD_EN__VIPPAD_EN__SHIFT 0 +#define VIPPAD_EN__VIPPAD_EN_TVODATA__MASK 0x000003FF +#define VIPPAD_EN__VIPPAD_EN_TVODATA__SHIFT 0 +#define VIPPAD_EN__VIPPAD_EN_TVOCLKO 0x00000400 +#define VIPPAD_EN__VIPPAD_EN_ROMCSb 0x00000800 +#define VIPPAD_EN__VIPPAD_EN_VHAD__MASK 0x00003000 +#define VIPPAD_EN__VIPPAD_EN_VHAD__SHIFT 12 +#define VIPPAD_EN__VIPPAD_EN_VPHCTL 0x00010000 +#define VIPPAD_EN__VIPPAD_EN_VIPCLK 0x00020000 +#define VIPPAD_EN__VIPPAD_EN_SI 0x00080000 +#define VIPPAD_EN__VIPPAD_EN_SO 0x00100000 +#define VIPPAD_EN__VIPPAD_EN_SCK 0x00200000 +#define VIPPAD_Y 0x000001A4 +#define VIPPAD_Y__VIPPAD_Y__MASK 0x0007FFFF +#define VIPPAD_Y__VIPPAD_Y__SHIFT 0 +#define VIPPAD_Y__VIPPAD_Y_TVODATA__MASK 0x000003FF +#define VIPPAD_Y__VIPPAD_Y_TVODATA__SHIFT 0 +#define VIPPAD_Y__VIPPAD_Y_TVOCLKO 0x00000400 +#define VIPPAD_Y__VIPPAD_Y_ROMCSb 0x00000800 +#define VIPPAD_Y__VIPPAD_Y_VHAD__MASK 0x00003000 +#define VIPPAD_Y__VIPPAD_Y_VHAD__SHIFT 12 +#define VIPPAD_Y__VIPPAD_Y_VPHCTL 0x00010000 +#define VIPPAD_Y__VIPPAD_Y_VIPCLK 0x00020000 +#define VIPPAD_Y__VIPPAD_Y_SI 0x00080000 +#define VIPPAD_Y__VIPPAD_Y_SO 0x00100000 +#define VIPPAD_Y__VIPPAD_Y_SCK 0x00200000 +#define VIPPAD1_EN 0x000001B0 +#define VIPPAD1_EN__VIPPAD1_EN__MASK 0x0003FFFF +#define VIPPAD1_EN__VIPPAD1_EN__SHIFT 0 +#define VIPPAD1_EN__VIPPAD_EN_VID__MASK 0x000000FF +#define VIPPAD1_EN__VIPPAD_EN_VID__SHIFT 0 +#define VIPPAD1_EN__VIPPAD_EN_VPCLK0 0x00000100 +#define VIPPAD1_EN__VIPPAD_EN_DVALID 0x00000200 +#define VIPPAD1_EN__VIPPAD_EN_PSYNC 0x00000400 +#define VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK 0x0FFF0000 +#define VIPPAD1_EN__VIPPAD_EN_DVODATA__SHIFT 16 +#define VIPPAD1_EN__VIPPAD_EN_DVOCNTL__MASK 0x70000000 +#define VIPPAD1_EN__VIPPAD_EN_DVOCNTL__SHIFT 28 +#define VIPPAD1_Y 0x000001B4 +#define VIPPAD1_Y__VIPPAD1_Y__MASK 0x0003FFFF +#define VIPPAD1_Y__VIPPAD1_Y__SHIFT 0 +#define VIPPAD1_Y__VIPPAD_Y_VID__MASK 0x000000FF +#define VIPPAD1_Y__VIPPAD_Y_VID__SHIFT 0 +#define VIPPAD1_Y__VIPPAD_Y_VPCLK0 0x00000100 +#define VIPPAD1_Y__VIPPAD_Y_DVALID 0x00000200 +#define VIPPAD1_Y__VIPPAD_Y_PSYNC 0x00000400 +#define VIPPAD1_Y__VIPPAD_Y_DVODATA__MASK 0x0FFF0000 +#define VIPPAD1_Y__VIPPAD_Y_DVODATA__SHIFT 16 +#define VIPPAD1_Y__VIPPAD_Y_DVOCNTL__MASK 0x70000000 +#define VIPPAD1_Y__VIPPAD_Y_DVOCNTL__SHIFT 28 +#define GPIO_DDC1 0x00000060 +#define GPIO_DDC1__DDC1_DATA_OUTPUT 0x00000001 +#define GPIO_DDC1__DDC1_CLK_OUTPUT 0x00000002 +#define GPIO_DDC1__DDC1_DATA_INPUT 0x00000100 +#define GPIO_DDC1__DDC1_CLK_INPUT 0x00000200 +#define GPIO_DDC1__DDC1_DATA_OUT_EN 0x00010000 +#define GPIO_DDC1__DDC1_CLK_OUT_EN 0x00020000 +#define GPIO_DDC1__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DDC1__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DDC1__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DDC1__HW_USING_DVI_I2C 0x00400000 +#define GPIO_DDC2 0x00000064 +#define GPIO_DDC2__DDC2_DATA_OUTPUT 0x00000001 +#define GPIO_DDC2__DDC2_CLK_OUTPUT 0x00000002 +#define GPIO_DDC2__DDC2_DATA_INPUT 0x00000100 +#define GPIO_DDC2__DDC2_CLK_INPUT 0x00000200 +#define GPIO_DDC2__DDC2_DATA_OUT_EN 0x00010000 +#define GPIO_DDC2__DDC2_CLK_OUT_EN 0x00020000 +#define GPIO_DDC2__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DDC2__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DDC2__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DDC2__HW_USING_DVI_I2C 0x00400000 +#define GPIO_DVI_DDC 0x00000064 +#define GPIO_DVI_DDC__DVI_DDC_DATA_OUTPUT 0x00000001 +#define GPIO_DVI_DDC__DVI_DCC_DATA_OUTPUT 0x00000001 +#define GPIO_DVI_DDC__DVI_DDC_CLK_OUTPUT 0x00000002 +#define GPIO_DVI_DDC__DVI_DDC_DATA_INPUT 0x00000100 +#define GPIO_DVI_DDC__DVI_DDC_CLK_INPUT 0x00000200 +#define GPIO_DVI_DDC__DVI_DDC_DATA_OUT_EN 0x00010000 +#define GPIO_DVI_DDC__DVI_DDC_CLK_OUT_EN 0x00020000 +#define GPIO_DVI_DDC__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DVI_DDC__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DVI_DDC__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DVI_DDC__HW_USING_DVI_I2C 0x00400000 +#define GPIO_MONID 0x00000068 +#define GPIO_MONID__GPIO_MONID_0_OUTPUT 0x00000001 +#define GPIO_MONID__GPIO_MONID_1_OUTPUT 0x00000002 +#define GPIO_MONID__GPIO_MONID_0_INPUT 0x00000100 +#define GPIO_MONID__GPIO_MONID_1_INPUT 0x00000200 +#define GPIO_MONID__GPIO_MONID_0_OUT_EN 0x00010000 +#define GPIO_MONID__GPIO_MONID_1_OUT_EN 0x00020000 +#define GPIO_CRT2_DDC 0x0000006C +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_OUTPUT 0x00000001 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_OUTPUT 0x00000002 +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT 0x00000100 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT 0x00000200 +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN 0x00010000 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN 0x00020000 +#define CLOCK_CNTL_INDEX 0x00000008 +#define CLOCK_CNTL_INDEX__PLL_ADDR__MASK 0x0000001F +#define CLOCK_CNTL_INDEX__PLL_ADDR__SHIFT 0 +#define CLOCK_CNTL_INDEX__PLL_WR_EN 0x00000080 +#define CLOCK_CNTL_INDEX__PPLL_DIV_SEL__MASK 0x00000300 +#define CLOCK_CNTL_INDEX__PPLL_DIV_SEL__SHIFT 8 +#define CLOCK_CNTL_INDEX__PLL_ADDR_R2__MASK 0x0000003F +#define CLOCK_CNTL_INDEX__PLL_ADDR_R2__SHIFT 0 +#define CLOCK_CNTL_DATA 0x0000000C +#define CLOCK_CNTL_DATA__PLL_DATA__MASK 0xFFFFFFFF +#define CLOCK_CNTL_DATA__PLL_DATA__SHIFT 0 +#define MCLK_CNTL 0x00000012 +#define MCLK_CNTL__MCLKA_SRC_SEL__MASK 0x00000007 +#define MCLK_CNTL__MCLKA_SRC_SEL__SHIFT 0 +#define MCLK_CNTL__YCLKA_SRC_SEL__MASK 0x00000070 +#define MCLK_CNTL__YCLKA_SRC_SEL__SHIFT 4 +#define MCLK_CNTL__MCLKB_SRC_SEL__MASK 0x00000700 +#define MCLK_CNTL__MCLKB_SRC_SEL__SHIFT 8 +#define MCLK_CNTL__YCLKB_SRC_SEL__MASK 0x00007000 +#define MCLK_CNTL__YCLKB_SRC_SEL__SHIFT 12 +#define MCLK_CNTL__FORCE_MCLKA 0x00010000 +#define MCLK_CNTL__FORCE_MCLKB 0x00020000 +#define MCLK_CNTL__FORCE_YCLKA 0x00040000 +#define MCLK_CNTL__FORCE_YCLKB 0x00080000 +#define MCLK_CNTL__FORCE_MC 0x00100000 +#define MCLK_CNTL__FORCE_AIC 0x00200000 +#define MCLK_CNTL__MRDCKA0_SOUTSEL__MASK 0x03000000 +#define MCLK_CNTL__MRDCKA0_SOUTSEL__SHIFT 24 +#define MCLK_CNTL__MRDCKA1_SOUTSEL__MASK 0x0C000000 +#define MCLK_CNTL__MRDCKA1_SOUTSEL__SHIFT 26 +#define MCLK_CNTL__MRDCKB0_SOUTSEL__MASK 0x30000000 +#define MCLK_CNTL__MRDCKB0_SOUTSEL__SHIFT 28 +#define MCLK_CNTL__MRDCKB1_SOUTSEL__MASK 0xC0000000 +#define MCLK_CNTL__MRDCKB1_SOUTSEL__SHIFT 30 +#define MCLK_CNTL__FORCE_MC_MCLKA 0x00010000 +#define MCLK_CNTL__FORCE_MC_MCLKB 0x00020000 +#define MCLK_CNTL__FORCE_MC_MCLK 0x00100000 +#define MCLK_CNTL__DISABLE_MC_MCLKA 0x00200000 +#define MCLK_CNTL__DISABLE_MC_MCLKB 0x00400000 +#define SCLK_CNTL 0x0000000D +#define SCLK_CNTL__SCLK_SRC_SEL__MASK 0x00000007 +#define SCLK_CNTL__SCLK_SRC_SEL__SHIFT 0 +#define SCLK_CNTL__TCLK_SRC_SEL__MASK 0x00000700 +#define SCLK_CNTL__TCLK_SRC_SEL__SHIFT 8 +#define SCLK_CNTL__FORCE_CP 0x00010000 +#define SCLK_CNTL__FORCE_HDP 0x00020000 +#define SCLK_CNTL__FORCE_DISP 0x00040000 +#define SCLK_CNTL__FORCE_TOP 0x00080000 +#define SCLK_CNTL__FORCE_E2 0x00100000 +#define SCLK_CNTL__FORCE_SE 0x00200000 +#define SCLK_CNTL__FORCE_IDCT 0x00400000 +#define SCLK_CNTL__FORCE_VIP 0x00800000 +#define SCLK_CNTL__FORCE_RE 0x01000000 +#define SCLK_CNTL__FORCE_PB 0x02000000 +#define SCLK_CNTL__FORCE_TAM 0x04000000 +#define SCLK_CNTL__FORCE_TDM 0x08000000 +#define SCLK_CNTL__FORCE_RB 0x10000000 +#define SCLK_CNTL__CP_MAX_DYN_STOP_LAT 0x00000008 +#define SCLK_CNTL__HDP_MAX_DYN_STOP_LAT 0x00000010 +#define SCLK_CNTL__E2_MAX_DYN_STOP_LAT 0x00000040 +#define SCLK_CNTL__SE_MAX_DYN_STOP_LAT 0x00000080 +#define SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT 0x00000100 +#define SCLK_CNTL__VIP_MAX_DYN_STOP_LAT 0x00000200 +#define SCLK_CNTL__RE_MAX_DYN_STOP_LAT 0x00000400 +#define SCLK_CNTL__PB_MAX_DYN_STOP_LAT 0x00000800 +#define SCLK_CNTL__TAM_MAX_DYN_STOP_LAT 0x00001000 +#define SCLK_CNTL__TDM_MAX_DYN_STOP_LAT 0x00002000 +#define SCLK_CNTL__RB_MAX_DYN_STOP_LAT 0x00004000 +#define SCLK_CNTL__FORCE_DISP2 0x00008000 +#define SCLK_CNTL__FORCE_DISP1 0x00040000 +#define SCLK_CNTL__FORCE_SUBPIC 0x40000000 +#define SCLK_CNTL__FORCE_OV0 0x80000000 +#define SCLK_CNTL__TV_MAX_DYN_STOP_LAT 0x00000020 +#define SCLK_CNTL__FORCE_TV_SCLK 0x20000000 +#define SCLK_CNTL__VAP_MAX_DYN_STOP_LAT 0x00000080 +#define SCLK_CNTL__SR_MAX_DYN_STOP_LAT 0x00000400 +#define SCLK_CNTL__PX_MAX_DYN_STOP_LAT 0x00000800 +#define SCLK_CNTL__TX_MAX_DYN_STOP_LAT 0x00001000 +#define SCLK_CNTL__US_MAX_DYN_STOP_LAT 0x00002000 +#define SCLK_CNTL__SU_MAX_DYN_STOP_LAT 0x00004000 +#define SCLK_CNTL__FORCE_VAP 0x00200000 +#define SCLK_CNTL__FORCE_SR 0x02000000 +#define SCLK_CNTL__FORCE_PX 0x04000000 +#define SCLK_CNTL__FORCE_TX 0x08000000 +#define SCLK_CNTL__FORCE_US 0x10000000 +#define SCLK_CNTL__FORCE_SU 0x40000000 +#define PPLL_CNTL 0x00000002 +#define PPLL_CNTL__PPLL_RESET 0x00000001 +#define PPLL_CNTL__PPLL_SLEEP 0x00000002 +#define PPLL_CNTL__PPLL_TST_EN 0x00000004 +#define PPLL_CNTL__PPLL_REFCLK_SEL 0x00000010 +#define PPLL_CNTL__PPLL_FBCLK_SEL 0x00000020 +#define PPLL_CNTL__PPLL_TCPOFF 0x00000040 +#define PPLL_CNTL__PPLL_TVCOMAX 0x00000080 +#define PPLL_CNTL__PPLL_PCP__MASK 0x00000700 +#define PPLL_CNTL__PPLL_PCP__SHIFT 8 +#define PPLL_CNTL__PPLL_PVG__MASK 0x00003800 +#define PPLL_CNTL__PPLL_PVG__SHIFT 11 +#define PPLL_CNTL__PPLL_PDC__MASK 0x0000C000 +#define PPLL_CNTL__PPLL_PDC__SHIFT 14 +#define PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN 0x00010000 +#define PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN 0x00020000 +#define PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC 0x00040000 +#define PPLL_CNTL__PPLL_DISABLE_AUTO_RESET 0x00080000 +#define PPLL_CNTL__PPLL_DIV_RESET 0x00000008 +#define PPLL_REF_DIV 0x00000003 +#define PPLL_REF_DIV__PPLL_REF_DIV__MASK 0x000003FF +#define PPLL_REF_DIV__PPLL_REF_DIV__SHIFT 0 +#define PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_REF_DIV__PPLL_REF_DIV_SRC__MASK 0x00030000 +#define PPLL_REF_DIV__PPLL_REF_DIV_SRC__SHIFT 16 +#define PPLL_REF_DIV_SRC__XTALIN 0x0 +#define PPLL_REF_DIV_SRC__PLLSCLK_2 0x1 +#define PPLL_REF_DIV_SRC__PLLSCLK_4 0x2 +#define PPLL_REF_DIV_SRC__SREFCLK 0x3 +#define PPLL_REF_DIV__PPLL_REF_DIV_ACC__MASK 0x0FFC0000 +#define PPLL_REF_DIV__PPLL_REF_DIV_ACC__SHIFT 18 +#define PPLL_DIV_0 0x00000004 +#define PPLL_DIV_0__PPLL_FB0_DIV__MASK 0x000007FF +#define PPLL_DIV_0__PPLL_FB0_DIV__SHIFT 0 +#define PPLL_DIV_0__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_0__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_0__PPLL_POST0_DIV__MASK 0x00070000 +#define PPLL_DIV_0__PPLL_POST0_DIV__SHIFT 16 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION__MASK 0x00380000 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION__SHIFT 19 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION_UPDATE 0x00400000 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION_EN 0x00800000 +#define PPLL_DIV_1 0x00000005 +#define PPLL_DIV_1__PPLL_FB1_DIV__MASK 0x000007FF +#define PPLL_DIV_1__PPLL_FB1_DIV__SHIFT 0 +#define PPLL_DIV_1__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_1__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_1__PPLL_POST1_DIV__MASK 0x00070000 +#define PPLL_DIV_1__PPLL_POST1_DIV__SHIFT 16 +#define PPLL_DIV_2 0x00000006 +#define PPLL_DIV_2__PPLL_FB2_DIV__MASK 0x000007FF +#define PPLL_DIV_2__PPLL_FB2_DIV__SHIFT 0 +#define PPLL_DIV_2__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_2__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_2__PPLL_POST2_DIV__MASK 0x00070000 +#define PPLL_DIV_2__PPLL_POST2_DIV__SHIFT 16 +#define PPLL_DIV_3 0x00000007 +#define PPLL_DIV_3__PPLL_FB3_DIV__MASK 0x000007FF +#define PPLL_DIV_3__PPLL_FB3_DIV__SHIFT 0 +#define PPLL_DIV_3__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_3__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_3__PPLL_POST3_DIV__MASK 0x00070000 +#define PPLL_DIV_3__PPLL_POST3_DIV__SHIFT 16 +#define VCLK_ECP_CNTL 0x00000008 +#define VCLK_ECP_CNTL__VCLK_SRC_SEL__MASK 0x00000003 +#define VCLK_ECP_CNTL__VCLK_SRC_SEL__SHIFT 0 +#define VCLK_SRC_SEL__CPUCLK 0x0 +#define VCLK_SRC_SEL__PSCANCLK 0x1 +#define VCLK_SRC_SEL__BYTE_CLK 0x2 +#define VCLK_SRC_SEL__PPLLCLK 0x3 +#define VCLK_ECP_CNTL__VCLK_INVERT 0x00000010 +#define VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb 0x00000040 +#define VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb 0x00000080 +#define VCLK_ECP_CNTL__ECP_DIV__MASK 0x00000300 +#define VCLK_ECP_CNTL__ECP_DIV__SHIFT 8 +#define VCLK_ECP_CNTL__ECP_FORCE_ON 0x00040000 +#define VCLK_ECP_CNTL__SUBCLK_FORCE_ON 0x00080000 +#define VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__MASK 0x00030000 +#define VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__SHIFT 16 +#define VCLK_ECP_CNTL__BYTE_CLK_OUT_EN 0x00100000 +#define VCLK_ECP_CNTL__BYTE_CLK_SKEW__MASK 0x07000000 +#define VCLK_ECP_CNTL__BYTE_CLK_SKEW__SHIFT 24 +#define VCLK_ECP_CNTL__PCICLK_INVERT 0x00000020 +#define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT 0x00000020 +#define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT_R3 0x08000000 +#define VCLK_ECP_CNTL__DISP_DAC_PIXCLK_DAC_BLANK_OFF 0x00800000 +#define HTOTAL_CNTL 0x00000009 +#define HTOTAL_CNTL__HTOT_PIX_SLIP__MASK 0x0000000F +#define HTOTAL_CNTL__HTOT_PIX_SLIP__SHIFT 0 +#define HTOTAL_CNTL__HTOT_VCLK_SLIP__MASK 0x00000F00 +#define HTOTAL_CNTL__HTOT_VCLK_SLIP__SHIFT 8 +#define HTOTAL_CNTL__HTOT_PPLL_SLIP__MASK 0x00070000 +#define HTOTAL_CNTL__HTOT_PPLL_SLIP__SHIFT 16 +#define HTOTAL_CNTL__HTOT_CNTL_EDGE 0x01000000 +#define HTOTAL_CNTL__HTOT_CNTL_VGA_EN 0x10000000 +#define FP_H_SYNC_STRT_WID 0x000002C4 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__MASK 0x00000007 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__SHIFT 0 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__MASK 0x00001FF8 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__SHIFT 3 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__MASK 0x003F0000 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__SHIFT 16 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_POL 0x00800000 +#define FP_V_SYNC_STRT_WID 0x000002C8 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__MASK 0x00000FFF +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__SHIFT 0 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__MASK 0x001F0000 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__SHIFT 16 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_POL 0x00800000 +#define FP_CRTC_H_TOTAL_DISP 0x00000250 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__MASK 0x000003FF +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__SHIFT 0 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__MASK 0x01FF0000 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__SHIFT 16 +#define FP_CRTC_V_TOTAL_DISP 0x00000254 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__MASK 0x00000FFF +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__SHIFT 0 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__MASK 0x0FFF0000 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__SHIFT 16 +#define PALETTE_INDEX 0x000000B0 +#define PALETTE_INDEX__PALETTE_W_INDEX__MASK 0x000000FF +#define PALETTE_INDEX__PALETTE_W_INDEX__SHIFT 0 +#define PALETTE_INDEX__PALETTE_R_INDEX__MASK 0x00FF0000 +#define PALETTE_INDEX__PALETTE_R_INDEX__SHIFT 16 +#define PALETTE_DATA 0x000000B4 +#define PALETTE_DATA__PALETTE_DATA_B__MASK 0x000000FF +#define PALETTE_DATA__PALETTE_DATA_B__SHIFT 0 +#define PALETTE_DATA__PALETTE_DATA_G__MASK 0x0000FF00 +#define PALETTE_DATA__PALETTE_DATA_G__SHIFT 8 +#define PALETTE_DATA__PALETTE_DATA_R__MASK 0x00FF0000 +#define PALETTE_DATA__PALETTE_DATA_R__SHIFT 16 +#define PALETTE_30_DATA 0x000000B8 +#define PALETTE_30_DATA__PALETTE_DATA_B__MASK 0x000003FF +#define PALETTE_30_DATA__PALETTE_DATA_B__SHIFT 0 +#define PALETTE_30_DATA__PALETTE_DATA_G__MASK 0x000FFC00 +#define PALETTE_30_DATA__PALETTE_DATA_G__SHIFT 10 +#define PALETTE_30_DATA__PALETTE_DATA_R__MASK 0x3FF00000 +#define PALETTE_30_DATA__PALETTE_DATA_R__SHIFT 20 +#define SURFACE_CNTL 0x00000B00 +#define SURFACE_CNTL__SURF_TRANSLATION_DIS 0x00000100 +#define SURFACE_CNTL__NONSURF_AP0_SWP__MASK 0x00300000 +#define SURFACE_CNTL__NONSURF_AP0_SWP__SHIFT 20 +#define SURFACE_CNTL__NONSURF_AP1_SWP__MASK 0x00C00000 +#define SURFACE_CNTL__NONSURF_AP1_SWP__SHIFT 22 +#define SURFACE0_INFO 0x00000B0C +#define SURFACE0_INFO__SURF0_PITCHSEL__MASK 0x000003FF +#define SURFACE0_INFO__SURF0_PITCHSEL__SHIFT 0 +#define SURFACE0_INFO__SURF0_TILE_MODE__MASK 0x00030000 +#define SURFACE0_INFO__SURF0_TILE_MODE__SHIFT 16 +#define SURF0_TILE_MODE__NO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MACRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MICRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MACRO_MICRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__32_BIT_Z_TILING(p) 0x0 +#define SURF0_TILE_MODE__16_BIT_Z_TILING(p) 0x0 +#define SURFACE0_INFO__SURF0_AP0_SWP__MASK 0x00300000 +#define SURFACE0_INFO__SURF0_AP0_SWP__SHIFT 20 +#define SURFACE0_INFO__SURF0_AP1_SWP__MASK 0x00C00000 +#define SURFACE0_INFO__SURF0_AP1_SWP__SHIFT 22 +#define SURFACE0_INFO__SURF0_WRITE_FLAG 0x01000000 +#define SURFACE0_INFO__SURF0_READ_FLAG 0x02000000 +#define SURFACE0_INFO__SURF0_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE0_INFO__SURF0_TILE_MODE_R2__SHIFT 16 +#define SURFACE0_INFO__SURF0_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE0_INFO__SURF0_PITCHSEL_R3__SHIFT 0 +#define SURFACE0_LOWER_BOUND 0x00000B04 +#define SURFACE0_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE0_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE0_UPPER_BOUND 0x00000B08 +#define SURFACE0_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE0_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE1_INFO 0x00000B1C +#define SURFACE1_INFO__SURF1_PITCHSEL__MASK 0x000003FF +#define SURFACE1_INFO__SURF1_PITCHSEL__SHIFT 0 +#define SURFACE1_INFO__SURF1_TILE_MODE__MASK 0x00030000 +#define SURFACE1_INFO__SURF1_TILE_MODE__SHIFT 16 +#define SURFACE1_INFO__SURF1_AP0_SWP__MASK 0x00300000 +#define SURFACE1_INFO__SURF1_AP0_SWP__SHIFT 20 +#define SURFACE1_INFO__SURF1_AP1_SWP__MASK 0x00C00000 +#define SURFACE1_INFO__SURF1_AP1_SWP__SHIFT 22 +#define SURFACE1_INFO__SURF1_WRITE_FLAG 0x01000000 +#define SURFACE1_INFO__SURF1_READ_FLAG 0x02000000 +#define SURFACE1_INFO__SURF1_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE1_INFO__SURF1_TILE_MODE_R2__SHIFT 16 +#define SURFACE1_INFO__SURF1_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE1_INFO__SURF1_PITCHSEL_R3__SHIFT 0 +#define SURFACE1_LOWER_BOUND 0x00000B14 +#define SURFACE1_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE1_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE1_UPPER_BOUND 0x00000B18 +#define SURFACE1_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE1_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE2_INFO 0x00000B2C +#define SURFACE2_INFO__SURF2_PITCHSEL__MASK 0x000003FF +#define SURFACE2_INFO__SURF2_PITCHSEL__SHIFT 0 +#define SURFACE2_INFO__SURF2_TILE_MODE__MASK 0x00030000 +#define SURFACE2_INFO__SURF2_TILE_MODE__SHIFT 16 +#define SURFACE2_INFO__SURF2_AP0_SWP__MASK 0x00300000 +#define SURFACE2_INFO__SURF2_AP0_SWP__SHIFT 20 +#define SURFACE2_INFO__SURF2_AP1_SWP__MASK 0x00C00000 +#define SURFACE2_INFO__SURF2_AP1_SWP__SHIFT 22 +#define SURFACE2_INFO__SURF2_WRITE_FLAG 0x01000000 +#define SURFACE2_INFO__SURF2_READ_FLAG 0x02000000 +#define SURFACE2_INFO__SURF2_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE2_INFO__SURF2_TILE_MODE_R2__SHIFT 16 +#define SURFACE2_INFO__SURF2_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE2_INFO__SURF2_PITCHSEL_R3__SHIFT 0 +#define SURFACE2_LOWER_BOUND 0x00000B24 +#define SURFACE2_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE2_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE2_UPPER_BOUND 0x00000B28 +#define SURFACE2_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE2_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE3_INFO 0x00000B3C +#define SURFACE3_INFO__SURF3_PITCHSEL__MASK 0x000003FF +#define SURFACE3_INFO__SURF3_PITCHSEL__SHIFT 0 +#define SURFACE3_INFO__SURF3_TILE_MODE__MASK 0x00030000 +#define SURFACE3_INFO__SURF3_TILE_MODE__SHIFT 16 +#define SURFACE3_INFO__SURF3_AP0_SWP__MASK 0x00300000 +#define SURFACE3_INFO__SURF3_AP0_SWP__SHIFT 20 +#define SURFACE3_INFO__SURF3_AP1_SWP__MASK 0x00C00000 +#define SURFACE3_INFO__SURF3_AP1_SWP__SHIFT 22 +#define SURFACE3_INFO__SURF3_WRITE_FLAG 0x01000000 +#define SURFACE3_INFO__SURF3_READ_FLAG 0x02000000 +#define SURFACE3_INFO__SURF3_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE3_INFO__SURF3_TILE_MODE_R2__SHIFT 16 +#define SURFACE3_INFO__SURF3_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE3_INFO__SURF3_PITCHSEL_R3__SHIFT 0 +#define SURFACE3_LOWER_BOUND 0x00000B34 +#define SURFACE3_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE3_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE3_UPPER_BOUND 0x00000B38 +#define SURFACE3_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE3_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE4_INFO 0x00000B4C +#define SURFACE4_INFO__SURF4_PITCHSEL__MASK 0x000003FF +#define SURFACE4_INFO__SURF4_PITCHSEL__SHIFT 0 +#define SURFACE4_INFO__SURF4_TILE_MODE__MASK 0x00030000 +#define SURFACE4_INFO__SURF4_TILE_MODE__SHIFT 16 +#define SURFACE4_INFO__SURF4_AP0_SWP__MASK 0x00300000 +#define SURFACE4_INFO__SURF4_AP0_SWP__SHIFT 20 +#define SURFACE4_INFO__SURF4_AP1_SWP__MASK 0x00C00000 +#define SURFACE4_INFO__SURF4_AP1_SWP__SHIFT 22 +#define SURFACE4_INFO__SURF4_WRITE_FLAG 0x01000000 +#define SURFACE4_INFO__SURF4_READ_FLAG 0x02000000 +#define SURFACE4_INFO__SURF4_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE4_INFO__SURF4_TILE_MODE_R2__SHIFT 16 +#define SURFACE4_INFO__SURF4_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE4_INFO__SURF4_PITCHSEL_R3__SHIFT 0 +#define SURFACE4_LOWER_BOUND 0x00000B44 +#define SURFACE4_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE4_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE4_UPPER_BOUND 0x00000B48 +#define SURFACE4_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE4_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE5_INFO 0x00000B5C +#define SURFACE5_INFO__SURF5_PITCHSEL__MASK 0x000003FF +#define SURFACE5_INFO__SURF5_PITCHSEL__SHIFT 0 +#define SURFACE5_INFO__SURF5_TILE_MODE__MASK 0x00030000 +#define SURFACE5_INFO__SURF5_TILE_MODE__SHIFT 16 +#define SURFACE5_INFO__SURF5_AP0_SWP__MASK 0x00300000 +#define SURFACE5_INFO__SURF5_AP0_SWP__SHIFT 20 +#define SURFACE5_INFO__SURF5_AP1_SWP__MASK 0x00C00000 +#define SURFACE5_INFO__SURF5_AP1_SWP__SHIFT 22 +#define SURFACE5_INFO__SURF5_WRITE_FLAG 0x01000000 +#define SURFACE5_INFO__SURF5_READ_FLAG 0x02000000 +#define SURFACE5_INFO__SURF5_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE5_INFO__SURF5_TILE_MODE_R2__SHIFT 16 +#define SURFACE5_INFO__SURF5_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE5_INFO__SURF5_PITCHSEL_R3__SHIFT 0 +#define SURFACE5_LOWER_BOUND 0x00000B54 +#define SURFACE5_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE5_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE5_UPPER_BOUND 0x00000B58 +#define SURFACE5_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE5_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE6_INFO 0x00000B6C +#define SURFACE6_INFO__SURF6_PITCHSEL__MASK 0x000003FF +#define SURFACE6_INFO__SURF6_PITCHSEL__SHIFT 0 +#define SURFACE6_INFO__SURF6_TILE_MODE__MASK 0x00030000 +#define SURFACE6_INFO__SURF6_TILE_MODE__SHIFT 16 +#define SURFACE6_INFO__SURF6_AP0_SWP__MASK 0x00300000 +#define SURFACE6_INFO__SURF6_AP0_SWP__SHIFT 20 +#define SURFACE6_INFO__SURF6_AP1_SWP__MASK 0x00C00000 +#define SURFACE6_INFO__SURF6_AP1_SWP__SHIFT 22 +#define SURFACE6_INFO__SURF6_WRITE_FLAG 0x01000000 +#define SURFACE6_INFO__SURF6_READ_FLAG 0x02000000 +#define SURFACE6_INFO__SURF6_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE6_INFO__SURF6_TILE_MODE_R2__SHIFT 16 +#define SURFACE6_INFO__SURF6_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE6_INFO__SURF6_PITCHSEL_R3__SHIFT 0 +#define SURFACE6_LOWER_BOUND 0x00000B64 +#define SURFACE6_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE6_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE6_UPPER_BOUND 0x00000B68 +#define SURFACE6_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE6_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE7_INFO 0x00000B7C +#define SURFACE7_INFO__SURF7_PITCHSEL__MASK 0x000003FF +#define SURFACE7_INFO__SURF7_PITCHSEL__SHIFT 0 +#define SURFACE7_INFO__SURF7_TILE_MODE__MASK 0x00030000 +#define SURFACE7_INFO__SURF7_TILE_MODE__SHIFT 16 +#define SURFACE7_INFO__SURF7_AP0_SWP__MASK 0x00300000 +#define SURFACE7_INFO__SURF7_AP0_SWP__SHIFT 20 +#define SURFACE7_INFO__SURF7_AP1_SWP__MASK 0x00C00000 +#define SURFACE7_INFO__SURF7_AP1_SWP__SHIFT 22 +#define SURFACE7_INFO__SURF7_WRITE_FLAG 0x01000000 +#define SURFACE7_INFO__SURF7_READ_FLAG 0x02000000 +#define SURFACE7_INFO__SURF7_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE7_INFO__SURF7_TILE_MODE_R2__SHIFT 16 +#define SURFACE7_INFO__SURF7_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE7_INFO__SURF7_PITCHSEL_R3__SHIFT 0 +#define SURFACE7_LOWER_BOUND 0x00000B74 +#define SURFACE7_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE7_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE7_UPPER_BOUND 0x00000B78 +#define SURFACE7_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE7_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define ISYNC_CNTL 0x00001724 +#define ISYNC_CNTL__ISYNC_ANY2D_IDLE3D 0x00000001 +#define ISYNC_CNTL__ISYNC_ANY3D_IDLE2D 0x00000002 +#define ISYNC_CNTL__ISYNC_TRIG2D_IDLE3D 0x00000004 +#define ISYNC_CNTL__ISYNC_TRIG3D_IDLE2D 0x00000008 +#define ISYNC_CNTL__ISYNC_WAIT_IDLEGUI 0x00000010 +#define ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI 0x00000020 +#define GA_SOFT_RESET 0x0000429C +#define GA_SOFT_RESET__SOFT_RESET_COUNT__MASK 0x0000FFFF +#define GA_SOFT_RESET__SOFT_RESET_COUNT__SHIFT 0 +#define RBBM_CNTL 0x000000EC +#define RBBM_CNTL__RB_SETTLE__MASK 0x0000000F +#define RBBM_CNTL__RB_SETTLE__SHIFT 0 +#define RBBM_CNTL__ABORTCLKS_HI__MASK 0x00000070 +#define RBBM_CNTL__ABORTCLKS_HI__SHIFT 4 +#define RBBM_CNTL__ABORTCLKS_CP__MASK 0x00000700 +#define RBBM_CNTL__ABORTCLKS_CP__SHIFT 8 +#define RBBM_CNTL__ABORTCLKS_CFIFO__MASK 0x00007000 +#define RBBM_CNTL__ABORTCLKS_CFIFO__SHIFT 12 +#define RBBM_CNTL__CPQ_DATA_SWAP 0x00020000 +#define RBBM_CNTL__NO_ABORT_IDCT 0x00200000 +#define RBBM_CNTL__NO_ABORT_BIOS 0x00400000 +#define RBBM_CNTL__NO_ABORT_FB 0x00800000 +#define RBBM_CNTL__NO_ABORT_CP 0x01000000 +#define RBBM_CNTL__NO_ABORT_HI 0x02000000 +#define RBBM_CNTL__NO_ABORT_HDP 0x04000000 +#define RBBM_CNTL__NO_ABORT_MC 0x08000000 +#define RBBM_CNTL__NO_ABORT_AIC 0x10000000 +#define RBBM_CNTL__NO_ABORT_VIP 0x20000000 +#define RBBM_CNTL__NO_ABORT_DISP 0x40000000 +#define RBBM_CNTL__NO_ABORT_CG 0x80000000 +#define RBBM_CNTL__NO_ABORT_VAP 0x00080000 +#define RBBM_CNTL__NO_ABORT_GA 0x00100000 +#define RBBM_CNTL__NO_ABORT_TVOUT 0x00800000 +#define RBBM_STATUS 0x00000E40 +#define RBBM_STATUS__CMDFIFO_AVAIL__MASK 0x0000007F +#define RBBM_STATUS__CMDFIFO_AVAIL__SHIFT 0 +#define RBBM_STATUS__HIRQ_ON_RBB 0x00000100 +#define RBBM_STATUS__CPRQ_ON_RBB 0x00000200 +#define RBBM_STATUS__CFRQ_ON_RBB 0x00000400 +#define RBBM_STATUS__HIRQ_IN_RTBUF 0x00000800 +#define RBBM_STATUS__CPRQ_IN_RTBUF 0x00001000 +#define RBBM_STATUS__CFRQ_IN_RTBUF 0x00002000 +#define RBBM_STATUS__CF_PIPE_BUSY 0x00004000 +#define RBBM_STATUS__ENG_EV_BUSY 0x00008000 +#define RBBM_STATUS__CP_CMDSTRM_BUSY 0x00010000 +#define RBBM_STATUS__E2_BUSY 0x00020000 +#define RBBM_STATUS__RB2D_BUSY 0x00040000 +#define RBBM_STATUS__RB3D_BUSY 0x00080000 +#define RBBM_STATUS__SE_BUSY 0x00100000 +#define RBBM_STATUS__RE_BUSY 0x00200000 +#define RBBM_STATUS__TAM_BUSY 0x00400000 +#define RBBM_STATUS__TDM_BUSY 0x00800000 +#define RBBM_STATUS__PB_BUSY 0x01000000 +#define RBBM_STATUS__GUI_ACTIVE 0x80000000 +#define RBBM_STATUS__VAP_BUSY 0x00100000 +#define RBBM_STATUS__TIM_BUSY 0x02000000 +#define RBBM_STATUS__GA_BUSY 0x04000000 +#define RBBM_STATUS__CBA2D_BUSY 0x08000000 +#define RBBM_SOFT_RESET 0x000000F0 +#define RBBM_SOFT_RESET__SOFT_RESET_CP 0x00000001 +#define RBBM_SOFT_RESET__SOFT_RESET_HI 0x00000002 +#define RBBM_SOFT_RESET__SOFT_RESET_SE 0x00000004 +#define RBBM_SOFT_RESET__SOFT_RESET_RE 0x00000008 +#define RBBM_SOFT_RESET__SOFT_RESET_PP 0x00000010 +#define RBBM_SOFT_RESET__SOFT_RESET_E2 0x00000020 +#define RBBM_SOFT_RESET__SOFT_RESET_RB 0x00000040 +#define RBBM_SOFT_RESET__SOFT_RESET_HDP 0x00000080 +#define RBBM_SOFT_RESET__SOFT_RESET_MC 0x00000100 +#define RBBM_SOFT_RESET__SOFT_RESET_AIC 0x00000200 +#define RBBM_SOFT_RESET__SOFT_RESET_VIP 0x00000400 +#define RBBM_SOFT_RESET__SOFT_RESET_DISP 0x00000800 +#define RBBM_SOFT_RESET__SOFT_RESET_CG 0x00001000 +#define RBBM_SOFT_RESET__SOFT_RESET_VAP 0x00000004 +#define RBBM_SOFT_RESET__SOFT_RESET_GA 0x00002000 +#define RBBM_SOFT_RESET__SOFT_RESET_IDCT 0x00004000 +#define RBBM_CMDFIFO_ADDR 0x00000E70 +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR__MASK 0x0000003F +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR__SHIFT 0 +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR_R3__MASK 0x000001FF +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR_R3__SHIFT 0 +#define RBBM_CMDFIFO_DATA 0x00000E74 +#define RBBM_CMDFIFO_DATA__CMDFIFO_DATA__MASK 0xFFFFFFFF +#define RBBM_CMDFIFO_DATA__CMDFIFO_DATA__SHIFT 0 +#define RBBM_CMDFIFO_STAT 0x00000E7C +#define RBBM_CMDFIFO_STAT__CMDFIFO_RPTR__MASK 0x0000003F +#define RBBM_CMDFIFO_STAT__CMDFIFO_RPTR__SHIFT 0 +#define RBBM_CMDFIFO_STAT__CMDFIFO_WPTR__MASK 0x00003F00 +#define RBBM_CMDFIFO_STAT__CMDFIFO_WPTR__SHIFT 8 +#define WAIT_UNTIL 0x00001720 +#define WAIT_UNTIL__WAIT_CRTC_PFLIP 0x00000001 +#define WAIT_UNTIL__WAIT_RE_CRTC_VLINE 0x00000002 +#define WAIT_UNTIL__WAIT_FE_CRTC_VLINE 0x00000004 +#define WAIT_UNTIL__WAIT_CRTC_VLINE 0x00000008 +#define WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE 0x00000010 +#define WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE 0x00000020 +#define WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE 0x00000040 +#define WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE 0x00000080 +#define WAIT_UNTIL__WAIT_DMA_VID_IDLE 0x00000100 +#define WAIT_UNTIL__WAIT_DMA_GUI_IDLE 0x00000200 +#define WAIT_UNTIL__WAIT_CMDFIFO 0x00000400 +#define WAIT_UNTIL__WAIT_OV0_FLIP 0x00000800 +#define WAIT_UNTIL__WAIT_OV0_SLICEDONE 0x00001000 +#define WAIT_UNTIL__WAIT_2D_IDLE 0x00004000 +#define WAIT_UNTIL__WAIT_3D_IDLE 0x00008000 +#define WAIT_UNTIL__WAIT_2D_IDLECLEAN 0x00010000 +#define WAIT_UNTIL__WAIT_3D_IDLECLEAN 0x00020000 +#define WAIT_UNTIL__WAIT_HOST_IDLECLEAN 0x00040000 +#define WAIT_UNTIL__WAIT_EXTERN_SIG 0x00080000 +#define WAIT_UNTIL__CMDFIFO_ENTRIES__MASK 0x07F00000 +#define WAIT_UNTIL__CMDFIFO_ENTRIES__SHIFT 20 +#define WAIT_UNTIL__WAIT_BOTH_CRTC_PFLIP 0x40000000 +#define WAIT_UNTIL__ENG_DISPLAY_SELECT 0x80000000 +#define WAIT_UNTIL__WAIT_AGP_FLUSH 0x00002000 +#define WAIT_UNTIL__WAIT_IDCT_SEMAPHORE 0x08000000 +#define WAIT_UNTIL__WAIT_VAP_IDLE 0x10000000 +#define DISPLAY_BASE_ADDR 0x0000023C +#define DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF +#define DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__SHIFT 0 +#define CRTC2_DISPLAY_BASE_ADDR 0x0000033C +#define CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF +#define CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__SHIFT 0 +#define AIC_CTRL 0x000001D0 +#define AIC_CTRL__TRANSLATE_EN 0x00000001 +#define AIC_CTRL__HW_0_DEBUG 0x00000002 +#define AIC_CTRL__HW_1_DEBUG 0x00000004 +#define AIC_CTRL__HW_2_DEBUG 0x00000008 +#define AIC_CTRL__HW_3_DEBUG 0x00000010 +#define AIC_CTRL__HW_4_DEBUG 0x00000020 +#define AIC_CTRL__HW_5_DEBUG 0x00000040 +#define AIC_CTRL__HW_6_DEBUG 0x00000080 +#define AIC_CTRL__HW_7_DEBUG 0x00000100 +#define AIC_CTRL__HW_8_DEBUG 0x00000200 +#define AIC_CTRL__HW_9_DEBUG 0x00000400 +#define AIC_CTRL__HW_A_DEBUG 0x00000800 +#define AIC_CTRL__HW_B_DEBUG 0x00001000 +#define AIC_CTRL__HW_C_DEBUG 0x00002000 +#define AIC_CTRL__HW_D_DEBUG 0x00004000 +#define AIC_CTRL__HW_E_DEBUG 0x00008000 +#define AIC_CTRL__HW_F_DEBUG 0x00010000 +#define AIC_CTRL__HW_10_DEBUG 0x00020000 +#define AIC_CTRL__HW_11_DEBUG 0x00040000 +#define AIC_CTRL__HW_12_DEBUG 0x00080000 +#define AIC_CTRL__HW_13_DEBUG 0x00100000 +#define AIC_CTRL__HW_14_DEBUG 0x00200000 +#define AIC_CTRL__HW_15_DEBUG 0x00400000 +#define AIC_CTRL__HW_16_DEBUG 0x00800000 +#define AIC_CTRL__HW_17_DEBUG 0x01000000 +#define AIC_CTRL__HW_18_DEBUG 0x02000000 +#define AIC_CTRL__HW_19_DEBUG 0x04000000 +#define AIC_CTRL__HW_1A_DEBUG 0x08000000 +#define AIC_CTRL__HW_1B_DEBUG 0x10000000 +#define AIC_CTRL__HW_1C_DEBUG 0x20000000 +#define AIC_CTRL__HW_1D_DEBUG 0x40000000 +#define AIC_CTRL__HW_1E_DEBUG 0x80000000 +#define AIC_CTRL__DIS_OUT_OF_PCI_GART_ACCESS 0x00000002 +#define AIC_CTRL__HW_02_DEBUG 0x00000004 +#define AIC_CTRL__HW_03_DEBUG 0x00000008 +#define AIC_CTRL__TEST_RBF_DIV_VAL__MASK 0x00000070 +#define AIC_CTRL__TEST_RBF_DIV_VAL__SHIFT 4 +#define AIC_CTRL__TEST_RBF_EN 0x00000080 +#define AIC_CTRL__HW_08_DEBUG 0x00000100 +#define AIC_CTRL__HW_09_DEBUG 0x00000200 +#define AIC_CTRL__HW_10_DEBUG_R3 0x00000400 +#define AIC_CTRL__HW_11_DEBUG_R3 0x00000800 +#define AIC_CTRL__HW_12_DEBUG_R3 0x00001000 +#define AIC_CTRL__HW_13_DEBUG_R3 0x00002000 +#define AIC_CTRL__HW_14_DEBUG_R3 0x00004000 +#define AIC_CTRL__HW_15_DEBUG_R3 0x00008000 +#define AIC_CTRL__HW_16_DEBUG_R3 0x00010000 +#define AIC_CTRL__HW_17_DEBUG_R3 0x00020000 +#define AIC_CTRL__HW_18_DEBUG_R3 0x00040000 +#define AIC_CTRL__HW_19_DEBUG_R3 0x00080000 +#define AIC_CTRL__HW_20_DEBUG 0x00100000 +#define AIC_CTRL__HW_21_DEBUG 0x00200000 +#define AIC_CTRL__HW_22_DEBUG 0x00400000 +#define AIC_CTRL__HW_23_DEBUG 0x00800000 +#define AIC_CTRL__HW_24_DEBUG 0x01000000 +#define AIC_CTRL__HW_25_DEBUG 0x02000000 +#define AIC_CTRL__HW_26_DEBUG 0x04000000 +#define AIC_CTRL__HW_27_DEBUG 0x08000000 +#define AIC_CTRL__HW_28_DEBUG 0x10000000 +#define AIC_CTRL__HW_29_DEBUG 0x20000000 +#define AIC_CTRL__HW_30_DEBUG 0x40000000 +#define AIC_CTRL__HW_31_DEBUG 0x80000000 +#define BUS_CNTL 0x00000030 +#define BUS_CNTL__BUS_DBL_RESYNC 0x00000001 +#define BUS_CNTL__BUS_MSTR_RESET 0x00000002 +#define BUS_CNTL__BUS_FLUSH_BUF 0x00000004 +#define BUS_CNTL__BUS_STOP_REQ_DIS 0x00000008 +#define BUS_CNTL__BUS_READ_COMBINE_EN 0x00000010 +#define BUS_CNTL__BUS_WRT_COMBINE_EN 0x00000020 +#define BUS_CNTL__BUS_MASTER_DIS 0x00000040 +#define BUS_CNTL__BIOS_ROM_WRT_EN 0x00000080 +#define BUS_CNTL__BUS_PREFETCH_MODE__MASK 0x00000300 +#define BUS_CNTL__BUS_PREFETCH_MODE__SHIFT 8 +#define BUS_CNTL__BUS_VGA_PREFETCH_EN 0x00000400 +#define BUS_CNTL__BUS_SGL_READ_DISABLE 0x00000800 +#define BUS_CNTL__BIOS_DIS_ROM 0x00001000 +#define BUS_CNTL__BUS_PCI_READ_RETRY_EN 0x00002000 +#define BUS_CNTL__BUS_AGP_AD_STEPPING_EN 0x00004000 +#define BUS_CNTL__BUS_PCI_WRT_RETRY_EN 0x00008000 +#define BUS_CNTL__BUS_RETRY_WS__MASK 0x000F0000 +#define BUS_CNTL__BUS_RETRY_WS__SHIFT 16 +#define BUS_CNTL__BUS_MSTR_RD_MULT 0x00100000 +#define BUS_CNTL__BUS_MSTR_RD_LINE 0x00200000 +#define BUS_CNTL__BUS_SUSPEND 0x00400000 +#define BUS_CNTL__LAT_16X 0x00800000 +#define BUS_CNTL__BUS_RD_DISCARD_EN 0x01000000 +#define BUS_CNTL__ENFRCWRDY 0x02000000 +#define BUS_CNTL__BUS_MSTR_WS 0x04000000 +#define BUS_CNTL__BUS_PARKING_DIS 0x08000000 +#define BUS_CNTL__BUS_MSTR_DISCONNECT_EN 0x10000000 +#define BUS_CNTL__SERR_EN 0x20000000 +#define BUS_CNTL__BUS_READ_BURST 0x40000000 +#define BUS_CNTL__BUS_RDY_READ_DLY 0x80000000 +#define BUS_CNTL__BUS_PM4_READ_COMBINE_EN 0x00000010 +#define BUS_CNTL__BM_DAC_CRIPPLE 0x00000100 +#define BUS_CNTL__BUS_NON_PM4_READ_COMBINE_EN 0x00000200 +#define BUS_CNTL__BUS_XFERD_DISCARD_EN 0x00000400 +#define MC_STATUS 0x00000150 +#define MC_STATUS__MEM_PWRUP_COMPL_A 0x00000001 +#define MC_STATUS__MEM_PWRUP_COMPL_B 0x00000002 +#define MC_STATUS__MC_IDLE 0x00000004 +#define MC_STATUS__SPARE__MASK 0x0000FFF8 +#define MC_STATUS__SPARE__SHIFT 3 +#define MC_STATUS__IMP_N_VALUE_R_BACK__MASK 0x00000078 +#define MC_STATUS__IMP_N_VALUE_R_BACK__SHIFT 3 +#define MC_STATUS__IMP_P_VALUE_R_BACK__MASK 0x00000780 +#define MC_STATUS__IMP_P_VALUE_R_BACK__SHIFT 7 +#define MC_STATUS__TEST_OUT_R_BACK 0x00000800 +#define MC_STATUS__DUMMY_OUT_R_BACK 0x00001000 +#define MC_STATUS__IMP_N_VALUE_A_R_BACK__MASK 0x0001E000 +#define MC_STATUS__IMP_N_VALUE_A_R_BACK__SHIFT 13 +#define MC_STATUS__IMP_P_VALUE_A_R_BACK__MASK 0x001E0000 +#define MC_STATUS__IMP_P_VALUE_A_R_BACK__SHIFT 17 +#define MC_STATUS__IMP_N_VALUE_CK_R_BACK__MASK 0x01E00000 +#define MC_STATUS__IMP_N_VALUE_CK_R_BACK__SHIFT 21 +#define MC_STATUS__IMP_P_VALUE_CK_R_BACK__MASK 0x1E000000 +#define MC_STATUS__IMP_P_VALUE_CK_R_BACK__SHIFT 25 +#define MC_STATUS__MEM_PWRUP_COMPL_C 0x00000004 +#define MC_STATUS__MEM_PWRUP_COMPL_D 0x00000008 +#define MC_STATUS__MC_IDLE_R3 0x00000010 +#define MC_STATUS__IMP_CAL_COUNT__MASK 0x0000F000 +#define MC_STATUS__IMP_CAL_COUNT__SHIFT 12 +#define OV0_SCALE_CNTL 0x00000420 +#define OV0_SCALE_CNTL__OV0_NO_READ_BEHIND_SCAN 0x00000002 +#define OV0_SCALE_CNTL__OV0_HORZ_PICK_NEAREST 0x00000004 +#define OV0_SCALE_CNTL__OV0_VERT_PICK_NEAREST 0x00000008 +#define OV0_SCALE_CNTL__OV0_SIGNED_UV 0x00000010 +#define OV0_SCALE_CNTL__OV0_GAMMA_SEL__MASK 0x000000E0 +#define OV0_SCALE_CNTL__OV0_GAMMA_SEL__SHIFT 5 +#define OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__MASK 0x00000F00 +#define OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__SHIFT 8 +#define OV0_SURFACE_FORMAT__RESERVED0 0x0 +#define OV0_SURFACE_FORMAT__RESERVED1 0x100 +#define OV0_SURFACE_FORMAT__RESERVED2 0x200 +#define OV0_SURFACE_FORMAT__16BPP_ARGB 0x300 +#define OV0_SURFACE_FORMAT__16BPP_RGB 0x400 +#define OV0_SURFACE_FORMAT__RESERVED5 0x500 +#define OV0_SURFACE_FORMAT__32BPP_ARGB 0x600 +#define OV0_SURFACE_FORMAT__RESERVED7 0x700 +#define OV0_SURFACE_FORMAT__RESERVED8 0x800 +#define OV0_SURFACE_FORMAT__IF09_PLANAR 0x900 +#define OV0_SURFACE_FORMAT__YV12_PLANAR 0xA00 +#define OV0_SURFACE_FORMAT__YUY2_PACKED 0xB00 +#define OV0_SURFACE_FORMAT__UYVY_PACKED 0xC00 +#define OV0_SURFACE_FORMAT__YYUV9_PLANAR 0xD00 +#define OV0_SURFACE_FORMAT__YYUV12_PLANAR 0xE00 +#define OV0_SURFACE_FORMAT__RESERVED15 0xF00 +#define OV0_SCALE_CNTL__OV0_ADAPTIVE_DEINT 0x00001000 +#define OV0_SCALE_CNTL__OV0_CRTC_SEL 0x00004000 +#define OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__MASK 0x007F0000 +#define OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__SHIFT 16 +#define OV0_SCALE_CNTL__OV0_DOUBLE_BUFFER_REGS 0x01000000 +#define OV0_SCALE_CNTL__OV0_BANDWIDTH 0x04000000 +#define OV0_SCALE_CNTL__OV0_LIN_TRANS_BYPASS 0x10000000 +#define OV0_SCALE_CNTL__OV0_INT_EMU 0x20000000 +#define OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK 0x40000000 +#define OV0_SCALE_CNTL__OV0_OVERLAY_EN__SHIFT 30 +#define OV0_OVERLAY_EN__ENABLE 0x40000000 +#define OV0_SCALE_CNTL__OV0_SOFT_RESET__MASK 0x80000000 +#define OV0_SCALE_CNTL__OV0_SOFT_RESET__SHIFT 31 +#define OV0_SOFT_RESET__RESET 0x80000000 +#define OV0_SCALE_CNTL__OV0_TEMPORAL_DEINT 0x00002000 +#define OV0_SCALE_CNTL__OV0_PULLDOWN_ON_P1_ONLY 0x00008000 +#define OV0_SCALE_CNTL__OV0_FULL_BYPASS 0x00000020 +#define OV0_SCALE_CNTL__OV0_DYNAMIC_EXT 0x00000040 +#define OV0_SCALE_CNTL__OV0_RGB30_ON 0x00000080 +#define CRTC2_GEN_CNTL 0x000003F8 +#define CRTC2_GEN_CNTL__CRTC2_DBL_SCAN_EN 0x00000001 +#define CRTC2_GEN_CNTL__CRTC2_INTERLACE_EN 0x00000002 +#define CRTC2_GEN_CNTL__CRTC2_SYNC_TRISTATE 0x00000010 +#define CRTC2_GEN_CNTL__CRTC2_HSYNC_TRISTATE 0x00000020 +#define CRTC2_GEN_CNTL__CRTC2_VSYNC_TRISTATE 0x00000040 +#define CRTC2_GEN_CNTL__CRT2_ON 0x00000080 +#define CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__MASK 0x00000F00 +#define CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__SHIFT 8 +#define CRTC2_GEN_CNTL__CRTC2_ICON_EN 0x00008000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_EN 0x00010000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_MODE__MASK 0x00700000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_MODE__SHIFT 20 +#define CRTC2_GEN_CNTL__CRTC2_DISPLAY_DIS 0x00800000 +#define CRTC2_GEN_CNTL__CRTC2_EN 0x02000000 +#define CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B 0x04000000 +#define CRTC2_GEN_CNTL__CRTC2_C_SYNC_EN 0x08000000 +#define CRTC2_GEN_CNTL__CRTC2_HSYNC_DIS 0x10000000 +#define CRTC2_GEN_CNTL__CRTC2_VSYNC_DIS 0x20000000 +#define CRTC2_GEN_CNTL__CRTC2_MODE9_COLOR_ORDER 0x00001000 +#define CRTC2_GEN_CNTL__CRTC2_FIX_VSYNC_EDGE_POSITION_EN 0x40000000 +#define CRTC2_OFFSET 0x00000324 +#define CRTC2_OFFSET__CRTC2_OFFSET__MASK 0x07FFFFFF +#define CRTC2_OFFSET__CRTC2_OFFSET__SHIFT 0 +#define CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET 0x40000000 +#define CRTC2_OFFSET__CRTC2_OFFSET_LOCK 0x80000000 +#define CRTC2_OFFSET__CRTC2_OFFSET_R3__MASK 0x0FFFFFFF +#define CRTC2_OFFSET__CRTC2_OFFSET_R3__SHIFT 0 +#define CRTC2_OFFSET_CNTL 0x00000328 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__MASK 0x0000000F +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__SHIFT 0 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_EN 0x00008000 +#define CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL 0x00010000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_LEFT_EN 0x10000000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET 0x40000000 +#define CRTC2_OFFSET_CNTL__CRTC2_OFFSET_LOCK 0x80000000 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__MASK 0x000000F0 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__SHIFT 4 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_EN_RIGHT 0x00004000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_OFFSET_EN 0x00020000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__MASK 0x000C0000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__SHIFT 18 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC 0x00200000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_RIGHT_EN 0x20000000 +#define CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN_RIGHT 0x00000100 +#define CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN 0x00000200 +#define CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN_RIGHT 0x00001000 +#define CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN 0x00002000 +#define CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN_RIGHT 0x00004000 +#define CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN 0x00008000 +#define CUR_OFFSET 0x00000260 +#define CUR_OFFSET__CUR_OFFSET__MASK 0x07FFFFFF +#define CUR_OFFSET__CUR_OFFSET__SHIFT 0 +#define CUR_OFFSET__CUR_LOCK 0x80000000 +#define CUR2_OFFSET 0x00000360 +#define CUR2_OFFSET__CUR2_OFFSET__MASK 0x07FFFFFF +#define CUR2_OFFSET__CUR2_OFFSET__SHIFT 0 +#define CUR2_OFFSET__CUR2_LOCK 0x80000000 +#define HOST_PATH_CNTL 0x00000130 +#define HOST_PATH_CNTL__HDP_APER_CNTL 0x00800000 +#define HOST_PATH_CNTL__HP_LIN_RD_CACHE_DIS 0x01000000 +#define HOST_PATH_CNTL__HP_RBBM_LOCK_DIS 0x02000000 +#define HOST_PATH_CNTL__HDP_SOFT_RESET 0x04000000 +#define HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__MASK 0x70000000 +#define HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__SHIFT 28 +#define HOST_PATH_CNTL__HP_TEST_RST_CNTL 0x80000000 +#define HOST_PATH_CNTL__HDP_WRITE_THROUGH_CACHE_DIS 0x00400000 +#define HOST_PATH_CNTL__HDP_READ_BUFFER_INVALIDATE 0x08000000 +#define DST_PITCH_OFFSET 0x0000142C +#define DST_PITCH_OFFSET__DST_OFFSET__MASK 0x003FFFFF +#define DST_PITCH_OFFSET__DST_OFFSET__SHIFT 0 +#define DST_PITCH_OFFSET__DST_PITCH__MASK 0x3FC00000 +#define DST_PITCH_OFFSET__DST_PITCH__SHIFT 22 +#define DST_PITCH_OFFSET__DST_TILE__MASK 0xC0000000 +#define DST_PITCH_OFFSET__DST_TILE__SHIFT 30 +#define DST_TILE__MACRO 0x1 +#define DST_TILE__MICRO 0x2 +#define SRC_PITCH_OFFSET 0x00001428 +#define SRC_PITCH_OFFSET__SRC_OFFSET__MASK 0x003FFFFF +#define SRC_PITCH_OFFSET__SRC_OFFSET__SHIFT 0 +#define SRC_PITCH_OFFSET__SRC_PITCH__MASK 0x3FC00000 +#define SRC_PITCH_OFFSET__SRC_PITCH__SHIFT 22 +#define SRC_PITCH_OFFSET__SRC_TILE 0x40000000 +#define DEFAULT_SC_BOTTOM_RIGHT 0x000016E8 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK 0x00003FFF +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT 0 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK 0x3FFF0000 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT 16 +#define DEFAULT2_SC_BOTTOM_RIGHT 0x000016DC +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK 0x00003FFF +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT 0 +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK 0x3FFF0000 +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT 16 +#define DP_DATATYPE 0x000016C4 +#define DP_DATATYPE__DP_DST_DATATYPE__MASK 0x0000000F +#define DP_DATATYPE__DP_DST_DATATYPE__SHIFT 0 +#define DP_DATATYPE__DP_BRUSH_DATATYPE__MASK 0x00000F00 +#define DP_DATATYPE__DP_BRUSH_DATATYPE__SHIFT 8 +#define DP_DATATYPE__DP_SRC_DATATYPE__MASK 0x00070000 +#define DP_DATATYPE__DP_SRC_DATATYPE__SHIFT 16 +#define DP_DATATYPE__DP_BYTE_PIX_ORDER 0x40000000 +#define DP_GUI_MASTER_CNTL 0x0000146C +#define DP_GUI_MASTER_CNTL__GMC_SRC_PITCH_OFFSET_CNTL 0x00000001 +#define DP_GUI_MASTER_CNTL__GMC_DST_PITCH_OFFSET_CNTL 0x00000002 +#define DP_GUI_MASTER_CNTL__GMC_SRC_CLIPPING 0x00000004 +#define DP_GUI_MASTER_CNTL__GMC_DST_CLIPPING 0x00000008 +#define DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__MASK 0x000000F0 +#define DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__SHIFT 4 +#define GMC_BRUSH_DATATYPE__8X8_MONO_FG_BG 0x0 +#define GMC_BRUSH_DATATYPE__8X8_MONO_FG 0x1 +#define GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG_BG 0x6 +#define GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG 0x7 +#define GMC_BRUSH_DATATYPE__8X8_COLOR 0xA +#define GMC_BRUSH_DATATYPE__SOLID_COLOR_FG 0xD +#define GMC_BRUSH_DATATYPE__SOLID_COLOR_RESERVED 0xF +#define GMC_BRUSH_DATATYPE__SOLID 0xD0 +#define GMC_BRUSH_DATATYPE__MONO8x8 0x0 +#define GMC_BRUSH_DATATYPE__COLOR8x8 0xA0 +#define DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__MASK 0x00000F00 +#define DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__SHIFT 8 +#define GMC_DST_DATATYPE__8BPP_CLUT 0x2 +#define GMC_DST_DATATYPE__16BPP_1555 0x3 +#define GMC_DST_DATATYPE__16BPP_565 0x4 +#define GMC_DST_DATATYPE__32BPP_8888 0x6 +#define GMC_DST_DATATYPE__CI8 0x200 +#define GMC_DST_DATATYPE__RGB16_1555 0x300 +#define GMC_DST_DATATYPE__RGB16_565 0x400 +#define GMC_DST_DATATYPE__RGB32 0x600 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__MASK 0x00003000 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__SHIFT 12 +#define GMC_SRC_DATATYPE__BUILD(x) 0x0 +#define GMC_SRC_DATATYPE__MONO_OPAQUE 0x0 +#define GMC_SRC_DATATYPE__MONO_TRANSPARENT 0x0 +#define GMC_SRC_DATATYPE__SAME_AS_DST 0x0 +#define GMC_SRC_DATATYPE__8BPP_CLUT_XLAT 0x0 +#define GMC_SRC_DATATYPE__32BPP_CLUT_XLAT 0x0 +#define GMC_SRC_DATATYPE__MONO_FG_BG 0x0 +#define GMC_SRC_DATATYPE__MONO_FG 0x1000 +#define GMC_SRC_DATATYPE__COLOR 0x3000 +#define GMC_SRC_DATATYPE__DST 0x3000 +#define DP_GUI_MASTER_CNTL__GMC_BYTE_PIX_ORDER 0x00004000 +#define DP_GUI_MASTER_CNTL__GMC_DEFAULT_SEL 0x00008000 +#define DP_GUI_MASTER_CNTL__GMC_ROP3__MASK 0x00FF0000 +#define DP_GUI_MASTER_CNTL__GMC_ROP3__SHIFT 16 +#define GMC_ROP3__SRCCPY 0xCC +#define GMC_ROP3__WHITENESS 0xFF +#define GMC_ROP3__BLACKNESS 0x0 +#define DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__MASK 0x07000000 +#define DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__SHIFT 24 +#define GMC_DP_SRC_SOURCE__VIDEO_MEM 0x2 +#define GMC_DP_SRC_SOURCE__HOSTDATA 0x3 +#define GMC_DP_SRC_SOURCE__HOSTDATA_BYTE 0x4 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE2 0x08000000 +#define DP_GUI_MASTER_CNTL__GMC_CLR_CMP_FCN_DIS 0x10000000 +#define DP_GUI_MASTER_CNTL__GMC_WR_MSK_DIS 0x40000000 +#define DP_BRUSH_FRGD_CLR 0x0000147C +#define DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__MASK 0xFFFFFFFF +#define DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__SHIFT 0 +#define DP_BRUSH_BKGD_CLR 0x00001478 +#define DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__MASK 0xFFFFFFFF +#define DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__SHIFT 0 +#define DP_SRC_FRGD_CLR 0x000015D8 +#define DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__MASK 0xFFFFFFFF +#define DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__SHIFT 0 +#define DP_SRC_BKGD_CLR 0x000015DC +#define DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__MASK 0xFFFFFFFF +#define DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__SHIFT 0 +#define DP_WRITE_MSK 0x000016CC +#define DP_WRITE_MSK__DP_WRITE_MSK__MASK 0xFFFFFFFF +#define DP_WRITE_MSK__DP_WRITE_MSK__SHIFT 0 +#define US_CONFIG 0x00004600 +#define US_CONFIG__NLEVEL__MASK 0x00000007 +#define US_CONFIG__NLEVEL__SHIFT 0 +#define US_CONFIG__FIRST_TEX 0x00000008 +#define US_CONFIG__PERF0__MASK 0x000001F0 +#define US_CONFIG__PERF0__SHIFT 4 +#define US_CONFIG__PERF1__MASK 0x00003E00 +#define US_CONFIG__PERF1__SHIFT 9 +#define US_CONFIG__PERF2__MASK 0x0007C000 +#define US_CONFIG__PERF2__SHIFT 14 +#define US_CONFIG__PERF3__MASK 0x00F80000 +#define US_CONFIG__PERF3__SHIFT 19 +#define US_RESET 0x0000460C +#define VAP_PVS_STATE_FLUSH_REG 0x00002284 +#define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__MASK 0xFFFFFFFF +#define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__SHIFT 0 + +/* packet stuff **************************************************************/ +#define PACKET_HEADER_MASK 0xC0000000 +#define PACKET_HEADER_SHIFT 30 +#define PACKET_HEADER_GET(p) (((p) & PACKET_HEADER_MASK) >> PACKET_HEADER_SHIFT) +#define PACKET_HEADER_SET(p) (((p) << PACKET_HEADER_SHIFT) & PACKET_HEADER_MASK) + +#define PACKET0_HEADER 0x0 +# define PACKET0_REG_MASK 0x00001FFF +# define PACKET0_REG_SHIFT 0 +# define PACKET0_COUNT_MASK 0x3FFF0000 +# define PACKET0_COUNT_SHIFT 16 +#define PACKET1_HEADER 0x1 +#define PACKET2_HEADER 0x2 +#define PACKET3_HEADER 0x3 +# define PACKET3_OPCODE_MASK 0x0000FF00 +# define PACKET3_OPCODE_SHIFT 8 +# define PACKET3_OPCODE_NOP 0x10 +# define PACKET3_OPCODE_BITBLT 0x92 +# define PACKET3_OPCODE_BITBLT_MULTI 0x9B +# define PACKET3_COUNT_MASK 0x3FFF0000 +# define PACKET3_COUNT_SHIFT 16 + +#define CP_PACKET0(r, n) (PACKET_HEADER_SET(PACKET0_HEADER) |\ + ((((r)>>2)<<PACKET0_REG_SHIFT) & PACKET0_REG_MASK) |\ + (((n) << PACKET0_COUNT_SHIFT) & PACKET0_COUNT_MASK)) +#define CP_PACKET3(o, n) (PACKET_HEADER_SET(PACKET3_HEADER) |\ + (((o)<<PACKET3_OPCODE_SHIFT) & PACKET3_OPCODE_MASK) |\ + (((n)<<PACKET3_COUNT_SHIFT) & PACKET3_COUNT_MASK)) + +#endif diff --git a/shared-core/radeon_ms_rom.c b/shared-core/radeon_ms_rom.c new file mode 100644 index 00000000..b4db02be --- /dev/null +++ b/shared-core/radeon_ms_rom.c @@ -0,0 +1,91 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +int radeon_ms_rom_get_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_combios_get_properties(dev); + } + return 0; +} + +int radeon_ms_rom_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + void *rom_mapped; + char atomstr[5] = {0, 0, 0, 0, 0}; + uint16_t *offset; + + dev_priv->rom.type = ROM_UNKNOWN; + /* copy rom if any */ + rom_mapped = pci_map_rom(dev->pdev, &rom->rom_size); + if (rom_mapped && rom->rom_size) { + rom->rom_image = drm_alloc(rom->rom_size, DRM_MEM_DRIVER); + if (rom->rom_image == NULL) { + return -1; + } + memcpy(rom->rom_image, rom_mapped, rom->rom_size); + DRM_INFO("[radeon_ms] ROM %d bytes copied\n", rom->rom_size); + } else { + DRM_INFO("[radeon_ms] no ROM\n"); + return 0; + } + pci_unmap_rom(dev->pdev, rom_mapped); + + if (rom->rom_image[0] != 0x55 || rom->rom_image[1] != 0xaa) { + DRM_INFO("[radeon_ms] no ROM\n"); + DRM_INFO("[radeon_ms] ROM signature 0x55 0xaa missing\n"); + return 0; + } + offset = (uint16_t *)&rom->rom_image[ROM_HEADER]; + memcpy(atomstr, &rom->rom_image[*offset + 4], 4); + if (!strcpy(atomstr, "ATOM") || !strcpy(atomstr, "MOTA")) { + DRM_INFO("[radeon_ms] ATOMBIOS ROM detected\n"); + return 0; + } else { + struct combios_header **header; + + header = &rom->rom.combios_header; + if ((*offset + sizeof(struct combios_header)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS header offset\n"); + return -1; + } + dev_priv->rom.type = ROM_COMBIOS; + *header = (struct combios_header *)&rom->rom_image[*offset]; + DRM_INFO("[radeon_ms] COMBIOS type : %d\n", + (*header)->ucTypeDefinition); + DRM_INFO("[radeon_ms] COMBIOS OEM ID: %02x %02x\n", + (*header)->ucOemID1, (*header)->ucOemID2); + } + return 0; +} diff --git a/shared-core/radeon_ms_rom.h b/shared-core/radeon_ms_rom.h new file mode 100644 index 00000000..36a54cbb --- /dev/null +++ b/shared-core/radeon_ms_rom.h @@ -0,0 +1,51 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_ROM_H__ +#define __RADEON_MS_ROM_H__ + +#include "radeon_ms_combios.h" + +enum radeon_rom_type { + ROM_COMBIOS, + ROM_ATOMBIOS, + ROM_UNKNOWN +}; + +union radeon_ms_rom_type { + struct combios_header *combios_header; +}; + +struct radeon_ms_rom { + uint8_t type; + size_t rom_size; + uint8_t *rom_image; + union radeon_ms_rom_type rom; +}; + +#endif + diff --git a/shared-core/radeon_ms_state.c b/shared-core/radeon_ms_state.c new file mode 100644 index 00000000..17f8b764 --- /dev/null +++ b/shared-core/radeon_ms_state.c @@ -0,0 +1,45 @@ +/* + * 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 <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +void radeon_ms_state_restore(struct drm_device *dev, struct radeon_state *state) +{ + radeon_ms_irq_restore(dev, state); + radeon_ms_gpu_restore(dev, state); + radeon_ms_cp_restore(dev, state); + radeon_ms_crtc1_restore(dev, state); +} + +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state) +{ + radeon_ms_crtc1_save(dev, state); + radeon_ms_cp_save(dev, state); + radeon_ms_gpu_save(dev, state); + radeon_ms_irq_save(dev, state); +} diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 57e3a3bb..6de4b135 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -745,13 +745,14 @@ static struct { */ static void radeon_clear_box(drm_radeon_private_t * dev_priv, + struct drm_radeon_master_private *master_priv, int x, int y, int w, int h, int r, int g, int b) { u32 color; RING_LOCALS; - x += dev_priv->sarea_priv->boxes[0].x1; - y += dev_priv->sarea_priv->boxes[0].y1; + x += master_priv->sarea_priv->boxes[0].x1; + y += master_priv->sarea_priv->boxes[0].y1; switch (dev_priv->color_fmt) { case RADEON_COLOR_FORMAT_RGB565: @@ -779,7 +780,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (master_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -793,7 +794,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, ADVANCE_RING(); } -static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) +static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv, struct drm_radeon_master_private *master_priv) { /* Collapse various things into a wait flag -- trying to * guess if userspase slept -- better just to have them tell us. @@ -810,12 +811,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Purple box for page flipping */ if (dev_priv->stats.boxes & RADEON_BOX_FLIP) - radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255); + radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255); /* Red box if we have to wait for idle at any point */ if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) - radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0); + radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0); /* Blue box: lost context? */ @@ -823,12 +824,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Yellow box for texture swaps */ if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) - radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0); + radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0); /* Green box if hardware never idles (as far as we can tell) */ if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) - radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); + radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0); /* Draw bars indicating number of buffers allocated * (not a great measure, easily confused) @@ -837,7 +838,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) if (dev_priv->stats.requested_bufs > 100) dev_priv->stats.requested_bufs = 100; - radeon_clear_box(dev_priv, 4, 16, + radeon_clear_box(dev_priv, master_priv, 4, 16, dev_priv->stats.requested_bufs, 4, 196, 128, 128); } @@ -851,11 +852,13 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) */ static void radeon_cp_dispatch_clear(struct drm_device * dev, + struct drm_master *master, drm_radeon_clear_t * clear, drm_radeon_clear_rect_t * depth_boxes) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; @@ -867,7 +870,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, dev_priv->stats.clears++; - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -893,7 +896,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { int x = pbox[i].x1; @@ -970,7 +973,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. * we haven't touched any "normal" state - still need this? */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; if ((dev_priv->flags & RADEON_HAS_HIERZ) && (flags & RADEON_USE_HIERZ)) { @@ -1220,7 +1223,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1291,7 +1294,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1334,20 +1337,21 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * wait on this value before performing the clear ioctl. We * need this because the card's so damned fast... */ - dev_priv->sarea_priv->last_clear++; + sarea_priv->last_clear++; BEGIN_RING(4); - RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear); + RADEON_CLEAR_AGE(sarea_priv->last_clear); RADEON_WAIT_UNTIL_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_swap(struct drm_device * dev) +static void radeon_cp_dispatch_swap(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; int i; @@ -1357,7 +1361,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); /* Wait for the 3D stream to idle before dispatching the bitblt. * This will prevent data corruption between the two streams. @@ -1391,7 +1395,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->sarea_priv->pfCurrentPage == 0) { + if (sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1411,31 +1415,32 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; + sarea_priv->last_frame++; BEGIN_RING(4); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(sarea_priv->last_frame); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_flip(struct drm_device * dev) +void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle; - int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) + struct drm_radeon_master_private *master_priv = master->driver_priv; + struct drm_sarea *sarea = (struct drm_sarea *) master_priv->sarea->handle; + int offset = (master_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; DRM_DEBUG("pfCurrentPage=%d\n", - dev_priv->sarea_priv->pfCurrentPage); + master_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) { dev_priv->stats.boxes |= RADEON_BOX_FLIP; - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); } /* Update the frame offsets for both CRTCs @@ -1447,7 +1452,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) ((sarea->frame.y * dev_priv->front_pitch + sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) + offset); - OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base + OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base + offset); ADVANCE_RING(); @@ -1456,13 +1461,13 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = - 1 - dev_priv->sarea_priv->pfCurrentPage; + master_priv->sarea_priv->last_frame++; + master_priv->sarea_priv->pfCurrentPage = + 1 - master_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame); ADVANCE_RING(); } @@ -1500,11 +1505,13 @@ typedef struct { } drm_radeon_tcl_prim_t; static void radeon_cp_dispatch_vertex(struct drm_device * dev, + struct drm_file *file_priv, struct drm_buf * buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; int numverts = (int)prim->numverts; int nbox = sarea_priv->nbox; @@ -1545,13 +1552,14 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, } while (i < nbox); } -static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf) +static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_master *master, struct drm_buf * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; RING_LOCALS; - buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; + buf_priv->age = ++master_priv->sarea_priv->last_dispatch; /* Emit the vertex buffer age */ BEGIN_RING(2); @@ -1596,12 +1604,14 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev, } } -static void radeon_cp_dispatch_indices(struct drm_device * dev, +static void radeon_cp_dispatch_indices(struct drm_device *dev, + struct drm_master *master, struct drm_buf * elt_buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + prim->offset; u32 *data; int dwords; @@ -1876,7 +1886,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, ADVANCE_RING(); COMMIT_RING(); - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); /* Update the input parameters for next time */ image->y += height; @@ -2126,7 +2136,8 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_clear_t *clear = data; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG("\n"); @@ -2142,7 +2153,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * sarea_priv->nbox * sizeof(depth_boxes[0]))) return -EFAULT; - radeon_cp_dispatch_clear(dev, clear, depth_boxes); + radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes); COMMIT_RING(); return 0; @@ -2150,9 +2161,10 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * /* Not sure why this isn't set all the time: */ -static int radeon_do_init_pageflip(struct drm_device * dev) +static int radeon_do_init_pageflip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; RING_LOCALS; DRM_DEBUG("\n"); @@ -2169,8 +2181,8 @@ static int radeon_do_init_pageflip(struct drm_device * dev) dev_priv->page_flipping = 1; - if (dev_priv->sarea_priv->pfCurrentPage != 1) - dev_priv->sarea_priv->pfCurrentPage = 0; + if (master_priv->sarea_priv->pfCurrentPage != 1) + master_priv->sarea_priv->pfCurrentPage = 0; return 0; } @@ -2188,9 +2200,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f RING_SPACE_TEST_WITH_RETURN(dev_priv); if (!dev_priv->page_flipping) - radeon_do_init_pageflip(dev); + radeon_do_init_pageflip(dev, file_priv->master); - radeon_cp_dispatch_flip(dev); + radeon_cp_dispatch_flip(dev, file_priv->master); COMMIT_RING(); return 0; @@ -2199,7 +2211,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; + DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -2209,8 +2223,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - radeon_cp_dispatch_swap(dev); - dev_priv->sarea_priv->ctx_owner = 0; + radeon_cp_dispatch_swap(dev, file_priv->master); + sarea_priv->ctx_owner = 0; COMMIT_RING(); return 0; @@ -2219,6 +2233,7 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2232,7 +2247,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); @@ -2286,13 +2301,13 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file prim.finish = vertex->count; /* unused */ prim.prim = vertex->prim; prim.numverts = vertex->count; - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_vertex(dev, buf, &prim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim); } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2302,6 +2317,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2315,7 +2331,7 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file DRM_ERROR("called with no initialization\n"); return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", DRM_CURRENTPID, elts->idx, elts->start, elts->end, @@ -2382,11 +2398,11 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file prim.prim = elts->prim; prim.offset = 0; /* offset from start of dma buffers */ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_indices(dev, buf, &prim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim); if (elts->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2502,7 +2518,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil */ radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); if (indirect->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2512,6 +2528,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2526,7 +2543,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->discard); @@ -2588,12 +2605,12 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file tclprim.offset = prim.numverts * 64; tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - radeon_cp_dispatch_indices(dev, buf, &tclprim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim); } else { tclprim.numverts = prim.numverts; tclprim.offset = 0; /* not used */ - radeon_cp_dispatch_vertex(dev, buf, &tclprim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim); } if (sarea_priv->nbox == 1) @@ -2601,7 +2618,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2955,7 +2972,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file goto err; } - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); break; case RADEON_CMD_PACKET3: @@ -3071,7 +3088,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil */ case RADEON_PARAM_SAREA_HANDLE: /* The lock is the first dword in the sarea. */ - value = (long)dev->lock.hw_lock; + value = (long)dev->primary->master->lock.hw_lock; break; #endif case RADEON_PARAM_GART_TEX_HANDLE: @@ -3116,6 +3133,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_setparam_t *sp = data; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3135,14 +3153,14 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil DRM_DEBUG("color tiling disabled\n"); dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->tiling_enabled = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 0; } else if (sp->value == 1) { DRM_DEBUG("color tiling enabled\n"); dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->tiling_enabled = 1; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 1; } break; case RADEON_SETPARAM_PCIGART_LOCATION: @@ -3189,14 +3207,6 @@ void radeon_driver_preclose(struct drm_device *dev, void radeon_driver_lastclose(struct drm_device *dev) { - if (dev->dev_private) { - drm_radeon_private_t *dev_priv = dev->dev_private; - - if (dev_priv->sarea_priv && - dev_priv->sarea_priv->pfCurrentPage != 0) - radeon_cp_dispatch_flip(dev); - } - radeon_do_release(dev); } @@ -3257,7 +3267,18 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH) + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PIN, radeon_gem_pin_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_UNPIN, radeon_gem_unpin_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_INDIRECT, radeon_gem_indirect_ioctl, DRM_AUTH), }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); |