// 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/dma-buf-map.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_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.
*/
static void mga_crtc_load_lut(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
struct drm_framebuffer *fb;
u16 *r_ptr, *g_ptr, *b_ptr;
int i;
if (!crtc->enabled)
return;
if (!mdev->display_pipe.plane.state)
return;
fb = mdev->display_pipe.plane.state->fb;
r_ptr = crtc->gamma_store;
g_ptr = r_ptr + crtc->gamma_size;
b_ptr = g_ptr + crtc->gamma_size;
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
if (fb && fb->format->cpp[0] * 8 == 16) {
int inc = (fb->format->depth == 15) ? 8 : 4;
u8 r, b;
for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
if (fb->format->depth == 16) {
if (i > (MGAG200_LUT_SIZE >> 1)) {
r = b = 0;
} else {
r = *r_ptr++ >> 8;
b = *b_ptr++ >> 8;
r_ptr++;
b_ptr++;
}
} else {
r = *r_ptr++ >> 8;
b = *b_ptr++ >> 8;
}
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
}
return;
}
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8);
}
}
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));
}
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