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: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> Tested-by: Jocelyn Falempe <jfalempe@redhat.com> Acked-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220728124103.30159-11-tzimmermann@suse.de
This commit is contained in:
parent
f639f74a78
commit
8aeeb3144f
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
mgag200-y := \
|
||||
mgag200_bmc.o \
|
||||
mgag200_drv.o \
|
||||
mgag200_g200.o \
|
||||
mgag200_g200eh.o \
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// 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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -131,95 +131,6 @@ static inline void mga_wait_busy(struct mga_device *mdev)
|
|||
} while ((status & 0x01) && time_before(jiffies, timeout));
|
||||
}
|
||||
|
||||
static void mgag200_g200wb_hold_bmc(struct mga_device *mdev)
|
||||
{
|
||||
u8 tmp;
|
||||
int iter_max;
|
||||
|
||||
/* 1- The first step is to warn 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 and further scan request
|
||||
* This will be 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 verifu if there is an active scan
|
||||
* We are searching 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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mgag200_g200wb_release_bmc(struct mga_device *mdev)
|
||||
{
|
||||
u8 tmp;
|
||||
|
||||
/* 1- The first step is to ensure that the vrsten and hrsten are set */
|
||||
WREG8(MGAREG_CRTCEXT_INDEX, 1);
|
||||
tmp = RREG8(MGAREG_CRTCEXT_DATA);
|
||||
WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);
|
||||
|
||||
/* 2- second step is to assert the rstlvl2 */
|
||||
WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
|
||||
tmp = RREG8(DAC_DATA);
|
||||
tmp |= 0x8;
|
||||
WREG8(DAC_DATA, tmp);
|
||||
|
||||
/* wait 10 us */
|
||||
udelay(10);
|
||||
|
||||
/* 3- deassert rstlvl2 */
|
||||
tmp &= ~0x08;
|
||||
WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
|
||||
WREG8(DAC_DATA, tmp);
|
||||
|
||||
/* 4- remove mask of scan request */
|
||||
WREG8(DAC_INDEX, MGA1064_SPAREREG);
|
||||
tmp = RREG8(DAC_DATA);
|
||||
tmp &= ~0x80;
|
||||
WREG8(DAC_DATA, tmp);
|
||||
|
||||
/* 5- 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is how the framebuffer base address is stored in g200 cards:
|
||||
* * Assume @offset is the gpu_addr variable of the framebuffer object
|
||||
|
@ -802,14 +713,15 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
|
|||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct mga_device *mdev = to_mga_device(dev);
|
||||
const struct mgag200_device_funcs *funcs = mdev->funcs;
|
||||
struct drm_crtc_state *crtc_state = crtc->state;
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
|
||||
const struct drm_format_info *format = mgag200_crtc_state->format;
|
||||
struct mgag200_pll *pixpll = &mdev->pixpll;
|
||||
|
||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
||||
mgag200_g200wb_hold_bmc(mdev);
|
||||
if (funcs->disable_vidrst)
|
||||
funcs->disable_vidrst(mdev);
|
||||
|
||||
mgag200_set_format_regs(mdev, format);
|
||||
mgag200_set_mode_regs(mdev, adjusted_mode);
|
||||
|
@ -826,22 +738,23 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
|
|||
|
||||
mgag200_enable_display(mdev);
|
||||
|
||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
||||
mgag200_g200wb_release_bmc(mdev);
|
||||
if (funcs->enable_vidrst)
|
||||
funcs->enable_vidrst(mdev);
|
||||
}
|
||||
|
||||
static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct mga_device *mdev = to_mga_device(crtc->dev);
|
||||
const struct mgag200_device_funcs *funcs = mdev->funcs;
|
||||
|
||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
||||
mgag200_g200wb_hold_bmc(mdev);
|
||||
if (funcs->disable_vidrst)
|
||||
funcs->disable_vidrst(mdev);
|
||||
|
||||
mgag200_disable_display(mdev);
|
||||
|
||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
||||
mgag200_g200wb_release_bmc(mdev);
|
||||
if (funcs->enable_vidrst)
|
||||
funcs->enable_vidrst(mdev);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = {
|
||||
|
|
Loading…
Reference in New Issue