Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,35 @@
#
# Copyright 2017 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.
#
#
# Makefile for the 'controller' sub-component of DAL.
# It provides the control and status of HW CRTC block.
CFLAGS_$(AMDDALPATH)/dc/dce110/dce110_resource.o = -Wno-override-init
DCE110 = dce110_timing_generator.o \
dce110_compressor.o dce110_opp_regamma_v.o \
dce110_opp_csc_v.o dce110_timing_generator_v.o \
dce110_mem_input_v.o dce110_opp_v.o dce110_transform_v.o
AMD_DAL_DCE110 = $(addprefix $(AMDDALPATH)/dc/dce110/,$(DCE110))
AMD_DISPLAY_FILES += $(AMD_DAL_DCE110)
@@ -0,0 +1,458 @@
/*
* Copyright 2012-15 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 "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#include "gmc/gmc_8_2_sh_mask.h"
#include "gmc/gmc_8_2_d.h"
#include "include/logger_interface.h"
#include "dce110_compressor.h"
#define DC_LOGGER \
cp110->base.ctx->logger
#define DCP_REG(reg)\
(reg + cp110->offsets.dcp_offset)
#define DMIF_REG(reg)\
(reg + cp110->offsets.dmif_offset)
static const struct dce110_compressor_reg_offsets reg_offsets[] = {
{
.dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
.dmif_offset =
(mmDMIF_PG0_DPG_PIPE_DPM_CONTROL
- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
},
{
.dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
.dmif_offset =
(mmDMIF_PG1_DPG_PIPE_DPM_CONTROL
- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
},
{
.dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
.dmif_offset =
(mmDMIF_PG2_DPG_PIPE_DPM_CONTROL
- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
}
};
static uint32_t align_to_chunks_number_per_line(uint32_t pixels)
{
return 256 * ((pixels + 255) / 256);
}
static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst)
{
uint32_t value;
uint32_t frame_count;
uint32_t status_pos;
uint32_t retry = 0;
struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
cp110->offsets = reg_offsets[crtc_inst];
status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION));
/* Only if CRTC is enabled and counter is moving we wait for one frame. */
if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) {
/* Resetting LB on VBlank */
value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT));
for (retry = 10000; retry > 0; retry--) {
if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)))
break;
udelay(10);
}
if (!retry)
dm_error("Frame count did not increase for 100ms.\n");
/* Resetting LB on VBlank */
value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
}
}
static void wait_for_fbc_state_changed(
struct dce110_compressor *cp110,
bool enabled)
{
uint32_t counter = 0;
uint32_t addr = mmFBC_STATUS;
uint32_t value;
while (counter < 1000) {
value = dm_read_reg(cp110->base.ctx, addr);
if (get_reg_field_value(
value,
FBC_STATUS,
FBC_ENABLE_STATUS) == enabled)
break;
udelay(100);
counter++;
}
if (counter == 1000) {
DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied",
__func__);
} else {
DC_LOG_SYNC("FBC status changed to %d", enabled);
}
}
void dce110_compressor_power_up_fbc(struct compressor *compressor)
{
uint32_t value;
uint32_t addr;
addr = mmFBC_CNTL;
value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
/* HW needs to do power measurement comparison. */
set_reg_field_value(
value,
0,
FBC_CNTL,
FBC_COMP_CLK_GATE_EN);
}
dm_write_reg(compressor->ctx, addr, value);
addr = mmFBC_COMP_MODE;
value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
dm_write_reg(compressor->ctx, addr, value);
addr = mmFBC_COMP_CNTL;
value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
dm_write_reg(compressor->ctx, addr, value);
/*FBC_MIN_COMPRESSION 0 ==> 2:1 */
/* 1 ==> 4:1 */
/* 2 ==> 8:1 */
/* 0xF ==> 1:1 */
set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
dm_write_reg(compressor->ctx, addr, value);
compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
value = 0;
dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
value = 0xFFFFFF;
dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
}
void dce110_compressor_enable_fbc(
struct compressor *compressor,
struct compr_addr_and_pitch_params *params)
{
struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
if (compressor->options.bits.FBC_SUPPORT &&
(!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL))) {
uint32_t addr;
uint32_t value, misc_value;
addr = mmFBC_CNTL;
value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
/* params->inst is valid HW CRTC instance start from 0 */
set_reg_field_value(
value,
params->inst,
FBC_CNTL, FBC_SRC_SEL);
dm_write_reg(compressor->ctx, addr, value);
/* Keep track of enum controller_id FBC is attached to */
compressor->is_enabled = true;
/* attached_inst is SW CRTC instance start from 1
* 0 = CONTROLLER_ID_UNDEFINED means not attached crtc
*/
compressor->attached_inst = params->inst + CONTROLLER_ID_D0;
/* Toggle it as there is bug in HW */
set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
dm_write_reg(compressor->ctx, addr, value);
/* FBC usage with scatter & gather for dce110 */
misc_value = dm_read_reg(compressor->ctx, mmFBC_MISC);
set_reg_field_value(misc_value, 1,
FBC_MISC, FBC_INVALIDATE_ON_ERROR);
set_reg_field_value(misc_value, 1,
FBC_MISC, FBC_DECOMPRESS_ERROR_CLEAR);
set_reg_field_value(misc_value, 0x14,
FBC_MISC, FBC_SLOW_REQ_INTERVAL);
dm_write_reg(compressor->ctx, mmFBC_MISC, misc_value);
/* Enable FBC */
set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
dm_write_reg(compressor->ctx, addr, value);
wait_for_fbc_state_changed(cp110, true);
}
}
void dce110_compressor_disable_fbc(struct compressor *compressor)
{
struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
uint32_t crtc_inst = 0;
if (compressor->options.bits.FBC_SUPPORT) {
if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) {
uint32_t reg_data;
/* Turn off compression */
reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
/* Reset enum controller_id to undefined */
compressor->attached_inst = 0;
compressor->is_enabled = false;
wait_for_fbc_state_changed(cp110, false);
}
/* Sync line buffer which fbc was attached to dce100/110 only */
if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3)
reset_lb_on_vblank(compressor,
crtc_inst - CONTROLLER_ID_D0);
}
}
bool dce110_compressor_is_fbc_enabled_in_hw(
struct compressor *compressor,
uint32_t *inst)
{
/* Check the hardware register */
uint32_t value;
value = dm_read_reg(compressor->ctx, mmFBC_STATUS);
if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
if (inst != NULL)
*inst = compressor->attached_inst;
return true;
}
value = dm_read_reg(compressor->ctx, mmFBC_MISC);
if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
value = dm_read_reg(compressor->ctx, mmFBC_CNTL);
if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
if (inst != NULL)
*inst =
compressor->attached_inst;
return true;
}
}
return false;
}
void dce110_compressor_program_compressed_surface_address_and_pitch(
struct compressor *compressor,
struct compr_addr_and_pitch_params *params)
{
struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
uint32_t value = 0;
uint32_t fbc_pitch = 0;
uint32_t compressed_surf_address_low_part =
compressor->compr_surface_address.addr.low_part;
cp110->offsets = reg_offsets[params->inst];
/* Clear content first. */
dm_write_reg(
compressor->ctx,
DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
0);
dm_write_reg(compressor->ctx,
DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
/* Write address, HIGH has to be first. */
dm_write_reg(compressor->ctx,
DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
compressor->compr_surface_address.addr.high_part);
dm_write_reg(compressor->ctx,
DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
compressed_surf_address_low_part);
fbc_pitch = align_to_chunks_number_per_line(params->source_view_width);
if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
fbc_pitch = fbc_pitch / 8;
else
DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio",
__func__);
/* Clear content first. */
dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
/* Write FBC Pitch. */
set_reg_field_value(
value,
fbc_pitch,
GRPH_COMPRESS_PITCH,
GRPH_COMPRESS_PITCH);
dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
}
void dce110_compressor_set_fbc_invalidation_triggers(
struct compressor *compressor,
uint32_t fbc_trigger)
{
/* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19)
* for DCE 11 regions cannot be used - does not work with S/G
*/
uint32_t addr = mmFBC_CLIENT_REGION_MASK;
uint32_t value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(
value,
0,
FBC_CLIENT_REGION_MASK,
FBC_MEMORY_REGION_MASK);
dm_write_reg(compressor->ctx, addr, value);
/* Setup events when to clear all CSM entries (effectively marking
* current compressed data invalid)
* For DCE 11 CSM metadata 11111 means - "Not Compressed"
* Used as the initial value of the metadata sent to the compressor
* after invalidation, to indicate that the compressor should attempt
* to compress all chunks on the current pass. Also used when the chunk
* is not successfully written to memory.
* When this CSM value is detected, FBC reads from the uncompressed
* buffer. Set events according to passed in value, these events are
* valid for DCE11:
* - bit 0 - display register updated
* - bit 28 - memory write from any client except from MCIF
* - bit 29 - CG static screen signal is inactive
* In addition, DCE11.1 also needs to set new DCE11.1 specific events
* that are used to trigger invalidation on certain register changes,
* for example enabling of Alpha Compression may trigger invalidation of
* FBC once bit is set. These events are as follows:
* - Bit 2 - FBC_GRPH_COMP_EN register updated
* - Bit 3 - FBC_SRC_SEL register updated
* - Bit 4 - FBC_MIN_COMPRESSION register updated
* - Bit 5 - FBC_ALPHA_COMP_EN register updated
* - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated
* - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated
*/
addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
value = dm_read_reg(compressor->ctx, addr);
set_reg_field_value(
value,
fbc_trigger,
FBC_IDLE_FORCE_CLEAR_MASK,
FBC_IDLE_FORCE_CLEAR_MASK);
dm_write_reg(compressor->ctx, addr, value);
}
struct compressor *dce110_compressor_create(struct dc_context *ctx)
{
struct dce110_compressor *cp110 =
kzalloc_obj(struct dce110_compressor);
if (!cp110)
return NULL;
dce110_compressor_construct(cp110, ctx);
return &cp110->base;
}
void dce110_compressor_destroy(struct compressor **compressor)
{
kfree(TO_DCE110_COMPRESSOR(*compressor));
*compressor = NULL;
}
static const struct compressor_funcs dce110_compressor_funcs = {
.power_up_fbc = dce110_compressor_power_up_fbc,
.enable_fbc = dce110_compressor_enable_fbc,
.disable_fbc = dce110_compressor_disable_fbc,
.set_fbc_invalidation_triggers = dce110_compressor_set_fbc_invalidation_triggers,
.surface_address_and_pitch = dce110_compressor_program_compressed_surface_address_and_pitch,
.is_fbc_enabled_in_hw = dce110_compressor_is_fbc_enabled_in_hw
};
void dce110_compressor_construct(struct dce110_compressor *compressor,
struct dc_context *ctx)
{
compressor->base.options.raw = 0;
compressor->base.options.bits.FBC_SUPPORT = true;
/* for dce 11 always use one dram channel for lpt */
compressor->base.lpt_channels_num = 1;
compressor->base.options.bits.DUMMY_BACKEND = false;
/*
* check if this system has more than 1 dram channel; if only 1 then lpt
* should not be supported
*/
compressor->base.options.bits.CLK_GATING_DISABLED = false;
compressor->base.ctx = ctx;
compressor->base.embedded_panel_h_size = 0;
compressor->base.embedded_panel_v_size = 0;
compressor->base.memory_bus_width = ctx->asic_id.vram_width;
compressor->base.allocated_size = 0;
compressor->base.preferred_requested_size = 0;
compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
compressor->base.banks_num = 0;
compressor->base.raw_size = 0;
compressor->base.channel_interleave_size = 0;
compressor->base.dram_channels_num = 0;
compressor->base.lpt_channels_num = 0;
compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED;
compressor->base.is_enabled = false;
compressor->base.funcs = &dce110_compressor_funcs;
}
@@ -0,0 +1,79 @@
/* Copyright 2012-15 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
*
*/
#ifndef __DC_COMPRESSOR_DCE110_H__
#define __DC_COMPRESSOR_DCE110_H__
#include "../inc/compressor.h"
#define TO_DCE110_COMPRESSOR(compressor)\
container_of(compressor, struct dce110_compressor, base)
struct dce110_compressor_reg_offsets {
uint32_t dcp_offset;
uint32_t dmif_offset;
};
struct dce110_compressor {
struct compressor base;
struct dce110_compressor_reg_offsets offsets;
};
struct compressor *dce110_compressor_create(struct dc_context *ctx);
void dce110_compressor_construct(struct dce110_compressor *cp110,
struct dc_context *ctx);
void dce110_compressor_destroy(struct compressor **cp);
/* FBC RELATED */
void dce110_compressor_power_up_fbc(struct compressor *cp);
void dce110_compressor_enable_fbc(struct compressor *cp,
struct compr_addr_and_pitch_params *params);
void dce110_compressor_disable_fbc(struct compressor *cp);
void dce110_compressor_set_fbc_invalidation_triggers(struct compressor *cp,
uint32_t fbc_trigger);
void dce110_compressor_program_compressed_surface_address_and_pitch(
struct compressor *cp,
struct compr_addr_and_pitch_params *params);
bool dce110_compressor_is_fbc_enabled_in_hw(struct compressor *cp,
uint32_t *fbc_mapped_crtc_id);
/* LPT RELATED */
void dce110_compressor_enable_lpt(struct compressor *cp);
void dce110_compressor_disable_lpt(struct compressor *cp);
void dce110_compressor_program_lpt_control(struct compressor *cp,
struct compr_addr_and_pitch_params *params);
bool dce110_compressor_is_lpt_enabled_in_hw(struct compressor *cp);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,35 @@
/* Copyright 2012-16 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
*
*/
#ifndef __DC_MEM_INPUT_V_DCE110_H__
#define __DC_MEM_INPUT_V_DCE110_H__
#include "mem_input.h"
#include "dce/dce_mem_input.h"
void dce110_mem_input_v_construct(
struct dce_mem_input *dce_mi,
struct dc_context *ctx);
#endif
@@ -0,0 +1,747 @@
/*
* Copyright 2012-15 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 "dce110_transform_v.h"
#include "basics/conversion.h"
/* include DCE11 register header files */
#include "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#include "dce/dce_11_0_enum.h"
enum {
OUTPUT_CSC_MATRIX_SIZE = 12
};
/* constrast:0 - 2.0, default 1.0 */
#define UNDERLAY_CONTRAST_DEFAULT 100
#define UNDERLAY_CONTRAST_MAX 200
#define UNDERLAY_CONTRAST_MIN 0
#define UNDERLAY_CONTRAST_STEP 1
#define UNDERLAY_CONTRAST_DIVIDER 100
/* Saturation: 0 - 2.0; default 1.0 */
#define UNDERLAY_SATURATION_DEFAULT 100 /*1.00*/
#define UNDERLAY_SATURATION_MIN 0
#define UNDERLAY_SATURATION_MAX 200 /* 2.00 */
#define UNDERLAY_SATURATION_STEP 1 /* 0.01 */
/*actual max overlay saturation
* value = UNDERLAY_SATURATION_MAX /UNDERLAY_SATURATION_DIVIDER
*/
/* Hue */
#define UNDERLAY_HUE_DEFAULT 0
#define UNDERLAY_HUE_MIN -300
#define UNDERLAY_HUE_MAX 300
#define UNDERLAY_HUE_STEP 5
#define UNDERLAY_HUE_DIVIDER 10 /* HW range: -30 ~ +30 */
#define UNDERLAY_SATURATION_DIVIDER 100
/* Brightness: in DAL usually -.25 ~ .25.
* In MMD is -100 to +100 in 16-235 range; which when scaled to full range is
* ~-116 to +116. When normalized this is about 0.4566.
* With 100 divider this becomes 46, but we may use another for better precision
* The ideal one is 100/219 ((100/255)*(255/219)),
* i.e. min/max = +-100, divider = 219
* default 0.0
*/
#define UNDERLAY_BRIGHTNESS_DEFAULT 0
#define UNDERLAY_BRIGHTNESS_MIN -46 /* ~116/255 */
#define UNDERLAY_BRIGHTNESS_MAX 46
#define UNDERLAY_BRIGHTNESS_STEP 1 /* .01 */
#define UNDERLAY_BRIGHTNESS_DIVIDER 100
static const struct out_csc_color_matrix global_color_matrix[] = {
{ COLOR_SPACE_SRGB,
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_SRGB_LIMITED,
{ 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
{ COLOR_SPACE_YCBCR601,
{ 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
0xF6B9, 0xE00, 0x1000} },
{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
/* TODO: correct values below */
{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
{ COLOR_SPACE_2020_RGB_FULLRANGE,
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */
{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733,
0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }
};
enum csc_color_mode {
/* 00 - BITS2:0 Bypass */
CSC_COLOR_MODE_GRAPHICS_BYPASS,
/* 01 - hard coded coefficient TV RGB */
CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
/* 04 - programmable OUTPUT CSC coefficient */
CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
};
enum grph_color_adjust_option {
GRPH_COLOR_MATRIX_HW_DEFAULT = 1,
GRPH_COLOR_MATRIX_SW
};
static void program_color_matrix_v(
struct dce_transform *xfm_dce,
const struct out_csc_color_matrix *tbl_entry,
enum grph_color_adjust_option options)
{
(void)options;
struct dc_context *ctx = xfm_dce->base.ctx;
uint32_t cntl_value = dm_read_reg(ctx, mmCOL_MAN_OUTPUT_CSC_CONTROL);
bool use_set_a = (get_reg_field_value(cntl_value,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE) != 4);
set_reg_field_value(
cntl_value,
0,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
if (use_set_a) {
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C11_C12_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[0],
OUTPUT_CSC_C11_C12_A,
OUTPUT_CSC_C11_A);
set_reg_field_value(
value,
tbl_entry->regval[1],
OUTPUT_CSC_C11_C12_A,
OUTPUT_CSC_C12_A);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C13_C14_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[2],
OUTPUT_CSC_C13_C14_A,
OUTPUT_CSC_C13_A);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[3],
OUTPUT_CSC_C13_C14_A,
OUTPUT_CSC_C14_A);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C21_C22_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[4],
OUTPUT_CSC_C21_C22_A,
OUTPUT_CSC_C21_A);
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[5],
OUTPUT_CSC_C21_C22_A,
OUTPUT_CSC_C22_A);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C23_C24_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[6],
OUTPUT_CSC_C23_C24_A,
OUTPUT_CSC_C23_A);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[7],
OUTPUT_CSC_C23_C24_A,
OUTPUT_CSC_C24_A);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C31_C32_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[8],
OUTPUT_CSC_C31_C32_A,
OUTPUT_CSC_C31_A);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[9],
OUTPUT_CSC_C31_C32_A,
OUTPUT_CSC_C32_A);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C33_C34_A;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[10],
OUTPUT_CSC_C33_C34_A,
OUTPUT_CSC_C33_A);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[11],
OUTPUT_CSC_C33_C34_A,
OUTPUT_CSC_C34_A);
dm_write_reg(ctx, addr, value);
}
set_reg_field_value(
cntl_value,
4,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
} else {
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C11_C12_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[0],
OUTPUT_CSC_C11_C12_B,
OUTPUT_CSC_C11_B);
set_reg_field_value(
value,
tbl_entry->regval[1],
OUTPUT_CSC_C11_C12_B,
OUTPUT_CSC_C12_B);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C13_C14_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[2],
OUTPUT_CSC_C13_C14_B,
OUTPUT_CSC_C13_B);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[3],
OUTPUT_CSC_C13_C14_B,
OUTPUT_CSC_C14_B);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C21_C22_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[4],
OUTPUT_CSC_C21_C22_B,
OUTPUT_CSC_C21_B);
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[5],
OUTPUT_CSC_C21_C22_B,
OUTPUT_CSC_C22_B);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C23_C24_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[6],
OUTPUT_CSC_C23_C24_B,
OUTPUT_CSC_C23_B);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[7],
OUTPUT_CSC_C23_C24_B,
OUTPUT_CSC_C24_B);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C31_C32_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[8],
OUTPUT_CSC_C31_C32_B,
OUTPUT_CSC_C31_B);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[9],
OUTPUT_CSC_C31_C32_B,
OUTPUT_CSC_C32_B);
dm_write_reg(ctx, addr, value);
}
{
uint32_t value = 0;
uint32_t addr = mmOUTPUT_CSC_C33_C34_B;
/* fixed S2.13 format */
set_reg_field_value(
value,
tbl_entry->regval[10],
OUTPUT_CSC_C33_C34_B,
OUTPUT_CSC_C33_B);
/* fixed S0.13 format */
set_reg_field_value(
value,
tbl_entry->regval[11],
OUTPUT_CSC_C33_C34_B,
OUTPUT_CSC_C34_B);
dm_write_reg(ctx, addr, value);
}
set_reg_field_value(
cntl_value,
5,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
}
dm_write_reg(ctx, mmCOL_MAN_OUTPUT_CSC_CONTROL, cntl_value);
}
static bool configure_graphics_mode_v(
struct dce_transform *xfm_dce,
enum csc_color_mode config,
enum graphics_csc_adjust_type csc_adjust_type,
enum dc_color_space color_space)
{
struct dc_context *ctx = xfm_dce->base.ctx;
uint32_t addr = mmCOL_MAN_OUTPUT_CSC_CONTROL;
uint32_t value = dm_read_reg(ctx, addr);
set_reg_field_value(
value,
0,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC)
return true;
switch (color_space) {
case COLOR_SPACE_SRGB:
/* by pass */
set_reg_field_value(
value,
0,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
case COLOR_SPACE_SRGB_LIMITED:
/* not supported for underlay on CZ */
return false;
case COLOR_SPACE_YCBCR601_LIMITED:
/* YCbCr601 */
set_reg_field_value(
value,
2,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_YCBCR709_LIMITED:
/* YCbCr709 */
set_reg_field_value(
value,
3,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
default:
return false;
}
} else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
switch (color_space) {
case COLOR_SPACE_SRGB:
/* by pass */
set_reg_field_value(
value,
0,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
case COLOR_SPACE_SRGB_LIMITED:
/* not supported for underlay on CZ */
return false;
case COLOR_SPACE_YCBCR601:
case COLOR_SPACE_YCBCR601_LIMITED:
/* YCbCr601 */
set_reg_field_value(
value,
2,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_YCBCR709_LIMITED:
/* YCbCr709 */
set_reg_field_value(
value,
3,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
break;
default:
return false;
}
} else
/* by pass */
set_reg_field_value(
value,
0,
COL_MAN_OUTPUT_CSC_CONTROL,
OUTPUT_CSC_MODE);
addr = mmCOL_MAN_OUTPUT_CSC_CONTROL;
dm_write_reg(ctx, addr, value);
return true;
}
/*TODO: color depth is not correct when this is called*/
static void set_Denormalization(struct transform *xfm,
enum dc_color_depth color_depth)
{
uint32_t value = dm_read_reg(xfm->ctx, mmDENORM_CLAMP_CONTROL);
switch (color_depth) {
case COLOR_DEPTH_888:
/* 255/256 for 8 bit output color depth */
set_reg_field_value(
value,
1,
DENORM_CLAMP_CONTROL,
DENORM_MODE);
break;
case COLOR_DEPTH_101010:
/* 1023/1024 for 10 bit output color depth */
set_reg_field_value(
value,
2,
DENORM_CLAMP_CONTROL,
DENORM_MODE);
break;
case COLOR_DEPTH_121212:
/* 4095/4096 for 12 bit output color depth */
set_reg_field_value(
value,
3,
DENORM_CLAMP_CONTROL,
DENORM_MODE);
break;
default:
/* not valid case */
break;
}
set_reg_field_value(
value,
1,
DENORM_CLAMP_CONTROL,
DENORM_10BIT_OUT);
dm_write_reg(xfm->ctx, mmDENORM_CLAMP_CONTROL, value);
}
struct input_csc_matrix {
enum dc_color_space color_space;
uint32_t regval[12];
};
static const struct input_csc_matrix input_csc_matrix[] = {
{COLOR_SPACE_SRGB,
/*1_1 1_2 1_3 1_4 2_1 2_2 2_3 2_4 3_1 3_2 3_3 3_4 */
{0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{COLOR_SPACE_SRGB_LIMITED,
{0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{COLOR_SPACE_YCBCR601,
{0x2cdd, 0x2000, 0x0, 0xe991, 0xe926, 0x2000, 0xf4fd, 0x10ef,
0x0, 0x2000, 0x38b4, 0xe3a6} },
{COLOR_SPACE_YCBCR601_LIMITED,
{0x3353, 0x2568, 0x0, 0xe400, 0xe5dc, 0x2568, 0xf367, 0x1108,
0x0, 0x2568, 0x40de, 0xdd3a} },
{COLOR_SPACE_YCBCR709,
{0x3265, 0x2000, 0, 0xe6ce, 0xf105, 0x2000, 0xfa01, 0xa7d, 0,
0x2000, 0x3b61, 0xe24f} },
{COLOR_SPACE_YCBCR709_LIMITED,
{0x39a6, 0x2568, 0, 0xe0d6, 0xeedd, 0x2568, 0xf925, 0x9a8, 0,
0x2568, 0x43ee, 0xdbb2} }
};
static void program_input_csc(
struct transform *xfm, enum dc_color_space color_space)
{
int arr_size = sizeof(input_csc_matrix)/sizeof(struct input_csc_matrix);
struct dc_context *ctx = xfm->ctx;
const uint32_t *regval = NULL;
bool use_set_a;
uint32_t value;
int i;
for (i = 0; i < arr_size; i++)
if (input_csc_matrix[i].color_space == color_space) {
regval = input_csc_matrix[i].regval;
break;
}
if (regval == NULL) {
BREAK_TO_DEBUGGER();
return;
}
/*
* 1 == set A, the logic is 'if currently we're not using set A,
* then use set A, otherwise use set B'
*/
value = dm_read_reg(ctx, mmCOL_MAN_INPUT_CSC_CONTROL);
use_set_a = get_reg_field_value(
value, COL_MAN_INPUT_CSC_CONTROL, INPUT_CSC_MODE) != 1;
if (use_set_a) {
/* fixed S2.13 format */
value = 0;
set_reg_field_value(
value, regval[0], INPUT_CSC_C11_C12_A, INPUT_CSC_C11_A);
set_reg_field_value(
value, regval[1], INPUT_CSC_C11_C12_A, INPUT_CSC_C12_A);
dm_write_reg(ctx, mmINPUT_CSC_C11_C12_A, value);
value = 0;
set_reg_field_value(
value, regval[2], INPUT_CSC_C13_C14_A, INPUT_CSC_C13_A);
set_reg_field_value(
value, regval[3], INPUT_CSC_C13_C14_A, INPUT_CSC_C14_A);
dm_write_reg(ctx, mmINPUT_CSC_C13_C14_A, value);
value = 0;
set_reg_field_value(
value, regval[4], INPUT_CSC_C21_C22_A, INPUT_CSC_C21_A);
set_reg_field_value(
value, regval[5], INPUT_CSC_C21_C22_A, INPUT_CSC_C22_A);
dm_write_reg(ctx, mmINPUT_CSC_C21_C22_A, value);
value = 0;
set_reg_field_value(
value, regval[6], INPUT_CSC_C23_C24_A, INPUT_CSC_C23_A);
set_reg_field_value(
value, regval[7], INPUT_CSC_C23_C24_A, INPUT_CSC_C24_A);
dm_write_reg(ctx, mmINPUT_CSC_C23_C24_A, value);
value = 0;
set_reg_field_value(
value, regval[8], INPUT_CSC_C31_C32_A, INPUT_CSC_C31_A);
set_reg_field_value(
value, regval[9], INPUT_CSC_C31_C32_A, INPUT_CSC_C32_A);
dm_write_reg(ctx, mmINPUT_CSC_C31_C32_A, value);
value = 0;
set_reg_field_value(
value, regval[10], INPUT_CSC_C33_C34_A, INPUT_CSC_C33_A);
set_reg_field_value(
value, regval[11], INPUT_CSC_C33_C34_A, INPUT_CSC_C34_A);
dm_write_reg(ctx, mmINPUT_CSC_C33_C34_A, value);
} else {
/* fixed S2.13 format */
value = 0;
set_reg_field_value(
value, regval[0], INPUT_CSC_C11_C12_B, INPUT_CSC_C11_B);
set_reg_field_value(
value, regval[1], INPUT_CSC_C11_C12_B, INPUT_CSC_C12_B);
dm_write_reg(ctx, mmINPUT_CSC_C11_C12_B, value);
value = 0;
set_reg_field_value(
value, regval[2], INPUT_CSC_C13_C14_B, INPUT_CSC_C13_B);
set_reg_field_value(
value, regval[3], INPUT_CSC_C13_C14_B, INPUT_CSC_C14_B);
dm_write_reg(ctx, mmINPUT_CSC_C13_C14_B, value);
value = 0;
set_reg_field_value(
value, regval[4], INPUT_CSC_C21_C22_B, INPUT_CSC_C21_B);
set_reg_field_value(
value, regval[5], INPUT_CSC_C21_C22_B, INPUT_CSC_C22_B);
dm_write_reg(ctx, mmINPUT_CSC_C21_C22_B, value);
value = 0;
set_reg_field_value(
value, regval[6], INPUT_CSC_C23_C24_B, INPUT_CSC_C23_B);
set_reg_field_value(
value, regval[7], INPUT_CSC_C23_C24_B, INPUT_CSC_C24_B);
dm_write_reg(ctx, mmINPUT_CSC_C23_C24_B, value);
value = 0;
set_reg_field_value(
value, regval[8], INPUT_CSC_C31_C32_B, INPUT_CSC_C31_B);
set_reg_field_value(
value, regval[9], INPUT_CSC_C31_C32_B, INPUT_CSC_C32_B);
dm_write_reg(ctx, mmINPUT_CSC_C31_C32_B, value);
value = 0;
set_reg_field_value(
value, regval[10], INPUT_CSC_C33_C34_B, INPUT_CSC_C33_B);
set_reg_field_value(
value, regval[11], INPUT_CSC_C33_C34_B, INPUT_CSC_C34_B);
dm_write_reg(ctx, mmINPUT_CSC_C33_C34_B, value);
}
/* KK: leave INPUT_CSC_CONVERSION_MODE at default */
value = 0;
/*
* select 8.4 input type instead of default 12.0. From the discussion
* with HW team, this format depends on the UNP surface format, so for
* 8-bit we should select 8.4 (4 bits truncated). For 10 it should be
* 10.2. For Carrizo we only support 8-bit surfaces on underlay pipe
* so we can always keep this at 8.4 (input_type=2). If the later asics
* start supporting 10+ bits, we will have a problem: surface
* programming including UNP_GRPH* is being done in DalISR after this,
* so either we pass surface format to here, or move this logic to ISR
*/
set_reg_field_value(
value, 2, COL_MAN_INPUT_CSC_CONTROL, INPUT_CSC_INPUT_TYPE);
set_reg_field_value(
value,
use_set_a ? 1 : 2,
COL_MAN_INPUT_CSC_CONTROL,
INPUT_CSC_MODE);
dm_write_reg(ctx, mmCOL_MAN_INPUT_CSC_CONTROL, value);
}
void dce110_opp_v_set_csc_default(
struct transform *xfm,
const struct default_adjustment *default_adjust)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
enum csc_color_mode config =
CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
if (default_adjust->force_hw_default == false) {
const struct out_csc_color_matrix *elm;
/* currently parameter not in use */
enum grph_color_adjust_option option;
uint32_t i;
/*
* HW default false we program locally defined matrix
* HW default true we use predefined hw matrix and we
* do not need to program matrix
* OEM wants the HW default via runtime parameter.
*/
option = GRPH_COLOR_MATRIX_SW;
for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
elm = &global_color_matrix[i];
if (elm->color_space != default_adjust->out_color_space)
continue;
/* program the matrix with default values from this
* file
*/
program_color_matrix_v(xfm_dce, elm, option);
config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
break;
}
}
program_input_csc(xfm, default_adjust->in_color_space);
/* configure the what we programmed :
* 1. Default values from this file
* 2. Use hardware default from ROM_A and we do not need to program
* matrix
*/
configure_graphics_mode_v(xfm_dce, config,
default_adjust->csc_adjust_type,
default_adjust->out_color_space);
set_Denormalization(xfm, default_adjust->color_depth);
}
void dce110_opp_v_set_csc_adjustment(
struct transform *xfm,
const struct out_csc_color_matrix *tbl_entry)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
enum csc_color_mode config =
CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
program_color_matrix_v(
xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW);
/* We did everything ,now program DxOUTPUT_CSC_CONTROL */
configure_graphics_mode_v(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW,
tbl_entry->color_space);
/*TODO: Check if denormalization is needed*/
/*set_Denormalization(opp, adjust->color_depth);*/
}
@@ -0,0 +1,557 @@
/*
* Copyright 2012-15 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 DCE11 register header files */
#include "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#include "dce110_transform_v.h"
static void power_on_lut(struct transform *xfm,
bool power_on, bool inputgamma, bool regamma)
{
uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
int i;
if (power_on) {
if (inputgamma)
set_reg_field_value(
value,
1,
DCFEV_MEM_PWR_CTRL,
COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
if (regamma)
set_reg_field_value(
value,
1,
DCFEV_MEM_PWR_CTRL,
COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
} else {
if (inputgamma)
set_reg_field_value(
value,
0,
DCFEV_MEM_PWR_CTRL,
COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
if (regamma)
set_reg_field_value(
value,
0,
DCFEV_MEM_PWR_CTRL,
COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
}
dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value);
for (i = 0; i < 3; i++) {
value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
if (get_reg_field_value(value,
DCFEV_MEM_PWR_CTRL,
COL_MAN_INPUT_GAMMA_MEM_PWR_DIS) &&
get_reg_field_value(value,
DCFEV_MEM_PWR_CTRL,
COL_MAN_GAMMA_CORR_MEM_PWR_DIS))
break;
udelay(2);
}
}
static void set_bypass_input_gamma(struct dce_transform *xfm_dce)
{
uint32_t value;
value = dm_read_reg(xfm_dce->base.ctx,
mmCOL_MAN_INPUT_GAMMA_CONTROL1);
set_reg_field_value(
value,
0,
COL_MAN_INPUT_GAMMA_CONTROL1,
INPUT_GAMMA_MODE);
dm_write_reg(xfm_dce->base.ctx,
mmCOL_MAN_INPUT_GAMMA_CONTROL1, value);
}
static void configure_regamma_mode(struct dce_transform *xfm_dce, uint32_t mode)
{
uint32_t value = 0;
set_reg_field_value(
value,
mode,
GAMMA_CORR_CONTROL,
GAMMA_CORR_MODE);
dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CONTROL, 0);
}
/*
*****************************************************************************
* Function: regamma_config_regions_and_segments
*
* build regamma curve by using predefined hw points
* uses interface parameters ,like EDID coeff.
*
* @param : parameters interface parameters
* @return void
*
* @note
*
* @see
*
*****************************************************************************
*/
static void regamma_config_regions_and_segments(
struct dce_transform *xfm_dce, const struct pwl_params *params)
{
const struct gamma_curve *curve;
uint32_t value = 0;
{
set_reg_field_value(
value,
params->arr_points[0].custom_float_x,
GAMMA_CORR_CNTLA_START_CNTL,
GAMMA_CORR_CNTLA_EXP_REGION_START);
set_reg_field_value(
value,
0,
GAMMA_CORR_CNTLA_START_CNTL,
GAMMA_CORR_CNTLA_EXP_REGION_START_SEGMENT);
dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_START_CNTL,
value);
}
{
value = 0;
set_reg_field_value(
value,
params->arr_points[0].custom_float_slope,
GAMMA_CORR_CNTLA_SLOPE_CNTL,
GAMMA_CORR_CNTLA_EXP_REGION_LINEAR_SLOPE);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_SLOPE_CNTL, value);
}
{
value = 0;
set_reg_field_value(
value,
params->arr_points[1].custom_float_x,
GAMMA_CORR_CNTLA_END_CNTL1,
GAMMA_CORR_CNTLA_EXP_REGION_END);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_END_CNTL1, value);
}
{
value = 0;
set_reg_field_value(
value,
params->arr_points[1].custom_float_slope,
GAMMA_CORR_CNTLA_END_CNTL2,
GAMMA_CORR_CNTLA_EXP_REGION_END_BASE);
set_reg_field_value(
value,
params->arr_points[1].custom_float_y,
GAMMA_CORR_CNTLA_END_CNTL2,
GAMMA_CORR_CNTLA_EXP_REGION_END_SLOPE);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_END_CNTL2, value);
}
curve = params->arr_curve_points;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_0_1,
GAMMA_CORR_CNTLA_EXP_REGION0_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_0_1,
GAMMA_CORR_CNTLA_EXP_REGION0_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_0_1,
GAMMA_CORR_CNTLA_EXP_REGION1_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_0_1,
GAMMA_CORR_CNTLA_EXP_REGION1_NUM_SEGMENTS);
dm_write_reg(
xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_0_1,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_2_3,
GAMMA_CORR_CNTLA_EXP_REGION2_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_2_3,
GAMMA_CORR_CNTLA_EXP_REGION2_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_2_3,
GAMMA_CORR_CNTLA_EXP_REGION3_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_2_3,
GAMMA_CORR_CNTLA_EXP_REGION3_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_2_3,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_4_5,
GAMMA_CORR_CNTLA_EXP_REGION4_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_4_5,
GAMMA_CORR_CNTLA_EXP_REGION4_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_4_5,
GAMMA_CORR_CNTLA_EXP_REGION5_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_4_5,
GAMMA_CORR_CNTLA_EXP_REGION5_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_4_5,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_6_7,
GAMMA_CORR_CNTLA_EXP_REGION6_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_6_7,
GAMMA_CORR_CNTLA_EXP_REGION6_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_6_7,
GAMMA_CORR_CNTLA_EXP_REGION7_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_6_7,
GAMMA_CORR_CNTLA_EXP_REGION7_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_6_7,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_8_9,
GAMMA_CORR_CNTLA_EXP_REGION8_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_8_9,
GAMMA_CORR_CNTLA_EXP_REGION8_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_8_9,
GAMMA_CORR_CNTLA_EXP_REGION9_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_8_9,
GAMMA_CORR_CNTLA_EXP_REGION9_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_8_9,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_10_11,
GAMMA_CORR_CNTLA_EXP_REGION10_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_10_11,
GAMMA_CORR_CNTLA_EXP_REGION10_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_10_11,
GAMMA_CORR_CNTLA_EXP_REGION11_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_10_11,
GAMMA_CORR_CNTLA_EXP_REGION11_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_10_11,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_12_13,
GAMMA_CORR_CNTLA_EXP_REGION12_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_12_13,
GAMMA_CORR_CNTLA_EXP_REGION12_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_12_13,
GAMMA_CORR_CNTLA_EXP_REGION13_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_12_13,
GAMMA_CORR_CNTLA_EXP_REGION13_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_12_13,
value);
}
curve += 2;
{
value = 0;
set_reg_field_value(
value,
curve[0].offset,
GAMMA_CORR_CNTLA_REGION_14_15,
GAMMA_CORR_CNTLA_EXP_REGION14_LUT_OFFSET);
set_reg_field_value(
value,
curve[0].segments_num,
GAMMA_CORR_CNTLA_REGION_14_15,
GAMMA_CORR_CNTLA_EXP_REGION14_NUM_SEGMENTS);
set_reg_field_value(
value,
curve[1].offset,
GAMMA_CORR_CNTLA_REGION_14_15,
GAMMA_CORR_CNTLA_EXP_REGION15_LUT_OFFSET);
set_reg_field_value(
value,
curve[1].segments_num,
GAMMA_CORR_CNTLA_REGION_14_15,
GAMMA_CORR_CNTLA_EXP_REGION15_NUM_SEGMENTS);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_CNTLA_REGION_14_15,
value);
}
}
static void program_pwl(struct dce_transform *xfm_dce,
const struct pwl_params *params)
{
uint32_t value = 0;
set_reg_field_value(
value,
7,
GAMMA_CORR_LUT_WRITE_EN_MASK,
GAMMA_CORR_LUT_WRITE_EN_MASK);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_LUT_WRITE_EN_MASK, value);
dm_write_reg(xfm_dce->base.ctx,
mmGAMMA_CORR_LUT_INDEX, 0);
/* Program REGAMMA_LUT_DATA */
{
const uint32_t addr = mmGAMMA_CORR_LUT_DATA;
uint32_t i = 0;
const struct pwl_result_data *rgb =
params->rgb_resulted;
while (i != params->hw_points_num) {
dm_write_reg(xfm_dce->base.ctx, addr, rgb->red_reg);
dm_write_reg(xfm_dce->base.ctx, addr, rgb->green_reg);
dm_write_reg(xfm_dce->base.ctx, addr, rgb->blue_reg);
dm_write_reg(xfm_dce->base.ctx, addr,
rgb->delta_red_reg);
dm_write_reg(xfm_dce->base.ctx, addr,
rgb->delta_green_reg);
dm_write_reg(xfm_dce->base.ctx, addr,
rgb->delta_blue_reg);
++rgb;
++i;
}
}
}
void dce110_opp_program_regamma_pwl_v(
struct transform *xfm,
const struct pwl_params *params)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
/* Setup regions */
regamma_config_regions_and_segments(xfm_dce, params);
set_bypass_input_gamma(xfm_dce);
/* Power on gamma LUT memory */
power_on_lut(xfm, true, false, true);
/* Program PWL */
program_pwl(xfm_dce, params);
/* program regamma config */
configure_regamma_mode(xfm_dce, 1);
/* Power return to auto back */
power_on_lut(xfm, false, false, true);
}
void dce110_opp_power_on_regamma_lut_v(
struct transform *xfm,
bool power_on)
{
uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
set_reg_field_value(
value,
0,
DCFEV_MEM_PWR_CTRL,
COL_MAN_GAMMA_CORR_MEM_PWR_FORCE);
set_reg_field_value(
value,
power_on,
DCFEV_MEM_PWR_CTRL,
COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
set_reg_field_value(
value,
0,
DCFEV_MEM_PWR_CTRL,
COL_MAN_INPUT_GAMMA_MEM_PWR_FORCE);
set_reg_field_value(
value,
power_on,
DCFEV_MEM_PWR_CTRL,
COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value);
}
void dce110_opp_set_regamma_mode_v(
struct transform *xfm,
enum opp_regamma mode)
{
(void)xfm;
(void)mode;
// TODO: need to implement the function
}
@@ -0,0 +1,54 @@
/*
* Copyright 2012-15 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 DCE11 register header files */
#include "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#include "dce/dce_opp.h"
#include "dce110_opp_v.h"
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
static const struct opp_funcs funcs = {
.opp_set_dyn_expansion = dce110_opp_set_dyn_expansion,
.opp_destroy = dce110_opp_destroy,
.opp_program_fmt = dce110_opp_program_fmt,
.opp_program_bit_depth_reduction =
dce110_opp_program_bit_depth_reduction
};
void dce110_opp_v_construct(struct dce110_opp *opp110,
struct dc_context *ctx)
{
opp110->base.funcs = &funcs;
opp110->base.ctx = ctx;
}
@@ -0,0 +1,39 @@
/* Copyright 2012-15 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
*
*/
#ifndef __DC_OPP_DCE110_V_H__
#define __DC_OPP_DCE110_V_H__
#include "dc_types.h"
#include "opp.h"
#include "core_types.h"
void dce110_opp_v_construct(struct dce110_opp *opp110,
struct dc_context *ctx);
/* underlay callbacks */
#endif /* __DC_OPP_DCE110_V_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,294 @@
/*
* Copyright 2012-15 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
*
*/
#ifndef __DC_TIMING_GENERATOR_DCE110_H__
#define __DC_TIMING_GENERATOR_DCE110_H__
#include "timing_generator.h"
#include "../include/grph_object_id.h"
/* GSL Sync related values */
/* In VSync mode, after 4 units of time, master pipe will generate
* flip_ready signal */
#define VFLIP_READY_DELAY 4
/* In HSync mode, after 2 units of time, master pipe will generate
* flip_ready signal */
#define HFLIP_READY_DELAY 2
/* 6 lines delay between forcing flip and checking all pipes ready */
#define HFLIP_CHECK_DELAY 6
/* 3 lines before end of frame */
#define FLIP_READY_BACK_LOOKUP 3
/* Trigger Source Select - ASIC-defendant, actual values for the
* register programming */
enum trigger_source_select {
TRIGGER_SOURCE_SELECT_LOGIC_ZERO = 0,
TRIGGER_SOURCE_SELECT_CRTC_VSYNCA = 1,
TRIGGER_SOURCE_SELECT_CRTC_HSYNCA = 2,
TRIGGER_SOURCE_SELECT_CRTC_VSYNCB = 3,
TRIGGER_SOURCE_SELECT_CRTC_HSYNCB = 4,
TRIGGER_SOURCE_SELECT_GENERICF = 5,
TRIGGER_SOURCE_SELECT_GENERICE = 6,
TRIGGER_SOURCE_SELECT_VSYNCA = 7,
TRIGGER_SOURCE_SELECT_HSYNCA = 8,
TRIGGER_SOURCE_SELECT_VSYNCB = 9,
TRIGGER_SOURCE_SELECT_HSYNCB = 10,
TRIGGER_SOURCE_SELECT_HPD1 = 11,
TRIGGER_SOURCE_SELECT_HPD2 = 12,
TRIGGER_SOURCE_SELECT_GENERICD = 13,
TRIGGER_SOURCE_SELECT_GENERICC = 14,
TRIGGER_SOURCE_SELECT_VIDEO_CAPTURE = 15,
TRIGGER_SOURCE_SELECT_GSL_GROUP0 = 16,
TRIGGER_SOURCE_SELECT_GSL_GROUP1 = 17,
TRIGGER_SOURCE_SELECT_GSL_GROUP2 = 18,
TRIGGER_SOURCE_SELECT_BLONY = 19,
TRIGGER_SOURCE_SELECT_GENERICA = 20,
TRIGGER_SOURCE_SELECT_GENERICB = 21,
TRIGGER_SOURCE_SELECT_GSL_ALLOW_FLIP = 22,
TRIGGER_SOURCE_SELECT_MANUAL_TRIGGER = 23
};
/* Trigger Source Select - ASIC-dependant, actual values for the
* register programming */
enum trigger_polarity_select {
TRIGGER_POLARITY_SELECT_LOGIC_ZERO = 0,
TRIGGER_POLARITY_SELECT_CRTC = 1,
TRIGGER_POLARITY_SELECT_GENERICA = 2,
TRIGGER_POLARITY_SELECT_GENERICB = 3,
TRIGGER_POLARITY_SELECT_HSYNCA = 4,
TRIGGER_POLARITY_SELECT_HSYNCB = 5,
TRIGGER_POLARITY_SELECT_VIDEO_CAPTURE = 6,
TRIGGER_POLARITY_SELECT_GENERICC = 7
};
struct dce110_timing_generator_offsets {
int32_t crtc;
int32_t dcp;
/* DCE80 use only */
int32_t dmif;
};
struct dce110_timing_generator {
struct timing_generator base;
struct dce110_timing_generator_offsets offsets;
struct dce110_timing_generator_offsets derived_offsets;
enum controller_id controller_id;
uint32_t max_h_total;
uint32_t max_v_total;
uint32_t min_h_blank;
uint32_t min_h_front_porch;
uint32_t min_h_back_porch;
/* DCE 12 */
uint32_t min_h_sync_width;
uint32_t min_v_sync_width;
uint32_t min_v_blank;
};
#define DCE110TG_FROM_TG(tg)\
container_of(tg, struct dce110_timing_generator, base)
void dce110_timing_generator_construct(
struct dce110_timing_generator *tg,
struct dc_context *ctx,
uint32_t instance,
const struct dce110_timing_generator_offsets *offsets);
/* determine if given timing can be supported by TG */
bool dce110_timing_generator_validate_timing(
struct timing_generator *tg,
const struct dc_crtc_timing *timing,
enum signal_type signal);
/******** HW programming ************/
/* Program timing generator with given timing */
bool dce110_timing_generator_program_timing_generator(
struct timing_generator *tg,
const struct dc_crtc_timing *dc_crtc_timing);
/* Disable/Enable Timing Generator */
bool dce110_timing_generator_enable_crtc(struct timing_generator *tg);
bool dce110_timing_generator_disable_crtc(struct timing_generator *tg);
void dce110_timing_generator_set_early_control(
struct timing_generator *tg,
uint32_t early_cntl);
/**************** TG current status ******************/
/* return the current frame counter. Used by Linux kernel DRM */
uint32_t dce110_timing_generator_get_vblank_counter(
struct timing_generator *tg);
void dce110_timing_generator_get_position(
struct timing_generator *tg,
struct crtc_position *position);
/* return true if TG counter is moving. false if TG is stopped */
bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg);
/* wait until TG is in beginning of vertical blank region */
void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg);
/* wait until TG is in beginning of active region */
void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg);
/*********** Timing Generator Synchronization routines ****/
/* Setups Global Swap Lock group, TimingServer or TimingClient*/
void dce110_timing_generator_setup_global_swap_lock(
struct timing_generator *tg,
const struct dcp_gsl_params *gsl_params);
/* Clear all the register writes done by setup_global_swap_lock */
void dce110_timing_generator_tear_down_global_swap_lock(
struct timing_generator *tg);
/* Reset crtc position on master VSync */
void dce110_timing_generator_enable_crtc_reset(
struct timing_generator *tg,
int source,
struct crtc_trigger_info *crtc_tp);
/* Reset slave controllers on master VSync */
void dce110_timing_generator_enable_reset_trigger(
struct timing_generator *tg,
int source);
/* disabling trigger-reset */
void dce110_timing_generator_disable_reset_trigger(
struct timing_generator *tg);
/* Checks whether CRTC triggered reset occurred */
bool dce110_timing_generator_did_triggered_reset_occur(
struct timing_generator *tg);
/******** Stuff to move to other virtual HW objects *****************/
/* Move to enable accelerated mode */
void dce110_timing_generator_disable_vga(struct timing_generator *tg);
/* TODO: Should we move it to transform */
/* Fully program CRTC timing in timing generator */
void dce110_timing_generator_program_blanking(
struct timing_generator *tg,
const struct dc_crtc_timing *timing);
/* TODO: Should we move it to opp? */
/* Combine with below and move YUV/RGB color conversion to SW layer */
void dce110_timing_generator_program_blank_color(
struct timing_generator *tg,
const struct tg_color *black_color);
/* Combine with above and move YUV/RGB color conversion to SW layer */
void dce110_timing_generator_set_overscan_color_black(
struct timing_generator *tg,
const struct tg_color *color);
void dce110_timing_generator_color_space_to_black_color(
enum dc_color_space colorspace,
struct tg_color *black_color);
/*************** End-of-move ********************/
/* Not called yet */
void dce110_timing_generator_set_test_pattern(
struct timing_generator *tg,
/* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
* because this is not DP-specific (which is probably somewhere in DP
* encoder) */
enum controller_dp_test_pattern test_pattern,
enum dc_color_depth color_depth);
void dce110_timing_generator_set_drr(
struct timing_generator *tg,
const struct drr_params *params);
void dce110_timing_generator_set_static_screen_control(
struct timing_generator *tg,
uint32_t event_triggers,
uint32_t num_frames);
void dce110_timing_generator_get_crtc_scanoutpos(
struct timing_generator *tg,
uint32_t *v_blank_start,
uint32_t *v_blank_end,
uint32_t *h_position,
uint32_t *v_position);
void dce110_timing_generator_enable_advanced_request(
struct timing_generator *tg,
bool enable,
const struct dc_crtc_timing *timing);
void dce110_timing_generator_set_lock_master(struct timing_generator *tg,
bool lock);
void dce110_tg_program_blank_color(struct timing_generator *tg,
const struct tg_color *black_color);
void dce110_tg_set_overscan_color(struct timing_generator *tg,
const struct tg_color *overscan_color);
void dce110_tg_program_timing(struct timing_generator *tg,
const struct dc_crtc_timing *timing,
int vready_offset,
int vstartup_start,
int vupdate_offset,
int vupdate_width,
int pstate_keepout,
const enum signal_type signal,
bool use_vbios);
bool dce110_tg_is_blanked(struct timing_generator *tg);
void dce110_tg_set_blank(struct timing_generator *tg,
bool enable_blanking);
bool dce110_tg_validate_timing(struct timing_generator *tg,
const struct dc_crtc_timing *timing);
void dce110_tg_wait_for_state(struct timing_generator *tg,
enum crtc_state state);
void dce110_tg_set_colors(struct timing_generator *tg,
const struct tg_color *blank_color,
const struct tg_color *overscan_color);
bool dce110_arm_vert_intr(
struct timing_generator *tg, uint8_t width);
bool dce110_configure_crc(struct timing_generator *tg,
const struct crc_params *params);
bool dce110_get_crc(struct timing_generator *tg, uint8_t idx,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
bool dce110_is_two_pixels_per_container(const struct dc_crtc_timing *timing);
#endif /* __DC_TIMING_GENERATOR_DCE110_H__ */
@@ -0,0 +1,716 @@
/*
* Copyright 2017 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.
*
*/
#include "dm_services.h"
/* include DCE11 register header files */
#include "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#include "dc_types.h"
#include "dc_bios_types.h"
#include "dc.h"
#include "include/grph_object_id.h"
#include "include/logger_interface.h"
#include "dce110_timing_generator.h"
#include "dce110_timing_generator_v.h"
#include "timing_generator.h"
#define DC_LOGGER \
tg->ctx->logger
/** ********************************************************************************
*
* DCE11 Timing Generator Implementation
*
**********************************************************************************/
/*
* Enable CRTCV
*/
static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg)
{
/*
* Set MASTER_UPDATE_MODE to 0
* This is needed for DRR, and also suggested to be default value by Syed.
*/
uint32_t value;
value = 0;
set_reg_field_value(value, 0,
CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
dm_write_reg(tg->ctx,
mmCRTCV_MASTER_UPDATE_MODE, value);
/* TODO: may want this on for looking for underflow */
value = 0;
dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value);
value = 0;
set_reg_field_value(value, 1,
CRTCV_MASTER_EN, CRTC_MASTER_EN);
dm_write_reg(tg->ctx,
mmCRTCV_MASTER_EN, value);
return true;
}
static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg)
{
uint32_t value;
value = dm_read_reg(tg->ctx,
mmCRTCV_CONTROL);
set_reg_field_value(value, 0,
CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL);
set_reg_field_value(value, 0,
CRTCV_CONTROL, CRTC_MASTER_EN);
dm_write_reg(tg->ctx,
mmCRTCV_CONTROL, value);
/*
* TODO: call this when adding stereo support
* tg->funcs->disable_stereo(tg);
*/
return true;
}
static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg)
{
uint32_t addr = mmCRTCV_BLANK_CONTROL;
uint32_t value = dm_read_reg(tg->ctx, addr);
set_reg_field_value(
value,
1,
CRTCV_BLANK_CONTROL,
CRTC_BLANK_DATA_EN);
set_reg_field_value(
value,
0,
CRTCV_BLANK_CONTROL,
CRTC_BLANK_DE_MODE);
dm_write_reg(tg->ctx, addr, value);
}
static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg)
{
uint32_t addr = mmCRTCV_BLANK_CONTROL;
uint32_t value = dm_read_reg(tg->ctx, addr);
set_reg_field_value(
value,
0,
CRTCV_BLANK_CONTROL,
CRTC_BLANK_DATA_EN);
set_reg_field_value(
value,
0,
CRTCV_BLANK_CONTROL,
CRTC_BLANK_DE_MODE);
dm_write_reg(tg->ctx, addr, value);
}
static bool dce110_timing_generator_v_is_in_vertical_blank(
struct timing_generator *tg)
{
uint32_t addr = 0;
uint32_t value = 0;
uint32_t field = 0;
addr = mmCRTCV_STATUS;
value = dm_read_reg(tg->ctx, addr);
field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK);
return field == 1;
}
static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg)
{
uint32_t value;
uint32_t h1 = 0;
uint32_t h2 = 0;
uint32_t v1 = 0;
uint32_t v2 = 0;
value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
h1 = get_reg_field_value(
value,
CRTCV_STATUS_POSITION,
CRTC_HORZ_COUNT);
v1 = get_reg_field_value(
value,
CRTCV_STATUS_POSITION,
CRTC_VERT_COUNT);
value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
h2 = get_reg_field_value(
value,
CRTCV_STATUS_POSITION,
CRTC_HORZ_COUNT);
v2 = get_reg_field_value(
value,
CRTCV_STATUS_POSITION,
CRTC_VERT_COUNT);
if (h1 == h2 && v1 == v2)
return false;
else
return true;
}
static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg)
{
/* We want to catch beginning of VBlank here, so if the first try are
* in VBlank, we might be very close to Active, in this case wait for
* another frame
*/
while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
if (!dce110_timing_generator_v_is_counter_moving(tg)) {
/* error - no point to wait if counter is not moving */
break;
}
}
while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) {
if (!dce110_timing_generator_v_is_counter_moving(tg)) {
/* error - no point to wait if counter is not moving */
break;
}
}
}
/*
* Wait till we are in VActive (anywhere in VActive)
*/
static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg)
{
while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
if (!dce110_timing_generator_v_is_counter_moving(tg)) {
/* error - no point to wait if counter is not moving */
break;
}
}
}
static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg,
enum crtc_state state)
{
switch (state) {
case CRTC_STATE_VBLANK:
dce110_timing_generator_v_wait_for_vblank(tg);
break;
case CRTC_STATE_VACTIVE:
dce110_timing_generator_v_wait_for_vactive(tg);
break;
default:
break;
}
}
static void dce110_timing_generator_v_program_blanking(
struct timing_generator *tg,
const struct dc_crtc_timing *timing)
{
uint32_t vsync_offset = timing->v_border_bottom +
timing->v_front_porch;
uint32_t v_sync_start = timing->v_addressable + vsync_offset;
uint32_t hsync_offset = timing->h_border_right +
timing->h_front_porch;
uint32_t h_sync_start = timing->h_addressable + hsync_offset;
struct dc_context *ctx = tg->ctx;
uint32_t value = 0;
uint32_t addr = 0;
uint32_t tmp = 0;
addr = mmCRTCV_H_TOTAL;
value = dm_read_reg(ctx, addr);
set_reg_field_value(
value,
timing->h_total - 1,
CRTCV_H_TOTAL,
CRTC_H_TOTAL);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_V_TOTAL;
value = dm_read_reg(ctx, addr);
set_reg_field_value(
value,
timing->v_total - 1,
CRTCV_V_TOTAL,
CRTC_V_TOTAL);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_H_BLANK_START_END;
value = dm_read_reg(ctx, addr);
tmp = timing->h_total -
(h_sync_start + timing->h_border_left);
set_reg_field_value(
value,
tmp,
CRTCV_H_BLANK_START_END,
CRTC_H_BLANK_END);
tmp = tmp + timing->h_addressable +
timing->h_border_left + timing->h_border_right;
set_reg_field_value(
value,
tmp,
CRTCV_H_BLANK_START_END,
CRTC_H_BLANK_START);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_V_BLANK_START_END;
value = dm_read_reg(ctx, addr);
tmp = timing->v_total - (v_sync_start + timing->v_border_top);
set_reg_field_value(
value,
tmp,
CRTCV_V_BLANK_START_END,
CRTC_V_BLANK_END);
tmp = tmp + timing->v_addressable + timing->v_border_top +
timing->v_border_bottom;
set_reg_field_value(
value,
tmp,
CRTCV_V_BLANK_START_END,
CRTC_V_BLANK_START);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_H_SYNC_A;
value = 0;
set_reg_field_value(
value,
timing->h_sync_width,
CRTCV_H_SYNC_A,
CRTC_H_SYNC_A_END);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_H_SYNC_A_CNTL;
value = dm_read_reg(ctx, addr);
if (timing->flags.HSYNC_POSITIVE_POLARITY) {
set_reg_field_value(
value,
0,
CRTCV_H_SYNC_A_CNTL,
CRTC_H_SYNC_A_POL);
} else {
set_reg_field_value(
value,
1,
CRTCV_H_SYNC_A_CNTL,
CRTC_H_SYNC_A_POL);
}
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_V_SYNC_A;
value = 0;
set_reg_field_value(
value,
timing->v_sync_width,
CRTCV_V_SYNC_A,
CRTC_V_SYNC_A_END);
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_V_SYNC_A_CNTL;
value = dm_read_reg(ctx, addr);
if (timing->flags.VSYNC_POSITIVE_POLARITY) {
set_reg_field_value(
value,
0,
CRTCV_V_SYNC_A_CNTL,
CRTC_V_SYNC_A_POL);
} else {
set_reg_field_value(
value,
1,
CRTCV_V_SYNC_A_CNTL,
CRTC_V_SYNC_A_POL);
}
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_INTERLACE_CONTROL;
value = dm_read_reg(ctx, addr);
set_reg_field_value(
value,
timing->flags.INTERLACE,
CRTCV_INTERLACE_CONTROL,
CRTC_INTERLACE_ENABLE);
dm_write_reg(ctx, addr, value);
}
static void dce110_timing_generator_v_enable_advanced_request(
struct timing_generator *tg,
bool enable,
const struct dc_crtc_timing *timing)
{
uint32_t addr = mmCRTCV_START_LINE_CONTROL;
uint32_t value = dm_read_reg(tg->ctx, addr);
if (enable) {
if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
set_reg_field_value(
value,
3,
CRTCV_START_LINE_CONTROL,
CRTC_ADVANCED_START_LINE_POSITION);
} else {
set_reg_field_value(
value,
4,
CRTCV_START_LINE_CONTROL,
CRTC_ADVANCED_START_LINE_POSITION);
}
set_reg_field_value(
value,
0,
CRTCV_START_LINE_CONTROL,
CRTC_LEGACY_REQUESTOR_EN);
} else {
set_reg_field_value(
value,
2,
CRTCV_START_LINE_CONTROL,
CRTC_ADVANCED_START_LINE_POSITION);
set_reg_field_value(
value,
1,
CRTCV_START_LINE_CONTROL,
CRTC_LEGACY_REQUESTOR_EN);
}
dm_write_reg(tg->ctx, addr, value);
}
static void dce110_timing_generator_v_set_blank(struct timing_generator *tg,
bool enable_blanking)
{
if (enable_blanking)
dce110_timing_generator_v_blank_crtc(tg);
else
dce110_timing_generator_v_unblank_crtc(tg);
}
static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
const struct dc_crtc_timing *timing,
int vready_offset,
int vstartup_start,
int vupdate_offset,
int vupdate_width,
int pstate_keepout,
const enum signal_type signal,
bool use_vbios)
{
(void)vready_offset;
(void)vstartup_start;
(void)vupdate_offset;
(void)vupdate_width;
(void)pstate_keepout;
(void)signal;
if (use_vbios)
dce110_timing_generator_program_timing_generator(tg, timing);
else
dce110_timing_generator_v_program_blanking(tg, timing);
}
static void dce110_timing_generator_v_program_blank_color(
struct timing_generator *tg,
const struct tg_color *black_color)
{
uint32_t addr = mmCRTCV_BLACK_COLOR;
uint32_t value = dm_read_reg(tg->ctx, addr);
set_reg_field_value(
value,
black_color->color_b_cb,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_B_CB);
set_reg_field_value(
value,
black_color->color_g_y,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_G_Y);
set_reg_field_value(
value,
black_color->color_r_cr,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_R_CR);
dm_write_reg(tg->ctx, addr, value);
}
static void dce110_timing_generator_v_set_overscan_color_black(
struct timing_generator *tg,
const struct tg_color *color)
{
struct dc_context *ctx = tg->ctx;
uint32_t addr;
uint32_t value = 0;
set_reg_field_value(
value,
color->color_b_cb,
CRTC_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_BLUE);
set_reg_field_value(
value,
color->color_r_cr,
CRTC_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_RED);
set_reg_field_value(
value,
color->color_g_y,
CRTC_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_GREEN);
addr = mmCRTCV_OVERSCAN_COLOR;
dm_write_reg(ctx, addr, value);
addr = mmCRTCV_BLACK_COLOR;
dm_write_reg(ctx, addr, value);
/* This is desirable to have a constant DAC output voltage during the
* blank time that is higher than the 0 volt reference level that the
* DAC outputs when the NBLANK signal
* is asserted low, such as for output to an analog TV. */
addr = mmCRTCV_BLANK_DATA_COLOR;
dm_write_reg(ctx, addr, value);
/* TO DO we have to program EXT registers and we need to know LB DATA
* format because it is used when more 10 , i.e. 12 bits per color
*
* m_mmDxCRTC_OVERSCAN_COLOR_EXT
* m_mmDxCRTC_BLACK_COLOR_EXT
* m_mmDxCRTC_BLANK_DATA_COLOR_EXT
*/
}
static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
const struct tg_color *black_color)
{
uint32_t addr = mmCRTCV_BLACK_COLOR;
uint32_t value = dm_read_reg(tg->ctx, addr);
set_reg_field_value(
value,
black_color->color_b_cb,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_B_CB);
set_reg_field_value(
value,
black_color->color_g_y,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_G_Y);
set_reg_field_value(
value,
black_color->color_r_cr,
CRTCV_BLACK_COLOR,
CRTC_BLACK_COLOR_R_CR);
dm_write_reg(tg->ctx, addr, value);
addr = mmCRTCV_BLANK_DATA_COLOR;
dm_write_reg(tg->ctx, addr, value);
}
static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
const struct tg_color *overscan_color)
{
struct dc_context *ctx = tg->ctx;
uint32_t value = 0;
uint32_t addr;
set_reg_field_value(
value,
overscan_color->color_b_cb,
CRTCV_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_BLUE);
set_reg_field_value(
value,
overscan_color->color_g_y,
CRTCV_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_GREEN);
set_reg_field_value(
value,
overscan_color->color_r_cr,
CRTCV_OVERSCAN_COLOR,
CRTC_OVERSCAN_COLOR_RED);
addr = mmCRTCV_OVERSCAN_COLOR;
dm_write_reg(ctx, addr, value);
}
static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
const struct tg_color *blank_color,
const struct tg_color *overscan_color)
{
if (blank_color != NULL)
dce110_tg_v_program_blank_color(tg, blank_color);
if (overscan_color != NULL)
dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
}
static void dce110_timing_generator_v_set_early_control(
struct timing_generator *tg,
uint32_t early_cntl)
{
uint32_t regval;
uint32_t address = mmCRTC_CONTROL;
regval = dm_read_reg(tg->ctx, address);
set_reg_field_value(regval, early_cntl,
CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
dm_write_reg(tg->ctx, address, regval);
}
static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
{
uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
uint32_t value = dm_read_reg(tg->ctx, addr);
uint32_t field = get_reg_field_value(
value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
return field;
}
static bool dce110_timing_generator_v_did_triggered_reset_occur(
struct timing_generator *tg)
{
DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
return false;
}
static void dce110_timing_generator_v_setup_global_swap_lock(
struct timing_generator *tg,
const struct dcp_gsl_params *gsl_params)
{
(void)gsl_params;
DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
return;
}
static void dce110_timing_generator_v_enable_reset_trigger(
struct timing_generator *tg,
int source_tg_inst)
{
(void)source_tg_inst;
DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
return;
}
static void dce110_timing_generator_v_disable_reset_trigger(
struct timing_generator *tg)
{
DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
return;
}
static void dce110_timing_generator_v_tear_down_global_swap_lock(
struct timing_generator *tg)
{
DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
return;
}
static void dce110_timing_generator_v_disable_vga(
struct timing_generator *tg)
{
(void)tg;
return;
}
/** ********************************************************************************************
*
* DCE11 Timing Generator Constructor / Destructor
*
*********************************************************************************************/
static const struct timing_generator_funcs dce110_tg_v_funcs = {
.validate_timing = dce110_tg_validate_timing,
.program_timing = dce110_timing_generator_v_program_timing,
.enable_crtc = dce110_timing_generator_v_enable_crtc,
.disable_crtc = dce110_timing_generator_v_disable_crtc,
.is_counter_moving = dce110_timing_generator_v_is_counter_moving,
.get_position = NULL, /* Not to be implemented for underlay*/
.get_frame_count = dce110_timing_generator_v_get_vblank_counter,
.set_early_control = dce110_timing_generator_v_set_early_control,
.wait_for_state = dce110_timing_generator_v_wait_for_state,
.set_blank = dce110_timing_generator_v_set_blank,
.set_colors = dce110_timing_generator_v_set_colors,
.set_overscan_blank_color =
dce110_timing_generator_v_set_overscan_color_black,
.set_blank_color = dce110_timing_generator_v_program_blank_color,
.disable_vga = dce110_timing_generator_v_disable_vga,
.did_triggered_reset_occur =
dce110_timing_generator_v_did_triggered_reset_occur,
.setup_global_swap_lock =
dce110_timing_generator_v_setup_global_swap_lock,
.enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
.disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
.tear_down_global_swap_lock =
dce110_timing_generator_v_tear_down_global_swap_lock,
.enable_advanced_request =
dce110_timing_generator_v_enable_advanced_request,
.is_two_pixels_per_container = dce110_is_two_pixels_per_container,
};
void dce110_timing_generator_v_construct(
struct dce110_timing_generator *tg110,
struct dc_context *ctx)
{
tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
tg110->base.funcs = &dce110_tg_v_funcs;
tg110->base.ctx = ctx;
tg110->base.bp = ctx->dc_bios;
tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
tg110->min_h_blank = 56;
tg110->min_h_front_porch = 4;
tg110->min_h_back_porch = 4;
}
@@ -0,0 +1,33 @@
/*
* Copyright 2012-15 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
*
*/
#ifndef __DC_TIMING_GENERATOR_V_DCE110_H__
#define __DC_TIMING_GENERATOR_V_DCE110_H__
void dce110_timing_generator_v_construct(
struct dce110_timing_generator *tg110,
struct dc_context *ctx);
#endif /* __DC_TIMING_GENERATOR_V_DCE110_H__ */
@@ -0,0 +1,723 @@
/*
* Copyright 2012-15 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 "dce110_transform_v.h"
#include "dm_services.h"
#include "dc.h"
#include "dce/dce_11_0_d.h"
#include "dce/dce_11_0_sh_mask.h"
#define SCLV_PHASES 64
#define DC_LOGGER \
xfm->ctx->logger
struct sclv_ratios_inits {
uint32_t h_int_scale_ratio_luma;
uint32_t h_int_scale_ratio_chroma;
uint32_t v_int_scale_ratio_luma;
uint32_t v_int_scale_ratio_chroma;
struct init_int_and_frac h_init_luma;
struct init_int_and_frac h_init_chroma;
struct init_int_and_frac v_init_luma;
struct init_int_and_frac v_init_chroma;
};
static void calculate_viewport(
const struct scaler_data *scl_data,
struct rect *luma_viewport,
struct rect *chroma_viewport)
{
/*Do not set chroma vp for rgb444 pixel format*/
luma_viewport->x = scl_data->viewport.x - scl_data->viewport.x % 2;
luma_viewport->y = scl_data->viewport.y - scl_data->viewport.y % 2;
luma_viewport->width =
scl_data->viewport.width - scl_data->viewport.width % 2;
luma_viewport->height =
scl_data->viewport.height - scl_data->viewport.height % 2;
chroma_viewport->x = luma_viewport->x;
chroma_viewport->y = luma_viewport->y;
chroma_viewport->height = luma_viewport->height;
chroma_viewport->width = luma_viewport->width;
if (scl_data->format == PIXEL_FORMAT_420BPP8) {
luma_viewport->height += luma_viewport->height % 2;
luma_viewport->width += luma_viewport->width % 2;
/*for 420 video chroma is 1/4 the area of luma, scaled
*vertically and horizontally
*/
chroma_viewport->x = luma_viewport->x / 2;
chroma_viewport->y = luma_viewport->y / 2;
chroma_viewport->height = luma_viewport->height / 2;
chroma_viewport->width = luma_viewport->width / 2;
}
}
static void program_viewport(
struct dce_transform *xfm_dce,
struct rect *luma_view_port,
struct rect *chroma_view_port)
{
struct dc_context *ctx = xfm_dce->base.ctx;
uint32_t value = 0;
uint32_t addr = 0;
if (luma_view_port->width != 0 && luma_view_port->height != 0) {
addr = mmSCLV_VIEWPORT_START;
value = 0;
set_reg_field_value(
value,
luma_view_port->x,
SCLV_VIEWPORT_START,
VIEWPORT_X_START);
set_reg_field_value(
value,
luma_view_port->y,
SCLV_VIEWPORT_START,
VIEWPORT_Y_START);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VIEWPORT_SIZE;
value = 0;
set_reg_field_value(
value,
luma_view_port->height,
SCLV_VIEWPORT_SIZE,
VIEWPORT_HEIGHT);
set_reg_field_value(
value,
luma_view_port->width,
SCLV_VIEWPORT_SIZE,
VIEWPORT_WIDTH);
dm_write_reg(ctx, addr, value);
}
if (chroma_view_port->width != 0 && chroma_view_port->height != 0) {
addr = mmSCLV_VIEWPORT_START_C;
value = 0;
set_reg_field_value(
value,
chroma_view_port->x,
SCLV_VIEWPORT_START_C,
VIEWPORT_X_START_C);
set_reg_field_value(
value,
chroma_view_port->y,
SCLV_VIEWPORT_START_C,
VIEWPORT_Y_START_C);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VIEWPORT_SIZE_C;
value = 0;
set_reg_field_value(
value,
chroma_view_port->height,
SCLV_VIEWPORT_SIZE_C,
VIEWPORT_HEIGHT_C);
set_reg_field_value(
value,
chroma_view_port->width,
SCLV_VIEWPORT_SIZE_C,
VIEWPORT_WIDTH_C);
dm_write_reg(ctx, addr, value);
}
}
/*
* Function:
* void setup_scaling_configuration
*
* Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps
* Input: data
*
* Output:
* void
*/
static bool setup_scaling_configuration(
struct dce_transform *xfm_dce,
const struct scaler_data *data)
{
bool is_scaling_needed = false;
struct dc_context *ctx = xfm_dce->base.ctx;
uint32_t value = 0;
set_reg_field_value(value, data->taps.h_taps - 1,
SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS);
set_reg_field_value(value, data->taps.v_taps - 1,
SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS);
set_reg_field_value(value, data->taps.h_taps_c - 1,
SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS_C);
set_reg_field_value(value, data->taps.v_taps_c - 1,
SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS_C);
dm_write_reg(ctx, mmSCLV_TAP_CONTROL, value);
value = 0;
if (data->taps.h_taps + data->taps.v_taps > 2) {
set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE);
set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN);
is_scaling_needed = true;
} else {
set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE);
set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN);
}
if (data->taps.h_taps_c + data->taps.v_taps_c > 2) {
set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE_C);
set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN_C);
is_scaling_needed = true;
} else if (data->format != PIXEL_FORMAT_420BPP8) {
set_reg_field_value(
value,
get_reg_field_value(value, SCLV_MODE, SCL_MODE),
SCLV_MODE,
SCL_MODE_C);
set_reg_field_value(
value,
get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN),
SCLV_MODE,
SCL_PSCL_EN_C);
} else {
set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C);
set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C);
}
dm_write_reg(ctx, mmSCLV_MODE, value);
value = 0;
/*
* 0 - Replaced out of bound pixels with black pixel
* (or any other required color)
* 1 - Replaced out of bound pixels with the edge pixel
*/
set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE);
dm_write_reg(ctx, mmSCLV_CONTROL, value);
return is_scaling_needed;
}
/*
* Function:
* void program_overscan
*
* Purpose: Programs overscan border
* Input: overscan
*
* Output: void
*/
static void program_overscan(
struct dce_transform *xfm_dce,
const struct scaler_data *data)
{
uint32_t overscan_left_right = 0;
uint32_t overscan_top_bottom = 0;
int overscan_right = data->h_active - data->recout.x - data->recout.width;
int overscan_bottom = data->v_active - data->recout.y - data->recout.height;
if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
overscan_bottom += 2;
overscan_right += 2;
}
if (overscan_right < 0) {
BREAK_TO_DEBUGGER();
overscan_right = 0;
}
if (overscan_bottom < 0) {
BREAK_TO_DEBUGGER();
overscan_bottom = 0;
}
set_reg_field_value(overscan_left_right, data->recout.x,
EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT);
set_reg_field_value(overscan_left_right, overscan_right,
EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT);
set_reg_field_value(overscan_top_bottom, data->recout.y,
EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP);
set_reg_field_value(overscan_top_bottom, overscan_bottom,
EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM);
dm_write_reg(xfm_dce->base.ctx,
mmSCLV_EXT_OVERSCAN_LEFT_RIGHT,
overscan_left_right);
dm_write_reg(xfm_dce->base.ctx,
mmSCLV_EXT_OVERSCAN_TOP_BOTTOM,
overscan_top_bottom);
}
static void set_coeff_update_complete(
struct dce_transform *xfm_dce)
{
uint32_t value;
value = dm_read_reg(xfm_dce->base.ctx, mmSCLV_UPDATE);
set_reg_field_value(value, 1, SCLV_UPDATE, SCL_COEF_UPDATE_COMPLETE);
dm_write_reg(xfm_dce->base.ctx, mmSCLV_UPDATE, value);
}
static void program_multi_taps_filter(
struct dce_transform *xfm_dce,
int taps,
const uint16_t *coeffs,
enum ram_filter_type filter_type)
{
struct dc_context *ctx = xfm_dce->base.ctx;
int i, phase, pair;
int array_idx = 0;
int taps_pairs = (taps + 1) / 2;
int phases_to_program = SCLV_PHASES / 2 + 1;
uint32_t select = 0;
uint32_t power_ctl, power_ctl_off;
if (!coeffs)
return;
/*We need to disable power gating on coeff memory to do programming*/
power_ctl = dm_read_reg(ctx, mmDCFEV_MEM_PWR_CTRL);
power_ctl_off = power_ctl;
set_reg_field_value(power_ctl_off, 1, DCFEV_MEM_PWR_CTRL, SCLV_COEFF_MEM_PWR_DIS);
dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl_off);
/*Wait to disable gating:*/
for (i = 0; i < 10; i++) {
if (get_reg_field_value(
dm_read_reg(ctx, mmDCFEV_MEM_PWR_STATUS),
DCFEV_MEM_PWR_STATUS,
SCLV_COEFF_MEM_PWR_STATE) == 0)
break;
udelay(1);
}
set_reg_field_value(select, filter_type, SCLV_COEF_RAM_SELECT, SCL_C_RAM_FILTER_TYPE);
for (phase = 0; phase < phases_to_program; phase++) {
/*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror
phase 0 is unique and phase N/2 is unique if N is even*/
set_reg_field_value(select, phase, SCLV_COEF_RAM_SELECT, SCL_C_RAM_PHASE);
for (pair = 0; pair < taps_pairs; pair++) {
uint32_t data = 0;
set_reg_field_value(select, pair,
SCLV_COEF_RAM_SELECT, SCL_C_RAM_TAP_PAIR_IDX);
dm_write_reg(ctx, mmSCLV_COEF_RAM_SELECT, select);
set_reg_field_value(
data, 1,
SCLV_COEF_RAM_TAP_DATA,
SCL_C_RAM_EVEN_TAP_COEF_EN);
set_reg_field_value(
data, coeffs[array_idx],
SCLV_COEF_RAM_TAP_DATA,
SCL_C_RAM_EVEN_TAP_COEF);
if (taps % 2 && pair == taps_pairs - 1) {
set_reg_field_value(
data, 0,
SCLV_COEF_RAM_TAP_DATA,
SCL_C_RAM_ODD_TAP_COEF_EN);
array_idx++;
} else {
set_reg_field_value(
data, 1,
SCLV_COEF_RAM_TAP_DATA,
SCL_C_RAM_ODD_TAP_COEF_EN);
set_reg_field_value(
data, coeffs[array_idx + 1],
SCLV_COEF_RAM_TAP_DATA,
SCL_C_RAM_ODD_TAP_COEF);
array_idx += 2;
}
dm_write_reg(ctx, mmSCLV_COEF_RAM_TAP_DATA, data);
}
}
/*We need to restore power gating on coeff memory to initial state*/
dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl);
}
static void calculate_inits(
struct dce_transform *xfm_dce,
const struct scaler_data *data,
struct sclv_ratios_inits *inits,
struct rect *luma_viewport,
struct rect *chroma_viewport)
{
(void)xfm_dce;
(void)luma_viewport;
(void)chroma_viewport;
inits->h_int_scale_ratio_luma =
dc_fixpt_u2d19(data->ratios.horz) << 5;
inits->v_int_scale_ratio_luma =
dc_fixpt_u2d19(data->ratios.vert) << 5;
inits->h_int_scale_ratio_chroma =
dc_fixpt_u2d19(data->ratios.horz_c) << 5;
inits->v_int_scale_ratio_chroma =
dc_fixpt_u2d19(data->ratios.vert_c) << 5;
inits->h_init_luma.integer = 1;
inits->v_init_luma.integer = 1;
inits->h_init_chroma.integer = 1;
inits->v_init_chroma.integer = 1;
}
static void program_scl_ratios_inits(
struct dce_transform *xfm_dce,
struct sclv_ratios_inits *inits)
{
struct dc_context *ctx = xfm_dce->base.ctx;
uint32_t addr = mmSCLV_HORZ_FILTER_SCALE_RATIO;
uint32_t value = 0;
set_reg_field_value(
value,
inits->h_int_scale_ratio_luma,
SCLV_HORZ_FILTER_SCALE_RATIO,
SCL_H_SCALE_RATIO);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VERT_FILTER_SCALE_RATIO;
value = 0;
set_reg_field_value(
value,
inits->v_int_scale_ratio_luma,
SCLV_VERT_FILTER_SCALE_RATIO,
SCL_V_SCALE_RATIO);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_HORZ_FILTER_SCALE_RATIO_C;
value = 0;
set_reg_field_value(
value,
inits->h_int_scale_ratio_chroma,
SCLV_HORZ_FILTER_SCALE_RATIO_C,
SCL_H_SCALE_RATIO_C);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VERT_FILTER_SCALE_RATIO_C;
value = 0;
set_reg_field_value(
value,
inits->v_int_scale_ratio_chroma,
SCLV_VERT_FILTER_SCALE_RATIO_C,
SCL_V_SCALE_RATIO_C);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_HORZ_FILTER_INIT;
value = 0;
set_reg_field_value(
value,
inits->h_init_luma.fraction,
SCLV_HORZ_FILTER_INIT,
SCL_H_INIT_FRAC);
set_reg_field_value(
value,
inits->h_init_luma.integer,
SCLV_HORZ_FILTER_INIT,
SCL_H_INIT_INT);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VERT_FILTER_INIT;
value = 0;
set_reg_field_value(
value,
inits->v_init_luma.fraction,
SCLV_VERT_FILTER_INIT,
SCL_V_INIT_FRAC);
set_reg_field_value(
value,
inits->v_init_luma.integer,
SCLV_VERT_FILTER_INIT,
SCL_V_INIT_INT);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_HORZ_FILTER_INIT_C;
value = 0;
set_reg_field_value(
value,
inits->h_init_chroma.fraction,
SCLV_HORZ_FILTER_INIT_C,
SCL_H_INIT_FRAC_C);
set_reg_field_value(
value,
inits->h_init_chroma.integer,
SCLV_HORZ_FILTER_INIT_C,
SCL_H_INIT_INT_C);
dm_write_reg(ctx, addr, value);
addr = mmSCLV_VERT_FILTER_INIT_C;
value = 0;
set_reg_field_value(
value,
inits->v_init_chroma.fraction,
SCLV_VERT_FILTER_INIT_C,
SCL_V_INIT_FRAC_C);
set_reg_field_value(
value,
inits->v_init_chroma.integer,
SCLV_VERT_FILTER_INIT_C,
SCL_V_INIT_INT_C);
dm_write_reg(ctx, addr, value);
}
static const uint16_t *get_filter_coeffs_64p(int taps, struct fixed31_32 ratio)
{
if (taps == 4)
return get_filter_4tap_64p(ratio);
else if (taps == 2)
return get_filter_2tap_64p();
else if (taps == 1)
return NULL;
else {
/* should never happen, bug */
BREAK_TO_DEBUGGER();
return NULL;
}
}
static bool dce110_xfmv_power_up_line_buffer(struct transform *xfm)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
uint32_t value;
value = dm_read_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL);
/*Use all three pieces of memory always*/
set_reg_field_value(value, 0, LBV_MEMORY_CTRL, LB_MEMORY_CONFIG);
/*hard coded number DCE11 1712(0x6B0) Partitions: 720/960/1712*/
set_reg_field_value(value, xfm_dce->lb_memory_size, LBV_MEMORY_CTRL,
LB_MEMORY_SIZE);
dm_write_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL, value);
return true;
}
static void dce110_xfmv_set_scaler(
struct transform *xfm,
const struct scaler_data *data)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
bool is_scaling_required = false;
bool filter_updated = false;
const uint16_t *coeffs_v, *coeffs_h, *coeffs_h_c, *coeffs_v_c;
struct rect luma_viewport = {0};
struct rect chroma_viewport = {0};
dce110_xfmv_power_up_line_buffer(xfm);
/* 1. Calculate viewport, viewport programming should happen after init
* calculations as they may require an adjustment in the viewport.
*/
calculate_viewport(data, &luma_viewport, &chroma_viewport);
/* 2. Program overscan */
program_overscan(xfm_dce, data);
/* 3. Program taps and configuration */
is_scaling_required = setup_scaling_configuration(xfm_dce, data);
if (is_scaling_required) {
/* 4. Calculate and program ratio, filter initialization */
struct sclv_ratios_inits inits = { 0 };
calculate_inits(
xfm_dce,
data,
&inits,
&luma_viewport,
&chroma_viewport);
program_scl_ratios_inits(xfm_dce, &inits);
coeffs_v = get_filter_coeffs_64p(data->taps.v_taps, data->ratios.vert);
coeffs_h = get_filter_coeffs_64p(data->taps.h_taps, data->ratios.horz);
coeffs_v_c = get_filter_coeffs_64p(data->taps.v_taps_c, data->ratios.vert_c);
coeffs_h_c = get_filter_coeffs_64p(data->taps.h_taps_c, data->ratios.horz_c);
if (coeffs_v != xfm_dce->filter_v
|| coeffs_v_c != xfm_dce->filter_v_c
|| coeffs_h != xfm_dce->filter_h
|| coeffs_h_c != xfm_dce->filter_h_c) {
/* 5. Program vertical filters */
program_multi_taps_filter(
xfm_dce,
data->taps.v_taps,
coeffs_v,
FILTER_TYPE_RGB_Y_VERTICAL);
program_multi_taps_filter(
xfm_dce,
data->taps.v_taps_c,
coeffs_v_c,
FILTER_TYPE_CBCR_VERTICAL);
/* 6. Program horizontal filters */
program_multi_taps_filter(
xfm_dce,
data->taps.h_taps,
coeffs_h,
FILTER_TYPE_RGB_Y_HORIZONTAL);
program_multi_taps_filter(
xfm_dce,
data->taps.h_taps_c,
coeffs_h_c,
FILTER_TYPE_CBCR_HORIZONTAL);
xfm_dce->filter_v = coeffs_v;
xfm_dce->filter_v_c = coeffs_v_c;
xfm_dce->filter_h = coeffs_h;
xfm_dce->filter_h_c = coeffs_h_c;
filter_updated = true;
}
}
/* 7. Program the viewport */
program_viewport(xfm_dce, &luma_viewport, &chroma_viewport);
/* 8. Set bit to flip to new coefficient memory */
if (filter_updated)
set_coeff_update_complete(xfm_dce);
}
static void dce110_xfmv_reset(struct transform *xfm)
{
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
xfm_dce->filter_h = NULL;
xfm_dce->filter_v = NULL;
xfm_dce->filter_h_c = NULL;
xfm_dce->filter_v_c = NULL;
}
static void dce110_xfmv_set_gamut_remap(
struct transform *xfm,
const struct xfm_grph_csc_adjustment *adjust)
{
(void)xfm;
(void)adjust;
/* DO NOTHING*/
}
static void dce110_xfmv_set_pixel_storage_depth(
struct transform *xfm,
enum lb_pixel_depth depth,
const struct bit_depth_reduction_params *bit_depth_params)
{
(void)bit_depth_params;
struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
int pixel_depth = 0;
int expan_mode = 0;
uint32_t reg_data = 0;
switch (depth) {
case LB_PIXEL_DEPTH_18BPP:
pixel_depth = 2;
expan_mode = 1;
break;
case LB_PIXEL_DEPTH_24BPP:
pixel_depth = 1;
expan_mode = 1;
break;
case LB_PIXEL_DEPTH_30BPP:
pixel_depth = 0;
expan_mode = 1;
break;
case LB_PIXEL_DEPTH_36BPP:
pixel_depth = 3;
expan_mode = 0;
break;
default:
BREAK_TO_DEBUGGER();
break;
}
set_reg_field_value(
reg_data,
expan_mode,
LBV_DATA_FORMAT,
PIXEL_EXPAN_MODE);
set_reg_field_value(
reg_data,
pixel_depth,
LBV_DATA_FORMAT,
PIXEL_DEPTH);
dm_write_reg(xfm->ctx, mmLBV_DATA_FORMAT, reg_data);
if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
/*we should use unsupported capabilities
* unless it is required by w/a*/
DC_LOG_WARNING("%s: Capability not supported",
__func__);
}
}
static const struct transform_funcs dce110_xfmv_funcs = {
.transform_reset = dce110_xfmv_reset,
.transform_set_scaler = dce110_xfmv_set_scaler,
.transform_set_gamut_remap =
dce110_xfmv_set_gamut_remap,
.opp_set_csc_default = dce110_opp_v_set_csc_default,
.opp_set_csc_adjustment = dce110_opp_v_set_csc_adjustment,
.opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut_v,
.opp_program_regamma_pwl = dce110_opp_program_regamma_pwl_v,
.opp_set_regamma_mode = dce110_opp_set_regamma_mode_v,
.transform_set_pixel_storage_depth =
dce110_xfmv_set_pixel_storage_depth,
.transform_get_optimal_number_of_taps =
dce_transform_get_optimal_number_of_taps
};
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
bool dce110_transform_v_construct(
struct dce_transform *xfm_dce,
struct dc_context *ctx)
{
xfm_dce->base.ctx = ctx;
xfm_dce->base.funcs = &dce110_xfmv_funcs;
xfm_dce->lb_pixel_depth_supported =
LB_PIXEL_DEPTH_18BPP |
LB_PIXEL_DEPTH_24BPP |
LB_PIXEL_DEPTH_30BPP |
LB_PIXEL_DEPTH_36BPP;
xfm_dce->prescaler_on = true;
xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;
xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/
return true;
}
@@ -0,0 +1,58 @@
/* Copyright 2012-15 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
*
*/
#ifndef __DAL_TRANSFORM_V_DCE110_H__
#define __DAL_TRANSFORM_V_DCE110_H__
#include "../dce/dce_transform.h"
#define LB_TOTAL_NUMBER_OF_ENTRIES 1712
#define LB_BITS_PER_ENTRY 144
bool dce110_transform_v_construct(
struct dce_transform *xfm110,
struct dc_context *ctx);
void dce110_opp_v_set_csc_default(
struct transform *xfm,
const struct default_adjustment *default_adjust);
void dce110_opp_v_set_csc_adjustment(
struct transform *xfm,
const struct out_csc_color_matrix *tbl_entry);
void dce110_opp_program_regamma_pwl_v(
struct transform *xfm,
const struct pwl_params *params);
void dce110_opp_power_on_regamma_lut_v(
struct transform *xfm,
bool power_on);
void dce110_opp_set_regamma_mode_v(
struct transform *xfm,
enum opp_regamma mode);
#endif