android13/u-boot/drivers/video/drm/drm_modes.c

277 lines
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright © 1997-2003 by The XFree86 Project, Inc.
* Copyright © 2007 Dave Airlie
* Copyright © 2007-2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
* Copyright 2005-2006 Luc Verhaegen
* Copyright (c) 2001, Andy Ritger aritger@nvidia.com
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
#include <common.h>
#include <drm_modes.h>
#include <linux/compat.h>
#include <malloc.h>
#define PICOS2KHZ(a) (1000000000UL / (a))
#define KHZ2PICOS(a) (1000000000UL / (a))
/**
* drm_mode_create - create a new display mode
*
* Create a new, cleared drm_display_mode.
*
* Returns:
* Pointer to new mode on success, NULL on error.
*/
struct drm_display_mode *drm_mode_create(void)
{
struct drm_display_mode *nmode;
nmode = malloc(sizeof(struct drm_display_mode));
memset(nmode, 0, sizeof(struct drm_display_mode));
if (!nmode)
return NULL;
return nmode;
}
/**
* drm_mode_copy - copy the mode
* @dst: mode to overwrite
* @src: mode to copy
*
* Copy an existing mode into another mode, preserving the object id and
* list head of the destination mode.
*/
void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
{
*dst = *src;
}
/**
* drm_mode_destroy - remove a mode
* @mode: mode to remove
*/
void drm_mode_destroy(struct drm_display_mode *mode)
{
if (!mode)
return;
kfree(mode);
}
static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
return mode1->hdisplay == mode2->hdisplay &&
mode1->hsync_start == mode2->hsync_start &&
mode1->hsync_end == mode2->hsync_end &&
mode1->htotal == mode2->htotal &&
mode1->hskew == mode2->hskew &&
mode1->vdisplay == mode2->vdisplay &&
mode1->vsync_start == mode2->vsync_start &&
mode1->vsync_end == mode2->vsync_end &&
mode1->vtotal == mode2->vtotal &&
mode1->vscan == mode2->vscan;
}
static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
/*
* do clock check convert to PICOS
* so fb modes get matched the same
*/
if (mode1->clock && mode2->clock)
return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
else
return mode1->clock == mode2->clock;
}
static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
(mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
}
static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
(mode2->flags & DRM_MODE_FLAG_3D_MASK);
}
static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
}
/**
* drm_mode_match - test modes for (partial) equality
* @mode1: first mode
* @mode2: second mode
* @match_flags: which parts need to match (DRM_MODE_MATCH_*)
*
* Check to see if @mode1 and @mode2 are equivalent.
*
* Returns:
* True if the modes are (partially) equal, false otherwise.
*/
bool drm_mode_match(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2,
unsigned int match_flags)
{
if (!mode1 && !mode2)
return true;
if (!mode1 || !mode2)
return false;
if (match_flags & DRM_MODE_MATCH_TIMINGS &&
!drm_mode_match_timings(mode1, mode2))
return false;
if (match_flags & DRM_MODE_MATCH_CLOCK &&
!drm_mode_match_clock(mode1, mode2))
return false;
if (match_flags & DRM_MODE_MATCH_FLAGS &&
!drm_mode_match_flags(mode1, mode2))
return false;
if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
!drm_mode_match_3d_flags(mode1, mode2))
return false;
if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
!drm_mode_match_aspect_ratio(mode1, mode2))
return false;
return true;
}
/**
* drm_mode_equal - test modes for equality
* @mode1: first mode
* @mode2: second mode
*
* Check to see if @mode1 and @mode2 are equivalent.
*
* Returns:
* True if the modes are equal, false otherwise.
*/
bool drm_mode_equal(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2)
{
return drm_mode_match(mode1, mode2,
DRM_MODE_MATCH_TIMINGS |
DRM_MODE_MATCH_CLOCK |
DRM_MODE_MATCH_FLAGS |
DRM_MODE_MATCH_3D_FLAGS |
DRM_MODE_MATCH_ASPECT_RATIO);
}
/**
* drm_display_mode_from_videomode - fill in @dmode using @vm,
* @vm: videomode structure to use as source
* @dmode: drm_display_mode structure to use as destination
*
* Fills out @dmode using the display mode specified in @vm.
*/
void drm_display_mode_from_videomode(const struct videomode *vm,
struct drm_display_mode *dmode)
{
dmode->hdisplay = vm->hactive;
dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
dmode->htotal = dmode->hsync_end + vm->hback_porch;
dmode->vdisplay = vm->vactive;
dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
dmode->vtotal = dmode->vsync_end + vm->vback_porch;
dmode->clock = vm->pixelclock / 1000;
dmode->flags = 0;
if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PHSYNC;
else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NHSYNC;
if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PVSYNC;
else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NVSYNC;
if (vm->flags & DISPLAY_FLAGS_INTERLACED)
dmode->flags |= DRM_MODE_FLAG_INTERLACE;
if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
dmode->flags |= DRM_MODE_FLAG_DBLCLK;
}
/**
* drm_display_mode_to_videomode - fill in @vm using @dmode,
* @dmode: drm_display_mode structure to use as source
* @vm: videomode structure to use as destination
*
* Fills out @vm using the display mode specified in @dmode.
*/
void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
struct videomode *vm)
{
vm->hactive = dmode->hdisplay;
vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
vm->hback_porch = dmode->htotal - dmode->hsync_end;
vm->vactive = dmode->vdisplay;
vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
vm->vback_porch = dmode->vtotal - dmode->vsync_end;
vm->pixelclock = dmode->clock * 1000;
vm->flags = 0;
if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
vm->flags |= DISPLAY_FLAGS_INTERLACED;
if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
}