Commit 98da4b99 authored by Thomas Zimmermann's avatar Thomas Zimmermann

drm/mgag200: Store maximum resolution and memory bandwidth in device info

The maximum resolution and memory bandwidth are model-specific limits.
Both are used during display-mode validation. Store the values in struct
mgag200_device_info and simplify the validation code.

v2:
	* 'bandwith' -> 'bandwidth' in commit message
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarJocelyn Falempe <jfalempe@redhat.com>
Tested-by: default avatarJocelyn Falempe <jfalempe@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-9-tzimmermann@suse.de
parent 21e74bf9
...@@ -191,6 +191,15 @@ enum mga_type { ...@@ -191,6 +191,15 @@ enum mga_type {
#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
struct mgag200_device_info { struct mgag200_device_info {
u16 max_hdisplay;
u16 max_vdisplay;
/*
* Maximum memory bandwidth (MiB/sec). Setting this to zero disables
* the rsp test during mode validation.
*/
unsigned long max_mem_bandwidth;
/* /*
* HW does not handle 'startadd' register correctly. Always set * HW does not handle 'startadd' register correctly. Always set
* it's value to 0. * it's value to 0.
...@@ -198,8 +207,12 @@ struct mgag200_device_info { ...@@ -198,8 +207,12 @@ struct mgag200_device_info {
bool bug_no_startadd:1; bool bug_no_startadd:1;
}; };
#define MGAG200_DEVICE_INFO_INIT(_bug_no_startadd) \ #define MGAG200_DEVICE_INFO_INIT(_max_hdisplay, _max_vdisplay, _max_mem_bandwidth, \
_bug_no_startadd) \
{ \ { \
.max_hdisplay = (_max_hdisplay), \
.max_vdisplay = (_max_vdisplay), \
.max_mem_bandwidth = (_max_mem_bandwidth), \
.bug_no_startadd = (_bug_no_startadd), \ .bug_no_startadd = (_bug_no_startadd), \
} }
......
...@@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) ...@@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev)
*/ */
static const struct mgag200_device_info mgag200_g200_device_info = static const struct mgag200_device_info mgag200_g200_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false);
static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200,
const unsigned char *bios, size_t size) const unsigned char *bios, size_t size)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200eh_device_info = static const struct mgag200_device_info mgag200_g200eh_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false);
struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type) enum mga_type type)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200eh3_device_info = static const struct mgag200_device_info mgag200_g200eh3_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false);
struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
const struct drm_driver *drv, const struct drm_driver *drv,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200er_device_info = static const struct mgag200_device_info mgag200_g200er_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false);
struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type) enum mga_type type)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200ev_device_info = static const struct mgag200_device_info mgag200_g200ev_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false);
struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type) enum mga_type type)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200ew3_device_info = static const struct mgag200_device_info mgag200_g200ew3_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false);
static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
{ {
......
...@@ -32,21 +32,37 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) ...@@ -32,21 +32,37 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev)
* DRM device * DRM device
*/ */
static const struct mgag200_device_info mgag200_g200se_a_device_info = static const struct mgag200_device_info mgag200_g200se_a_01_device_info =
MGAG200_DEVICE_INFO_INIT(true); MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, true);
static const struct mgag200_device_info mgag200_g200se_b_device_info = static const struct mgag200_device_info mgag200_g200se_a_02_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, true);
static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) static const struct mgag200_device_info mgag200_g200se_a_03_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false);
static const struct mgag200_device_info mgag200_g200se_b_01_device_info =
MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false);
static const struct mgag200_device_info mgag200_g200se_b_02_device_info =
MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false);
static const struct mgag200_device_info mgag200_g200se_b_03_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false);
static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se)
{ {
struct mga_device *mdev = &g200se->base; struct mga_device *mdev = &g200se->base;
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
/* stash G200 SE model number for later use */ /* stash G200 SE model number for later use */
g200se->unique_rev_id = RREG32(0x1e24); g200se->unique_rev_id = RREG32(0x1e24);
if (!g200se->unique_rev_id)
return -ENODEV;
drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id); drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id);
return 0;
} }
struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
...@@ -75,14 +91,26 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru ...@@ -75,14 +91,26 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
mgag200_g200se_init_unique_id(g200se); ret = mgag200_g200se_init_unique_rev_id(g200se);
if (ret)
return ERR_PTR(ret);
switch (type) { switch (type) {
case G200_SE_A: case G200_SE_A:
info = &mgag200_g200se_a_device_info; if (g200se->unique_rev_id >= 0x03)
info = &mgag200_g200se_a_03_device_info;
else if (g200se->unique_rev_id >= 0x02)
info = &mgag200_g200se_a_02_device_info;
else
info = &mgag200_g200se_a_01_device_info;
break; break;
case G200_SE_B: case G200_SE_B:
info = &mgag200_g200se_b_device_info; if (g200se->unique_rev_id >= 0x03)
info = &mgag200_g200se_b_03_device_info;
else if (g200se->unique_rev_id >= 0x02)
info = &mgag200_g200se_b_02_device_info;
else
info = &mgag200_g200se_b_01_device_info;
break; break;
default: default:
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
static const struct mgag200_device_info mgag200_g200wb_device_info = static const struct mgag200_device_info mgag200_g200wb_device_info =
MGAG200_DEVICE_INFO_INIT(false); MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, false);
struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type) enum mga_type type)
......
...@@ -725,30 +725,17 @@ static enum drm_mode_status ...@@ -725,30 +725,17 @@ static enum drm_mode_status
mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
struct drm_device *dev = pipe->crtc.dev; struct mga_device *mdev = to_mga_device(pipe->crtc.dev);
struct mga_device *mdev = to_mga_device(dev); const struct mgag200_device_info *info = mdev->info;
struct mgag200_g200se_device *g200se;
/*
if (IS_G200_SE(mdev)) { * Some devices have additional limits on the size of the
g200se = to_mgag200_g200se_device(dev); * display mode.
*/
if (g200se->unique_rev_id == 0x01) { if (mode->hdisplay > info->max_hdisplay)
if (mode->hdisplay > 1600) return MODE_VIRTUAL_X;
return MODE_VIRTUAL_X; if (mode->vdisplay > info->max_vdisplay)
if (mode->vdisplay > 1200) return MODE_VIRTUAL_Y;
return MODE_VIRTUAL_Y;
} else if (g200se->unique_rev_id == 0x02) {
if (mode->hdisplay > 1920)
return MODE_VIRTUAL_X;
if (mode->vdisplay > 1200)
return MODE_VIRTUAL_Y;
}
} else if (mdev->type == G200_WB) {
if (mode->hdisplay > 1280)
return MODE_VIRTUAL_X;
if (mode->vdisplay > 1024)
return MODE_VIRTUAL_Y;
}
if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 ||
(mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) {
...@@ -1028,7 +1015,7 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de ...@@ -1028,7 +1015,7 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de
static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888 static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888
struct mga_device *mdev = to_mga_device(dev); struct mga_device *mdev = to_mga_device(dev);
unsigned long fbsize, fbpages, max_fbpages; unsigned long fbsize, fbpages, max_fbpages;
struct mgag200_g200se_device *g200se; const struct mgag200_device_info *info = mdev->info;
max_fbpages = mdev->vram_available >> PAGE_SHIFT; max_fbpages = mdev->vram_available >> PAGE_SHIFT;
...@@ -1038,30 +1025,14 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de ...@@ -1038,30 +1025,14 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de
if (fbpages > max_fbpages) if (fbpages > max_fbpages)
return MODE_MEM; return MODE_MEM;
if (IS_G200_SE(mdev)) { /*
g200se = to_mgag200_g200se_device(dev); * Test the mode's required memory bandwidth if the device
* specifies a maximum. Not all devices do though.
if (g200se->unique_rev_id == 0x01) { */
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (24400 * 1024)) if (info->max_mem_bandwidth) {
return MODE_BAD; uint32_t mode_bandwidth = mgag200_calculate_mode_bandwidth(mode, max_bpp * 8);
} else if (g200se->unique_rev_id == 0x02) {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (30100 * 1024)) if (mode_bandwidth > (info->max_mem_bandwidth * 1024))
return MODE_BAD;
} else {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024))
return MODE_BAD;
}
} else if (mdev->type == G200_WB) {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (31877 * 1024))
return MODE_BAD;
} else if (mdev->type == G200_EV) {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (32700 * 1024))
return MODE_BAD;
} else if (mdev->type == G200_EH) {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (37500 * 1024))
return MODE_BAD;
} else if (mdev->type == G200_ER) {
if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024))
return MODE_BAD; return MODE_BAD;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment