Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/mgag200/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 21 kB image not shown  

Quelle  mgag200_mode.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2010 Matt Turner.
 * Copyright 2012 Red Hat
 *
 * Authors: Matthew Garrett
 *     Matt Turner
 *     Dave Airlie
 */


#include <linux/delay.h>
#include <linux/iosys-map.h>

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_edid.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_panic.h>
#include <drm/drm_print.h>

#include "mgag200_ddc.h"
#include "mgag200_drv.h"

/*
 * This file contains setup code for the CRTC.
 */


static void mgag200_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
      u16 red, u16 green, u16 blue)
{
 struct drm_device *dev = crtc->dev;
 struct mga_device *mdev = to_mga_device(dev);
 u8 i8 = index & 0xff;
 u8 r8 = red >> 8;
 u8 g8 = green >> 8;
 u8 b8 = blue >> 8;

 if (drm_WARN_ON_ONCE(dev, index != i8))
  return/* driver bug */

 WREG8(DAC_INDEX + MGA1064_INDEX, i8);
 WREG8(DAC_INDEX + MGA1064_COL_PAL, r8);
 WREG8(DAC_INDEX + MGA1064_COL_PAL, g8);
 WREG8(DAC_INDEX + MGA1064_COL_PAL, b8);
}

void mgag200_crtc_fill_gamma(struct mga_device *mdev,
        const struct drm_format_info *format)
{
 struct drm_crtc *crtc = &mdev->crtc;

 switch (format->format) {
 case DRM_FORMAT_RGB565:
  drm_crtc_fill_gamma_565(crtc, mgag200_set_gamma_lut);
  break;
 case DRM_FORMAT_RGB888:
 case DRM_FORMAT_XRGB8888:
  drm_crtc_fill_gamma_888(crtc, mgag200_set_gamma_lut);
  break;
 default:
  drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n",
         &format->format);
  break;
 }
}

void mgag200_crtc_load_gamma(struct mga_device *mdev,
        const struct drm_format_info *format,
        struct drm_color_lut *lut)
{
 struct drm_crtc *crtc = &mdev->crtc;

 switch (format->format) {
 case DRM_FORMAT_RGB565:
  drm_crtc_load_gamma_565_from_888(crtc, lut, mgag200_set_gamma_lut);
  break;
 case DRM_FORMAT_RGB888:
 case DRM_FORMAT_XRGB8888:
  drm_crtc_load_gamma_888(crtc, lut, mgag200_set_gamma_lut);
  break;
 default:
  drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n",
         &format->format);
  break;
 }
}

static inline void mga_wait_vsync(struct mga_device *mdev)
{
 unsigned long timeout = jiffies + HZ/10;
 unsigned int status = 0;

 do {
  status = RREG32(MGAREG_STATUS);
 } while ((status & 0x08) && time_before(jiffies, timeout));
 timeout = jiffies + HZ/10;
 status = 0;
 do {
  status = RREG32(MGAREG_STATUS);
 } while (!(status & 0x08) && time_before(jiffies, timeout));
}

static inline void mga_wait_busy(struct mga_device *mdev)
{
 unsigned long timeout = jiffies + HZ;
 unsigned int status = 0;
 do {
  status = RREG8(MGAREG_STATUS + 2);
 } while ((status & 0x01) && time_before(jiffies, timeout));
}

/*
 * This is how the framebuffer base address is stored in g200 cards:
 *   * Assume @offset is the gpu_addr variable of the framebuffer object
 *   * Then addr is the number of _pixels_ (not bytes) from the start of
 *     VRAM to the first pixel we want to display. (divided by 2 for 32bit
 *     framebuffers)
 *   * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
 *      addr<20> -> CRTCEXT0<6>
 *      addr<19-16> -> CRTCEXT0<3-0>
 *      addr<15-8> -> CRTCC<7-0>
 *      addr<7-0> -> CRTCD<7-0>
 *
 *  CRTCEXT0 has to be programmed last to trigger an update and make the
 *  new addr variable take effect.
 */

static void mgag200_set_startadd(struct mga_device *mdev,
     unsigned long offset)
{
 struct drm_device *dev = &mdev->base;
 u32 startadd;
 u8 crtcc, crtcd, crtcext0;

 startadd = offset / 8;

 if (startadd > 0)
  drm_WARN_ON_ONCE(dev, mdev->info->bug_no_startadd);

 /*
 * Can't store addresses any higher than that, but we also
 * don't have more than 16 MiB of memory, so it should be fine.
 */

 drm_WARN_ON(dev, startadd > 0x1fffff);

 RREG_ECRT(0x00, crtcext0);

 crtcc = (startadd >> 8) & 0xff;
 crtcd = startadd & 0xff;
 crtcext0 &= 0xb0;
 crtcext0 |= ((startadd >> 14) & BIT(6)) |
      ((startadd >> 16) & 0x0f);

 WREG_CRT(0x0c, crtcc);
 WREG_CRT(0x0d, crtcd);
 WREG_ECRT(0x00, crtcext0);
}

void mgag200_init_registers(struct mga_device *mdev)
{
 u8 crtc11, misc;

 WREG_SEQ(2, 0x0f);
 WREG_SEQ(3, 0x00);
 WREG_SEQ(4, 0x0e);

 WREG_CRT(10, 0);
 WREG_CRT(11, 0);
 WREG_CRT(12, 0);
 WREG_CRT(13, 0);
 WREG_CRT(14, 0);
 WREG_CRT(15, 0);

 RREG_CRT(0x11, crtc11);
 crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
      MGAREG_CRTC11_VINTEN |
      MGAREG_CRTC11_VINTCLR);
 WREG_CRT(0x11, crtc11);

 misc = RREG8(MGA_MISC_IN);
 misc |= MGAREG_MISC_IOADSEL;
 WREG8(MGA_MISC_OUT, misc);
}

void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode,
      bool set_vidrst)
{
 unsigned int hdispend, hsyncstr, hsyncend, htotal, hblkstr, hblkend;
 unsigned int vdispend, vsyncstr, vsyncend, vtotal, vblkstr, vblkend;
 unsigned int linecomp;
 u8 misc, crtcext1, crtcext2, crtcext5;

 hdispend = mode->crtc_hdisplay / 8 - 1;
 hsyncstr = mode->crtc_hsync_start / 8 - 1;
 hsyncend = mode->crtc_hsync_end / 8 - 1;
 htotal = mode->crtc_htotal / 8 - 1;
 /* Work around hardware quirk */
 if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
  htotal++;
 hblkstr = mode->crtc_hblank_start / 8 - 1;
 hblkend = htotal;

 vdispend = mode->crtc_vdisplay - 1;
 vsyncstr = mode->crtc_vsync_start - 1;
 vsyncend = mode->crtc_vsync_end - 1;
 vtotal = mode->crtc_vtotal - 2;
 vblkstr = mode->crtc_vblank_start - 1;
 vblkend = vtotal + 1;

 linecomp = vdispend;

 misc = RREG8(MGA_MISC_IN);

 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
  misc |= MGAREG_MISC_HSYNCPOL;
 else
  misc &= ~MGAREG_MISC_HSYNCPOL;

 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
  misc |= MGAREG_MISC_VSYNCPOL;
 else
  misc &= ~MGAREG_MISC_VSYNCPOL;

 crtcext1 = (((htotal - 4) & 0x100) >> 8) |
     ((hblkstr & 0x100) >> 7) |
     ((hsyncstr & 0x100) >> 6) |
      (hblkend & 0x40);
 if (set_vidrst)
  crtcext1 |= MGAREG_CRTCEXT1_VRSTEN |
       MGAREG_CRTCEXT1_HRSTEN;

 crtcext2 = ((vtotal & 0xc00) >> 10) |
     ((vdispend & 0x400) >> 8) |
     ((vblkstr & 0xc00) >> 7) |
     ((vsyncstr & 0xc00) >> 5) |
     ((linecomp & 0x400) >> 3);
 crtcext5 = 0x00;

 WREG_CRT(0x00, htotal - 4);
 WREG_CRT(0x01, hdispend);
 WREG_CRT(0x02, hblkstr);
 WREG_CRT(0x03, (hblkend & 0x1f) | 0x80);
 WREG_CRT(0x04, hsyncstr);
 WREG_CRT(0x05, ((hblkend & 0x20) << 2) | (hsyncend & 0x1f));
 WREG_CRT(0x06, vtotal & 0xff);
 WREG_CRT(0x07, ((vtotal & 0x100) >> 8) |
         ((vdispend & 0x100) >> 7) |
         ((vsyncstr & 0x100) >> 6) |
         ((vblkstr & 0x100) >> 5) |
         ((linecomp & 0x100) >> 4) |
         ((vtotal & 0x200) >> 4) |
         ((vdispend & 0x200) >> 3) |
         ((vsyncstr & 0x200) >> 2));
 WREG_CRT(0x09, ((vblkstr & 0x200) >> 4) |
         ((linecomp & 0x200) >> 3));
 WREG_CRT(0x10, vsyncstr & 0xff);
 WREG_CRT(0x11, (vsyncend & 0x0f) | 0x20);
 WREG_CRT(0x12, vdispend & 0xff);
 WREG_CRT(0x14, 0);
 WREG_CRT(0x15, vblkstr & 0xff);
 WREG_CRT(0x16, vblkend & 0xff);
 WREG_CRT(0x17, 0xc3);
 WREG_CRT(0x18, linecomp & 0xff);

 WREG_ECRT(0x01, crtcext1);
 WREG_ECRT(0x02, crtcext2);
 WREG_ECRT(0x05, crtcext5);

 WREG8(MGA_MISC_OUT, misc);
}

