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 
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 	memset(&cmd, 0, sizeof(cmd));
61 	cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
62 	cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
63 	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
64 	cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
65 
66 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
67 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
68 	dc_dmub_srv_wait_idle(dc->dmub_srv);
69 }
70 
71 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
72 {
73 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
74 
75 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
76 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
77 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103);
78 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101);
79 	REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101);
80 
81 	REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
82 			ABM1_HG_NUM_OF_BINS_SEL, 0,
83 			ABM1_HG_VMAX_SEL, 1,
84 			ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
85 
86 	REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
87 			ABM1_IPCSC_COEFF_SEL_R, 2,
88 			ABM1_IPCSC_COEFF_SEL_G, 4,
89 			ABM1_IPCSC_COEFF_SEL_B, 2);
90 
91 	REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
92 			BL1_PWM_CURRENT_ABM_LEVEL, backlight);
93 
94 	REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
95 			BL1_PWM_TARGET_ABM_LEVEL, backlight);
96 
97 	REG_UPDATE(BL1_PWM_USER_LEVEL,
98 			BL1_PWM_USER_LEVEL, backlight);
99 
100 	REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
101 			ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
102 			ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
103 
104 	REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
105 			ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
106 			ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
107 			ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
108 
109 	dmub_abm_enable_fractional_pwm(abm->ctx);
110 }
111 
112 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
113 {
114 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
115 	unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
116 
117 	/* return backlight in hardware format which is unsigned 17 bits, with
118 	 * 1 bit integer and 16 bit fractional
119 	 */
120 	return backlight;
121 }
122 
123 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
124 {
125 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
126 	unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
127 
128 	/* return backlight in hardware format which is unsigned 17 bits, with
129 	 * 1 bit integer and 16 bit fractional
130 	 */
131 	return backlight;
132 }
133 
134 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
135 {
136 	union dmub_rb_cmd cmd;
137 	struct dc_context *dc = abm->ctx;
138 
139 	memset(&cmd, 0, sizeof(cmd));
140 	cmd.abm_set_level.header.type = DMUB_CMD__ABM;
141 	cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
142 	cmd.abm_set_level.abm_set_level_data.level = level;
143 	cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
144 
145 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
146 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
147 	dc_dmub_srv_wait_idle(dc->dmub_srv);
148 
149 	return true;
150 }
151 
152 static bool dmub_abm_init_config(struct abm *abm,
153 	const char *src,
154 	unsigned int bytes)
155 {
156 	union dmub_rb_cmd cmd;
157 	struct dc_context *dc = abm->ctx;
158 
159 	// TODO: Optimize by only reading back final 4 bytes
160 	dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
161 
162 	// Copy iramtable into cw7
163 	memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
164 
165 	memset(&cmd, 0, sizeof(cmd));
166 	// Fw will copy from cw7 to fw_state
167 	cmd.abm_init_config.header.type = DMUB_CMD__ABM;
168 	cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
169 	cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
170 	cmd.abm_init_config.abm_init_config_data.bytes = bytes;
171 	cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
172 
173 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
174 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
175 	dc_dmub_srv_wait_idle(dc->dmub_srv);
176 
177 	return true;
178 }
179 
180 static const struct abm_funcs abm_funcs = {
181 	.abm_init = dmub_abm_init,
182 	.set_abm_level = dmub_abm_set_level,
183 	.get_current_backlight = dmub_abm_get_current_backlight,
184 	.get_target_backlight = dmub_abm_get_target_backlight,
185 	.init_abm_config = dmub_abm_init_config,
186 };
187 
188 static void dmub_abm_construct(
189 	struct dce_abm *abm_dce,
190 	struct dc_context *ctx,
191 	const struct dce_abm_registers *regs,
192 	const struct dce_abm_shift *abm_shift,
193 	const struct dce_abm_mask *abm_mask)
194 {
195 	struct abm *base = &abm_dce->base;
196 
197 	base->ctx = ctx;
198 	base->funcs = &abm_funcs;
199 	base->dmcu_is_running = false;
200 
201 	abm_dce->regs = regs;
202 	abm_dce->abm_shift = abm_shift;
203 	abm_dce->abm_mask = abm_mask;
204 }
205 
206 struct abm *dmub_abm_create(
207 	struct dc_context *ctx,
208 	const struct dce_abm_registers *regs,
209 	const struct dce_abm_shift *abm_shift,
210 	const struct dce_abm_mask *abm_mask)
211 {
212 	struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
213 
214 	if (abm_dce == NULL) {
215 		BREAK_TO_DEBUGGER();
216 		return NULL;
217 	}
218 
219 	dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
220 
221 	return &abm_dce->base;
222 }
223 
224 void dmub_abm_destroy(struct abm **abm)
225 {
226 	struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
227 
228 	kfree(abm_dce);
229 	*abm = NULL;
230 }
231