drm/amd/display: Add DCE12 core support

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Harry Wentland 2017-03-06 14:36:02 -05:00 committed by Alex Deucher
parent 9a48d68448
commit b8fdfcc6a9
12 changed files with 3387 additions and 0 deletions

View File

@ -0,0 +1,197 @@
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "dm_services.h"
#include "dc.h"
#include "core_dc.h"
#include "core_types.h"
#include "dce120_hw_sequencer.h"
#include "dce110/dce110_hw_sequencer.h"
/* include DCE12.0 register header files */
#include "vega10/DC/dce_12_0_offset.h"
#include "vega10/DC/dce_12_0_sh_mask.h"
#include "vega10/soc15ip.h"
#include "reg_helper.h"
struct dce120_hw_seq_reg_offsets {
uint32_t crtc;
};
static const struct dce120_hw_seq_reg_offsets reg_offsets[] = {
{
.crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
},
{
.crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
},
{
.crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
},
{
.crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
},
{
.crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
},
{
.crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
}
};
#define HW_REG_CRTC(reg, id)\
(reg + reg_offsets[id].crtc)
#define CNTL_ID(controller_id)\
controller_id
/*******************************************************************************
* Private definitions
******************************************************************************/
#if 0
static void dce120_init_pte(struct dc_context *ctx, uint8_t controller_id)
{
uint32_t addr;
uint32_t value = 0;
uint32_t chunk_int = 0;
uint32_t chunk_mul = 0;
/*
addr = mmDCP0_DVMM_PTE_CONTROL + controller_id *
(mmDCP1_DVMM_PTE_CONTROL- mmDCP0_DVMM_PTE_CONTROL);
value = dm_read_reg(ctx, addr);
set_reg_field_value(
value, 0, DCP, controller_id,
DVMM_PTE_CONTROL,
DVMM_USE_SINGLE_PTE);
set_reg_field_value_soc15(
value, 1, DCP, controller_id,
DVMM_PTE_CONTROL,
DVMM_PTE_BUFFER_MODE0);
set_reg_field_value_soc15(
value, 1, DCP, controller_id,
DVMM_PTE_CONTROL,
DVMM_PTE_BUFFER_MODE1);
dm_write_reg(ctx, addr, value);*/
addr = mmDVMM_PTE_REQ;
value = dm_read_reg(ctx, addr);
chunk_int = get_reg_field_value(
value,
DVMM_PTE_REQ,
HFLIP_PTEREQ_PER_CHUNK_INT);
chunk_mul = get_reg_field_value(
value,
DVMM_PTE_REQ,
HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
if (chunk_int != 0x4 || chunk_mul != 0x4) {
set_reg_field_value(
value,
255,
DVMM_PTE_REQ,
MAX_PTEREQ_TO_ISSUE);
set_reg_field_value(
value,
4,
DVMM_PTE_REQ,
HFLIP_PTEREQ_PER_CHUNK_INT);
set_reg_field_value(
value,
4,
DVMM_PTE_REQ,
HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
dm_write_reg(ctx, addr, value);
}
}
#endif
static bool dce120_enable_display_power_gating(
struct core_dc *dc,
uint8_t controller_id,
struct dc_bios *dcb,
enum pipe_gating_control power_gating)
{
/* disable for bringup */
#if 0
enum bp_result bp_result = BP_RESULT_OK;
enum bp_pipe_control_action cntl;
struct dc_context *ctx = dc->ctx;
if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
return true;
if (power_gating == PIPE_GATING_CONTROL_INIT)
cntl = ASIC_PIPE_INIT;
else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
cntl = ASIC_PIPE_ENABLE;
else
cntl = ASIC_PIPE_DISABLE;
if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) {
bp_result = dcb->funcs->enable_disp_power_gating(
dcb, controller_id + 1, cntl);
/* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2
* by default when command table is called
*/
dm_write_reg(ctx,
HW_REG_CRTC(mmCRTC0_CRTC_MASTER_UPDATE_MODE, controller_id),
0);
}
if (power_gating != PIPE_GATING_CONTROL_ENABLE)
dce120_init_pte(ctx, controller_id);
if (bp_result == BP_RESULT_OK)
return true;
else
return false;
#endif
return false;
}
bool dce120_hw_sequencer_construct(struct core_dc *dc)
{
/* All registers used by dce11.2 match those in dce11 in offset and
* structure
*/
dce110_hw_sequencer_construct(dc);
dc->hwss.enable_display_power_gating = dce120_enable_display_power_gating;
return true;
}

View File

@ -0,0 +1,36 @@
/*
* 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_HWSS_DCE120_H__
#define __DC_HWSS_DCE120_H__
#include "core_types.h"
struct core_dc;
bool dce120_hw_sequencer_construct(struct core_dc *dc);
#endif /* __DC_HWSS_DCE112_H__ */

View File

@ -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
*
*/
#include "dm_services.h"
#include "include/logger_interface.h"
#include "vega10/DC/dce_12_0_offset.h"
#include "vega10/DC/dce_12_0_sh_mask.h"
#include "vega10/soc15ip.h"
#include "dce120_ipp.h"
static const struct ipp_funcs funcs = {
.ipp_cursor_set_attributes = dce120_ipp_cursor_set_attributes,
.ipp_cursor_set_position = dce120_ipp_cursor_set_position,
.ipp_program_prescale = dce120_ipp_program_prescale,
.ipp_program_input_lut = dce120_ipp_program_input_lut,
.ipp_set_degamma = dce120_ipp_set_degamma,
};
bool dce120_ipp_construct(
struct dce110_ipp *ipp,
struct dc_context *ctx,
uint32_t inst,
const struct dce110_ipp_reg_offsets *offset)
{
if (!dce110_ipp_construct(ipp, ctx, inst, offset)) {
ASSERT_CRITICAL(false);
return false;
}
ipp->base.funcs = &funcs;
return true;
}

View File

@ -0,0 +1,62 @@
/*
* 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_IPP_DCE120_H__
#define __DC_IPP_DCE120_H__
#include "ipp.h"
#include "../dce110/dce110_ipp.h"
bool dce120_ipp_construct(
struct dce110_ipp *ipp,
struct dc_context *ctx,
enum controller_id id,
const struct dce110_ipp_reg_offsets *offset);
/* CURSOR RELATED */
void dce120_ipp_cursor_set_position(
struct input_pixel_processor *ipp,
const struct dc_cursor_position *position,
const struct dc_cursor_mi_param *param);
bool dce120_ipp_cursor_set_attributes(
struct input_pixel_processor *ipp,
const struct dc_cursor_attributes *attributes);
/* DEGAMMA RELATED */
bool dce120_ipp_set_degamma(
struct input_pixel_processor *ipp,
enum ipp_degamma_mode mode);
void dce120_ipp_program_prescale(
struct input_pixel_processor *ipp,
struct ipp_prescale_params *params);
void dce120_ipp_program_input_lut(
struct input_pixel_processor *ipp,
const struct dc_gamma *gamma);
#endif /*__DC_IPP_DCE120_H__*/

View File

@ -0,0 +1,202 @@
/*
* 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 "include/logger_interface.h"
#include "vega10/DC/dce_12_0_offset.h"
#include "vega10/DC/dce_12_0_sh_mask.h"
#include "vega10/soc15ip.h"
#include "../dce110/dce110_ipp.h"
#define DCP_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
#define DCP_REG_SET_N(reg_name, n, ...) \
generic_reg_set_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
#define DCP_REG_UPDATE(reg, field, val) \
DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2) \
DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define DCP_REG_SET(reg, field, val) \
DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_SET_2(reg, field1, val1, field2, val2) \
DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
/* TODO: DAL3 does not implement cursor memory control
* MCIF_MEM_CONTROL, DMIF_CURSOR_MEM_CONTROL
*/
static void lock(
struct dce110_ipp *ipp110, bool lock)
{
DCP_REG_UPDATE(DCP0_CUR_UPDATE, CURSOR_UPDATE_LOCK, lock);
}
static bool program_control(
struct dce110_ipp *ipp110,
enum dc_cursor_color_format color_format,
bool enable_magnification,
bool inverse_transparent_clamping)
{
uint32_t mode = 0;
switch (color_format) {
case CURSOR_MODE_MONO:
mode = 0;
break;
case CURSOR_MODE_COLOR_1BIT_AND:
mode = 1;
break;
case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
mode = 2;
break;
case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
mode = 3;
break;
default:
return false;
}
DCP_REG_UPDATE_3(
DCP0_CUR_CONTROL,
CURSOR_MODE, mode,
CURSOR_2X_MAGNIFY, enable_magnification,
CUR_INV_TRANS_CLAMP, inverse_transparent_clamping);
if (color_format == CURSOR_MODE_MONO) {
DCP_REG_SET_3(
DCP0_CUR_COLOR1,
CUR_COLOR1_BLUE, 0,
CUR_COLOR1_GREEN, 0,
CUR_COLOR1_RED, 0);
DCP_REG_SET_3(
DCP0_CUR_COLOR2,
CUR_COLOR2_BLUE, 0xff,
CUR_COLOR2_GREEN, 0xff,
CUR_COLOR2_RED, 0xff);
}
return true;
}
static void program_address(
struct dce110_ipp *ipp110,
PHYSICAL_ADDRESS_LOC address)
{
/* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
* surface base address in byte. It is 4K byte aligned.
* The correct way to program cursor surface address is to first write
* to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
*/
DCP_REG_SET(
DCP0_CUR_SURFACE_ADDRESS_HIGH,
CURSOR_SURFACE_ADDRESS_HIGH, address.high_part);
DCP_REG_SET(
DCP0_CUR_SURFACE_ADDRESS,
CURSOR_SURFACE_ADDRESS, address.low_part);
}
void dce120_ipp_cursor_set_position(
struct input_pixel_processor *ipp,
const struct dc_cursor_position *position,
const struct dc_cursor_mi_param *param)
{
struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
/* lock cursor registers */
lock(ipp110, true);
/* Flag passed in structure differentiates cursor enable/disable. */
/* Update if it differs from cached state. */
DCP_REG_UPDATE(DCP0_CUR_CONTROL, CURSOR_EN, position->enable);
DCP_REG_SET_2(
DCP0_CUR_POSITION,
CURSOR_X_POSITION, position->x,
CURSOR_Y_POSITION, position->y);
if (position->hot_spot_enable)
DCP_REG_SET_2(
DCP0_CUR_HOT_SPOT,
CURSOR_HOT_SPOT_X, position->x_hotspot,
CURSOR_HOT_SPOT_Y, position->y_hotspot);
/* unlock cursor registers */
lock(ipp110, false);
}
bool dce120_ipp_cursor_set_attributes(
struct input_pixel_processor *ipp,
const struct dc_cursor_attributes *attributes)
{
struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
/* Lock cursor registers */
lock(ipp110, true);
/* Program cursor control */
program_control(
ipp110,
attributes->color_format,
attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
/* Program hot spot coordinates */
DCP_REG_SET_2(
DCP0_CUR_HOT_SPOT,
CURSOR_HOT_SPOT_X, attributes->x_hot,
CURSOR_HOT_SPOT_Y, attributes->y_hot);
/*
* Program cursor size -- NOTE: HW spec specifies that HW register
* stores size as (height - 1, width - 1)
*/
DCP_REG_SET_2(
DCP0_CUR_SIZE,
CURSOR_WIDTH, attributes->width-1,
CURSOR_HEIGHT, attributes->height-1);
/* Program cursor surface address */
program_address(ipp110, attributes->address);
/* Unlock Cursor registers. */
lock(ipp110, false);
return true;
}

View File

@ -0,0 +1,167 @@
/*
* 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 "include/logger_interface.h"
#include "include/fixed31_32.h"
#include "basics/conversion.h"
#include "vega10/DC/dce_12_0_offset.h"
#include "vega10/DC/dce_12_0_sh_mask.h"
#include "vega10/soc15ip.h"
#include "../dce110/dce110_ipp.h"
#define DCP_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
#define DCP_REG_SET_N(reg_name, n, ...) \
generic_reg_set_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
#define DCP_REG_UPDATE(reg, field, val) \
DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2) \
DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define DCP_REG_SET(reg, field, val) \
DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_SET_2(reg, field1, val1, field2, val2) \
DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
bool dce120_ipp_set_degamma(
struct input_pixel_processor *ipp,
enum ipp_degamma_mode mode)
{
struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS ||
mode == IPP_DEGAMMA_MODE_HW_sRGB);
DCP_REG_SET_3(
DCP0_DEGAMMA_CONTROL,
GRPH_DEGAMMA_MODE, degamma_type,
CURSOR_DEGAMMA_MODE, degamma_type,
CURSOR2_DEGAMMA_MODE, degamma_type);
return true;
}
void dce120_ipp_program_prescale(
struct input_pixel_processor *ipp,
struct ipp_prescale_params *params)
{
struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
/* set to bypass mode first before change */
DCP_REG_UPDATE(
DCP0_PRESCALE_GRPH_CONTROL,
GRPH_PRESCALE_BYPASS,
1);
DCP_REG_SET_2(
DCP0_PRESCALE_VALUES_GRPH_R,
GRPH_PRESCALE_SCALE_R, params->scale,
GRPH_PRESCALE_BIAS_R, params->bias);
DCP_REG_SET_2(
DCP0_PRESCALE_VALUES_GRPH_G,
GRPH_PRESCALE_SCALE_G, params->scale,
GRPH_PRESCALE_BIAS_G, params->bias);
DCP_REG_SET_2(
DCP0_PRESCALE_VALUES_GRPH_B,
GRPH_PRESCALE_SCALE_B, params->scale,
GRPH_PRESCALE_BIAS_B, params->bias);
if (params->mode != IPP_PRESCALE_MODE_BYPASS) {
DCP_REG_UPDATE(DCP0_PRESCALE_GRPH_CONTROL,
GRPH_PRESCALE_BYPASS, 0);
/* If prescale is in use, then legacy lut should be bypassed */
DCP_REG_UPDATE(DCP0_INPUT_GAMMA_CONTROL,
GRPH_INPUT_GAMMA_MODE, 1);
}
}
static void dce120_helper_select_lut(struct dce110_ipp *ipp110)
{
/* enable all */
DCP_REG_SET(
DCP0_DC_LUT_WRITE_EN_MASK,
DC_LUT_WRITE_EN_MASK,
0x7);
/* 256 entry mode */
DCP_REG_UPDATE(DCP0_DC_LUT_RW_MODE, DC_LUT_RW_MODE, 0);
/* LUT-256, unsigned, integer, new u0.12 format */
DCP_REG_SET_3(
DCP0_DC_LUT_CONTROL,
DC_LUT_DATA_R_FORMAT, 3,
DC_LUT_DATA_G_FORMAT, 3,
DC_LUT_DATA_B_FORMAT, 3);
/* start from index 0 */
DCP_REG_SET(
DCP0_DC_LUT_RW_INDEX,
DC_LUT_RW_INDEX,
0);
}
void dce120_ipp_program_input_lut(
struct input_pixel_processor *ipp,
const struct dc_gamma *gamma)
{
int i;
struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
/* power on LUT memory */
DCP_REG_SET(DCFE0_DCFE_MEM_PWR_CTRL, DCP_LUT_MEM_PWR_DIS, 1);
dce120_helper_select_lut(ipp110);
for (i = 0; i < INPUT_LUT_ENTRIES; i++) {
DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->red[i]);
DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->green[i]);
DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->blue[i]);
}
/* power off LUT memory */
DCP_REG_SET(DCFE0_DCFE_MEM_PWR_CTRL, DCP_LUT_MEM_PWR_DIS, 0);
/* bypass prescale, enable legacy LUT */
DCP_REG_UPDATE(DCP0_PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
DCP_REG_UPDATE(DCP0_INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
}

View File

@ -0,0 +1,340 @@
/*
* 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 "dce120_mem_input.h"
#include "vega10/DC/dce_12_0_offset.h"
#include "vega10/DC/dce_12_0_sh_mask.h"
#include "vega10/soc15ip.h"
#define GENERAL_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(mem_input110->base.ctx, 0, reg_name, n, __VA_ARGS__)
#define GENERAL_REG_UPDATE(reg, field, val) \
GENERAL_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define GENERAL_REG_UPDATE_2(reg, field1, val1, field2, val2) \
GENERAL_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.dcp, reg_name, n, __VA_ARGS__)
#define DCP_REG_SET_N(reg_name, n, ...) \
generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.dcp, reg_name, n, __VA_ARGS__)
#define DCP_REG_UPDATE(reg, field, val) \
DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2) \
DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define DCP_REG_SET(reg, field, val) \
DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
#define DCP_REG_SET_2(reg, field1, val1, field2, val2) \
DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define DMIF_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.dmif, reg_name, n, __VA_ARGS__)
#define DMIF_REG_SET_N(reg_name, n, ...) \
generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.dmif, reg_name, n, __VA_ARGS__)
#define DMIF_REG_UPDATE(reg, field, val) \
DMIF_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define DMIF_REG_UPDATE_2(reg, field1, val1, field2, val2) \
DMIF_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DMIF_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
DMIF_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define DMIF_REG_SET(reg, field, val) \
DMIF_REG_SET_N(reg, 1, FD(reg##__##field), val)
#define DMIF_REG_SET_2(reg, field1, val1, field2, val2) \
DMIF_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define DMIF_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
DMIF_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define PIPE_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.pipe, reg_name, n, __VA_ARGS__)
#define PIPE_REG_SET_N(reg_name, n, ...) \
generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.pipe, reg_name, n, __VA_ARGS__)
#define PIPE_REG_UPDATE(reg, field, val) \
PIPE_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
#define PIPE_REG_UPDATE_2(reg, field1, val1, field2, val2) \
PIPE_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define PIPE_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
PIPE_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
#define PIPE_REG_SET(reg, field, val) \
PIPE_REG_SET_N(reg, 1, FD(reg##__##field), val)
#define PIPE_REG_SET_2(reg, field1, val1, field2, val2) \
PIPE_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
#define PIPE_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
PIPE_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
static void program_sec_addr(
struct dce110_mem_input *mem_input110,
PHYSICAL_ADDRESS_LOC address)
{
uint32_t temp;
/*high register MUST be programmed first*/
temp = address.high_part &
DCP0_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH__GRPH_SECONDARY_SURFACE_ADDRESS_HIGH_MASK;
DCP_REG_SET(
DCP0_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
temp);
temp = address.low_part >>
DCP0_GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS__SHIFT;
DCP_REG_SET_2(
DCP0_GRPH_SECONDARY_SURFACE_ADDRESS,
GRPH_SECONDARY_SURFACE_ADDRESS, temp,
GRPH_SECONDARY_DFQ_ENABLE, 0);
}
static void program_pri_addr(
struct dce110_mem_input *mem_input110,
PHYSICAL_ADDRESS_LOC address)
{
uint32_t temp;
/*high register MUST be programmed first*/
temp = address.high_part &
DCP0_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_MASK;
DCP_REG_SET(
DCP0_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
temp);
temp = address.low_part >>
DCP0_GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS__SHIFT;
DCP_REG_SET(
DCP0_GRPH_PRIMARY_SURFACE_ADDRESS,
GRPH_PRIMARY_SURFACE_ADDRESS,
temp);
}
static bool mem_input_is_flip_pending(struct mem_input *mem_input)
{
struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
uint32_t value;
value = dm_read_reg_soc15(mem_input110->base.ctx,
mmDCP0_GRPH_UPDATE, mem_input110->offsets.dcp);
if (get_reg_field_value(value, DCP0_GRPH_UPDATE,
GRPH_SURFACE_UPDATE_PENDING))
return true;
mem_input->current_address = mem_input->request_address;
return false;
}
static bool mem_input_program_surface_flip_and_addr(
struct mem_input *mem_input,
const struct dc_plane_address *address,
bool flip_immediate)
{
struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
/* TODO: Figure out if two modes are needed:
* non-XDMA Mode: GRPH_SURFACE_UPDATE_IMMEDIATE_EN = 1
* XDMA Mode: GRPH_SURFACE_UPDATE_H_RETRACE_EN = 1
*/
DCP_REG_UPDATE(DCP0_GRPH_UPDATE,
GRPH_UPDATE_LOCK, 1);
if (flip_immediate) {
DCP_REG_UPDATE_2(
DCP0_GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 1);
} else {
DCP_REG_UPDATE_2(
DCP0_GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
}
switch (address->type) {
case PLN_ADDR_TYPE_GRAPHICS:
if (address->grph.addr.quad_part == 0)
break;
program_pri_addr(mem_input110, address->grph.addr);
break;
case PLN_ADDR_TYPE_GRPH_STEREO:
if (address->grph_stereo.left_addr.quad_part == 0
|| address->grph_stereo.right_addr.quad_part == 0)
break;
program_pri_addr(mem_input110, address->grph_stereo.left_addr);
program_sec_addr(mem_input110, address->grph_stereo.right_addr);
break;
default:
/* not supported */
BREAK_TO_DEBUGGER();
break;
}
mem_input->request_address = *address;
if (flip_immediate)
mem_input->current_address = *address;
DCP_REG_UPDATE(DCP0_GRPH_UPDATE,
GRPH_UPDATE_LOCK, 0);
return true;
}
static void mem_input_update_dchub(struct mem_input *mi,
struct dchub_init_data *dh_data)
{
struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mi);
/* TODO: port code from dal2 */
switch (dh_data->fb_mode) {
case FRAME_BUFFER_MODE_ZFB_ONLY:
/*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
GENERAL_REG_UPDATE_2(
DCHUB_FB_LOCATION,
FB_TOP, 0,
FB_BASE, 0x0FFFF);
GENERAL_REG_UPDATE(
DCHUB_AGP_BASE,
AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
GENERAL_REG_UPDATE(
DCHUB_AGP_BOT,
AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
GENERAL_REG_UPDATE(
DCHUB_AGP_TOP,
AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
break;
case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
GENERAL_REG_UPDATE(
DCHUB_AGP_BASE,
AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
GENERAL_REG_UPDATE(
DCHUB_AGP_BOT,
AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
GENERAL_REG_UPDATE(
DCHUB_AGP_TOP,
AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
break;
case FRAME_BUFFER_MODE_LOCAL_ONLY:
/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
GENERAL_REG_UPDATE(
DCHUB_AGP_BASE,
AGP_BASE, 0);
GENERAL_REG_UPDATE(
DCHUB_AGP_BOT,
AGP_BOT, 0x03FFFF);
GENERAL_REG_UPDATE(
DCHUB_AGP_TOP,
AGP_TOP, 0);
break;
default:
break;
}
dh_data->dchub_initialzied = true;
dh_data->dchub_info_valid = false;
}
static struct mem_input_funcs dce120_mem_input_funcs = {
.mem_input_program_display_marks = dce_mem_input_program_display_marks,
.allocate_mem_input = dce_mem_input_allocate_dmif,
.free_mem_input = dce_mem_input_free_dmif,
.mem_input_program_surface_flip_and_addr =
mem_input_program_surface_flip_and_addr,
.mem_input_program_pte_vm = dce_mem_input_program_pte_vm,
.mem_input_program_surface_config =
dce_mem_input_program_surface_config,
.mem_input_is_flip_pending = mem_input_is_flip_pending,
.mem_input_update_dchub = mem_input_update_dchub
};
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
bool dce120_mem_input_construct(
struct dce110_mem_input *mem_input110,
struct dc_context *ctx,
uint32_t inst,
const struct dce110_mem_input_reg_offsets *offsets)
{
/* supported stutter method
* STUTTER_MODE_ENHANCED
* STUTTER_MODE_QUAD_DMIF_BUFFER
* STUTTER_MODE_WATERMARK_NBP_STATE
*/
if (!dce110_mem_input_construct(mem_input110, ctx, inst, offsets))
return false;
mem_input110->base.funcs = &dce120_mem_input_funcs;
mem_input110->offsets = *offsets;
return true;
}

View File

@ -0,0 +1,37 @@
/* 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_MEM_INPUT_DCE120_H__
#define __DC_MEM_INPUT_DCE120_H__
#include "mem_input.h"
#include "dce110/dce110_mem_input.h"
bool dce120_mem_input_construct(
struct dce110_mem_input *mem_input110,
struct dc_context *ctx,
uint32_t inst,
const struct dce110_mem_input_reg_offsets *offsets);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -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_RESOURCE_DCE120_H__
#define __DC_RESOURCE_DCE120_H__
#include "core_types.h"
struct core_dc;
struct resource_pool;
struct resource_pool *dce120_create_resource_pool(
uint8_t num_virtual_links,
struct core_dc *dc);
#endif /* __DC_RESOURCE_DCE120_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*
* 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_DCE120_H__
#define __DC_TIMING_GENERATOR_DCE120_H__
#include "timing_generator.h"
#include "../include/grph_object_id.h"
#include "../include/hw_sequencer_types.h"
#include "dce110/dce110_timing_generator.h"
bool dce120_timing_generator_construct(
struct dce110_timing_generator *tg110,
struct dc_context *ctx,
uint32_t instance,
const struct dce110_timing_generator_offsets *offsets);
#endif /* __DC_TIMING_GENERATOR_DCE120_H__ */