static u8 mgag200_get_bpp_shift(const struct drm_format_info *format)
{
 static const u8 bpp_shift[] = {0, 1, 0, 2};

 return bpp_shift[format->cpp[0] - 1];
}

/*
 * Calculates the HW offset value from the framebuffer's pitch. The
 * offset is a multiple of the pixel size and depends on the display
 * format.
 */

static u32 mgag200_calculate_offset(struct mga_device *mdev,
        const struct drm_framebuffer *fb)
{
 u32 offset = fb->pitches[0] / fb->format->cpp[0];
 u8 bppshift = mgag200_get_bpp_shift(fb->format);

 if (fb->format->cpp[0] * 8 == 24)
  offset = (offset * 3) >> (4 - bppshift);
 else
  offset = offset >> (4 - bppshift);

 return offset;
}

static void mgag200_set_offset(struct mga_device *mdev,
          const struct drm_framebuffer *fb)
{
 u8 crtc13, crtcext0;
 u32 offset = mgag200_calculate_offset(mdev, fb);

 RREG_ECRT(0, crtcext0);

 crtc13 = offset & 0xff;

 crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK;
 crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK;

 WREG_CRT(0x13, crtc13);
 WREG_ECRT(0x00, crtcext0);
}

void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format)
{
 struct drm_device *dev = &mdev->base;
 unsigned int bpp, bppshift, scale;
 u8 crtcext3, xmulctrl;

 bpp = format->cpp[0] * 8;

 bppshift = mgag200_get_bpp_shift(format);
 switch (bpp) {
 case 24:
  scale = ((1 << bppshift) * 3) - 1;
  break;
 default:
  scale = (1 << bppshift) - 1;
  break;
 }

 RREG_ECRT(3, crtcext3);

 switch (bpp) {
 case 8:
  xmulctrl = MGA1064_MUL_CTL_8bits;
  break;
 case 16:
  if (format->depth == 15)
   xmulctrl = MGA1064_MUL_CTL_15bits;
  else
   xmulctrl = MGA1064_MUL_CTL_16bits;
  break;
 case 24:
  xmulctrl = MGA1064_MUL_CTL_24bits;
  break;
 case 32:
  xmulctrl = MGA1064_MUL_CTL_32_24bits;
  break;
 default:
  /* BUG: We should have caught this problem already. */
  drm_WARN_ON(dev, "invalid format depth\n");
  return;
 }

 crtcext3 &= ~GENMASK(2, 0);
 crtcext3 |= scale;

 WREG_DAC(MGA1064_MUL_CTL, xmulctrl);

 WREG_GFX(0, 0x00);
 WREG_GFX(1, 0x00);
 WREG_GFX(2, 0x00);
 WREG_GFX(3, 0x00);
 WREG_GFX(4, 0x00);
 WREG_GFX(5, 0x40);
 /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode),
 * so that it doesn't hang when running kexec/kdump on G200_SE rev42.
 */

 WREG_GFX(6, 0x0d);
 WREG_GFX(7, 0x0f);
 WREG_GFX(8, 0x0f);

 WREG_ECRT(3, crtcext3);
}

void mgag200_enable_display(struct mga_device *mdev)
{
 u8 seq0, crtcext1;

 RREG_SEQ(0x00, seq0);
 seq0 |= MGAREG_SEQ0_SYNCRST |
  MGAREG_SEQ0_ASYNCRST;
 WREG_SEQ(0x00, seq0);

 /*
 * TODO: replace busy waiting with vblank IRQ; put
 *       msleep(50) before changing SCROFF
 */

 mga_wait_vsync(mdev);
 mga_wait_busy(mdev);

 RREG_ECRT(0x01, crtcext1);
 crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
 crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
 WREG_ECRT(0x01, crtcext1);
}

static void mgag200_disable_display(struct mga_device *mdev)
{
 u8 seq0, crtcext1;

 RREG_SEQ(0x00, seq0);
 seq0 &= ~MGAREG_SEQ0_SYNCRST;
 WREG_SEQ(0x00, seq0);

 /*
 * TODO: replace busy waiting with vblank IRQ; put
 *       msleep(50) before changing SCROFF
 */

 mga_wait_vsync(mdev);
 mga_wait_busy(mdev);

 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);
}

