2 * Copyright 2019 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
29 #include "dc_dmub_srv.h"
30 #include "dmub/dmub_srv.h"
31 #include "core_types.h"
32 #include "dm_services.h"
33 #include "reg_helper.h"
34 #include "fixed31_32.h"
38 #define TO_DMUB_ABM(abm)\
39 container_of(abm, struct dce_abm, base)
45 #define FN(reg_name, field_name) \
46 dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
51 #define DISABLE_ABM_IMMEDIATELY 255
55 static void dmub_abm_enable_fractional_pwm(struct dc_context
*dc
)
57 union dmub_rb_cmd cmd
;
58 uint32_t fractional_pwm
= (dc
->dc
->config
.disable_fractional_pwm
== false) ? 1 : 0;
60 cmd
.abm_set_pwm_frac
.header
.type
= DMUB_CMD__ABM
;
61 cmd
.abm_set_pwm_frac
.header
.sub_type
= DMUB_CMD__ABM_SET_PWM_FRAC
;
62 cmd
.abm_set_pwm_frac
.abm_set_pwm_frac_data
.fractional_pwm
= fractional_pwm
;
63 cmd
.abm_set_pwm_frac
.header
.payload_bytes
= sizeof(struct dmub_cmd_abm_set_pwm_frac_data
);
65 dc_dmub_srv_cmd_queue(dc
->dmub_srv
, &cmd
);
66 dc_dmub_srv_cmd_execute(dc
->dmub_srv
);
67 dc_dmub_srv_wait_idle(dc
->dmub_srv
);
70 static void dmub_abm_init(struct abm
*abm
, uint32_t backlight
)
72 struct dce_abm
*dce_abm
= TO_DMUB_ABM(abm
);
74 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE
, 0x103);
75 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE
, 0x101);
76 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE
, 0x103);
77 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE
, 0x101);
78 REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE
, 0x101);
80 REG_SET_3(DC_ABM1_HG_MISC_CTRL
, 0,
81 ABM1_HG_NUM_OF_BINS_SEL
, 0,
83 ABM1_HG_BIN_BITWIDTH_SIZE_SEL
, 0);
85 REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL
, 0,
86 ABM1_IPCSC_COEFF_SEL_R
, 2,
87 ABM1_IPCSC_COEFF_SEL_G
, 4,
88 ABM1_IPCSC_COEFF_SEL_B
, 2);
90 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL
,
91 BL1_PWM_CURRENT_ABM_LEVEL
, backlight
);
93 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL
,
94 BL1_PWM_TARGET_ABM_LEVEL
, backlight
);
96 REG_UPDATE(BL1_PWM_USER_LEVEL
,
97 BL1_PWM_USER_LEVEL
, backlight
);
99 REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES
,
100 ABM1_LS_MIN_PIXEL_VALUE_THRES
, 0,
101 ABM1_LS_MAX_PIXEL_VALUE_THRES
, 1000);
103 REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS
, 0,
104 ABM1_HG_REG_READ_MISSED_FRAME_CLEAR
, 1,
105 ABM1_LS_REG_READ_MISSED_FRAME_CLEAR
, 1,
106 ABM1_BL_REG_READ_MISSED_FRAME_CLEAR
, 1);
108 dmub_abm_enable_fractional_pwm(abm
->ctx
);
111 static unsigned int dmub_abm_get_current_backlight(struct abm
*abm
)
113 struct dce_abm
*dce_abm
= TO_DMUB_ABM(abm
);
114 unsigned int backlight
= REG_READ(BL1_PWM_CURRENT_ABM_LEVEL
);
116 /* return backlight in hardware format which is unsigned 17 bits, with
117 * 1 bit integer and 16 bit fractional
122 static unsigned int dmub_abm_get_target_backlight(struct abm
*abm
)
124 struct dce_abm
*dce_abm
= TO_DMUB_ABM(abm
);
125 unsigned int backlight
= REG_READ(BL1_PWM_TARGET_ABM_LEVEL
);
127 /* return backlight in hardware format which is unsigned 17 bits, with
128 * 1 bit integer and 16 bit fractional
133 static bool dmub_abm_set_level(struct abm
*abm
, uint32_t level
)
135 union dmub_rb_cmd cmd
;
136 struct dc_context
*dc
= abm
->ctx
;
138 cmd
.abm_set_level
.header
.type
= DMUB_CMD__ABM
;
139 cmd
.abm_set_level
.header
.sub_type
= DMUB_CMD__ABM_SET_LEVEL
;
140 cmd
.abm_set_level
.abm_set_level_data
.level
= level
;
141 cmd
.abm_set_level
.header
.payload_bytes
= sizeof(struct dmub_cmd_abm_set_level_data
);
143 dc_dmub_srv_cmd_queue(dc
->dmub_srv
, &cmd
);
144 dc_dmub_srv_cmd_execute(dc
->dmub_srv
);
145 dc_dmub_srv_wait_idle(dc
->dmub_srv
);
150 static bool dmub_abm_init_config(struct abm
*abm
,
154 union dmub_rb_cmd cmd
;
155 struct dc_context
*dc
= abm
->ctx
;
157 // TODO: Optimize by only reading back final 4 bytes
158 dmub_flush_buffer_mem(&dc
->dmub_srv
->dmub
->scratch_mem_fb
);
160 // Copy iramtable into cw7
161 memcpy(dc
->dmub_srv
->dmub
->scratch_mem_fb
.cpu_addr
, (void *)src
, bytes
);
163 // Fw will copy from cw7 to fw_state
164 cmd
.abm_init_config
.header
.type
= DMUB_CMD__ABM
;
165 cmd
.abm_init_config
.header
.sub_type
= DMUB_CMD__ABM_INIT_CONFIG
;
166 cmd
.abm_init_config
.abm_init_config_data
.src
.quad_part
= dc
->dmub_srv
->dmub
->scratch_mem_fb
.gpu_addr
;
167 cmd
.abm_init_config
.abm_init_config_data
.bytes
= bytes
;
168 cmd
.abm_init_config
.header
.payload_bytes
= sizeof(struct dmub_cmd_abm_init_config_data
);
170 dc_dmub_srv_cmd_queue(dc
->dmub_srv
, &cmd
);
171 dc_dmub_srv_cmd_execute(dc
->dmub_srv
);
172 dc_dmub_srv_wait_idle(dc
->dmub_srv
);
177 static const struct abm_funcs abm_funcs
= {
178 .abm_init
= dmub_abm_init
,
179 .set_abm_level
= dmub_abm_set_level
,
180 .get_current_backlight
= dmub_abm_get_current_backlight
,
181 .get_target_backlight
= dmub_abm_get_target_backlight
,
182 .init_abm_config
= dmub_abm_init_config
,
185 static void dmub_abm_construct(
186 struct dce_abm
*abm_dce
,
187 struct dc_context
*ctx
,
188 const struct dce_abm_registers
*regs
,
189 const struct dce_abm_shift
*abm_shift
,
190 const struct dce_abm_mask
*abm_mask
)
192 struct abm
*base
= &abm_dce
->base
;
195 base
->funcs
= &abm_funcs
;
196 base
->dmcu_is_running
= false;
198 abm_dce
->regs
= regs
;
199 abm_dce
->abm_shift
= abm_shift
;
200 abm_dce
->abm_mask
= abm_mask
;
203 struct abm
*dmub_abm_create(
204 struct dc_context
*ctx
,
205 const struct dce_abm_registers
*regs
,
206 const struct dce_abm_shift
*abm_shift
,
207 const struct dce_abm_mask
*abm_mask
)
209 struct dce_abm
*abm_dce
= kzalloc(sizeof(*abm_dce
), GFP_KERNEL
);
211 if (abm_dce
== NULL
) {
216 dmub_abm_construct(abm_dce
, ctx
, regs
, abm_shift
, abm_mask
);
218 return &abm_dce
->base
;
221 void dmub_abm_destroy(struct abm
**abm
)
223 struct dce_abm
*abm_dce
= TO_DMUB_ABM(*abm
);