File Index
Files and directories
Sign in
FILE

dp_hw.c

File preview with syntax highlighting.

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