mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
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
6 changed files with 129 additions and 97 deletions
|
@ -1,5 +1,6 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
mgag200-y := \
|
mgag200-y := \
|
||||||
|
mgag200_bmc.o \
|
||||||
mgag200_drv.o \
|
mgag200_drv.o \
|
||||||
mgag200_g200.o \
|
mgag200_g200.o \
|
||||||
mgag200_g200eh.o \
|
mgag200_g200eh.o \
|
||||||
|
|
99
drivers/gpu/drm/mgag200/mgag200_bmc.c
Normal file
99
drivers/gpu/drm/mgag200/mgag200_bmc.c
Normal file
|
@ -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 {
|
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 {
|
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);
|
void mgag200_init_registers(struct mga_device *mdev);
|
||||||
int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_available);
|
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 */
|
/* mgag200_i2c.c */
|
||||||
int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);
|
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);
|
MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
|
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)
|
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);
|
MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
|
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,
|
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));
|
} 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:
|
* This is how the framebuffer base address is stored in g200 cards:
|
||||||
* * Assume @offset is the gpu_addr variable of the framebuffer object
|
* * 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 drm_device *dev = crtc->dev;
|
||||||
struct mga_device *mdev = to_mga_device(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_crtc_state *crtc_state = crtc->state;
|
||||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||||
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
|
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
|
||||||
const struct drm_format_info *format = mgag200_crtc_state->format;
|
const struct drm_format_info *format = mgag200_crtc_state->format;
|
||||||
struct mgag200_pll *pixpll = &mdev->pixpll;
|
struct mgag200_pll *pixpll = &mdev->pixpll;
|
||||||
|
|
||||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
if (funcs->disable_vidrst)
|
||||||
mgag200_g200wb_hold_bmc(mdev);
|
funcs->disable_vidrst(mdev);
|
||||||
|
|
||||||
mgag200_set_format_regs(mdev, format);
|
mgag200_set_format_regs(mdev, format);
|
||||||
mgag200_set_mode_regs(mdev, adjusted_mode);
|
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);
|
mgag200_enable_display(mdev);
|
||||||
|
|
||||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
if (funcs->enable_vidrst)
|
||||||
mgag200_g200wb_release_bmc(mdev);
|
funcs->enable_vidrst(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc,
|
static void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc,
|
||||||
struct drm_atomic_state *old_state)
|
struct drm_atomic_state *old_state)
|
||||||
{
|
{
|
||||||
struct mga_device *mdev = to_mga_device(crtc->dev);
|
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)
|
if (funcs->disable_vidrst)
|
||||||
mgag200_g200wb_hold_bmc(mdev);
|
funcs->disable_vidrst(mdev);
|
||||||
|
|
||||||
mgag200_disable_display(mdev);
|
mgag200_disable_display(mdev);
|
||||||
|
|
||||||
if (mdev->type == G200_WB || mdev->type == G200_EW3)
|
if (funcs->enable_vidrst)
|
||||||
mgag200_g200wb_release_bmc(mdev);
|
funcs->enable_vidrst(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = {
|
static const struct drm_crtc_helper_funcs mgag200_crtc_helper_funcs = {
|
||||||
|
|
Loading…
Reference in a new issue