Commit 8aeeb314 authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

drm/mgag200: Provide per-device callbacks for BMC synchronization



Move the BMC-related code into its own file and wire it up with device
callbacks.

While programming a new display mode, G200EW3 and G200WB have to de-
synchronize with the BMC. Synchronization is done via VIDRST pins
and controlled via VRSTEN and HRSTEN bits. Move the BMC code behind
a serviceable interface and call it from the CRTC's enable and
disable functions.

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>
Acked-by: default avatarSam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220728124103.30159-11-tzimmermann@suse.de
parent f639f74a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
mgag200-y := \
	mgag200_bmc.o \
	mgag200_drv.o \
	mgag200_g200.o \
	mgag200_g200eh.o \
+99 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/delay.h>

#include "mgag200_drv.h"

void mgag200_bmc_disable_vidrst(struct mga_device *mdev)
{
	u8 tmp;
	int iter_max;

	/*
	 * 1 - The first step is to inform the BMC of an upcoming mode
	 * change. We are putting the misc<0> to output.
	 */

	WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
	tmp = RREG8(DAC_DATA);
	tmp |= 0x10;
	WREG_DAC(MGA1064_GEN_IO_CTL, tmp);

	/* we are putting a 1 on the misc<0> line */
	WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
	tmp = RREG8(DAC_DATA);
	tmp |= 0x10;
	WREG_DAC(MGA1064_GEN_IO_DATA, tmp);

	/*
	 * 2- Second step to mask any further scan request. This is
	 * done by asserting the remfreqmsk bit (XSPAREREG<7>)
	 */

	WREG8(DAC_INDEX, MGA1064_SPAREREG);
	tmp = RREG8(DAC_DATA);
	tmp |= 0x80;
	WREG_DAC(MGA1064_SPAREREG, tmp);

	/*
	 * 3a- The third step is to verify if there is an active scan.
	 * We are waiting for a 0 on remhsyncsts <XSPAREREG<0>).
	 */
	iter_max = 300;
	while (!(tmp & 0x1) && iter_max) {
		WREG8(DAC_INDEX, MGA1064_SPAREREG);
		tmp = RREG8(DAC_DATA);
		udelay(1000);
		iter_max--;
	}

	/*
	 * 3b- This step occurs only if the remove is actually
	 * scanning. We are waiting for the end of the frame which is
	 * a 1 on remvsyncsts (XSPAREREG<1>)
	 */
	if (iter_max) {
		iter_max = 300;
		while ((tmp & 0x2) && iter_max) {
			WREG8(DAC_INDEX, MGA1064_SPAREREG);
			tmp = RREG8(DAC_DATA);
			udelay(1000);
			iter_max--;
		}
	}
}

void mgag200_bmc_enable_vidrst(struct mga_device *mdev)
{
	u8 tmp;

	/* Ensure that the vrsten and hrsten are set */
	WREG8(MGAREG_CRTCEXT_INDEX, 1);
	tmp = RREG8(MGAREG_CRTCEXT_DATA);
	WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);

	/* Assert rstlvl2 */
	WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
	tmp = RREG8(DAC_DATA);
	tmp |= 0x8;
	WREG8(DAC_DATA, tmp);

	udelay(10);

	/* Deassert rstlvl2 */
	tmp &= ~0x08;
	WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
	WREG8(DAC_DATA, tmp);

	/* Remove mask of scan request */
	WREG8(DAC_INDEX, MGA1064_SPAREREG);
	tmp = RREG8(DAC_DATA);
	tmp &= ~0x80;
	WREG8(DAC_DATA, tmp);

	/* Put back a 0 on the misc<0> line */
	WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
	tmp = RREG8(DAC_DATA);
	tmp &= ~0x10;
	WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
}
+15 −0
Original line number Diff line number Diff line
@@ -263,6 +263,17 @@ struct mgag200_device_info {
	}

struct mgag200_device_funcs {
	/*
	 * Disables an external reset source (i.e., BMC) before programming
	 * a new display mode.
	 */
	void (*disable_vidrst)(struct mga_device *mdev);

	/*
	 * Enables an external reset source (i.e., BMC) after programming
	 * a new display mode.
	 */
	void (*enable_vidrst)(struct mga_device *mdev);
};

struct mga_device {
@@ -354,6 +365,10 @@ resource_size_t mgag200_device_probe_vram(struct mga_device *mdev);
void mgag200_init_registers(struct mga_device *mdev);
int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_available);

				/* mgag200_bmc.c */
void mgag200_bmc_disable_vidrst(struct mga_device *mdev);
void mgag200_bmc_enable_vidrst(struct mga_device *mdev);

				/* mgag200_i2c.c */
int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);

+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ static const struct mgag200_device_info mgag200_g200ew3_device_info =
	MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);

static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
	.disable_vidrst = mgag200_bmc_disable_vidrst,
	.enable_vidrst = mgag200_bmc_enable_vidrst,
};

static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
+2 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ static const struct mgag200_device_info mgag200_g200wb_device_info =
	MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);

static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
	.disable_vidrst = mgag200_bmc_disable_vidrst,
	.enable_vidrst = mgag200_bmc_enable_vidrst,
};

struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
Loading