/*
 * Primary plane
 */


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 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;

 if (new_crtc)
  new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc);

 ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
        DRM_PLANE_NO_SCALING,
        DRM_PLANE_NO_SCALING,
        falsetrue);
 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;
}

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;

 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);
}

void mgag200_primary_plane_helper_atomic_enable(struct drm_plane *plane,
      struct drm_atomic_state *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);
}

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);
}

int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
          struct drm_scanout_buffer *sb)
{
 struct mga_device *mdev = to_mga_device(plane->dev);
 struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);

 if (plane->state && plane->state->fb) {
  sb->format = plane->state->fb->format;
  sb->width = plane->state->fb->width;
  sb->height = plane->state->fb->height;
  sb->pitch[0] = plane->state->fb->pitches[0];
  sb->map[0] = map;
  return 0;
 }
 return -ENODEV;
}

/*
 * CRTC
 */


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(crtc->dev);
 const struct mgag200_device_info *info = mdev->info;

 /*
 * Some devices have additional limits on the size of the
 * display mode.
 */

 if (mode->hdisplay > info->max_hdisplay)
  return MODE_VIRTUAL_X;
 if (mode->vdisplay > info->max_vdisplay)
  return MODE_VIRTUAL_Y;

 if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 ||
     (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) {
  return MODE_H_ILLEGAL;
 }

 if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
     mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
     mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 ||
     mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) {
  return MODE_BAD;
 }

 return MODE_OK;
}

int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
{
 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 *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 (!new_crtc_state->enable)
  return 0;

 ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
 if (ret)
  return ret;

 if (new_crtc_state->mode_changed) {
  if (funcs->pixpllc_atomic_check) {
   ret = funcs->pixpllc_atomic_check(crtc, new_state);
   if (ret)
    return ret;
  }
 }

 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;
  }
 }

 return 0;
}

void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
 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);

 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_load_gamma(mdev, format, crtc_state->gamma_lut->data);
  else
   mgag200_crtc_fill_gamma(mdev, format);
 }
}

void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
 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;

 mgag200_set_format_regs(mdev, format);
 mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);

 if (funcs->pixpllc_atomic_update)
  funcs->pixpllc_atomic_update(crtc, old_state);

 if (crtc_state->gamma_lut)
  mgag200_crtc_load_gamma(mdev, format, crtc_state->gamma_lut->data);
 else
  mgag200_crtc_fill_gamma(mdev, format);

 mgag200_enable_display(mdev);
}

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);

 mgag200_disable_display(mdev);
}

void mgag200_crtc_reset(struct drm_crtc *crtc)
{
 struct mgag200_crtc_state *mgag200_crtc_state;

 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);
}

struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *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;

 if (!crtc_state)
  return NULL;

 new_mgag200_crtc_state = kzalloc(sizeof(*new_mgag200_crtc_state), GFP_KERNEL);
 if (!new_mgag200_crtc_state)
  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));
 new_mgag200_crtc_state->set_vidrst = mgag200_crtc_state->set_vidrst;

 return &new_mgag200_crtc_state->base;
}

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);

 __drm_atomic_helper_crtc_destroy_state(&mgag200_crtc_state->base);
 kfree(mgag200_crtc_state);
}

/*
 * 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)
{
 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)
{
 static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888
 struct mga_device *mdev = to_mga_device(dev);
 unsigned long fbsize, fbpages, max_fbpages;
 const struct mgag200_device_info *info = mdev->info;

 max_fbpages = mdev->vram_available >> PAGE_SHIFT;

 fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
 fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);

 if (fbpages > max_fbpages)
  return MODE_MEM;

 /*
 * Test the mode's required memory bandwidth if the device
 * specifies a maximum. Not all devices do though.
 */

 if (info->max_mem_bandwidth) {
  uint32_t mode_bandwidth = mgag200_calculate_mode_bandwidth(mode, max_bpp * 8);

  if (mode_bandwidth > (info->max_mem_bandwidth * 1024))
   return MODE_BAD;
 }

 return MODE_OK;
}

static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
 .fb_create = drm_gem_fb_create_with_dirty,
 .mode_valid = mgag200_mode_config_mode_valid,
 .atomic_check = drm_atomic_helper_check,
 .atomic_commit = drm_atomic_helper_commit,
};

int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available)
{
 struct drm_device *dev = &mdev->base;
 int ret;

 mdev->vram_available = vram_available;

 ret = drmm_mode_config_init(dev);
 if (ret) {
  drm_err(dev, "drmm_mode_config_init() failed: %d\n", ret);
  return ret;
 }

 dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH;
 dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
 dev->mode_config.preferred_depth = 24;
 dev->mode_config.funcs = &mgag200_mode_config_funcs;
 dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs;

 return 0;
}

Messung V0.5
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.8 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.