summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/mgag200/mgag200_mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c')
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c726
1 files changed, 219 insertions, 507 deletions
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 225cca2ed60e..bbab2549243a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -11,24 +11,19 @@
#include <linux/delay.h>
#include <linux/iosys-map.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_atomic_state_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "mgag200_drv.h"
-#define MGAG200_LUT_SIZE 256
-
/*
* This file contains setup code for the CRTC.
*/
@@ -132,95 +127,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
@@ -267,86 +173,10 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
-static void mgag200_set_dac_regs(struct mga_device *mdev)
-{
- size_t i;
- u8 dacvalue[] = {
- /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
- /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
- /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40,
- /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
- /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
- /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- switch (mdev->type) {
- case G200_PCI:
- case G200_AGP:
- dacvalue[MGA1064_SYS_PLL_M] = 0x04;
- dacvalue[MGA1064_SYS_PLL_N] = 0x2D;
- dacvalue[MGA1064_SYS_PLL_P] = 0x19;
- break;
- case G200_SE_A:
- case G200_SE_B:
- dacvalue[MGA1064_VREF_CTL] = 0x03;
- dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
- MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_WB:
- case G200_EW3:
- dacvalue[MGA1064_VREF_CTL] = 0x07;
- break;
- case G200_EV:
- dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_EH:
- case G200_EH3:
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_ER:
- break;
- }
-
- for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
- if ((i <= 0x17) ||
- (i == 0x1b) ||
- (i == 0x1c) ||
- ((i >= 0x1f) && (i <= 0x29)) ||
- ((i >= 0x30) && (i <= 0x37)))
- continue;
- if (IS_G200_SE(mdev) &&
- ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
- continue;
- if ((mdev->type == G200_EV ||
- mdev->type == G200_WB ||
- mdev->type == G200_EH ||
- mdev->type == G200_EW3 ||
- mdev->type == G200_EH3) &&
- (i >= 0x44) && (i <= 0x4e))
- continue;
-
- WREG_DAC(i, dacvalue[i]);
- }
-
- if (mdev->type == G200_ER)
- WREG_DAC(0x90, 0);
-}
-
-static void mgag200_init_regs(struct mga_device *mdev)
+void mgag200_init_registers(struct mga_device *mdev)
{
u8 crtc11, misc;
- mgag200_set_dac_regs(mdev);
-
WREG_SEQ(2, 0x0f);
WREG_SEQ(3, 0x00);
WREG_SEQ(4, 0x0e);
@@ -364,19 +194,12 @@ static void mgag200_init_regs(struct mga_device *mdev)
MGAREG_CRTC11_VINTCLR);
WREG_CRT(0x11, crtc11);
- if (mdev->type == G200_ER)
- WREG_ECRT(0x24, 0x5);
-
- if (mdev->type == G200_EW3)
- WREG_ECRT(0x34, 0x5);
-
misc = RREG8(MGA_MISC_IN);
misc |= MGAREG_MISC_IOADSEL;
WREG8(MGA_MISC_OUT, misc);
}
-static void mgag200_set_mode_regs(struct mga_device *mdev,
- const struct drm_display_mode *mode)
+void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode)
{
const struct mgag200_device_info *info = mdev->info;
unsigned int hdisplay, hsyncstart, hsyncend, htotal;
@@ -500,11 +323,9 @@ static void mgag200_set_offset(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
-static void mgag200_set_format_regs(struct mga_device *mdev,
- const struct drm_framebuffer *fb)
+void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format)
{
struct drm_device *dev = &mdev->base;
- const struct drm_format_info *format = fb->format;
unsigned int bpp, bppshift, scale;
u8 crtcext3, xmulctrl;
@@ -565,76 +386,9 @@ static void mgag200_set_format_regs(struct mga_device *mdev,
WREG_ECRT(3, crtcext3);
}
-static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
+void mgag200_enable_display(struct mga_device *mdev)
{
- static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
- u32 memctl;
-
- memctl = RREG32(MGAREG_MEMCTL);
-
- memctl |= RESET_FLAG;
- WREG32(MGAREG_MEMCTL, memctl);
-
- udelay(1000);
-
- memctl &= ~RESET_FLAG;
- WREG32(MGAREG_MEMCTL, memctl);
-}
-
-static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
- const struct drm_display_mode *mode,
- const struct drm_framebuffer *fb)
-{
- struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base);
- unsigned int hiprilvl;
- u8 crtcext6;
-
- if (g200se->unique_rev_id >= 0x04) {
- hiprilvl = 0;
- } else if (g200se->unique_rev_id >= 0x02) {
- unsigned int bpp;
- unsigned long mb;
-
- if (fb->format->cpp[0] * 8 > 16)
- bpp = 32;
- else if (fb->format->cpp[0] * 8 > 8)
- bpp = 16;
- else
- bpp = 8;
-
- mb = (mode->clock * bpp) / 1000;
- if (mb > 3100)
- hiprilvl = 0;
- else if (mb > 2600)
- hiprilvl = 1;
- else if (mb > 1900)
- hiprilvl = 2;
- else if (mb > 1160)
- hiprilvl = 3;
- else if (mb > 440)
- hiprilvl = 4;
- else
- hiprilvl = 5;
-
- } else if (g200se->unique_rev_id >= 0x01) {
- hiprilvl = 3;
- } else {
- hiprilvl = 4;
- }
-
- crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
-
- WREG_ECRT(0x06, crtcext6);
-}
-
-static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
-{
- WREG_ECRT(0x06, 0x00);
-}
-
-static void mgag200_enable_display(struct mga_device *mdev)
-{
- u8 seq0, seq1, crtcext1;
+ u8 seq0, crtcext1;
RREG_SEQ(0x00, seq0);
seq0 |= MGAREG_SEQ0_SYNCRST |
@@ -648,12 +402,6 @@ static void mgag200_enable_display(struct mga_device *mdev)
mga_wait_vsync(mdev);
mga_wait_busy(mdev);
- RREG_SEQ(0x01, seq1);
- seq1 &= ~MGAREG_SEQ1_SCROFF;
- WREG_SEQ(0x01, seq1);
-
- msleep(20);
-
RREG_ECRT(0x01, crtcext1);
crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
@@ -662,7 +410,7 @@ static void mgag200_enable_display(struct mga_device *mdev)
static void mgag200_disable_display(struct mga_device *mdev)
{
- u8 seq0, seq1, crtcext1;
+ u8 seq0, crtcext1;
RREG_SEQ(0x00, seq0);
seq0 &= ~MGAREG_SEQ0_SYNCRST;
@@ -675,59 +423,127 @@ static void mgag200_disable_display(struct mga_device *mdev)
mga_wait_vsync(mdev);
mga_wait_busy(mdev);
- RREG_SEQ(0x01, seq1);
- seq1 |= MGAREG_SEQ1_SCROFF;
- WREG_SEQ(0x01, seq1);
-
- msleep(20);
-
RREG_ECRT(0x01, crtcext1);
crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF |
MGAREG_CRTCEXT1_HSYNCOFF;
WREG_ECRT(0x01, crtcext1);
}
+static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_map *vmap,
+ struct drm_framebuffer *fb, struct drm_rect *clip)
+{
+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
+
+ iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
+ drm_fb_memcpy(&dst, fb->pitches, vmap, fb, clip);
+}
+
/*
- * Connector
+ * Primary plane
*/
-static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector)
+const uint32_t mgag200_primary_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+};
+
+const size_t mgag200_primary_plane_formats_size = ARRAY_SIZE(mgag200_primary_plane_formats);
+
+const uint64_t mgag200_primary_plane_fmtmods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state)
{
- struct mga_device *mdev = to_mga_device(connector->dev);
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
+ struct drm_framebuffer *new_fb = new_plane_state->fb;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_crtc *new_crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_state = NULL;
+ struct mgag200_crtc_state *new_mgag200_crtc_state;
int ret;
- /*
- * Protect access to I/O registers from concurrent modesetting
- * by acquiring the I/O-register lock.
- */
- mutex_lock(&mdev->rmmio_lock);
- ret = drm_connector_helper_get_modes_from_ddc(connector);
- mutex_unlock(&mdev->rmmio_lock);
+ if (new_crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc);
- return ret;
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, true);
+ if (ret)
+ return ret;
+ else if (!new_plane_state->visible)
+ return 0;
+
+ if (plane->state)
+ fb = plane->state->fb;
+
+ if (!fb || (fb->format != new_fb->format))
+ new_crtc_state->mode_changed = true; /* update PLL settings */
+
+ new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ new_mgag200_crtc_state->format = new_fb->format;
+
+ return 0;
}
-static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
- .get_modes = mgag200_vga_connector_helper_get_modes,
-};
+void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = plane->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_plane_state *plane_state = plane->state;
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_rect damage;
+ u8 seq1;
-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,
-};
+ if (!fb)
+ return;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage);
+ }
+
+ /* Always scanout image at VRAM offset 0 */
+ mgag200_set_startadd(mdev, (u32)0);
+ mgag200_set_offset(mdev, fb);
+
+ if (!old_plane_state->crtc && plane_state->crtc) { // enabling
+ RREG_SEQ(0x01, seq1);
+ seq1 &= ~MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
+ msleep(20);
+ }
+}
+
+void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = plane->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ u8 seq1;
+
+ RREG_SEQ(0x01, seq1);
+ seq1 |= MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
+ msleep(20);
+}
/*
- * Simple Display Pipe
+ * CRTC
*/
-static enum drm_mode_status
-mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
- const struct drm_display_mode *mode)
+enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
{
- struct mga_device *mdev = to_mga_device(pipe->crtc.dev);
+ struct mga_device *mdev = to_mga_device(crtc->dev);
const struct mgag200_device_info *info = mdev->info;
/*
@@ -754,167 +570,112 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
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)
-{
- void __iomem *dst = mdev->vram;
- void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
-
- dst += drm_fb_clip_offset(fb->pitches[0], fb->format, clip);
- drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, clip);
-}
-
-static void
-mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
- struct mgag200_pll *pixpll = &mdev->pixpll;
- struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
- struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
- struct drm_framebuffer *fb = plane_state->fb;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_rect fullscreen = {
- .x1 = 0,
- .x2 = fb->width,
- .y1 = 0,
- .y2 = fb->height,
- };
-
- /*
- * Concurrent operations could possibly trigger a call to
- * drm_connector_helper_funcs.get_modes by trying to read the
- * display modes. Protect access to I/O registers by acquiring
- * the I/O-register lock.
- */
- mutex_lock(&mdev->rmmio_lock);
-
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mgag200_g200wb_hold_bmc(mdev);
-
- mgag200_set_format_regs(mdev, fb);
- mgag200_set_mode_regs(mdev, adjusted_mode);
-
- pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc);
-
- if (mdev->type == G200_ER)
- mgag200_g200er_reset_tagfifo(mdev);
-
- if (IS_G200_SE(mdev))
- mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb);
- else if (mdev->type == G200_EV)
- mgag200_g200ev_set_hiprilvl(mdev);
-
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mgag200_g200wb_release_bmc(mdev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
+ int ret;
- if (crtc_state->gamma_lut)
- mgag200_crtc_set_gamma(mdev, fb->format, crtc_state->gamma_lut->data);
- else
- mgag200_crtc_set_gamma_linear(mdev, fb->format);
+ ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false);
+ if (ret)
+ return ret;
- mgag200_enable_display(mdev);
+ if (!new_crtc_state->enable)
+ return 0;
- mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]);
+ if (new_crtc_state->mode_changed) {
+ if (funcs->pixpllc_atomic_check) {
+ ret = funcs->pixpllc_atomic_check(crtc, new_state);
+ if (ret)
+ return ret;
+ }
+ }
- /* Always scanout image at VRAM offset 0 */
- mgag200_set_startadd(mdev, (u32)0);
- mgag200_set_offset(mdev, fb);
+ if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
+ if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
+ drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length);
+ return -EINVAL;
+ }
+ }
- mutex_unlock(&mdev->rmmio_lock);
+ return drm_atomic_add_affected_planes(new_state, crtc);
}
-static void
-mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct mga_device *mdev = to_mga_device(crtc->dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
- mgag200_disable_display(mdev);
+ if (crtc_state->enable && crtc_state->color_mgmt_changed) {
+ const struct drm_format_info *format = mgag200_crtc_state->format;
+
+ if (crtc_state->gamma_lut)
+ mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);
+ else
+ mgag200_crtc_set_gamma_linear(mdev, format);
+ }
}
-static int
-mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state,
- struct drm_crtc_state *crtc_state)
+void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_plane *plane = plane_state->plane;
- struct drm_device *dev = plane->dev;
+ struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
- struct mgag200_pll *pixpll = &mdev->pixpll;
+ 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);
- struct drm_framebuffer *new_fb = plane_state->fb;
- struct drm_framebuffer *fb = NULL;
- int ret;
+ const struct drm_format_info *format = mgag200_crtc_state->format;
- if (!new_fb)
- return 0;
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
- if (plane->state)
- fb = plane->state->fb;
+ mgag200_set_format_regs(mdev, format);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
- if (!fb || (fb->format != new_fb->format))
- crtc_state->mode_changed = true; /* update PLL settings */
+ if (funcs->pixpllc_atomic_update)
+ funcs->pixpllc_atomic_update(crtc, old_state);
- if (crtc_state->mode_changed) {
- ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock,
- &mgag200_crtc_state->pixpllc);
- if (ret)
- return ret;
- }
+ mgag200_enable_display(mdev);
- if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
- if (crtc_state->gamma_lut->length !=
- MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
- drm_err(dev, "Wrong size for gamma_lut %zu\n",
- crtc_state->gamma_lut->length);
- return -EINVAL;
- }
- }
- return 0;
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
}
-static void
-mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_state)
+void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_plane *plane = &pipe->plane;
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_device *dev = plane->dev;
- struct mga_device *mdev = to_mga_device(dev);
- struct drm_plane_state *state = plane->state;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
- struct drm_framebuffer *fb = state->fb;
- struct drm_rect damage;
- struct drm_atomic_helper_damage_iter iter;
+ struct mga_device *mdev = to_mga_device(crtc->dev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
- if (!fb)
- return;
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
- mutex_lock(&mdev->rmmio_lock);
+ mgag200_disable_display(mdev);
- if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut)
- mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data);
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
+}
- drm_atomic_helper_damage_iter_init(&iter, old_state, state);
- drm_atomic_for_each_plane_damage(&iter, &damage) {
- mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]);
- }
- /* Always scanout image at VRAM offset 0 */
- mgag200_set_startadd(mdev, (u32)0);
- mgag200_set_offset(mdev, fb);
+void mgag200_crtc_reset(struct drm_crtc *crtc)
+{
+ struct mgag200_crtc_state *mgag200_crtc_state;
- mutex_unlock(&mdev->rmmio_lock);
+ if (crtc->state)
+ crtc->funcs->atomic_destroy_state(crtc, crtc->state);
+
+ mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
+ if (mgag200_crtc_state)
+ __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
}
-static struct drm_crtc_state *
-mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe)
+struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_crtc_state *crtc_state = crtc->state;
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
struct mgag200_crtc_state *new_mgag200_crtc_state;
@@ -927,14 +688,14 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe
return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base);
+ new_mgag200_crtc_state->format = mgag200_crtc_state->format;
memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc,
sizeof(new_mgag200_crtc_state->pixpllc));
return &new_mgag200_crtc_state->base;
}
-static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state)
+void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
{
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
@@ -942,50 +703,49 @@ static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis
kfree(mgag200_crtc_state);
}
-static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe)
+/*
+ * Connector
+ */
+
+int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct mgag200_crtc_state *mgag200_crtc_state;
+ struct mga_device *mdev = to_mga_device(connector->dev);
+ int ret;
- if (crtc->state) {
- mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state);
- crtc->state = NULL; /* must be set to NULL here */
- }
+ /*
+ * Protect access to I/O registers from concurrent modesetting
+ * by acquiring the I/O-register lock.
+ */
+ mutex_lock(&mdev->rmmio_lock);
+ ret = drm_connector_helper_get_modes_from_ddc(connector);
+ mutex_unlock(&mdev->rmmio_lock);
- mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
- if (!mgag200_crtc_state)
- return;
- __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
+ return ret;
}
-static const struct drm_simple_display_pipe_funcs
-mgag200_simple_display_pipe_funcs = {
- .mode_valid = mgag200_simple_display_pipe_mode_valid,
- .enable = mgag200_simple_display_pipe_enable,
- .disable = mgag200_simple_display_pipe_disable,
- .check = mgag200_simple_display_pipe_check,
- .update = mgag200_simple_display_pipe_update,
- .reset_crtc = mgag200_simple_display_pipe_reset_crtc,
- .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state,
- .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state,
- DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
-};
-
-static const uint32_t mgag200_simple_display_pipe_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
-};
-
-static const uint64_t mgag200_simple_display_pipe_fmtmods[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
-};
-
/*
* Mode config
*/
+static void mgag200_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct mga_device *mdev = to_mga_device(state->dev);
+
+ /*
+ * Concurrent operations could possibly trigger a call to
+ * drm_connector_helper_funcs.get_modes by trying to read the
+ * display modes. Protect access to I/O registers by acquiring
+ * the I/O-register lock.
+ */
+ mutex_lock(&mdev->rmmio_lock);
+ drm_atomic_helper_commit_tail(state);
+ mutex_unlock(&mdev->rmmio_lock);
+}
+
+static const struct drm_mode_config_helper_funcs mgag200_mode_config_helper_funcs = {
+ .atomic_commit_tail = mgag200_mode_config_helper_atomic_commit_tail,
+};
+
/* 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)
@@ -1048,23 +808,16 @@ static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
-int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available)
+int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available)
{
struct drm_device *dev = &mdev->base;
- struct mga_i2c_chan *i2c = &mdev->i2c;
- struct drm_connector *connector = &mdev->connector;
- struct drm_simple_display_pipe *pipe = &mdev->display_pipe;
- size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats);
int ret;
- mgag200_init_regs(mdev);
-
mdev->vram_available = vram_available;
ret = drmm_mode_config_init(dev);
if (ret) {
- drm_err(dev, "drmm_mode_config_init() failed, error %d\n",
- ret);
+ drm_err(dev, "drmm_mode_config_init() failed: %d\n", ret);
return ret;
}
@@ -1073,48 +826,7 @@ int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available
dev->mode_config.preferred_depth = 24;
dev->mode_config.fb_base = mdev->vram_res->start;
dev->mode_config.funcs = &mgag200_mode_config_funcs;
-
- ret = mgag200_i2c_init(mdev, i2c);
- if (ret) {
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
- return ret;
- }
-
- ret = drm_connector_init_with_ddc(dev, connector,
- &mga_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA,
- &i2c->adapter);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
-
- ret = mgag200_pixpll_init(&mdev->pixpll, mdev);
- if (ret)
- return ret;
-
- ret = drm_simple_display_pipe_init(dev, pipe,
- &mgag200_simple_display_pipe_funcs,
- mgag200_simple_display_pipe_formats,
- format_count,
- mgag200_simple_display_pipe_fmtmods,
- connector);
- if (ret) {
- drm_err(dev,
- "drm_simple_display_pipe_init() failed, error %d\n",
- ret);
- return ret;
- }
-
- drm_plane_enable_fb_damage_clips(&pipe->plane);
-
- /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
- drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE);
-
- drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE);
-
- drm_mode_config_reset(dev);
+ dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs;
return 0;
}