xref: /aosp_15_r20/external/coreboot/src/soc/mediatek/common/dp/dp_intf.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <edid.h>
5 #include <soc/addressmap.h>
6 #include <soc/dp_intf.h>
7 #include <soc/mcucfg.h>
8 #include <soc/pll.h>
9 #include <soc/pll_common.h>
10 #include <soc/spm.h>
11 
mtk_dpintf_mask(const struct mtk_dpintf * dpintf,u32 offset,u32 val,u32 mask)12 static void mtk_dpintf_mask(const struct mtk_dpintf *dpintf, u32 offset, u32 val, u32 mask)
13 {
14 	clrsetbits32(dpintf->regs + offset, mask, val);
15 }
16 
mtk_dpintf_sw_reset(const struct mtk_dpintf * dpintf,bool reset)17 static void mtk_dpintf_sw_reset(const struct mtk_dpintf *dpintf, bool reset)
18 {
19 	mtk_dpintf_mask(dpintf, DPINTF_RET, reset ? RST : 0, RST);
20 }
21 
mtk_dpintf_enable(const struct mtk_dpintf * dpintf)22 static void mtk_dpintf_enable(const struct mtk_dpintf *dpintf)
23 {
24 	mtk_dpintf_mask(dpintf, DPINTF_EN, EN, EN);
25 }
26 
mtk_dpintf_config_hsync(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync)27 static void mtk_dpintf_config_hsync(const struct mtk_dpintf *dpintf,
28 				    struct mtk_dpintf_sync_param *sync)
29 {
30 	mtk_dpintf_mask(dpintf, DPINTF_TGEN_HWIDTH,
31 			sync->sync_width << HPW, HPW_MASK);
32 	mtk_dpintf_mask(dpintf, DPINTF_TGEN_HPORCH,
33 			sync->back_porch << HBP, HBP_MASK);
34 	mtk_dpintf_mask(dpintf, DPINTF_TGEN_HPORCH,
35 			sync->front_porch << HFP, HFP_MASK);
36 }
37 
mtk_dpintf_config_vsync(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync,u32 width_addr,u32 porch_addr)38 static void mtk_dpintf_config_vsync(const struct mtk_dpintf *dpintf,
39 				    struct mtk_dpintf_sync_param *sync,
40 				    u32 width_addr, u32 porch_addr)
41 {
42 	mtk_dpintf_mask(dpintf, width_addr,
43 			sync->sync_width << VSYNC_WIDTH_SHIFT,
44 			VSYNC_WIDTH_MASK);
45 	mtk_dpintf_mask(dpintf, width_addr,
46 			sync->shift_half_line << VSYNC_HALF_LINE_SHIFT,
47 			VSYNC_HALF_LINE_MASK);
48 	mtk_dpintf_mask(dpintf, porch_addr,
49 			sync->back_porch << VSYNC_BACK_PORCH_SHIFT,
50 			VSYNC_BACK_PORCH_MASK);
51 	mtk_dpintf_mask(dpintf, porch_addr,
52 			sync->front_porch << VSYNC_FRONT_PORCH_SHIFT,
53 			VSYNC_FRONT_PORCH_MASK);
54 }
55 
mtk_dpintf_config_vsync_lodd(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync)56 static void mtk_dpintf_config_vsync_lodd(const struct mtk_dpintf *dpintf,
57 					 struct mtk_dpintf_sync_param *sync)
58 {
59 	mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH,
60 				DPINTF_TGEN_VPORCH);
61 }
62 
mtk_dpintf_config_vsync_leven(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync)63 static void mtk_dpintf_config_vsync_leven(const struct mtk_dpintf *dpintf,
64 					  struct mtk_dpintf_sync_param *sync)
65 {
66 	mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_LEVEN,
67 				DPINTF_TGEN_VPORCH_LEVEN);
68 }
69 
mtk_dpintf_config_vsync_rodd(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync)70 static void mtk_dpintf_config_vsync_rodd(const struct mtk_dpintf *dpintf,
71 					 struct mtk_dpintf_sync_param *sync)
72 {
73 	mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_RODD,
74 				DPINTF_TGEN_VPORCH_RODD);
75 }
76 
mtk_dpintf_config_vsync_reven(const struct mtk_dpintf * dpintf,struct mtk_dpintf_sync_param * sync)77 static void mtk_dpintf_config_vsync_reven(const struct mtk_dpintf *dpintf,
78 					  struct mtk_dpintf_sync_param *sync)
79 {
80 	mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_REVEN,
81 				DPINTF_TGEN_VPORCH_REVEN);
82 }
83 
mtk_dpintf_config_pol(const struct mtk_dpintf * dpintf,struct mtk_dpintf_polarities * dpintf_pol)84 static void mtk_dpintf_config_pol(const struct mtk_dpintf *dpintf,
85 				  struct mtk_dpintf_polarities *dpintf_pol)
86 {
87 	u32 pol;
88 
89 	pol = (dpintf_pol->hsync_pol == MTK_DPINTF_POLARITY_RISING ? 0 : HSYNC_POL) |
90 	      (dpintf_pol->vsync_pol == MTK_DPINTF_POLARITY_RISING ? 0 : VSYNC_POL);
91 	mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, pol, HSYNC_POL | VSYNC_POL);
92 }
93 
mtk_dpintf_config_3d(const struct mtk_dpintf * dpintf,bool en_3d)94 static void mtk_dpintf_config_3d(const struct mtk_dpintf *dpintf, bool en_3d)
95 {
96 	mtk_dpintf_mask(dpintf, DPINTF_CON, en_3d ? TDFP_EN : 0, TDFP_EN);
97 }
98 
mtk_dpintf_config_interface(const struct mtk_dpintf * dpintf,bool inter)99 static void mtk_dpintf_config_interface(const struct mtk_dpintf *dpintf, bool inter)
100 {
101 	mtk_dpintf_mask(dpintf, DPINTF_CON, inter ? INTL_EN : 0, INTL_EN);
102 }
103 
mtk_dpintf_config_fb_size(const struct mtk_dpintf * dpintf,u32 width,u32 height)104 static void mtk_dpintf_config_fb_size(const struct mtk_dpintf *dpintf,
105 				      u32 width, u32 height)
106 {
107 	mtk_dpintf_mask(dpintf, DPINTF_SIZE, width << HSIZE, HSIZE_MASK);
108 	mtk_dpintf_mask(dpintf, DPINTF_SIZE, height << VSIZE, VSIZE_MASK);
109 }
110 
mtk_dpintf_config_channel_limit(const struct mtk_dpintf * dpintf,struct mtk_dpintf_yc_limit * limit)111 static void mtk_dpintf_config_channel_limit(const struct mtk_dpintf *dpintf,
112 					    struct mtk_dpintf_yc_limit *limit)
113 {
114 	mtk_dpintf_mask(dpintf, DPINTF_Y_LIMIT,
115 			limit->y_bottom << Y_LIMINT_BOT, Y_LIMINT_BOT_MASK);
116 	mtk_dpintf_mask(dpintf, DPINTF_Y_LIMIT,
117 			limit->y_top << Y_LIMINT_TOP, Y_LIMINT_TOP_MASK);
118 	mtk_dpintf_mask(dpintf, DPINTF_C_LIMIT,
119 			limit->c_bottom << C_LIMIT_BOT, C_LIMIT_BOT_MASK);
120 	mtk_dpintf_mask(dpintf, DPINTF_C_LIMIT,
121 			limit->c_top << C_LIMIT_TOP, C_LIMIT_TOP_MASK);
122 }
123 
mtk_dpintf_config_bit_num(const struct mtk_dpintf * dpintf,enum mtk_dpintf_out_bit_num num)124 static void mtk_dpintf_config_bit_num(const struct mtk_dpintf *dpintf,
125 				      enum mtk_dpintf_out_bit_num num)
126 {
127 	u32 val;
128 
129 	switch (num) {
130 	case MTK_DPINTF_OUT_BIT_NUM_8BITS:
131 		val = OUT_BIT_8;
132 		break;
133 	case MTK_DPINTF_OUT_BIT_NUM_10BITS:
134 		val = OUT_BIT_10;
135 		break;
136 	case MTK_DPINTF_OUT_BIT_NUM_12BITS:
137 		val = OUT_BIT_12;
138 		break;
139 	case MTK_DPINTF_OUT_BIT_NUM_16BITS:
140 		val = OUT_BIT_16;
141 		break;
142 	default:
143 		val = OUT_BIT_8;
144 		break;
145 	}
146 	mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, val, OUT_BIT_MASK);
147 }
148 
mtk_dpintf_config_channel_swap(const struct mtk_dpintf * dpintf,enum mtk_dpintf_out_channel_swap swap)149 static void mtk_dpintf_config_channel_swap(const struct mtk_dpintf *dpintf,
150 					   enum mtk_dpintf_out_channel_swap swap)
151 {
152 	u32 val;
153 
154 	switch (swap) {
155 	case MTK_DPINTF_OUT_CHANNEL_SWAP_RGB:
156 		val = SWAP_RGB;
157 		break;
158 	case MTK_DPINTF_OUT_CHANNEL_SWAP_GBR:
159 		val = SWAP_GBR;
160 		break;
161 	case MTK_DPINTF_OUT_CHANNEL_SWAP_BRG:
162 		val = SWAP_BRG;
163 		break;
164 	case MTK_DPINTF_OUT_CHANNEL_SWAP_RBG:
165 		val = SWAP_RBG;
166 		break;
167 	case MTK_DPINTF_OUT_CHANNEL_SWAP_GRB:
168 		val = SWAP_GRB;
169 		break;
170 	case MTK_DPINTF_OUT_CHANNEL_SWAP_BGR:
171 		val = SWAP_BGR;
172 		break;
173 	default:
174 		val = SWAP_RGB;
175 		break;
176 	}
177 
178 	mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, val, CH_SWAP_MASK);
179 }
180 
mtk_dpintf_config_yuv422_enable(const struct mtk_dpintf * dpintf,bool enable)181 static void mtk_dpintf_config_yuv422_enable(const struct mtk_dpintf *dpintf, bool enable)
182 {
183 	mtk_dpintf_mask(dpintf, DPINTF_CON, enable ? YUV422_EN : 0, YUV422_EN);
184 }
185 
mtk_dpintf_config_color_format(const struct mtk_dpintf * dpintf,enum mtk_dpintf_out_color_format format)186 static void mtk_dpintf_config_color_format(const struct mtk_dpintf *dpintf,
187 					   enum mtk_dpintf_out_color_format format)
188 {
189 	bool enable;
190 	int channel_swap;
191 
192 	if (format == MTK_DPINTF_COLOR_FORMAT_YCBCR_444 ||
193 	    format == MTK_DPINTF_COLOR_FORMAT_YCBCR_444_FULL) {
194 		enable = false;
195 		channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_BGR;
196 	} else if (format == MTK_DPINTF_COLOR_FORMAT_YCBCR_422 ||
197 		   format == MTK_DPINTF_COLOR_FORMAT_YCBCR_422_FULL) {
198 		enable = true;
199 		channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_RGB;
200 	} else {
201 		enable = false;
202 		channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_RGB;
203 	}
204 
205 	mtk_dpintf_config_yuv422_enable(dpintf, enable);
206 	mtk_dpintf_config_channel_swap(dpintf, channel_swap);
207 }
208 
mtk_dpintf_power_on(const struct mtk_dpintf * dpintf,const struct edid * edid)209 static int mtk_dpintf_power_on(const struct mtk_dpintf *dpintf, const struct edid *edid)
210 {
211 	u32 clksrc;
212 	u32 pll_rate;
213 
214 	if (edid->mode.pixel_clock < 70000)
215 		clksrc = TVDPLL_D16;
216 	else if (edid->mode.pixel_clock < 200000)
217 		clksrc = TVDPLL_D8;
218 	else
219 		clksrc = TVDPLL_D4;
220 
221 	pll_rate = edid->mode.pixel_clock * 1000 * (1 << ((clksrc + 1) / 2));
222 
223 	mt_pll_set_tvd_pll1_freq(pll_rate / 4);
224 	mt_pll_edp_mux_set_sel(clksrc);
225 
226 	mtk_dpintf_enable(dpintf);
227 
228 	return 0;
229 }
230 
mtk_dpintf_set_display_mode(const struct mtk_dpintf * dpintf,const struct edid * edid)231 static int mtk_dpintf_set_display_mode(const struct mtk_dpintf *dpintf,
232 				       const struct edid *edid)
233 {
234 	struct mtk_dpintf_yc_limit limit;
235 	struct mtk_dpintf_polarities dpintf_pol;
236 	struct mtk_dpintf_sync_param hsync;
237 	struct mtk_dpintf_sync_param vsync_lodd = { 0 };
238 	struct mtk_dpintf_sync_param vsync_leven = { 0 };
239 	struct mtk_dpintf_sync_param vsync_rodd = { 0 };
240 	struct mtk_dpintf_sync_param vsync_reven = { 0 };
241 
242 	vsync_lodd.back_porch = edid->mode.vbl - edid->mode.vso -
243 				edid->mode.vspw - edid->mode.vborder;
244 	vsync_lodd.front_porch = edid->mode.vso - edid->mode.vborder;
245 	vsync_lodd.sync_width = edid->mode.vspw;
246 	vsync_lodd.shift_half_line = false;
247 
248 	hsync.sync_width = edid->mode.hspw / 4;
249 	hsync.back_porch = (edid->mode.hbl - edid->mode.hso -
250 			    edid->mode.hspw - edid->mode.hborder) / 4;
251 	hsync.front_porch = (edid->mode.hso - edid->mode.hborder) / 4;
252 	hsync.shift_half_line = false;
253 
254 	/* Let pll_rate be able to fix the valid range of tvdpll (1G~2GHz) */
255 	limit.c_bottom = 0x0000;
256 	limit.c_top = 0xfff;
257 	limit.y_bottom = 0x0000;
258 	limit.y_top = 0xfff;
259 
260 	dpintf_pol.ck_pol = MTK_DPINTF_POLARITY_FALLING;
261 	dpintf_pol.de_pol = MTK_DPINTF_POLARITY_RISING;
262 	dpintf_pol.hsync_pol = (edid->mode.phsync == '+') ?
263 			       MTK_DPINTF_POLARITY_FALLING :
264 			       MTK_DPINTF_POLARITY_RISING;
265 	dpintf_pol.vsync_pol = (edid->mode.pvsync == '+') ?
266 			       MTK_DPINTF_POLARITY_FALLING :
267 			       MTK_DPINTF_POLARITY_RISING;
268 
269 	mtk_dpintf_sw_reset(dpintf, true);
270 	mtk_dpintf_config_pol(dpintf, &dpintf_pol);
271 
272 	mtk_dpintf_config_hsync(dpintf, &hsync);
273 	mtk_dpintf_config_vsync_lodd(dpintf, &vsync_lodd);
274 	mtk_dpintf_config_vsync_rodd(dpintf, &vsync_rodd);
275 	mtk_dpintf_config_vsync_leven(dpintf, &vsync_leven);
276 	mtk_dpintf_config_vsync_reven(dpintf, &vsync_reven);
277 
278 	mtk_dpintf_config_3d(dpintf, false);
279 	mtk_dpintf_config_interface(dpintf, false);
280 	mtk_dpintf_config_fb_size(dpintf, edid->mode.ha, edid->mode.va);
281 
282 	mtk_dpintf_config_channel_limit(dpintf, &limit);
283 	mtk_dpintf_config_bit_num(dpintf, dpintf->bit_num);
284 	mtk_dpintf_config_channel_swap(dpintf, dpintf->channel_swap);
285 	mtk_dpintf_config_color_format(dpintf, dpintf->color_format);
286 
287 	mtk_dpintf_mask(dpintf, DPINTF_CON, dpintf->input_mode, INPUT_2P_EN);
288 	mtk_dpintf_sw_reset(dpintf, false);
289 
290 	return 0;
291 }
292 
dp_intf_config(const struct edid * edid)293 void dp_intf_config(const struct edid *edid)
294 {
295 	const struct mtk_dpintf *data = &dpintf_data;
296 
297 	mtk_dpintf_power_on(data, edid);
298 	mtk_dpintf_set_display_mode(data, edid);
299 }
300