// SPDX-License-Identifier: GPL-2.0-only
#include <linux/aperture.h>
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_connector.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_fbdev_shmem.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "drm_sysfb_helper.h"
#define DRIVER_NAME "ofdrm"
#define DRIVER_DESC "DRM driver for OF platform devices"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define PCI_VENDOR_ID_ATI_R520 0x7100
#define PCI_VENDOR_ID_ATI_R600 0x9400
#define OFDRM_GAMMA_LUT_SIZE 256
/* Definitions used by the Avivo palette */
#define AVIVO_DC_LUT_RW_SELECT 0x6480
#define AVIVO_DC_LUT_RW_MODE 0x6484
#define AVIVO_DC_LUT_RW_INDEX 0x6488
#define AVIVO_DC_LUT_SEQ_COLOR 0x648c
#define AVIVO_DC_LUT_PWL_DATA 0x6490
#define AVIVO_DC_LUT_30_COLOR 0x6494
#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
#define AVIVO_DC_LUT_AUTOFILL 0x64a0
#define AVIVO_DC_LUTA_CONTROL 0x64c0
#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
#define AVIVO_DC_LUTB_CONTROL 0x6cc0
#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
enum ofdrm_model {
OFDRM_MODEL_UNKNOWN,
OFDRM_MODEL_MACH64, /* ATI Mach64 */
OFDRM_MODEL_RAGE128, /* ATI Rage128 */
OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */
OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */
OFDRM_MODEL_RADEON, /* ATI Radeon */
OFDRM_MODEL_GXT2000, /* IBM GXT2000 */
OFDRM_MODEL_AVIVO, /* ATI R5xx */
OFDRM_MODEL_QEMU, /* QEMU VGA */
};
/*
* Helpers for display nodes
*/
static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value)
{
return drm_sysfb_get_validated_int(dev, name, value, INT_MAX);
}
static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value)
{
return drm_sysfb_get_validated_int0(dev, name, value, INT_MAX);
}
static const struct drm_format_info *display_get_validated_format(struct drm_device *dev,
u32 depth, bool big_endian)
{
const struct drm_format_info *info;
u32 format;
switch (depth) {
case 8:
format = drm_mode_legacy_fb_format(8, 8);
break;
case 15:
case 16:
format = drm_mode_legacy_fb_format(16, depth);
break;
case 32:
format = drm_mode_legacy_fb_format(32, 24);
break;
default:
drm_err(dev, "unsupported framebuffer depth %u\n", depth);
return ERR_PTR(-EINVAL);
}
/*
* DRM formats assume little-endian byte order. Update the format
* if the scanout buffer uses big-endian ordering.
*/
if (big_endian) {
switch (format) {
case DRM_FORMAT_XRGB8888:
format = DRM_FORMAT_BGRX8888;
break;
case DRM_FORMAT_ARGB8888:
format = DRM_FORMAT_BGRA8888;
break;
case DRM_FORMAT_RGB565:
format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN;
break;
case DRM_FORMAT_XRGB1555:
format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN;
break;
default:
break;
}
}
info = drm_format_info(format);
if (!info) {
drm_err(dev, "cannot find framebuffer format for depth %u\n", depth);
return ERR_PTR(-EINVAL);
}
return info;
}
static int