1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "reg_helper.h"
27#include "core_types.h"
28#include "dc_dmub_srv.h"
29#include "panel_cntl.h"
30#include "dce_panel_cntl.h"
31#include "atom.h"
32
33#define TO_DCE_PANEL_CNTL(panel_cntl)\
34 container_of(panel_cntl, struct dce_panel_cntl, base)
35
36#define CTX \
37 dce_panel_cntl->base.ctx
38
39#define DC_LOGGER \
40 dce_panel_cntl->base.ctx->logger
41
42#define REG(reg)\
43 dce_panel_cntl->regs->reg
44
45#undef FN
46#define FN(reg_name, field_name) \
47 dce_panel_cntl->shift->field_name, dce_panel_cntl->mask->field_name
48
49static unsigned int dce_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl)
50{
51 uint64_t current_backlight;
52 uint32_t round_result;
53 uint32_t bl_period, bl_int_count;
54 uint32_t bl_pwm, fractional_duty_cycle_en;
55 uint32_t bl_period_mask, bl_pwm_mask;
56 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
57
58 REG_READ(BL_PWM_PERIOD_CNTL);
59 REG_GET(BL_PWM_PERIOD_CNTL, BL_PWM_PERIOD, &bl_period);
60 REG_GET(BL_PWM_PERIOD_CNTL, BL_PWM_PERIOD_BITCNT, &bl_int_count);
61
62 REG_READ(BL_PWM_CNTL);
63 REG_GET(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, (uint32_t *)(&bl_pwm));
64 REG_GET(BL_PWM_CNTL, BL_PWM_FRACTIONAL_EN, &fractional_duty_cycle_en);
65
66 if (bl_int_count == 0)
67 bl_int_count = 16;
68
69 bl_period_mask = (1 << bl_int_count) - 1;
70 bl_period &= bl_period_mask;
71
72 bl_pwm_mask = bl_period_mask << (16 - bl_int_count);
73
74 if (fractional_duty_cycle_en == 0)
75 bl_pwm &= bl_pwm_mask;
76 else
77 bl_pwm &= 0xFFFF;
78
79 current_backlight = (uint64_t)bl_pwm << (1 + bl_int_count);
80
81 if (bl_period == 0)
82 bl_period = 0xFFFF;
83
84 current_backlight = div_u64(current_backlight, bl_period);
85 current_backlight = (current_backlight + 1) >> 1;
86
87 current_backlight = (uint64_t)(current_backlight) * bl_period;
88
89 round_result = (uint32_t)(current_backlight & 0xFFFFFFFF);
90
91 round_result = (round_result >> (bl_int_count-1)) & 1;
92
93 current_backlight >>= bl_int_count;
94 current_backlight += round_result;
95
96 return (uint32_t)(current_backlight);
97}
98
99static uint32_t dce_panel_cntl_hw_init(struct panel_cntl *panel_cntl)
100{
101 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
102 uint32_t value;
103 uint32_t current_backlight;
104
105
106
107
108
109 REG_GET(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, &value);
110
111 if (panel_cntl->stored_backlight_registers.BL_PWM_CNTL != 0) {
112 REG_WRITE(BL_PWM_CNTL,
113 panel_cntl->stored_backlight_registers.BL_PWM_CNTL);
114 REG_WRITE(BL_PWM_CNTL2,
115 panel_cntl->stored_backlight_registers.BL_PWM_CNTL2);
116 REG_WRITE(BL_PWM_PERIOD_CNTL,
117 panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL);
118 REG_UPDATE(PWRSEQ_REF_DIV,
119 BL_PWM_REF_DIV,
120 panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
121 } else if ((value != 0) && (value != 1)) {
122 panel_cntl->stored_backlight_registers.BL_PWM_CNTL =
123 REG_READ(BL_PWM_CNTL);
124 panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 =
125 REG_READ(BL_PWM_CNTL2);
126 panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL =
127 REG_READ(BL_PWM_PERIOD_CNTL);
128
129 REG_GET(PWRSEQ_REF_DIV, BL_PWM_REF_DIV,
130 &panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
131 } else {
132
133
134
135 REG_WRITE(BL_PWM_CNTL, 0x8000FA00);
136 REG_WRITE(BL_PWM_PERIOD_CNTL, 0x000C0FA0);
137 }
138
139
140
141 value = REG_READ(BIOS_SCRATCH_2);
142 value |= ATOM_S2_VRI_BRIGHT_ENABLE;
143 REG_WRITE(BIOS_SCRATCH_2, value);
144
145
146 REG_UPDATE(BL_PWM_CNTL, BL_PWM_EN, 1);
147
148
149 REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
150 BL_PWM_GRP1_REG_LOCK, 0);
151
152 current_backlight = dce_get_16_bit_backlight_from_pwm(panel_cntl);
153
154 return current_backlight;
155}
156
157static bool dce_is_panel_backlight_on(struct panel_cntl *panel_cntl)
158{
159 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
160 uint32_t blon, blon_ovrd, pwrseq_target_state;
161
162 REG_GET_2(PWRSEQ_CNTL, LVTMA_BLON, &blon, LVTMA_BLON_OVRD, &blon_ovrd);
163 REG_GET(PWRSEQ_CNTL, LVTMA_PWRSEQ_TARGET_STATE, &pwrseq_target_state);
164
165 if (blon_ovrd)
166 return blon;
167 else
168 return pwrseq_target_state;
169}
170
171static bool dce_is_panel_powered_on(struct panel_cntl *panel_cntl)
172{
173 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
174 uint32_t pwr_seq_state, dig_on, dig_on_ovrd;
175
176 REG_GET(PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &pwr_seq_state);
177
178 REG_GET_2(PWRSEQ_CNTL, LVTMA_DIGON, &dig_on, LVTMA_DIGON_OVRD, &dig_on_ovrd);
179
180 return (pwr_seq_state == 1) || (dig_on == 1 && dig_on_ovrd == 1);
181}
182
183static void dce_store_backlight_level(struct panel_cntl *panel_cntl)
184{
185 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
186
187 panel_cntl->stored_backlight_registers.BL_PWM_CNTL =
188 REG_READ(BL_PWM_CNTL);
189 panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 =
190 REG_READ(BL_PWM_CNTL2);
191 panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL =
192 REG_READ(BL_PWM_PERIOD_CNTL);
193
194 REG_GET(PWRSEQ_REF_DIV, BL_PWM_REF_DIV,
195 &panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
196}
197
198static void dce_driver_set_backlight(struct panel_cntl *panel_cntl,
199 uint32_t backlight_pwm_u16_16)
200{
201 uint32_t backlight_16bit;
202 uint32_t masked_pwm_period;
203 uint8_t bit_count;
204 uint64_t active_duty_cycle;
205 uint32_t pwm_period_bitcnt;
206 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl);
207
208
209
210
211
212
213
214
215 REG_GET_2(BL_PWM_PERIOD_CNTL,
216 BL_PWM_PERIOD_BITCNT, &pwm_period_bitcnt,
217 BL_PWM_PERIOD, &masked_pwm_period);
218
219 if (pwm_period_bitcnt == 0)
220 bit_count = 16;
221 else
222 bit_count = pwm_period_bitcnt;
223
224
225 masked_pwm_period = masked_pwm_period & ((1 << bit_count) - 1);
226
227
228
229
230
231 active_duty_cycle = backlight_pwm_u16_16 * masked_pwm_period;
232
233
234
235
236
237 backlight_16bit = active_duty_cycle >> bit_count;
238 backlight_16bit &= 0xFFFF;
239 backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;
240
241
242
243
244
245
246
247 REG_UPDATE_2(BL_PWM_GRP1_REG_LOCK,
248 BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN, 1,
249 BL_PWM_GRP1_REG_LOCK, 1);
250
251
252 REG_UPDATE(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, backlight_16bit);
253
254
255 REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
256 BL_PWM_GRP1_REG_LOCK, 0);
257
258
259 REG_WAIT(BL_PWM_GRP1_REG_LOCK,
260 BL_PWM_GRP1_REG_UPDATE_PENDING, 0,
261 1, 10000);
262}
263
264static void dce_panel_cntl_destroy(struct panel_cntl **panel_cntl)
265{
266 struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(*panel_cntl);
267
268 kfree(dce_panel_cntl);
269 *panel_cntl = NULL;
270}
271
272static const struct panel_cntl_funcs dce_link_panel_cntl_funcs = {
273 .destroy = dce_panel_cntl_destroy,
274 .hw_init = dce_panel_cntl_hw_init,
275 .is_panel_backlight_on = dce_is_panel_backlight_on,
276 .is_panel_powered_on = dce_is_panel_powered_on,
277 .store_backlight_level = dce_store_backlight_level,
278 .driver_set_backlight = dce_driver_set_backlight,
279 .get_current_backlight = dce_get_16_bit_backlight_from_pwm,
280};
281
282void dce_panel_cntl_construct(
283 struct dce_panel_cntl *dce_panel_cntl,
284 const struct panel_cntl_init_data *init_data,
285 const struct dce_panel_cntl_registers *regs,
286 const struct dce_panel_cntl_shift *shift,
287 const struct dce_panel_cntl_mask *mask)
288{
289 struct panel_cntl *base = &dce_panel_cntl->base;
290
291 base->stored_backlight_registers.BL_PWM_CNTL = 0;
292 base->stored_backlight_registers.BL_PWM_CNTL2 = 0;
293 base->stored_backlight_registers.BL_PWM_PERIOD_CNTL = 0;
294 base->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = 0;
295
296 dce_panel_cntl->regs = regs;
297 dce_panel_cntl->shift = shift;
298 dce_panel_cntl->mask = mask;
299
300 dce_panel_cntl->base.funcs = &dce_link_panel_cntl_funcs;
301 dce_panel_cntl->base.ctx = init_data->ctx;
302 dce_panel_cntl->base.inst = init_data->inst;
303}
304