@@ -168,37 +168,38 @@ enum mga_type {
#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
struct mga_device {
- struct drm_device *dev;
- unsigned long flags;
+ struct drm_device *dev;
+ unsigned long flags;
- resource_size_t rmmio_base;
- resource_size_t rmmio_size;
- void __iomem *rmmio;
+ resource_size_t rmmio_base;
+ resource_size_t rmmio_size;
+ void __iomem *rmmio;
- drm_local_map_t *framebuffer;
+ drm_local_map_t *framebuffer;
- struct mga_mc mc;
- struct mga_mode_info mode_info;
+ struct mga_mc mc;
+ struct mga_mode_info mode_info;
- struct mga_fbdev *mfbdev;
+ struct mga_fbdev *mfbdev;
- bool suspended;
- int num_crtc;
- enum mga_type type;
- int has_sdram;
- struct drm_display_mode mode;
+ bool suspended;
+ int num_crtc;
+ enum mga_type type;
+ int has_sdram;
+ struct drm_display_mode mode;
- int bpp_shifts[4];
+ int bpp_shifts[4];
- int fb_mtrr;
+ int fb_mtrr;
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
- struct ttm_bo_device bdev;
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_global_ref bo_global_ref;
+ struct ttm_bo_device bdev;
} ttm;
- u32 reg_1e24; /* SE model number */
+ /* SE model number stored in reg 0x1e24 */
+ u32 unique_rev_id;
};
@@ -176,7 +176,7 @@ static int mgag200_device_init(struct drm_device *dev,
/* stash G200 SE model number for later use */
if (IS_G200_SE(mdev))
- mdev->reg_1e24 = RREG32(0x1e24);
+ mdev->unique_rev_id = RREG32(0x1e24);
ret = mga_vram_init(mdev);
if (ret)
@@ -1008,7 +1008,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (IS_G200_SE(mdev)) {
- if (mdev->reg_1e24 >= 0x02) {
+ if (mdev->unique_rev_id >= 0x02) {
u8 hi_pri_lvl;
u32 bpp;
u32 mb;
@@ -1038,7 +1038,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
} else {
WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- if (mdev->reg_1e24 >= 0x01)
+ if (mdev->unique_rev_id >= 0x01)
WREG8(MGAREG_CRTCEXT_DATA, 0x03);
else
WREG8(MGAREG_CRTCEXT_DATA, 0x04);
@@ -1410,6 +1410,24 @@ static int mga_vga_get_modes(struct drm_connector *connector)
return ret;
}
+static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode * mode,
+ int bits_per_pixel)
+{
+ uint64_t active_area, total_area, pixels_per_second;
+ uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
+
+ if(!mode->htotal || !mode->vtotal || !mode->clock)
+ return 0;
+
+ active_area = mode->hdisplay * mode->vdisplay;
+ total_area = mode->htotal * mode->vtotal;
+ pixels_per_second = active_area * mode->clock * 1000 / total_area;
+
+ return (uint32_t)(pixels_per_second * bytes_per_pixel * 100 / (1024));
+}
+
+#define MODE_BANDWIDTH MODE_BAD
+
static int mga_vga_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
@@ -1422,6 +1440,39 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
int i = 0;
/* FIXME: Add bandwidth and g200se limitations */
+ if (IS_G200_SE(mdev)) {
+ if (mdev->unique_rev_id == 0x01) {
+ if (mode->hdisplay > 1600)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp) > (24400 * 1024))
+ return MODE_BANDWIDTH;
+ } else if (mdev->unique_rev_id >= 0x02) {
+ if (mode->hdisplay > 1920)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp) > (30100 * 1024))
+ return MODE_BANDWIDTH;
+ }
+ } else if (mdev->type == G200_WB) {
+ if (mode->hdisplay > 1280)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1024)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp > (31877 * 1024)))
+ return MODE_BANDWIDTH;
+ } else if (mdev->type == G200_EV &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp) > (32700 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mode->type == G200_EH &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp) > (37500 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mode->type == G200_ER &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp) > (55000 * 1024))) {
+ return MODE_BANDWIDTH;
+ }
if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
This code was ported from the old xorg mga driver. These limits were implemented as a solution to a number of problems that were seen. These problems were linked to the bandwidth limitations of the g200e series. Signed-off-by: Julia Lemire <jlemire@matrox.com> --- drivers/gpu/drm/mgag200/mgag200_drv.h | 41 ++++++++++++------------ drivers/gpu/drm/mgag200/mgag200_main.c | 2 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 55 ++++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 23 deletions(-)