mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-17 05:46:08 +07:00
drm/amd/display: DMCU PSR Refactor
- Move PSR programming from link encoder to dmcu Signed-off-by: Amy Zhang <Amy.Zhang@amd.com> Acked-by: Harry Wentland <Harry.Wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
d5b4f2bcff
commit
3548f0731a
@ -40,6 +40,7 @@
|
||||
#include "abm.h"
|
||||
#include "fixed31_32.h"
|
||||
#include "dpcd_defs.h"
|
||||
#include "dmcu.h"
|
||||
|
||||
#include "dce/dce_11_0_d.h"
|
||||
#include "dce/dce_11_0_enum.h"
|
||||
@ -1433,28 +1434,33 @@ bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level,
|
||||
bool dc_link_set_psr_enable(const struct dc_link *dc_link, bool enable)
|
||||
{
|
||||
struct core_link *link = DC_LINK_TO_CORE(dc_link);
|
||||
struct dc_context *ctx = link->ctx;
|
||||
struct core_dc *core_dc = DC_TO_CORE(ctx->dc);
|
||||
struct dmcu *dmcu = core_dc->res_pool->dmcu;
|
||||
|
||||
if (dmcu != NULL && dc_link->psr_caps.psr_version > 0)
|
||||
dmcu->funcs->set_psr_enable(dmcu, enable);
|
||||
|
||||
if (dc_link != NULL && dc_link->psr_caps.psr_version > 0)
|
||||
link->link_enc->funcs->set_dmcu_psr_enable(link->link_enc,
|
||||
enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_link_setup_psr(const struct dc_link *dc_link,
|
||||
const struct dc_stream *stream)
|
||||
{
|
||||
|
||||
struct core_link *link = DC_LINK_TO_CORE(dc_link);
|
||||
struct dc_context *ctx = link->ctx;
|
||||
struct core_dc *core_dc = DC_TO_CORE(ctx->dc);
|
||||
struct dmcu *dmcu = core_dc->res_pool->dmcu;
|
||||
struct core_stream *core_stream = DC_STREAM_TO_CORE(stream);
|
||||
struct psr_dmcu_context psr_context = {0};
|
||||
struct psr_context psr_context = {0};
|
||||
int i;
|
||||
|
||||
psr_context.controllerId = CONTROLLER_ID_UNDEFINED;
|
||||
|
||||
|
||||
if (dc_link != NULL && dc_link->psr_caps.psr_version > 0) {
|
||||
if (dc_link != NULL &&
|
||||
dmcu != NULL &&
|
||||
dc_link->psr_caps.psr_version > 0) {
|
||||
/* updateSinkPsrDpcdConfig*/
|
||||
union dpcd_psr_configuration psr_configuration;
|
||||
|
||||
@ -1552,8 +1558,7 @@ bool dc_link_setup_psr(const struct dc_link *dc_link,
|
||||
*/
|
||||
psr_context.frame_delay = 0;
|
||||
|
||||
link->link_enc->funcs->setup_dmcu_psr
|
||||
(link->link_enc, &psr_context);
|
||||
dmcu->funcs->setup_psr(dmcu, link, &psr_context);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
|
@ -23,6 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core_types.h"
|
||||
#include "link_encoder.h"
|
||||
#include "dce_dmcu.h"
|
||||
#include "dm_services.h"
|
||||
#include "reg_helper.h"
|
||||
@ -42,6 +44,12 @@
|
||||
#define CTX \
|
||||
dmcu_dce->base.ctx
|
||||
|
||||
/* PSR related commands */
|
||||
#define PSR_ENABLE 0x20
|
||||
#define PSR_EXIT 0x21
|
||||
#define PSR_SET 0x23
|
||||
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
|
||||
|
||||
bool dce_dmcu_load_iram(struct dmcu *dmcu,
|
||||
unsigned int start_offset,
|
||||
const char *src,
|
||||
@ -76,8 +84,208 @@ bool dce_dmcu_load_iram(struct dmcu *dmcu,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dce_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
|
||||
{
|
||||
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
||||
|
||||
uint32_t count = 0;
|
||||
uint32_t psrStateOffset = 0xf0;
|
||||
uint32_t value = -1;
|
||||
|
||||
/* Enable write access to IRAM */
|
||||
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
|
||||
|
||||
while (REG(DCI_MEM_PWR_STATUS) && value != 0 && count++ < 10) {
|
||||
dm_delay_in_microseconds(dmcu->ctx, 2);
|
||||
REG_GET(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, &value);
|
||||
}
|
||||
while (REG(DMU_MEM_PWR_CNTL) && value != 0 && count++ < 10) {
|
||||
dm_delay_in_microseconds(dmcu->ctx, 2);
|
||||
REG_GET(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, &value);
|
||||
}
|
||||
|
||||
/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
|
||||
REG_WRITE(DMCU_IRAM_RD_CTRL, psrStateOffset);
|
||||
|
||||
/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
|
||||
*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
|
||||
|
||||
/* Disable write access to IRAM after finished using IRAM
|
||||
* in order to allow dynamic sleep state
|
||||
*/
|
||||
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
|
||||
}
|
||||
|
||||
static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable)
|
||||
{
|
||||
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
||||
unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
|
||||
unsigned int dmcu_wait_reg_ready_interval = 100;
|
||||
|
||||
unsigned int regValue;
|
||||
|
||||
unsigned int retryCount;
|
||||
uint32_t psr_state = 0;
|
||||
|
||||
/* waitDMCUReadyForCmd */
|
||||
do {
|
||||
dm_delay_in_microseconds(dmcu->ctx,
|
||||
dmcu_wait_reg_ready_interval);
|
||||
regValue = REG_READ(MASTER_COMM_CNTL_REG);
|
||||
dmcu_max_retry_on_wait_reg_ready--;
|
||||
} while
|
||||
/* expected value is 0, loop while not 0*/
|
||||
((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
|
||||
dmcu_max_retry_on_wait_reg_ready > 0);
|
||||
|
||||
/* setDMCUParam_Cmd */
|
||||
if (enable)
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
|
||||
PSR_ENABLE);
|
||||
else
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
|
||||
PSR_EXIT);
|
||||
|
||||
/* notifyDMCUMsg */
|
||||
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
|
||||
|
||||
for (retryCount = 0; retryCount <= 100; retryCount++) {
|
||||
dce_get_dmcu_psr_state(dmcu, &psr_state);
|
||||
if (enable) {
|
||||
if (psr_state != 0)
|
||||
break;
|
||||
} else {
|
||||
if (psr_state == 0)
|
||||
break;
|
||||
}
|
||||
dm_delay_in_microseconds(dmcu->ctx, 10);
|
||||
}
|
||||
}
|
||||
|
||||
static void dce_dmcu_setup_psr(struct dmcu *dmcu,
|
||||
struct core_link *link,
|
||||
struct psr_context *psr_context)
|
||||
{
|
||||
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
||||
|
||||
unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
|
||||
unsigned int dmcu_wait_reg_ready_interval = 100;
|
||||
unsigned int regValue;
|
||||
|
||||
union dce_dmcu_psr_config_data_reg1 masterCmdData1;
|
||||
union dce_dmcu_psr_config_data_reg2 masterCmdData2;
|
||||
union dce_dmcu_psr_config_data_reg3 masterCmdData3;
|
||||
|
||||
link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
|
||||
psr_context->psrExitLinkTrainingRequired);
|
||||
|
||||
/* Enable static screen interrupts for PSR supported display */
|
||||
/* Disable the interrupt coming from other displays. */
|
||||
REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN2_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN3_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN4_INT_TO_UC_EN, 0);
|
||||
|
||||
switch (psr_context->controllerId) {
|
||||
/* Driver uses case 1 for unconfigured */
|
||||
case 1:
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 2:
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN2_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 3:
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN3_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 4:
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN4_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 5:
|
||||
/* CZ/NL only has 4 CRTC!!
|
||||
* really valid.
|
||||
* There is no interrupt enable mask for these instances.
|
||||
*/
|
||||
break;
|
||||
case 6:
|
||||
/* CZ/NL only has 4 CRTC!!
|
||||
* These are here because they are defined in HW regspec,
|
||||
* but not really valid. There is no interrupt enable mask
|
||||
* for these instances.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
|
||||
psr_context->sdpTransmitLineNumDeadline);
|
||||
|
||||
if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION)
|
||||
REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
|
||||
|
||||
/* waitDMCUReadyForCmd */
|
||||
do {
|
||||
dm_delay_in_microseconds(dmcu->ctx,
|
||||
dmcu_wait_reg_ready_interval);
|
||||
regValue = REG_READ(MASTER_COMM_CNTL_REG);
|
||||
dmcu_max_retry_on_wait_reg_ready--;
|
||||
} while
|
||||
/* expected value is 0, loop while not 0*/
|
||||
((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
|
||||
dmcu_max_retry_on_wait_reg_ready > 0);
|
||||
|
||||
/* setDMCUParam_PSRHostConfigData */
|
||||
masterCmdData1.u32All = 0;
|
||||
masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
|
||||
masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
|
||||
masterCmdData1.bits.rfb_update_auto_en =
|
||||
psr_context->rfb_update_auto_en;
|
||||
masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
|
||||
masterCmdData1.bits.dcp_sel = psr_context->controllerId;
|
||||
masterCmdData1.bits.phy_type = psr_context->phyType;
|
||||
masterCmdData1.bits.frame_cap_ind =
|
||||
psr_context->psrFrameCaptureIndicationReq;
|
||||
masterCmdData1.bits.aux_chan = psr_context->channel;
|
||||
masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
|
||||
dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
|
||||
masterCmdData1.u32All);
|
||||
|
||||
masterCmdData2.u32All = 0;
|
||||
masterCmdData2.bits.dig_fe = psr_context->engineId;
|
||||
masterCmdData2.bits.dig_be = psr_context->transmitterId;
|
||||
masterCmdData2.bits.skip_wait_for_pll_lock =
|
||||
psr_context->skipPsrWaitForPllLock;
|
||||
masterCmdData2.bits.frame_delay = psr_context->frame_delay;
|
||||
masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
|
||||
masterCmdData2.bits.num_of_controllers =
|
||||
psr_context->numberOfControllers;
|
||||
dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
|
||||
masterCmdData2.u32All);
|
||||
|
||||
masterCmdData3.u32All = 0;
|
||||
masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
|
||||
dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
|
||||
masterCmdData3.u32All);
|
||||
|
||||
/* setDMCUParam_Cmd */
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG,
|
||||
MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
|
||||
|
||||
/* notifyDMCUMsg */
|
||||
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
|
||||
}
|
||||
|
||||
static const struct dmcu_funcs dce_funcs = {
|
||||
.load_iram = dce_dmcu_load_iram,
|
||||
.set_psr_enable = dce_dmcu_set_psr_enable,
|
||||
.setup_psr = dce_dmcu_setup_psr,
|
||||
};
|
||||
|
||||
static void dce_dmcu_construct(
|
||||
|
@ -33,7 +33,16 @@
|
||||
SR(DMCU_CTRL), \
|
||||
SR(DMCU_RAM_ACCESS_CTRL), \
|
||||
SR(DMCU_IRAM_WR_CTRL), \
|
||||
SR(DMCU_IRAM_WR_DATA)
|
||||
SR(DMCU_IRAM_WR_DATA), \
|
||||
SR(MASTER_COMM_DATA_REG1), \
|
||||
SR(MASTER_COMM_DATA_REG2), \
|
||||
SR(MASTER_COMM_DATA_REG3), \
|
||||
SR(MASTER_COMM_CMD_REG), \
|
||||
SR(MASTER_COMM_CNTL_REG), \
|
||||
SR(DMCU_IRAM_RD_CTRL), \
|
||||
SR(DMCU_IRAM_RD_DATA), \
|
||||
SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \
|
||||
SR(SMU_INTERRUPT_CONTROL)
|
||||
|
||||
#define DMCU_DCE110_COMMON_REG_LIST() \
|
||||
DMCU_COMMON_REG_LIST_DCE_BASE(), \
|
||||
@ -48,18 +57,41 @@
|
||||
DMCU_SF(DMCU_RAM_ACCESS_CTRL, \
|
||||
IRAM_HOST_ACCESS_EN, mask_sh), \
|
||||
DMCU_SF(DMCU_RAM_ACCESS_CTRL, \
|
||||
IRAM_WR_ADDR_AUTO_INC, mask_sh)
|
||||
IRAM_WR_ADDR_AUTO_INC, mask_sh), \
|
||||
DMCU_SF(MASTER_COMM_CMD_REG, \
|
||||
MASTER_COMM_CMD_REG_BYTE0, mask_sh), \
|
||||
DMCU_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh), \
|
||||
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, mask_sh), \
|
||||
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
|
||||
STATIC_SCREEN2_INT_TO_UC_EN, mask_sh), \
|
||||
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
|
||||
STATIC_SCREEN3_INT_TO_UC_EN, mask_sh), \
|
||||
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
|
||||
STATIC_SCREEN4_INT_TO_UC_EN, mask_sh), \
|
||||
DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh)
|
||||
|
||||
#define DMCU_MASK_SH_LIST_DCE110(mask_sh) \
|
||||
DMCU_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh), \
|
||||
DMCU_SF(DCI_MEM_PWR_STATUS, \
|
||||
DMCU_IRAM_MEM_PWR_STATE, mask_sh)
|
||||
DMCU_IRAM_MEM_PWR_STATE, mask_sh)
|
||||
|
||||
#define DMCU_REG_FIELD_LIST(type) \
|
||||
type DMCU_IRAM_MEM_PWR_STATE; \
|
||||
type IRAM_HOST_ACCESS_EN; \
|
||||
type IRAM_WR_ADDR_AUTO_INC; \
|
||||
type DMCU_ENABLE
|
||||
type DMCU_ENABLE; \
|
||||
type MASTER_COMM_CMD_REG_BYTE0; \
|
||||
type MASTER_COMM_INTERRUPT; \
|
||||
type DPHY_RX_FAST_TRAINING_CAPABLE; \
|
||||
type DPHY_LOAD_BS_COUNT; \
|
||||
type STATIC_SCREEN1_INT_TO_UC_EN; \
|
||||
type STATIC_SCREEN2_INT_TO_UC_EN; \
|
||||
type STATIC_SCREEN3_INT_TO_UC_EN; \
|
||||
type STATIC_SCREEN4_INT_TO_UC_EN; \
|
||||
type DP_SEC_GSP0_LINE_NUM; \
|
||||
type DP_SEC_GSP0_PRIORITY; \
|
||||
type DC_SMU_INT_ENABLE
|
||||
|
||||
struct dce_dmcu_shift {
|
||||
DMCU_REG_FIELD_LIST(uint8_t);
|
||||
@ -76,6 +108,16 @@ struct dce_dmcu_registers {
|
||||
uint32_t DMU_MEM_PWR_CNTL;
|
||||
uint32_t DMCU_IRAM_WR_CTRL;
|
||||
uint32_t DMCU_IRAM_WR_DATA;
|
||||
|
||||
uint32_t MASTER_COMM_DATA_REG1;
|
||||
uint32_t MASTER_COMM_DATA_REG2;
|
||||
uint32_t MASTER_COMM_DATA_REG3;
|
||||
uint32_t MASTER_COMM_CMD_REG;
|
||||
uint32_t MASTER_COMM_CNTL_REG;
|
||||
uint32_t DMCU_IRAM_RD_CTRL;
|
||||
uint32_t DMCU_IRAM_RD_DATA;
|
||||
uint32_t DMCU_INTERRUPT_TO_UC_EN_MASK;
|
||||
uint32_t SMU_INTERRUPT_CONTROL;
|
||||
};
|
||||
|
||||
struct dce_dmcu {
|
||||
@ -85,6 +127,63 @@ struct dce_dmcu {
|
||||
const struct dce_dmcu_mask *dmcu_mask;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG1 Bit position Data
|
||||
* 7:0 hyst_frames[7:0]
|
||||
* 14:8 hyst_lines[6:0]
|
||||
* 15 RFB_UPDATE_AUTO_EN
|
||||
* 18:16 phy_num[2:0]
|
||||
* 21:19 dcp_sel[2:0]
|
||||
* 22 phy_type
|
||||
* 23 frame_cap_ind
|
||||
* 26:24 aux_chan[2:0]
|
||||
* 30:27 aux_repeat[3:0]
|
||||
* 31:31 reserved[31:31]
|
||||
******************************************************************/
|
||||
union dce_dmcu_psr_config_data_reg1 {
|
||||
struct {
|
||||
unsigned int timehyst_frames:8; /*[7:0]*/
|
||||
unsigned int hyst_lines:7; /*[14:8]*/
|
||||
unsigned int rfb_update_auto_en:1; /*[15:15]*/
|
||||
unsigned int dp_port_num:3; /*[18:16]*/
|
||||
unsigned int dcp_sel:3; /*[21:19]*/
|
||||
unsigned int phy_type:1; /*[22:22]*/
|
||||
unsigned int frame_cap_ind:1; /*[23:23]*/
|
||||
unsigned int aux_chan:3; /*[26:24]*/
|
||||
unsigned int aux_repeat:4; /*[30:27]*/
|
||||
unsigned int reserved:1; /*[31:31]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG2
|
||||
*******************************************************************/
|
||||
union dce_dmcu_psr_config_data_reg2 {
|
||||
struct {
|
||||
unsigned int dig_fe:3; /*[2:0]*/
|
||||
unsigned int dig_be:3; /*[5:3]*/
|
||||
unsigned int skip_wait_for_pll_lock:1; /*[6:6]*/
|
||||
unsigned int reserved:9; /*[15:7]*/
|
||||
unsigned int frame_delay:8; /*[23:16]*/
|
||||
unsigned int smu_phy_id:4; /*[27:24]*/
|
||||
unsigned int num_of_controllers:4; /*[31:28]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG3
|
||||
*******************************************************************/
|
||||
union dce_dmcu_psr_config_data_reg3 {
|
||||
struct {
|
||||
unsigned int psr_level:16; /*[15:0]*/
|
||||
unsigned int link_rate:4; /*[19:16]*/
|
||||
unsigned int reserved:12; /*[31:20]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
struct dmcu *dce_dmcu_create(
|
||||
struct dc_context *ctx,
|
||||
const struct dce_dmcu_registers *regs,
|
||||
|
@ -95,14 +95,6 @@
|
||||
/* For current ASICs pixel clock - 600MHz */
|
||||
#define MAX_ENCODER_CLOCK 600000
|
||||
|
||||
/* PSR related commands */
|
||||
#define PSR_ENABLE 0x20
|
||||
#define PSR_EXIT 0x21
|
||||
#define PSR_SET 0x23
|
||||
|
||||
/*TODO: Used for psr wakeup for set backlight level*/
|
||||
static unsigned int psr_crtc_offset;
|
||||
|
||||
enum {
|
||||
DP_MST_UPDATE_MAX_RETRY = 50
|
||||
};
|
||||
@ -126,8 +118,9 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
|
||||
.dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern,
|
||||
.update_mst_stream_allocation_table =
|
||||
dce110_link_encoder_update_mst_stream_allocation_table,
|
||||
.set_dmcu_psr_enable = dce110_link_encoder_set_dmcu_psr_enable,
|
||||
.setup_dmcu_psr = dce110_link_encoder_setup_dmcu_psr,
|
||||
.psr_program_dp_dphy_fast_training =
|
||||
dce110_psr_program_dp_dphy_fast_training,
|
||||
.psr_program_secondary_packet = dce110_psr_program_secondary_packet,
|
||||
.backlight_control = dce110_link_encoder_edp_backlight_control,
|
||||
.power_control = dce110_link_encoder_edp_power_control,
|
||||
.connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe,
|
||||
@ -136,7 +129,6 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
|
||||
.destroy = dce110_link_encoder_destroy
|
||||
};
|
||||
|
||||
|
||||
static enum bp_result link_transmitter_control(
|
||||
struct dce110_link_encoder *enc110,
|
||||
struct bp_transmitter_control *cntl)
|
||||
@ -721,6 +713,40 @@ static bool is_panel_backlight_on(struct dce110_link_encoder *enc110)
|
||||
return value;
|
||||
}
|
||||
|
||||
void dce110_psr_program_dp_dphy_fast_training(struct link_encoder *enc,
|
||||
bool exit_link_training_required)
|
||||
{
|
||||
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
|
||||
|
||||
if (exit_link_training_required)
|
||||
REG_UPDATE(DP_DPHY_FAST_TRAINING,
|
||||
DPHY_RX_FAST_TRAINING_CAPABLE, 1);
|
||||
else {
|
||||
REG_UPDATE(DP_DPHY_FAST_TRAINING,
|
||||
DPHY_RX_FAST_TRAINING_CAPABLE, 0);
|
||||
/*In DCE 11, we are able to pre-program a Force SR register
|
||||
* to be able to trigger SR symbol after 5 idle patterns
|
||||
* transmitted. Upon PSR Exit, DMCU can trigger
|
||||
* DPHY_LOAD_BS_COUNT_START = 1. Upon writing 1 to
|
||||
* DPHY_LOAD_BS_COUNT_START and the internal counter
|
||||
* reaches DPHY_LOAD_BS_COUNT, the next BS symbol will be
|
||||
* replaced by SR symbol once.
|
||||
*/
|
||||
|
||||
REG_UPDATE(DP_DPHY_BS_SR_SWAP_CNTL, DPHY_LOAD_BS_COUNT, 0x5);
|
||||
}
|
||||
}
|
||||
|
||||
void dce110_psr_program_secondary_packet(struct link_encoder *enc,
|
||||
unsigned int sdp_transmit_line_num_deadline)
|
||||
{
|
||||
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
|
||||
|
||||
REG_UPDATE_2(DP_SEC_CNTL1,
|
||||
DP_SEC_GSP0_LINE_NUM, sdp_transmit_line_num_deadline,
|
||||
DP_SEC_GSP0_PRIORITY, 1);
|
||||
}
|
||||
|
||||
/*todo: cloned in stream enc, fix*/
|
||||
/*
|
||||
* @brief
|
||||
@ -1560,238 +1586,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table(
|
||||
} while (retries < DP_MST_UPDATE_MAX_RETRY);
|
||||
}
|
||||
|
||||
static void get_dmcu_psr_state(struct link_encoder *enc, uint32_t *psr_state)
|
||||
{
|
||||
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
|
||||
struct dc_context *ctx = enc110->base.ctx;
|
||||
|
||||
uint32_t count = 0;
|
||||
uint32_t psrStateOffset = 0xf0;
|
||||
uint32_t value = -1;
|
||||
|
||||
/* Enable write access to IRAM */
|
||||
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
|
||||
|
||||
while (REG(DCI_MEM_PWR_STATUS) && value != 0 && count++ < 10) {
|
||||
dm_delay_in_microseconds(ctx, 2);
|
||||
REG_GET(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, &value);
|
||||
}
|
||||
while (REG(DMU_MEM_PWR_CNTL) && value != 0 && count++ < 10) {
|
||||
dm_delay_in_microseconds(ctx, 2);
|
||||
REG_GET(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, &value);
|
||||
}
|
||||
|
||||
/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
|
||||
REG_WRITE(DMCU_IRAM_RD_CTRL, psrStateOffset);
|
||||
|
||||
/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
|
||||
*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
|
||||
|
||||
/* Disable write access to IRAM after finished using IRAM
|
||||
* in order to allow dynamic sleep state
|
||||
*/
|
||||
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
|
||||
}
|
||||
|
||||
void dce110_link_encoder_set_dmcu_psr_enable(struct link_encoder *enc,
|
||||
bool enable)
|
||||
{
|
||||
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
|
||||
struct dc_context *ctx = enc110->base.ctx;
|
||||
|
||||
unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
|
||||
unsigned int dmcu_wait_reg_ready_interval = 100;
|
||||
|
||||
unsigned int regValue;
|
||||
|
||||
unsigned int retryCount;
|
||||
uint32_t psr_state = 0;
|
||||
|
||||
/* waitDMCUReadyForCmd */
|
||||
do {
|
||||
dm_delay_in_microseconds(ctx, dmcu_wait_reg_ready_interval);
|
||||
regValue = REG_READ(MASTER_COMM_CNTL_REG);
|
||||
dmcu_max_retry_on_wait_reg_ready--;
|
||||
} while
|
||||
/* expected value is 0, loop while not 0*/
|
||||
((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
|
||||
dmcu_max_retry_on_wait_reg_ready > 0);
|
||||
|
||||
/* setDMCUParam_Cmd */
|
||||
if (enable)
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_ENABLE);
|
||||
else
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_EXIT);
|
||||
|
||||
/* notifyDMCUMsg */
|
||||
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
|
||||
|
||||
for (retryCount = 0; retryCount <= 100; retryCount++) {
|
||||
get_dmcu_psr_state(enc, &psr_state);
|
||||
if (enable) {
|
||||
if (psr_state != 0)
|
||||
break;
|
||||
} else {
|
||||
if (psr_state == 0)
|
||||
break;
|
||||
}
|
||||
dm_delay_in_microseconds(ctx, 10);
|
||||
}
|
||||
}
|
||||
|
||||
void dce110_link_encoder_setup_dmcu_psr(struct link_encoder *enc,
|
||||
struct psr_dmcu_context *psr_context)
|
||||
{
|
||||
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
|
||||
struct dc_context *ctx = enc110->base.ctx;
|
||||
|
||||
unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
|
||||
unsigned int dmcu_wait_reg_ready_interval = 100;
|
||||
unsigned int regValue;
|
||||
|
||||
union dce110_dmcu_psr_config_data_reg1 masterCmdData1;
|
||||
union dce110_dmcu_psr_config_data_reg2 masterCmdData2;
|
||||
union dce110_dmcu_psr_config_data_reg3 masterCmdData3;
|
||||
|
||||
if (psr_context->psrExitLinkTrainingRequired)
|
||||
REG_UPDATE(DP_DPHY_FAST_TRAINING, DPHY_RX_FAST_TRAINING_CAPABLE, 1);
|
||||
else {
|
||||
REG_UPDATE(DP_DPHY_FAST_TRAINING, DPHY_RX_FAST_TRAINING_CAPABLE, 0);
|
||||
/*In DCE 11, we are able to pre-program a Force SR register
|
||||
* to be able to trigger SR symbol after 5 idle patterns
|
||||
* transmitted. Upon PSR Exit, DMCU can trigger
|
||||
* DPHY_LOAD_BS_COUNT_START = 1. Upon writing 1 to
|
||||
* DPHY_LOAD_BS_COUNT_START and the internal counter
|
||||
* reaches DPHY_LOAD_BS_COUNT, the next BS symbol will be
|
||||
* replaced by SR symbol once.
|
||||
*/
|
||||
|
||||
REG_UPDATE(DP_DPHY_BS_SR_SWAP_CNTL, DPHY_LOAD_BS_COUNT, 0x5);
|
||||
}
|
||||
|
||||
/* Enable static screen interrupts for PSR supported display */
|
||||
/* Disable the interrupt coming from other displays. */
|
||||
REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN2_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN3_INT_TO_UC_EN, 0,
|
||||
STATIC_SCREEN4_INT_TO_UC_EN, 0);
|
||||
|
||||
switch (psr_context->controllerId) {
|
||||
/* Driver uses case 1 for unconfigured */
|
||||
case 1:
|
||||
psr_crtc_offset = mmCRTC0_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 2:
|
||||
psr_crtc_offset = mmCRTC1_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN2_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 3:
|
||||
psr_crtc_offset = mmCRTC2_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN3_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 4:
|
||||
psr_crtc_offset = mmCRTC3_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN4_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
case 5:
|
||||
psr_crtc_offset = mmCRTC4_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
/* CZ/NL only has 4 CRTC!!
|
||||
* really valid.
|
||||
* There is no interrupt enable mask for these instances.
|
||||
*/
|
||||
break;
|
||||
case 6:
|
||||
psr_crtc_offset = mmCRTC5_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
/* CZ/NL only has 4 CRTC!!
|
||||
* These are here because they are defined in HW regspec,
|
||||
* but not really valid. There is no interrupt enable mask
|
||||
* for these instances.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
psr_crtc_offset = mmCRTC0_CRTC_STATIC_SCREEN_CONTROL -
|
||||
mmCRTC0_CRTC_STATIC_SCREEN_CONTROL;
|
||||
|
||||
REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
|
||||
STATIC_SCREEN1_INT_TO_UC_EN, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
REG_UPDATE_2(DP_SEC_CNTL1,
|
||||
DP_SEC_GSP0_LINE_NUM, psr_context->sdpTransmitLineNumDeadline,
|
||||
DP_SEC_GSP0_PRIORITY, 1);
|
||||
|
||||
if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION) {
|
||||
REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
|
||||
}
|
||||
|
||||
/* waitDMCUReadyForCmd */
|
||||
do {
|
||||
dm_delay_in_microseconds(ctx, dmcu_wait_reg_ready_interval);
|
||||
regValue = REG_READ(MASTER_COMM_CNTL_REG);
|
||||
dmcu_max_retry_on_wait_reg_ready--;
|
||||
} while
|
||||
/* expected value is 0, loop while not 0*/
|
||||
((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
|
||||
dmcu_max_retry_on_wait_reg_ready > 0);
|
||||
|
||||
/* setDMCUParam_PSRHostConfigData */
|
||||
masterCmdData1.u32All = 0;
|
||||
masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
|
||||
masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
|
||||
masterCmdData1.bits.rfb_update_auto_en =
|
||||
psr_context->rfb_update_auto_en;
|
||||
masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
|
||||
masterCmdData1.bits.dcp_sel = psr_context->controllerId;
|
||||
masterCmdData1.bits.phy_type = psr_context->phyType;
|
||||
masterCmdData1.bits.frame_cap_ind =
|
||||
psr_context->psrFrameCaptureIndicationReq;
|
||||
masterCmdData1.bits.aux_chan = psr_context->channel;
|
||||
masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
|
||||
dm_write_reg(ctx, REG(MASTER_COMM_DATA_REG1),
|
||||
masterCmdData1.u32All);
|
||||
|
||||
masterCmdData2.u32All = 0;
|
||||
masterCmdData2.bits.dig_fe = psr_context->engineId;
|
||||
masterCmdData2.bits.dig_be = psr_context->transmitterId;
|
||||
masterCmdData2.bits.skip_wait_for_pll_lock =
|
||||
psr_context->skipPsrWaitForPllLock;
|
||||
masterCmdData2.bits.frame_delay = psr_context->frame_delay;
|
||||
masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
|
||||
masterCmdData2.bits.num_of_controllers =
|
||||
psr_context->numberOfControllers;
|
||||
dm_write_reg(ctx, REG(MASTER_COMM_DATA_REG2),
|
||||
masterCmdData2.u32All);
|
||||
|
||||
masterCmdData3.u32All = 0;
|
||||
masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
|
||||
dm_write_reg(ctx, REG(MASTER_COMM_DATA_REG3),
|
||||
masterCmdData3.u32All);
|
||||
|
||||
/* setDMCUParam_Cmd */
|
||||
REG_UPDATE(MASTER_COMM_CMD_REG,
|
||||
MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
|
||||
|
||||
/* notifyDMCUMsg */
|
||||
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
|
||||
}
|
||||
|
||||
void dce110_link_encoder_connect_dig_be_to_fe(
|
||||
struct link_encoder *enc,
|
||||
enum engine_id engine,
|
||||
|
@ -39,11 +39,6 @@
|
||||
SRI(DC_HPD_CONTROL, HPD, id)
|
||||
|
||||
#define LE_COMMON_REG_LIST_BASE(id) \
|
||||
SR(MASTER_COMM_DATA_REG1), \
|
||||
SR(MASTER_COMM_DATA_REG2), \
|
||||
SR(MASTER_COMM_DATA_REG3), \
|
||||
SR(MASTER_COMM_CMD_REG), \
|
||||
SR(MASTER_COMM_CNTL_REG), \
|
||||
SR(LVTMA_PWRSEQ_CNTL), \
|
||||
SR(LVTMA_PWRSEQ_STATE), \
|
||||
SR(DMCU_RAM_ACCESS_CTRL), \
|
||||
@ -149,62 +144,6 @@ struct dce110_link_encoder {
|
||||
const struct dce110_link_enc_hpd_registers *hpd_regs;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG1 Bit position Data
|
||||
* 7:0 hyst_frames[7:0]
|
||||
* 14:8 hyst_lines[6:0]
|
||||
* 15 RFB_UPDATE_AUTO_EN
|
||||
* 18:16 phy_num[2:0]
|
||||
* 21:19 dcp_sel[2:0]
|
||||
* 22 phy_type
|
||||
* 23 frame_cap_ind
|
||||
* 26:24 aux_chan[2:0]
|
||||
* 30:27 aux_repeat[3:0]
|
||||
* 31:31 reserved[31:31]
|
||||
*******************************************************************/
|
||||
union dce110_dmcu_psr_config_data_reg1 {
|
||||
struct {
|
||||
unsigned int timehyst_frames:8; /*[7:0]*/
|
||||
unsigned int hyst_lines:7; /*[14:8]*/
|
||||
unsigned int rfb_update_auto_en:1; /*[15:15]*/
|
||||
unsigned int dp_port_num:3; /*[18:16]*/
|
||||
unsigned int dcp_sel:3; /*[21:19]*/
|
||||
unsigned int phy_type:1; /*[22:22]*/
|
||||
unsigned int frame_cap_ind:1; /*[23:23]*/
|
||||
unsigned int aux_chan:3; /*[26:24]*/
|
||||
unsigned int aux_repeat:4; /*[30:27]*/
|
||||
unsigned int reserved:1; /*[31:31]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG2
|
||||
*******************************************************************/
|
||||
union dce110_dmcu_psr_config_data_reg2 {
|
||||
struct {
|
||||
unsigned int dig_fe:3; /*[2:0]*/
|
||||
unsigned int dig_be:3; /*[5:3]*/
|
||||
unsigned int skip_wait_for_pll_lock:1; /*[6:6]*/
|
||||
unsigned int reserved:9; /*[15:7]*/
|
||||
unsigned int frame_delay:8; /*[23:16]*/
|
||||
unsigned int smu_phy_id:4; /*[27:24]*/
|
||||
unsigned int num_of_controllers:4; /*[31:28]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/*******************************************************************
|
||||
* MASTER_COMM_DATA_REG3
|
||||
*******************************************************************/
|
||||
union dce110_dmcu_psr_config_data_reg3 {
|
||||
struct {
|
||||
unsigned int psr_level:16; /*[15:0]*/
|
||||
unsigned int link_rate:4; /*[19:16]*/
|
||||
unsigned int reserved:12; /*[31:20]*/
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
bool dce110_link_encoder_construct(
|
||||
struct dce110_link_encoder *enc110,
|
||||
@ -290,12 +229,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table(
|
||||
struct link_encoder *enc,
|
||||
const struct link_mst_stream_allocation_table *table);
|
||||
|
||||
void dce110_link_encoder_set_dmcu_psr_enable(
|
||||
struct link_encoder *enc, bool enable);
|
||||
|
||||
void dce110_link_encoder_setup_dmcu_psr(struct link_encoder *enc,
|
||||
struct psr_dmcu_context *psr_context);
|
||||
|
||||
void dce110_link_encoder_edp_backlight_control(
|
||||
struct link_encoder *enc,
|
||||
bool enable);
|
||||
@ -317,4 +250,10 @@ void dce110_link_encoder_enable_hpd(struct link_encoder *enc);
|
||||
|
||||
void dce110_link_encoder_disable_hpd(struct link_encoder *enc);
|
||||
|
||||
void dce110_psr_program_dp_dphy_fast_training(struct link_encoder *enc,
|
||||
bool exit_link_training_required);
|
||||
|
||||
void dce110_psr_program_secondary_packet(struct link_encoder *enc,
|
||||
unsigned int sdp_transmit_line_num_deadline);
|
||||
|
||||
#endif /* __DC_LINK_ENCODER__DCE110_H__ */
|
||||
|
@ -37,6 +37,10 @@ struct dmcu_funcs {
|
||||
unsigned int start_offset,
|
||||
const char *src,
|
||||
unsigned int bytes);
|
||||
void (*set_psr_enable)(struct dmcu *dmcu, bool enable);
|
||||
void (*setup_psr)(struct dmcu *dmcu,
|
||||
struct core_link *link,
|
||||
struct psr_context *psr_context);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -116,7 +116,7 @@ union psr_sink_psr_status {
|
||||
unsigned char raw;
|
||||
};
|
||||
|
||||
struct psr_dmcu_context {
|
||||
struct psr_context {
|
||||
/* ddc line */
|
||||
enum channel_id channel;
|
||||
/* Transmitter id */
|
||||
@ -220,9 +220,10 @@ struct link_encoder_funcs {
|
||||
void (*update_mst_stream_allocation_table)(
|
||||
struct link_encoder *enc,
|
||||
const struct link_mst_stream_allocation_table *table);
|
||||
void (*set_dmcu_psr_enable)(struct link_encoder *enc, bool enable);
|
||||
void (*setup_dmcu_psr)(struct link_encoder *enc,
|
||||
struct psr_dmcu_context *psr_context);
|
||||
void (*psr_program_dp_dphy_fast_training)(struct link_encoder *enc,
|
||||
bool exit_link_training_required);
|
||||
void (*psr_program_secondary_packet)(struct link_encoder *enc,
|
||||
unsigned int sdp_transmit_line_num_deadline);
|
||||
void (*backlight_control) (struct link_encoder *enc,
|
||||
bool enable);
|
||||
void (*power_control) (struct link_encoder *enc,
|
||||
|
Loading…
Reference in New Issue
Block a user