xref: /linux/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c (revision 813b46808822db6838c43e92ba21ce013d23fcdc)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 // Copyright (c) 2024 Hisilicon Limited.
3 
4 #include <linux/io.h>
5 #include <linux/delay.h>
6 #include "dp_config.h"
7 #include "dp_comm.h"
8 #include "dp_reg.h"
9 #include "dp_hw.h"
10 
11 static void hibmc_dp_set_tu(struct hibmc_dp_dev *dp, struct drm_display_mode *mode)
12 {
13 	u32 tu_symbol_frac_size;
14 	u32 tu_symbol_size;
15 	u32 rate_ks;
16 	u8 lane_num;
17 	u32 value;
18 	u32 bpp;
19 
20 	lane_num = dp->link.cap.lanes;
21 	if (lane_num == 0) {
22 		drm_err(dp->dev, "set tu failed, lane num cannot be 0!\n");
23 		return;
24 	}
25 
26 	bpp = HIBMC_DP_BPP;
27 	rate_ks = dp->link.cap.link_rate * HIBMC_DP_LINK_RATE_CAL;
28 	value = (mode->clock * bpp * 5) / (61 * lane_num * rate_ks);
29 
30 	if (value % 10 == 9) { /* 9 carry */
31 		tu_symbol_size = value / 10 + 1;
32 		tu_symbol_frac_size = 0;
33 	} else {
34 		tu_symbol_size = value / 10;
35 		tu_symbol_frac_size = value % 10 + 1;
36 	}
37 
38 	drm_dbg_dp(dp->dev, "tu value: %u.%u value: %u\n",
39 		   tu_symbol_size, tu_symbol_frac_size, value);
40 
41 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_PACKET,
42 				 HIBMC_DP_CFG_STREAM_TU_SYMBOL_SIZE, tu_symbol_size);
43 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_PACKET,
44 				 HIBMC_DP_CFG_STREAM_TU_SYMBOL_FRAC_SIZE, tu_symbol_frac_size);
45 }
46 
47 static void hibmc_dp_set_sst(struct hibmc_dp_dev *dp, struct drm_display_mode *mode)
48 {
49 	u32 hblank_size;
50 	u32 htotal_size;
51 	u32 htotal_int;
52 	u32 hblank_int;
53 	u32 fclk; /* flink_clock */
54 
55 	fclk = dp->link.cap.link_rate * HIBMC_DP_LINK_RATE_CAL;
56 
57 	/* Considering the effect of spread spectrum, the value may be deviated.
58 	 * The coefficient (0.9947) is used to offset the deviation.
59 	 */
60 	htotal_int = mode->htotal * 9947 / 10000;
61 	htotal_size = htotal_int * fclk / (HIBMC_DP_SYMBOL_PER_FCLK * (mode->clock / 1000));
62 
63 	hblank_int = mode->htotal - mode->hdisplay - mode->hdisplay * 53 / 10000;
64 	hblank_size = hblank_int * fclk * 9947 /
65 		      (mode->clock * 10 * HIBMC_DP_SYMBOL_PER_FCLK);
66 
67 	drm_dbg_dp(dp->dev, "h_active %u v_active %u htotal_size %u hblank_size %u",
68 		   mode->hdisplay, mode->vdisplay, htotal_size, hblank_size);
69 	drm_dbg_dp(dp->dev, "flink_clock %u pixel_clock %d", fclk, mode->clock / 1000);
70 
71 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_HORIZONTAL_SIZE,
72 				 HIBMC_DP_CFG_STREAM_HTOTAL_SIZE, htotal_size);
73 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_HORIZONTAL_SIZE,
74 				 HIBMC_DP_CFG_STREAM_HBLANK_SIZE, hblank_size);
75 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_PACKET,
76 				 HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION,
77 				 HIBMC_DP_SYNC_DELAY(dp->link.cap.lanes));
78 }
79 
80 static void hibmc_dp_link_cfg(struct hibmc_dp_dev *dp, struct drm_display_mode *mode)
81 {
82 	u32 timing_delay;
83 	u32 vblank;
84 	u32 hstart;
85 	u32 vstart;
86 
87 	vblank = mode->vtotal - mode->vdisplay;
88 	timing_delay = mode->htotal - mode->hsync_start;
89 	hstart = mode->htotal - mode->hsync_start;
90 	vstart = mode->vtotal - mode->vsync_start;
91 
92 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_GEN_CONFIG0,
93 				 HIBMC_DP_CFG_TIMING_GEN0_HBLANK, mode->htotal - mode->hdisplay);
94 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_GEN_CONFIG0,
95 				 HIBMC_DP_CFG_TIMING_GEN0_HACTIVE, mode->hdisplay);
96 
97 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_GEN_CONFIG2,
98 				 HIBMC_DP_CFG_TIMING_GEN0_VBLANK, vblank);
99 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_GEN_CONFIG2,
100 				 HIBMC_DP_CFG_TIMING_GEN0_VACTIVE, mode->vdisplay);
101 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_GEN_CONFIG3,
102 				 HIBMC_DP_CFG_TIMING_GEN0_VFRONT_PORCH,
103 				 mode->vsync_start - mode->vdisplay);
104 
105 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG0,
106 				 HIBMC_DP_CFG_STREAM_HACTIVE, mode->hdisplay);
107 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG0,
108 				 HIBMC_DP_CFG_STREAM_HBLANK, mode->htotal - mode->hdisplay);
109 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG2,
110 				 HIBMC_DP_CFG_STREAM_HSYNC_WIDTH,
111 				 mode->hsync_end - mode->hsync_start);
112 
113 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG1,
114 				 HIBMC_DP_CFG_STREAM_VACTIVE, mode->vdisplay);
115 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG1,
116 				 HIBMC_DP_CFG_STREAM_VBLANK, vblank);
117 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG3,
118 				 HIBMC_DP_CFG_STREAM_VFRONT_PORCH,
119 				 mode->vsync_start - mode->vdisplay);
120 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CONFIG3,
121 				 HIBMC_DP_CFG_STREAM_VSYNC_WIDTH,
122 				 mode->vsync_end - mode->vsync_start);
123 
124 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_MSA0,
125 				 HIBMC_DP_CFG_STREAM_VSTART, vstart);
126 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_MSA0,
127 				 HIBMC_DP_CFG_STREAM_HSTART, hstart);
128 
129 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CTRL, HIBMC_DP_CFG_STREAM_VSYNC_POLARITY,
130 				 mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 : 0);
131 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CTRL, HIBMC_DP_CFG_STREAM_HSYNC_POLARITY,
132 				 mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 : 0);
133 
134 	/* MSA mic 0 and 1 */
135 	writel(HIBMC_DP_MSA1, dp->base + HIBMC_DP_VIDEO_MSA1);
136 	writel(HIBMC_DP_MSA2, dp->base + HIBMC_DP_VIDEO_MSA2);
137 
138 	hibmc_dp_set_tu(dp, mode);
139 
140 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CTRL, HIBMC_DP_CFG_STREAM_RGB_ENABLE, 0x1);
141 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CTRL, HIBMC_DP_CFG_STREAM_VIDEO_MAPPING, 0);
142 
143 	/* divide 2: up even */
144 	if (timing_delay % 2)
145 		timing_delay++;
146 
147 	hibmc_dp_reg_write_field(dp, HIBMC_DP_TIMING_MODEL_CTRL,
148 				 HIBMC_DP_CFG_PIXEL_NUM_TIMING_MODE_SEL1, timing_delay);
149 
150 	hibmc_dp_set_sst(dp, mode);
151 }
152 
153 int hibmc_dp_hw_init(struct hibmc_dp *dp)
154 {
155 	struct drm_device *drm_dev = dp->drm_dev;
156 	struct hibmc_dp_dev *dp_dev;
157 	int ret;
158 
159 	dp_dev = devm_kzalloc(drm_dev->dev, sizeof(struct hibmc_dp_dev), GFP_KERNEL);
160 	if (!dp_dev)
161 		return -ENOMEM;
162 
163 	mutex_init(&dp_dev->lock);
164 
165 	dp->dp_dev = dp_dev;
166 
167 	dp_dev->dev = drm_dev;
168 	dp_dev->base = dp->mmio + HIBMC_DP_OFFSET;
169 
170 	hibmc_dp_aux_init(dp);
171 
172 	ret = hibmc_dp_serdes_init(dp_dev);
173 	if (ret)
174 		return ret;
175 
176 	dp_dev->link.cap.lanes = 0x2;
177 	dp_dev->link.cap.link_rate = DP_LINK_BW_8_1;
178 
179 	/* hdcp data */
180 	writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
181 	/* int init */
182 	writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
183 	writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
184 	/* rst */
185 	writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL);
186 	/* clock enable */
187 	writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL);
188 
189 	return 0;
190 }
191 
192 void hibmc_dp_enable_int(struct hibmc_dp *dp)
193 {
194 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
195 
196 	writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
197 }
198 
199 void hibmc_dp_disable_int(struct hibmc_dp *dp)
200 {
201 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
202 
203 	writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
204 	writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
205 }
206 
207 void hibmc_dp_hpd_cfg(struct hibmc_dp *dp)
208 {
209 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
210 
211 	hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_SYNC_LEN_SEL, 0x0);
212 	hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_TIMER_TIMEOUT, 0x1);
213 	hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_MIN_PULSE_NUM, 0x9);
214 	writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
215 	writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
216 	writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
217 	writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
218 	writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL);
219 	writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL);
220 }
221 
222 void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable)
223 {
224 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
225 
226 	if (enable) {
227 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_VIDEO_CTRL, BIT(0), 0x1);
228 		writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
229 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_DPTX_GCTL0, BIT(10), 0x1);
230 		writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
231 	} else {
232 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_DPTX_GCTL0, BIT(10), 0);
233 		writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
234 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_VIDEO_CTRL, BIT(0), 0);
235 		writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
236 	}
237 
238 	msleep(50);
239 }
240 
241 int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode)
242 {
243 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
244 	int ret;
245 
246 	if (!dp_dev->link.status.channel_equalized) {
247 		ret = hibmc_dp_link_training(dp_dev);
248 		if (ret) {
249 			drm_err(dp->drm_dev, "dp link training failed, ret: %d\n", ret);
250 			return ret;
251 		}
252 	}
253 
254 	hibmc_dp_display_en(dp, false);
255 	hibmc_dp_link_cfg(dp_dev, mode);
256 
257 	return 0;
258 }
259 
260 void hibmc_dp_reset_link(struct hibmc_dp *dp)
261 {
262 	dp->dp_dev->link.status.clock_recovered = false;
263 	dp->dp_dev->link.status.channel_equalized = false;
264 }
265 
266 static const struct hibmc_dp_color_raw g_rgb_raw[] = {
267 	{CBAR_COLOR_BAR, 0x000, 0x000, 0x000},
268 	{CBAR_WHITE,     0xfff, 0xfff, 0xfff},
269 	{CBAR_RED,       0xfff, 0x000, 0x000},
270 	{CBAR_ORANGE,    0xfff, 0x800, 0x000},
271 	{CBAR_YELLOW,    0xfff, 0xfff, 0x000},
272 	{CBAR_GREEN,     0x000, 0xfff, 0x000},
273 	{CBAR_CYAN,      0x000, 0x800, 0x800},
274 	{CBAR_BLUE,      0x000, 0x000, 0xfff},
275 	{CBAR_PURPLE,    0x800, 0x000, 0x800},
276 	{CBAR_BLACK,     0x000, 0x000, 0x000},
277 };
278 
279 void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg)
280 {
281 	struct hibmc_dp_dev *dp_dev = dp->dp_dev;
282 	struct hibmc_dp_color_raw raw_data;
283 
284 	if (cfg->enable) {
285 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(9),
286 					 cfg->self_timing);
287 		hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(8, 1),
288 					 cfg->dynamic_rate);
289 		if (cfg->pattern == CBAR_COLOR_BAR) {
290 			hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 0);
291 		} else {
292 			raw_data = g_rgb_raw[cfg->pattern];
293 			drm_dbg_dp(dp->drm_dev, "r:%x g:%x b:%x\n", raw_data.r_value,
294 				   raw_data.g_value, raw_data.b_value);
295 			hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 1);
296 			hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(23, 12),
297 						 raw_data.r_value);
298 			hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(23, 12),
299 						 raw_data.g_value);
300 			hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(11, 0),
301 						 raw_data.b_value);
302 		}
303 	}
304 
305 	hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->enable);
306 	writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
307 }
308