Commit 475e2b97 authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

drm/mgag200: Split up connector's mode_valid helper



Split up the connector's mode_valid helper into a simple-pipe and a
mode-config helper. The simple-pipe helper tests for display-size
limits while the mode-config helper tests for memory-bandwidth limits.

Also add the mgag200_ prefix to mga_vga_calculate_mode_bandwidth() and
comment on the function's purpose.

The memory-bandwidth tests assume that the display uses 4 bytes per
pixel. The first models of G200SE-A only had 1.75 MiB of VRAM, which
limits these devices to 640x480-32.

v2:
	* note the memory constraints on early G200SE-A

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/20220516134343.6085-8-tzimmermann@suse.de
parent 69340e52
Loading
Loading
Loading
Loading
+69 −77
Original line number Diff line number Diff line
@@ -705,38 +705,27 @@ static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connecto
	return ret;
}

static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
							int bits_per_pixel)
{
	uint32_t total_area, divisor;
	uint64_t active_area, pixels_per_second, bandwidth;
	uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;

	divisor = 1024;

	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;
	do_div(pixels_per_second, total_area);

	bandwidth = pixels_per_second * bytes_per_pixel * 100;
	do_div(bandwidth, divisor);
static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
	.get_modes  = mgag200_vga_connector_helper_get_modes,
};

	return (uint32_t)(bandwidth);
}
static const struct drm_connector_funcs mga_vga_connector_funcs = {
	.reset                  = drm_atomic_helper_connector_reset,
	.fill_modes             = drm_helper_probe_single_connector_modes,
	.destroy                = drm_connector_cleanup,
	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
};

#define MODE_BANDWIDTH	MODE_BAD
/*
 * Simple Display Pipe
 */

static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
				 struct drm_display_mode *mode)
static enum drm_mode_status
mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
				       const struct drm_display_mode *mode)
{
	struct drm_device *dev = connector->dev;
	struct mga_device *mdev = to_mga_device(dev);
	int bpp = 32;
	struct mga_device *mdev = to_mga_device(pipe->crtc.dev);

	if (IS_G200_SE(mdev)) {
		u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
@@ -746,42 +735,17 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
				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 (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 (mga_vga_calculate_mode_bandwidth(mode, bpp)
				> (55000 * 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 (mdev->type == G200_EH &&
		(mga_vga_calculate_mode_bandwidth(mode, bpp)
			> (37500 * 1024))) {
		return MODE_BANDWIDTH;
	} else if (mdev->type == G200_ER &&
		(mga_vga_calculate_mode_bandwidth(mode,
			bpp) > (55000 * 1024))) {
		return MODE_BANDWIDTH;
	}

	if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 ||
@@ -799,30 +763,6 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
	return MODE_OK;
}

static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
	.get_modes  = mgag200_vga_connector_helper_get_modes,
	.mode_valid = mga_vga_mode_valid,
};

static const struct drm_connector_funcs mga_vga_connector_funcs = {
	.reset                  = drm_atomic_helper_connector_reset,
	.fill_modes             = drm_helper_probe_single_connector_modes,
	.destroy                = drm_connector_cleanup,
	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
};

/*
 * Simple Display Pipe
 */

static enum drm_mode_status
mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
				       const struct drm_display_mode *mode)
{
	return MODE_OK;
}

static void
mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
		      struct drm_rect *clip, const struct iosys_map *map)
@@ -1055,6 +995,31 @@ static const uint64_t mgag200_simple_display_pipe_fmtmods[] = {
 * Mode config
 */

/* Calculates a mode's required memory bandwidth (in KiB/sec). */
static uint32_t mgag200_calculate_mode_bandwidth(const struct drm_display_mode *mode,
						 unsigned int bits_per_pixel)
{
	uint32_t total_area, divisor;
	uint64_t active_area, pixels_per_second, bandwidth;
	uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;

	divisor = 1024;

	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;
	do_div(pixels_per_second, total_area);

	bandwidth = pixels_per_second * bytes_per_pixel * 100;
	do_div(bandwidth, divisor);

	return (uint32_t)bandwidth;
}

static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *dev,
							   const struct drm_display_mode *mode)
{
@@ -1070,6 +1035,33 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de
	if (fbpages > max_fbpages)
		return MODE_MEM;

	if (IS_G200_SE(mdev)) {
		u32 unique_rev_id = mdev->model.g200se.unique_rev_id;

		if (unique_rev_id == 0x01) {
			if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (24400 * 1024))
				return MODE_BAD;
		} else if (unique_rev_id == 0x02) {
			if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (30100 * 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_OK;
}