// 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_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_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 mgag200_crtc_set_gamma_linear(struct mga_device *mdev,
const struct drm_format_info *format)
{
int i;
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
switch (format->format) {
case DRM_FORMAT_RGB565:
/* Use better interpolation, to take 32 values from 0 to 255 */
for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4);
WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16);
WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4);
}
/* Green has one more bit, so add padding with 0 for red and blue. */
for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16);
WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
}
break;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_XRGB8888:
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
}
break;
default:
drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n",
&format->format);
break;
}
}
static void mgag200_crtc_set_gamma(struct mga_device *mdev,
const struct drm_format_info *format,
struct drm_color_lut *lut)
{
int i;
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
switch (format->format) {
case DRM_FORMAT_RGB565:
/* Use better interpolation, to take 32 values from lut[0] to lut[255] */
for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].red >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].blue >> 8);
}
/* Green has one more bit, so add padding with 0 for red and blue. */
for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
}
break;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_XRGB8888:
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].red >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].green >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].blue >> 8);
}
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 (!