/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* 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.
*
* Authors: AMD
*
*/
#include "dm_services.h"
#include "dc.h"
#include "mod_freesync.h"
#include "core_types.h"
#define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
#define MIN_REFRESH_RANGE_IN_US 10000000
/* Refresh rate ramp at a fixed rate of 65 Hz/second */
#define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
/* Number of elements in the render times cache array */
#define RENDER_TIMES_MAX_COUNT 10
/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
#define BTR_EXIT_MARGIN 2000
/* Threshold to change BTR multiplier (to avoid frequent changes) */
#define BTR_DRIFT_MARGIN 2000
/*Threshold to exit fixed refresh rate*/
#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4
/* Number of consecutive frames to check before entering/exiting fixed refresh*/
#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
#define FIXED_REFRESH_EXIT_FRAME_COUNT 5
struct core_freesync {
struct mod_freesync public;
struct dc *dc;
};
void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value)
{
unsigned int shift = 0;
if (!mask || !dest)
return;
while (!((mask >> shift) & 1))
shift++;
//reset
*dest = *dest & ~mask;
//set
//dont let value span past mask
value = value & (mask >> shift);
//insert value
*dest = *dest | (value << shift);
}
// VTEM Byte Offset
#define VRR_VTEM_PB0 0
#define VRR_VTEM_PB1 1
#define VRR_VTEM_PB2 2
#define VRR_VTEM_PB3 3
#define VRR_VTEM_PB4 4
#define VRR_VTEM_PB5 5
#define VRR_VTEM_PB6 6
#define VRR_VTEM_MD0 7
#define VRR_VTEM_MD1 8
#define VRR_VTEM_MD2 9
#define VRR_VTEM_MD3 10
// VTEM Byte Masks
//PB0
#define MASK__VRR_VTEM_PB0__RESERVED0 0x01
#define MASK__VRR_VTEM_PB0__SYNC 0x02
#define MASK__VRR_VTEM_PB0__VFR 0x04
#define MASK__VRR_VTEM_PB0__AFR 0x08
#define MASK__VRR_VTEM_PB0__DS_TYPE 0x30
//0: Periodic pseudo-static EM Data Set
//1: Periodic dynamic EM Data Set
//2: Unique EM Data Set
//3: Reserved
#define MASK__VRR_VTEM_PB0__END 0x40
#define MASK__VRR_VTEM_PB0__NEW 0x80
//PB1
#define MASK__VRR_VTEM_PB1__RESERVED1 0xFF
//PB2
#define MASK__VRR_VTEM_PB2__ORGANIZATION_ID 0xFF
//0: This is a Vendor Specific EM Data Set
//1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean)
//2: This EM Data Set is defined by CTA-861-G
//3: This EM Data Set is defined by VESA
//PB3
#define MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB 0xFF
//PB4
#define MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB 0xFF
//PB5
#define MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF
//PB6
#define MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF
//PB7-27 (20 bytes):
//PB7 = MD0
#define MASK__VRR_VTEM_MD0__VRR_EN 0x01
#define MASK__VRR_VTEM_MD0__M_CONST 0x02
#define MASK__VRR_VTEM_MD0__RESERVED2 0x0C
#define MASK__VRR_VTEM_MD0__FVA_FACTOR_M1 0xF0
//MD1
#define MASK__VRR_VTEM_MD1__BASE_VFRONT 0xFF
//MD2
#define MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98 0x03
#define MASK__VRR_VTEM_MD2__RB 0x04
#define MASK__VRR_VTEM_MD2__RESERVED3 0xF8
//MD3
#define MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF
#define MOD_FREESYNC_TO_CORE(mod_freesync)\
container_of(mod_freesync, struct core_freesync, public)
struct mod_freesync *mod_freesync_create(struct dc *dc)
{
struct core_freesync *core_freesync =
kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
if (core_freesync == NULL)
goto fail_alloc_context;
if (dc == NULL)
goto fail_construct;
core_freesync->dc = dc;
return &core_freesync->public;
fail_construct:
kfree(core_freesync);
fail_alloc_context:
return NULL;
}
void mod_freesync_destroy(struct mod_freesync *mod_freesync)
{
struct core_freesync *core_freesync = NULL;
if (mod_freesync == NULL)
return;
core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
kfree(core_freesync);
}
#if 0 /* unused currently */
static unsigned int calc_refresh_in_uhz_from_duration(
unsigned int duration_in_ns)
{
unsigned int refresh_in_uhz =
((unsigned int)(div64_u64((1000000000ULL * 1000000),
duration_in_ns)));
return refresh_in_uhz;