1 /*
2 * Copyright 2019 Advanced Micro Devices, Inc.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include "dmub_abm.h"
27 #include "dce_abm.h"
28 #include "dc.h"
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"
35
36 #include "atom.h"
37
38 #define TO_DMUB_ABM(abm)\
39 container_of(abm, struct dce_abm, base)
40
41 #define REG(reg) \
42 (dce_abm->regs->reg)
43
44 #undef FN
45 #define FN(reg_name, field_name) \
46 dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
47
48 #define CTX \
49 dce_abm->base.ctx
50
51 #define DISABLE_ABM_IMMEDIATELY 255
52
53
54
dmub_abm_enable_fractional_pwm(struct dc_context * dc)55 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
56 {
57 union dmub_rb_cmd cmd;
58 uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
59
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);
64
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);
68 }
69
dmub_abm_init(struct abm * abm,uint32_t backlight)70 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
71 {
72 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
73
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);
79
80 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
81 ABM1_HG_NUM_OF_BINS_SEL, 0,
82 ABM1_HG_VMAX_SEL, 1,
83 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
84
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);
89
90 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
91 BL1_PWM_CURRENT_ABM_LEVEL, backlight);
92
93 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
94 BL1_PWM_TARGET_ABM_LEVEL, backlight);
95
96 REG_UPDATE(BL1_PWM_USER_LEVEL,
97 BL1_PWM_USER_LEVEL, backlight);
98
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);
102
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);
107
108 dmub_abm_enable_fractional_pwm(abm->ctx);
109 }
110
dmub_abm_get_current_backlight(struct abm * abm)111 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
112 {
113 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
114 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
115
116 /* return backlight in hardware format which is unsigned 17 bits, with
117 * 1 bit integer and 16 bit fractional
118 */
119 return backlight;
120 }
121
dmub_abm_get_target_backlight(struct abm * abm)122 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
123 {
124 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
125 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
126
127 /* return backlight in hardware format which is unsigned 17 bits, with
128 * 1 bit integer and 16 bit fractional
129 */
130 return backlight;
131 }
132
dmub_abm_set_level(struct abm * abm,uint32_t level)133 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
134 {
135 union dmub_rb_cmd cmd;
136 struct dc_context *dc = abm->ctx;
137
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);
142
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);
146
147 return true;
148 }
149
dmub_abm_init_config(struct abm * abm,const char * src,unsigned int bytes)150 static bool dmub_abm_init_config(struct abm *abm,
151 const char *src,
152 unsigned int bytes)
153 {
154 union dmub_rb_cmd cmd;
155 struct dc_context *dc = abm->ctx;
156
157 // TODO: Optimize by only reading back final 4 bytes
158 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
159
160 // Copy iramtable into cw7
161 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
162
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);
169
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);
173
174 return true;
175 }
176
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,
183 };
184
dmub_abm_construct(struct dce_abm * abm_dce,struct dc_context * ctx,const struct dce_abm_registers * regs,const struct dce_abm_shift * abm_shift,const struct dce_abm_mask * abm_mask)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)
191 {
192 struct abm *base = &abm_dce->base;
193
194 base->ctx = ctx;
195 base->funcs = &abm_funcs;
196 base->dmcu_is_running = false;
197
198 abm_dce->regs = regs;
199 abm_dce->abm_shift = abm_shift;
200 abm_dce->abm_mask = abm_mask;
201 }
202
dmub_abm_create(struct dc_context * ctx,const struct dce_abm_registers * regs,const struct dce_abm_shift * abm_shift,const struct 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)
208 {
209 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
210
211 if (abm_dce == NULL) {
212 BREAK_TO_DEBUGGER();
213 return NULL;
214 }
215
216 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
217
218 return &abm_dce->base;
219 }
220
dmub_abm_destroy(struct abm ** abm)221 void dmub_abm_destroy(struct abm **abm)
222 {
223 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
224
225 kfree(abm_dce);
226 *abm = NULL;
227 }
228