diff options
author | Dave Airlie <airlied@redhat.com> | 2017-02-06 20:03:30 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-02-06 20:03:30 -0500 |
commit | 538f1dcdc5e20adb2488fa0932d56906de166405 (patch) | |
tree | da6f5198b14870f542e6cee044332e4f799665dd | |
parent | 31f408c8a8e7c1976e868206156ae14bf35e4ac9 (diff) | |
parent | ef1844b7ed847430955a95d20242f0d1b9f5fa64 (diff) |
Merge branch 'drm-rockchip-next-2017-02-05' of https://github.com/markyzq/kernel-drm-rockchip into drm-next
rockchip CDN-DP support.
* 'drm-rockchip-next-2017-02-05' of https://github.com/markyzq/kernel-drm-rockchip:
drm/rockchip: cdn-dp: don't configure hardware in mode_set
drm/rockchip: cdn-dp: retry to check sink count
drm/rockchip: cdn-dp: Move mutex_init to probe
drm/rockchip: cdn-dp: do not use drm_helper_hpd_irq_event
drm/rockchip: cdn-dp: Do not run worker while suspended
drm/rockchip: cdn-dp: Load firmware if no monitor connected
drm/rockchip: cdn-dp: add cdn DP support for rk3399
drm/rockchip: return ERR_PTR instead of NULL
drm/rockchip: vop: make vop register setting take effect
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-core.c | 1260 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-core.h | 112 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-reg.c | 979 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-reg.h | 483 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 |
10 files changed, 2872 insertions, 4 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 6f7f9c59f05b..ad31b3eb408f 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig | |||
@@ -21,6 +21,16 @@ config ROCKCHIP_ANALOGIX_DP | |||
21 | for the Analogix Core DP driver. If you want to enable DP | 21 | for the Analogix Core DP driver. If you want to enable DP |
22 | on RK3288 based SoC, you should selet this option. | 22 | on RK3288 based SoC, you should selet this option. |
23 | 23 | ||
24 | config ROCKCHIP_CDN_DP | ||
25 | tristate "Rockchip cdn DP" | ||
26 | depends on DRM_ROCKCHIP | ||
27 | select SND_SOC_HDMI_CODEC if SND_SOC | ||
28 | help | ||
29 | This selects support for Rockchip SoC specific extensions | ||
30 | for the cdn DP driver. If you want to enable Dp on | ||
31 | RK3399 based SoC, you should select this | ||
32 | option. | ||
33 | |||
24 | config ROCKCHIP_DW_HDMI | 34 | config ROCKCHIP_DW_HDMI |
25 | tristate "Rockchip specific extensions for Synopsys DW HDMI" | 35 | tristate "Rockchip specific extensions for Synopsys DW HDMI" |
26 | depends on DRM_ROCKCHIP | 36 | depends on DRM_ROCKCHIP |
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 9746365694ba..c931e2a7d8de 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile | |||
@@ -7,6 +7,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ | |||
7 | rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o | 7 | rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o |
8 | 8 | ||
9 | obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o | 9 | obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o |
10 | obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp.o | ||
11 | cdn-dp-objs := cdn-dp-core.o cdn-dp-reg.o | ||
10 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | 12 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o |
11 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o | 13 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o |
12 | obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o | 14 | obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o |
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c new file mode 100644 index 000000000000..9ab67a670885 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c | |||
@@ -0,0 +1,1260 @@ | |||
1 | /* | ||
2 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | ||
3 | * Author: Chris Zhong <zyw@rock-chips.com> | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <drm/drmP.h> | ||
16 | #include <drm/drm_atomic_helper.h> | ||
17 | #include <drm/drm_crtc_helper.h> | ||
18 | #include <drm/drm_dp_helper.h> | ||
19 | #include <drm/drm_edid.h> | ||
20 | #include <drm/drm_of.h> | ||
21 | |||
22 | #include <linux/clk.h> | ||
23 | #include <linux/component.h> | ||
24 | #include <linux/extcon.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/regmap.h> | ||
27 | #include <linux/reset.h> | ||
28 | #include <linux/mfd/syscon.h> | ||
29 | #include <linux/phy/phy.h> | ||
30 | |||
31 | #include <sound/hdmi-codec.h> | ||
32 | |||
33 | #include "cdn-dp-core.h" | ||
34 | #include "cdn-dp-reg.h" | ||
35 | #include "rockchip_drm_vop.h" | ||
36 | |||
37 | #define connector_to_dp(c) \ | ||
38 | container_of(c, struct cdn_dp_device, connector) | ||
39 | |||
40 | #define encoder_to_dp(c) \ | ||
41 | container_of(c, struct cdn_dp_device, encoder) | ||
42 | |||
43 | #define GRF_SOC_CON9 0x6224 | ||
44 | #define DP_SEL_VOP_LIT BIT(12) | ||
45 | #define GRF_SOC_CON26 0x6268 | ||
46 | #define UPHY_SEL_BIT 3 | ||
47 | #define UPHY_SEL_MASK BIT(19) | ||
48 | #define DPTX_HPD_SEL (3 << 12) | ||
49 | #define DPTX_HPD_DEL (2 << 12) | ||
50 | #define DPTX_HPD_SEL_MASK (3 << 28) | ||
51 | |||
52 | #define CDN_FW_TIMEOUT_MS (64 * 1000) | ||
53 | #define CDN_DPCD_TIMEOUT_MS 5000 | ||
54 | #define CDN_DP_FIRMWARE "rockchip/dptx.bin" | ||
55 | |||
56 | struct cdn_dp_data { | ||
57 | u8 max_phy; | ||
58 | }; | ||
59 | |||
60 | struct cdn_dp_data rk3399_cdn_dp = { | ||
61 | .max_phy = 2, | ||
62 | }; | ||
63 | |||
64 | static const struct of_device_id cdn_dp_dt_ids[] = { | ||
65 | { .compatible = "rockchip,rk3399-cdn-dp", | ||
66 | .data = (void *)&rk3399_cdn_dp }, | ||
67 | {} | ||
68 | }; | ||
69 | |||
70 | MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids); | ||
71 | |||
72 | static int cdn_dp_grf_write(struct cdn_dp_device *dp, | ||
73 | unsigned int reg, unsigned int val) | ||
74 | { | ||
75 | int ret; | ||
76 | |||
77 | ret = clk_prepare_enable(dp->grf_clk); | ||
78 | if (ret) { | ||
79 | DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n"); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | ret = regmap_write(dp->grf, reg, val); | ||
84 | if (ret) { | ||
85 | DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | clk_disable_unprepare(dp->grf_clk); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int cdn_dp_clk_enable(struct cdn_dp_device *dp) | ||
95 | { | ||
96 | int ret; | ||
97 | u32 rate; | ||
98 | |||
99 | ret = clk_prepare_enable(dp->pclk); | ||
100 | if (ret < 0) { | ||
101 | DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret); | ||
102 | goto err_pclk; | ||
103 | } | ||
104 | |||
105 | ret = clk_prepare_enable(dp->core_clk); | ||
106 | if (ret < 0) { | ||
107 | DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret); | ||
108 | goto err_core_clk; | ||
109 | } | ||
110 | |||
111 | ret = pm_runtime_get_sync(dp->dev); | ||
112 | if (ret < 0) { | ||
113 | DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret); | ||
114 | goto err_pclk; | ||
115 | } | ||
116 | |||
117 | reset_control_assert(dp->core_rst); | ||
118 | reset_control_assert(dp->dptx_rst); | ||
119 | reset_control_assert(dp->apb_rst); | ||
120 | reset_control_deassert(dp->core_rst); | ||
121 | reset_control_deassert(dp->dptx_rst); | ||
122 | reset_control_deassert(dp->apb_rst); | ||
123 | |||
124 | rate = clk_get_rate(dp->core_clk); | ||
125 | if (!rate) { | ||
126 | DRM_DEV_ERROR(dp->dev, "get clk rate failed: %d\n", rate); | ||
127 | goto err_set_rate; | ||
128 | } | ||
129 | |||
130 | cdn_dp_set_fw_clk(dp, rate); | ||
131 | cdn_dp_clock_reset(dp); | ||
132 | |||
133 | return 0; | ||
134 | |||
135 | err_set_rate: | ||
136 | clk_disable_unprepare(dp->core_clk); | ||
137 | err_core_clk: | ||
138 | clk_disable_unprepare(dp->pclk); | ||
139 | err_pclk: | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static void cdn_dp_clk_disable(struct cdn_dp_device *dp) | ||
144 | { | ||
145 | pm_runtime_put_sync(dp->dev); | ||
146 | clk_disable_unprepare(dp->pclk); | ||
147 | clk_disable_unprepare(dp->core_clk); | ||
148 | } | ||
149 | |||
150 | static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) | ||
151 | { | ||
152 | struct extcon_dev *edev = port->extcon; | ||
153 | union extcon_property_value property; | ||
154 | int dptx; | ||
155 | u8 lanes; | ||
156 | |||
157 | dptx = extcon_get_state(edev, EXTCON_DISP_DP); | ||
158 | if (dptx > 0) { | ||
159 | extcon_get_property(edev, EXTCON_DISP_DP, | ||
160 | EXTCON_PROP_USB_SS, &property); | ||
161 | if (property.intval) | ||
162 | lanes = 2; | ||
163 | else | ||
164 | lanes = 4; | ||
165 | } else { | ||
166 | lanes = 0; | ||
167 | } | ||
168 | |||
169 | return lanes; | ||
170 | } | ||
171 | |||
172 | static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) | ||
173 | { | ||
174 | int ret; | ||
175 | u8 value; | ||
176 | |||
177 | *sink_count = 0; | ||
178 | ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1); | ||
179 | if (ret) | ||
180 | return ret; | ||
181 | |||
182 | *sink_count = DP_GET_SINK_COUNT(value); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp) | ||
187 | { | ||
188 | struct cdn_dp_port *port; | ||
189 | int i, lanes; | ||
190 | |||
191 | for (i = 0; i < dp->ports; i++) { | ||
192 | port = dp->port[i]; | ||
193 | lanes = cdn_dp_get_port_lanes(port); | ||
194 | if (lanes) | ||
195 | return port; | ||
196 | } | ||
197 | return NULL; | ||
198 | } | ||
199 | |||
200 | static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) | ||
201 | { | ||
202 | unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS); | ||
203 | struct cdn_dp_port *port; | ||
204 | u8 sink_count = 0; | ||
205 | |||
206 | if (dp->active_port < 0 || dp->active_port >= dp->ports) { | ||
207 | DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n"); | ||
208 | return false; | ||
209 | } | ||
210 | |||
211 | port = dp->port[dp->active_port]; | ||
212 | |||
213 | /* | ||
214 | * Attempt to read sink count, retry in case the sink may not be ready. | ||
215 | * | ||
216 | * Sinks are *supposed* to come up within 1ms from an off state, but | ||
217 | * some docks need more time to power up. | ||
218 | */ | ||
219 | while (time_before(jiffies, timeout)) { | ||
220 | if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) | ||
221 | return false; | ||
222 | |||
223 | if (!cdn_dp_get_sink_count(dp, &sink_count)) | ||
224 | return sink_count ? true : false; | ||
225 | |||
226 | usleep_range(5000, 10000); | ||
227 | } | ||
228 | |||
229 | DRM_DEV_ERROR(dp->dev, "Get sink capability timed out\n"); | ||
230 | return false; | ||
231 | } | ||
232 | |||
233 | static enum drm_connector_status | ||
234 | cdn_dp_connector_detect(struct drm_connector *connector, bool force) | ||
235 | { | ||
236 | struct cdn_dp_device *dp = connector_to_dp(connector); | ||
237 | enum drm_connector_status status = connector_status_disconnected; | ||
238 | |||
239 | mutex_lock(&dp->lock); | ||
240 | if (dp->connected) | ||
241 | status = connector_status_connected; | ||
242 | mutex_unlock(&dp->lock); | ||
243 | |||
244 | return status; | ||
245 | } | ||
246 | |||
247 | static void cdn_dp_connector_destroy(struct drm_connector *connector) | ||
248 | { | ||
249 | drm_connector_unregister(connector); | ||
250 | drm_connector_cleanup(connector); | ||
251 | } | ||
252 | |||
253 | static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { | ||
254 | .dpms = drm_atomic_helper_connector_dpms, | ||
255 | .detect = cdn_dp_connector_detect, | ||
256 | .destroy = cdn_dp_connector_destroy, | ||
257 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
258 | .reset = drm_atomic_helper_connector_reset, | ||
259 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
260 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
261 | }; | ||
262 | |||
263 | static int cdn_dp_connector_get_modes(struct drm_connector *connector) | ||
264 | { | ||
265 | struct cdn_dp_device *dp = connector_to_dp(connector); | ||
266 | struct edid *edid; | ||
267 | int ret = 0; | ||
268 | |||
269 | mutex_lock(&dp->lock); | ||
270 | edid = dp->edid; | ||
271 | if (edid) { | ||
272 | DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", | ||
273 | edid->width_cm, edid->height_cm); | ||
274 | |||
275 | dp->sink_has_audio = drm_detect_monitor_audio(edid); | ||
276 | ret = drm_add_edid_modes(connector, edid); | ||
277 | if (ret) { | ||
278 | drm_mode_connector_update_edid_property(connector, | ||
279 | edid); | ||
280 | drm_edid_to_eld(connector, edid); | ||
281 | } | ||
282 | } | ||
283 | mutex_unlock(&dp->lock); | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static struct drm_encoder * | ||
289 | cdn_dp_connector_best_encoder(struct drm_connector *connector) | ||
290 | { | ||
291 | struct cdn_dp_device *dp = connector_to_dp(connector); | ||
292 | |||
293 | return &dp->encoder; | ||
294 | } | ||
295 | |||
296 | static int cdn_dp_connector_mode_valid(struct drm_connector *connector, | ||
297 | struct drm_display_mode *mode) | ||
298 | { | ||
299 | struct cdn_dp_device *dp = connector_to_dp(connector); | ||
300 | struct drm_display_info *display_info = &dp->connector.display_info; | ||
301 | u32 requested, actual, rate, sink_max, source_max = 0; | ||
302 | u8 lanes, bpc; | ||
303 | |||
304 | /* If DP is disconnected, every mode is invalid */ | ||
305 | if (!dp->connected) | ||
306 | return MODE_BAD; | ||
307 | |||
308 | switch (display_info->bpc) { | ||
309 | case 10: | ||
310 | bpc = 10; | ||
311 | break; | ||
312 | case 6: | ||
313 | bpc = 6; | ||
314 | break; | ||
315 | default: | ||
316 | bpc = 8; | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | requested = mode->clock * bpc * 3 / 1000; | ||
321 | |||
322 | source_max = dp->lanes; | ||
323 | sink_max = drm_dp_max_lane_count(dp->dpcd); | ||
324 | lanes = min(source_max, sink_max); | ||
325 | |||
326 | source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); | ||
327 | sink_max = drm_dp_max_link_rate(dp->dpcd); | ||
328 | rate = min(source_max, sink_max); | ||
329 | |||
330 | actual = rate * lanes / 100; | ||
331 | |||
332 | /* efficiency is about 0.8 */ | ||
333 | actual = actual * 8 / 10; | ||
334 | |||
335 | if (requested > actual) { | ||
336 | DRM_DEV_DEBUG_KMS(dp->dev, | ||
337 | "requested=%d, actual=%d, clock=%d\n", | ||
338 | requested, actual, mode->clock); | ||
339 | return MODE_CLOCK_HIGH; | ||
340 | } | ||
341 | |||
342 | return MODE_OK; | ||
343 | } | ||
344 | |||
345 | static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = { | ||
346 | .get_modes = cdn_dp_connector_get_modes, | ||
347 | .best_encoder = cdn_dp_connector_best_encoder, | ||
348 | .mode_valid = cdn_dp_connector_mode_valid, | ||
349 | }; | ||
350 | |||
351 | static int cdn_dp_firmware_init(struct cdn_dp_device *dp) | ||
352 | { | ||
353 | int ret; | ||
354 | const u32 *iram_data, *dram_data; | ||
355 | const struct firmware *fw = dp->fw; | ||
356 | const struct cdn_firmware_header *hdr; | ||
357 | |||
358 | hdr = (struct cdn_firmware_header *)fw->data; | ||
359 | if (fw->size != le32_to_cpu(hdr->size_bytes)) { | ||
360 | DRM_DEV_ERROR(dp->dev, "firmware is invalid\n"); | ||
361 | return -EINVAL; | ||
362 | } | ||
363 | |||
364 | iram_data = (const u32 *)(fw->data + hdr->header_size); | ||
365 | dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size); | ||
366 | |||
367 | ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size, | ||
368 | dram_data, hdr->dram_size); | ||
369 | if (ret) | ||
370 | return ret; | ||
371 | |||
372 | ret = cdn_dp_set_firmware_active(dp, true); | ||
373 | if (ret) { | ||
374 | DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | return cdn_dp_event_config(dp); | ||
379 | } | ||
380 | |||
381 | static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) | ||
382 | { | ||
383 | int ret; | ||
384 | |||
385 | if (!cdn_dp_check_sink_connection(dp)) | ||
386 | return -ENODEV; | ||
387 | |||
388 | ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, | ||
389 | DP_RECEIVER_CAP_SIZE); | ||
390 | if (ret) { | ||
391 | DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); | ||
392 | return ret; | ||
393 | } | ||
394 | |||
395 | kfree(dp->edid); | ||
396 | dp->edid = drm_do_get_edid(&dp->connector, | ||
397 | cdn_dp_get_edid_block, dp); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) | ||
402 | { | ||
403 | union extcon_property_value property; | ||
404 | int ret; | ||
405 | |||
406 | ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, | ||
407 | (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK); | ||
408 | if (ret) | ||
409 | return ret; | ||
410 | |||
411 | if (!port->phy_enabled) { | ||
412 | ret = phy_power_on(port->phy); | ||
413 | if (ret) { | ||
414 | DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n", | ||
415 | ret); | ||
416 | goto err_phy; | ||
417 | } | ||
418 | port->phy_enabled = true; | ||
419 | } | ||
420 | |||
421 | ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, | ||
422 | DPTX_HPD_SEL_MASK | DPTX_HPD_SEL); | ||
423 | if (ret) { | ||
424 | DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret); | ||
425 | goto err_power_on; | ||
426 | } | ||
427 | |||
428 | ret = cdn_dp_get_hpd_status(dp); | ||
429 | if (ret <= 0) { | ||
430 | if (!ret) | ||
431 | DRM_DEV_ERROR(dp->dev, "hpd does not exist\n"); | ||
432 | goto err_power_on; | ||
433 | } | ||
434 | |||
435 | ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, | ||
436 | EXTCON_PROP_USB_TYPEC_POLARITY, &property); | ||
437 | if (ret) { | ||
438 | DRM_DEV_ERROR(dp->dev, "get property failed\n"); | ||
439 | goto err_power_on; | ||
440 | } | ||
441 | |||
442 | port->lanes = cdn_dp_get_port_lanes(port); | ||
443 | ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); | ||
444 | if (ret) { | ||
445 | DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", | ||
446 | ret); | ||
447 | goto err_power_on; | ||
448 | } | ||
449 | |||
450 | dp->active_port = port->id; | ||
451 | return 0; | ||
452 | |||
453 | err_power_on: | ||
454 | if (phy_power_off(port->phy)) | ||
455 | DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); | ||
456 | else | ||
457 | port->phy_enabled = false; | ||
458 | |||
459 | err_phy: | ||
460 | cdn_dp_grf_write(dp, GRF_SOC_CON26, | ||
461 | DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | static int cdn_dp_disable_phy(struct cdn_dp_device *dp, | ||
466 | struct cdn_dp_port *port) | ||
467 | { | ||
468 | int ret; | ||
469 | |||
470 | if (port->phy_enabled) { | ||
471 | ret = phy_power_off(port->phy); | ||
472 | if (ret) { | ||
473 | DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); | ||
474 | return ret; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | port->phy_enabled = false; | ||
479 | port->lanes = 0; | ||
480 | dp->active_port = -1; | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int cdn_dp_disable(struct cdn_dp_device *dp) | ||
485 | { | ||
486 | int ret, i; | ||
487 | |||
488 | if (!dp->active) | ||
489 | return 0; | ||
490 | |||
491 | for (i = 0; i < dp->ports; i++) | ||
492 | cdn_dp_disable_phy(dp, dp->port[i]); | ||
493 | |||
494 | ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, | ||
495 | DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); | ||
496 | if (ret) { | ||
497 | DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n", | ||
498 | ret); | ||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | cdn_dp_set_firmware_active(dp, false); | ||
503 | cdn_dp_clk_disable(dp); | ||
504 | dp->active = false; | ||
505 | dp->link.rate = 0; | ||
506 | dp->link.num_lanes = 0; | ||
507 | if (!dp->connected) { | ||
508 | kfree(dp->edid); | ||
509 | dp->edid = NULL; | ||
510 | } | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int cdn_dp_enable(struct cdn_dp_device *dp) | ||
516 | { | ||
517 | int ret, i, lanes; | ||
518 | struct cdn_dp_port *port; | ||
519 | |||
520 | port = cdn_dp_connected_port(dp); | ||
521 | if (!port) { | ||
522 | DRM_DEV_ERROR(dp->dev, | ||
523 | "Can't enable without connection\n"); | ||
524 | return -ENODEV; | ||
525 | } | ||
526 | |||
527 | if (dp->active) | ||
528 | return 0; | ||
529 | |||
530 | ret = cdn_dp_clk_enable(dp); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | |||
534 | ret = cdn_dp_firmware_init(dp); | ||
535 | if (ret) { | ||
536 | DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret); | ||
537 | goto err_clk_disable; | ||
538 | } | ||
539 | |||
540 | /* only enable the port that connected with downstream device */ | ||
541 | for (i = port->id; i < dp->ports; i++) { | ||
542 | port = dp->port[i]; | ||
543 | lanes = cdn_dp_get_port_lanes(port); | ||
544 | if (lanes) { | ||
545 | ret = cdn_dp_enable_phy(dp, port); | ||
546 | if (ret) | ||
547 | continue; | ||
548 | |||
549 | ret = cdn_dp_get_sink_capability(dp); | ||
550 | if (ret) { | ||
551 | cdn_dp_disable_phy(dp, port); | ||
552 | } else { | ||
553 | dp->active = true; | ||
554 | dp->lanes = port->lanes; | ||
555 | return 0; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | err_clk_disable: | ||
561 | cdn_dp_clk_disable(dp); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, | ||
566 | struct drm_display_mode *mode, | ||
567 | struct drm_display_mode *adjusted) | ||
568 | { | ||
569 | struct cdn_dp_device *dp = encoder_to_dp(encoder); | ||
570 | struct drm_display_info *display_info = &dp->connector.display_info; | ||
571 | struct video_info *video = &dp->video_info; | ||
572 | |||
573 | switch (display_info->bpc) { | ||
574 | case 10: | ||
575 | video->color_depth = 10; | ||
576 | break; | ||
577 | case 6: | ||
578 | video->color_depth = 6; | ||
579 | break; | ||
580 | default: | ||
581 | video->color_depth = 8; | ||
582 | break; | ||
583 | } | ||
584 | |||
585 | video->color_fmt = PXL_RGB; | ||
586 | video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); | ||
587 | video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); | ||
588 | |||
589 | memcpy(&dp->mode, adjusted, sizeof(*mode)); | ||
590 | } | ||
591 | |||
592 | static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) | ||
593 | { | ||
594 | u8 link_status[DP_LINK_STATUS_SIZE]; | ||
595 | struct cdn_dp_port *port = cdn_dp_connected_port(dp); | ||
596 | u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd); | ||
597 | |||
598 | if (!port || !dp->link.rate || !dp->link.num_lanes) | ||
599 | return false; | ||
600 | |||
601 | if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, | ||
602 | DP_LINK_STATUS_SIZE)) { | ||
603 | DRM_ERROR("Failed to get link status\n"); | ||
604 | return false; | ||
605 | } | ||
606 | |||
607 | /* if link training is requested we should perform it always */ | ||
608 | return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes)); | ||
609 | } | ||
610 | |||
611 | static void cdn_dp_encoder_enable(struct drm_encoder *encoder) | ||
612 | { | ||
613 | struct cdn_dp_device *dp = encoder_to_dp(encoder); | ||
614 | int ret, val; | ||
615 | struct rockchip_crtc_state *state; | ||
616 | |||
617 | ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); | ||
618 | if (ret < 0) { | ||
619 | DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n", | ||
624 | (ret) ? "LIT" : "BIG"); | ||
625 | state = to_rockchip_crtc_state(encoder->crtc->state); | ||
626 | if (ret) { | ||
627 | val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16); | ||
628 | state->output_mode = ROCKCHIP_OUT_MODE_P888; | ||
629 | } else { | ||
630 | val = DP_SEL_VOP_LIT << 16; | ||
631 | state->output_mode = ROCKCHIP_OUT_MODE_AAAA; | ||
632 | } | ||
633 | |||
634 | ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val); | ||
635 | if (ret) | ||
636 | return; | ||
637 | |||
638 | mutex_lock(&dp->lock); | ||
639 | |||
640 | ret = cdn_dp_enable(dp); | ||
641 | if (ret) { | ||
642 | DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n", | ||
643 | ret); | ||
644 | goto out; | ||
645 | } | ||
646 | if (!cdn_dp_check_link_status(dp)) { | ||
647 | ret = cdn_dp_train_link(dp); | ||
648 | if (ret) { | ||
649 | DRM_DEV_ERROR(dp->dev, "Failed link train %d\n", ret); | ||
650 | goto out; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); | ||
655 | if (ret) { | ||
656 | DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); | ||
657 | goto out; | ||
658 | } | ||
659 | |||
660 | ret = cdn_dp_config_video(dp); | ||
661 | if (ret) { | ||
662 | DRM_DEV_ERROR(dp->dev, "Failed to config video %d\n", ret); | ||
663 | goto out; | ||
664 | } | ||
665 | |||
666 | ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); | ||
667 | if (ret) { | ||
668 | DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); | ||
669 | goto out; | ||
670 | } | ||
671 | out: | ||
672 | mutex_unlock(&dp->lock); | ||
673 | } | ||
674 | |||
675 | static void cdn_dp_encoder_disable(struct drm_encoder *encoder) | ||
676 | { | ||
677 | struct cdn_dp_device *dp = encoder_to_dp(encoder); | ||
678 | int ret; | ||
679 | |||
680 | mutex_lock(&dp->lock); | ||
681 | if (dp->active) { | ||
682 | ret = cdn_dp_disable(dp); | ||
683 | if (ret) { | ||
684 | DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n", | ||
685 | ret); | ||
686 | } | ||
687 | } | ||
688 | mutex_unlock(&dp->lock); | ||
689 | |||
690 | /* | ||
691 | * In the following 2 cases, we need to run the event_work to re-enable | ||
692 | * the DP: | ||
693 | * 1. If there is not just one port device is connected, and remove one | ||
694 | * device from a port, the DP will be disabled here, at this case, | ||
695 | * run the event_work to re-open DP for the other port. | ||
696 | * 2. If re-training or re-config failed, the DP will be disabled here. | ||
697 | * run the event_work to re-connect it. | ||
698 | */ | ||
699 | if (!dp->connected && cdn_dp_connected_port(dp)) | ||
700 | schedule_work(&dp->event_work); | ||
701 | } | ||
702 | |||
703 | static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, | ||
704 | struct drm_crtc_state *crtc_state, | ||
705 | struct drm_connector_state *conn_state) | ||
706 | { | ||
707 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); | ||
708 | |||
709 | s->output_mode = ROCKCHIP_OUT_MODE_AAAA; | ||
710 | s->output_type = DRM_MODE_CONNECTOR_DisplayPort; | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { | ||
716 | .mode_set = cdn_dp_encoder_mode_set, | ||
717 | .enable = cdn_dp_encoder_enable, | ||
718 | .disable = cdn_dp_encoder_disable, | ||
719 | .atomic_check = cdn_dp_encoder_atomic_check, | ||
720 | }; | ||
721 | |||
722 | static const struct drm_encoder_funcs cdn_dp_encoder_funcs = { | ||
723 | .destroy = drm_encoder_cleanup, | ||
724 | }; | ||
725 | |||
726 | static int cdn_dp_parse_dt(struct cdn_dp_device *dp) | ||
727 | { | ||
728 | struct device *dev = dp->dev; | ||
729 | struct device_node *np = dev->of_node; | ||
730 | struct platform_device *pdev = to_platform_device(dev); | ||
731 | struct resource *res; | ||
732 | |||
733 | dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | ||
734 | if (IS_ERR(dp->grf)) { | ||
735 | DRM_DEV_ERROR(dev, "cdn-dp needs rockchip,grf property\n"); | ||
736 | return PTR_ERR(dp->grf); | ||
737 | } | ||
738 | |||
739 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
740 | dp->regs = devm_ioremap_resource(dev, res); | ||
741 | if (IS_ERR(dp->regs)) { | ||
742 | DRM_DEV_ERROR(dev, "ioremap reg failed\n"); | ||
743 | return PTR_ERR(dp->regs); | ||
744 | } | ||
745 | |||
746 | dp->core_clk = devm_clk_get(dev, "core-clk"); | ||
747 | if (IS_ERR(dp->core_clk)) { | ||
748 | DRM_DEV_ERROR(dev, "cannot get core_clk_dp\n"); | ||
749 | return PTR_ERR(dp->core_clk); | ||
750 | } | ||
751 | |||
752 | dp->pclk = devm_clk_get(dev, "pclk"); | ||
753 | if (IS_ERR(dp->pclk)) { | ||
754 | DRM_DEV_ERROR(dev, "cannot get pclk\n"); | ||
755 | return PTR_ERR(dp->pclk); | ||
756 | } | ||
757 | |||
758 | dp->spdif_clk = devm_clk_get(dev, "spdif"); | ||
759 | if (IS_ERR(dp->spdif_clk)) { | ||
760 | DRM_DEV_ERROR(dev, "cannot get spdif_clk\n"); | ||
761 | return PTR_ERR(dp->spdif_clk); | ||
762 | } | ||
763 | |||
764 | dp->grf_clk = devm_clk_get(dev, "grf"); | ||
765 | if (IS_ERR(dp->grf_clk)) { | ||
766 | DRM_DEV_ERROR(dev, "cannot get grf clk\n"); | ||
767 | return PTR_ERR(dp->grf_clk); | ||
768 | } | ||
769 | |||
770 | dp->spdif_rst = devm_reset_control_get(dev, "spdif"); | ||
771 | if (IS_ERR(dp->spdif_rst)) { | ||
772 | DRM_DEV_ERROR(dev, "no spdif reset control found\n"); | ||
773 | return PTR_ERR(dp->spdif_rst); | ||
774 | } | ||
775 | |||
776 | dp->dptx_rst = devm_reset_control_get(dev, "dptx"); | ||
777 | if (IS_ERR(dp->dptx_rst)) { | ||
778 | DRM_DEV_ERROR(dev, "no uphy reset control found\n"); | ||
779 | return PTR_ERR(dp->dptx_rst); | ||
780 | } | ||
781 | |||
782 | dp->core_rst = devm_reset_control_get(dev, "core"); | ||
783 | if (IS_ERR(dp->core_rst)) { | ||
784 | DRM_DEV_ERROR(dev, "no core reset control found\n"); | ||
785 | return PTR_ERR(dp->core_rst); | ||
786 | } | ||
787 | |||
788 | dp->apb_rst = devm_reset_control_get(dev, "apb"); | ||
789 | if (IS_ERR(dp->apb_rst)) { | ||
790 | DRM_DEV_ERROR(dev, "no apb reset control found\n"); | ||
791 | return PTR_ERR(dp->apb_rst); | ||
792 | } | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static int cdn_dp_audio_hw_params(struct device *dev, void *data, | ||
798 | struct hdmi_codec_daifmt *daifmt, | ||
799 | struct hdmi_codec_params *params) | ||
800 | { | ||
801 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
802 | struct audio_info audio = { | ||
803 | .sample_width = params->sample_width, | ||
804 | .sample_rate = params->sample_rate, | ||
805 | .channels = params->channels, | ||
806 | }; | ||
807 | int ret; | ||
808 | |||
809 | mutex_lock(&dp->lock); | ||
810 | if (!dp->active) { | ||
811 | ret = -ENODEV; | ||
812 | goto out; | ||
813 | } | ||
814 | |||
815 | switch (daifmt->fmt) { | ||
816 | case HDMI_I2S: | ||
817 | audio.format = AFMT_I2S; | ||
818 | break; | ||
819 | case HDMI_SPDIF: | ||
820 | audio.format = AFMT_SPDIF; | ||
821 | break; | ||
822 | default: | ||
823 | DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); | ||
824 | ret = -EINVAL; | ||
825 | goto out; | ||
826 | } | ||
827 | |||
828 | ret = cdn_dp_audio_config(dp, &audio); | ||
829 | if (!ret) | ||
830 | dp->audio_info = audio; | ||
831 | |||
832 | out: | ||
833 | mutex_unlock(&dp->lock); | ||
834 | return ret; | ||
835 | } | ||
836 | |||
837 | static void cdn_dp_audio_shutdown(struct device *dev, void *data) | ||
838 | { | ||
839 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
840 | int ret; | ||
841 | |||
842 | mutex_lock(&dp->lock); | ||
843 | if (!dp->active) | ||
844 | goto out; | ||
845 | |||
846 | ret = cdn_dp_audio_stop(dp, &dp->audio_info); | ||
847 | if (!ret) | ||
848 | dp->audio_info.format = AFMT_UNUSED; | ||
849 | out: | ||
850 | mutex_unlock(&dp->lock); | ||
851 | } | ||
852 | |||
853 | static int cdn_dp_audio_digital_mute(struct device *dev, void *data, | ||
854 | bool enable) | ||
855 | { | ||
856 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
857 | int ret; | ||
858 | |||
859 | mutex_lock(&dp->lock); | ||
860 | if (!dp->active) { | ||
861 | ret = -ENODEV; | ||
862 | goto out; | ||
863 | } | ||
864 | |||
865 | ret = cdn_dp_audio_mute(dp, enable); | ||
866 | |||
867 | out: | ||
868 | mutex_unlock(&dp->lock); | ||
869 | return ret; | ||
870 | } | ||
871 | |||
872 | static int cdn_dp_audio_get_eld(struct device *dev, void *data, | ||
873 | u8 *buf, size_t len) | ||
874 | { | ||
875 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
876 | |||
877 | memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len)); | ||
878 | |||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | static const struct hdmi_codec_ops audio_codec_ops = { | ||
883 | .hw_params = cdn_dp_audio_hw_params, | ||
884 | .audio_shutdown = cdn_dp_audio_shutdown, | ||
885 | .digital_mute = cdn_dp_audio_digital_mute, | ||
886 | .get_eld = cdn_dp_audio_get_eld, | ||
887 | }; | ||
888 | |||
889 | static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, | ||
890 | struct device *dev) | ||
891 | { | ||
892 | struct hdmi_codec_pdata codec_data = { | ||
893 | .i2s = 1, | ||
894 | .spdif = 1, | ||
895 | .ops = &audio_codec_ops, | ||
896 | .max_i2s_channels = 8, | ||
897 | }; | ||
898 | |||
899 | dp->audio_pdev = platform_device_register_data( | ||
900 | dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, | ||
901 | &codec_data, sizeof(codec_data)); | ||
902 | |||
903 | return PTR_ERR_OR_ZERO(dp->audio_pdev); | ||
904 | } | ||
905 | |||
906 | static int cdn_dp_request_firmware(struct cdn_dp_device *dp) | ||
907 | { | ||
908 | int ret; | ||
909 | unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS); | ||
910 | unsigned long sleep = 1000; | ||
911 | |||
912 | WARN_ON(!mutex_is_locked(&dp->lock)); | ||
913 | |||
914 | if (dp->fw_loaded) | ||
915 | return 0; | ||
916 | |||
917 | /* Drop the lock before getting the firmware to avoid blocking boot */ | ||
918 | mutex_unlock(&dp->lock); | ||
919 | |||
920 | while (time_before(jiffies, timeout)) { | ||
921 | ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); | ||
922 | if (ret == -ENOENT) { | ||
923 | msleep(sleep); | ||
924 | sleep *= 2; | ||
925 | continue; | ||
926 | } else if (ret) { | ||
927 | DRM_DEV_ERROR(dp->dev, | ||
928 | "failed to request firmware: %d\n", ret); | ||
929 | goto out; | ||
930 | } | ||
931 | |||
932 | dp->fw_loaded = true; | ||
933 | ret = 0; | ||
934 | goto out; | ||
935 | } | ||
936 | |||
937 | DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n"); | ||
938 | ret = -ETIMEDOUT; | ||
939 | out: | ||
940 | mutex_lock(&dp->lock); | ||
941 | return ret; | ||
942 | } | ||
943 | |||
944 | static void cdn_dp_pd_event_work(struct work_struct *work) | ||
945 | { | ||
946 | struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, | ||
947 | event_work); | ||
948 | struct drm_connector *connector = &dp->connector; | ||
949 | enum drm_connector_status old_status; | ||
950 | |||
951 | int ret; | ||
952 | |||
953 | mutex_lock(&dp->lock); | ||
954 | |||
955 | if (dp->suspended) | ||
956 | goto out; | ||
957 | |||
958 | ret = cdn_dp_request_firmware(dp); | ||
959 | if (ret) | ||
960 | goto out; | ||
961 | |||
962 | dp->connected = true; | ||
963 | |||
964 | /* Not connected, notify userspace to disable the block */ | ||
965 | if (!cdn_dp_connected_port(dp)) { | ||
966 | DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n"); | ||
967 | dp->connected = false; | ||
968 | |||
969 | /* Connected but not enabled, enable the block */ | ||
970 | } else if (!dp->active) { | ||
971 | DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n"); | ||
972 | ret = cdn_dp_enable(dp); | ||
973 | if (ret) { | ||
974 | DRM_DEV_ERROR(dp->dev, "Enable dp failed %d\n", ret); | ||
975 | dp->connected = false; | ||
976 | } | ||
977 | |||
978 | /* Enabled and connected to a dongle without a sink, notify userspace */ | ||
979 | } else if (!cdn_dp_check_sink_connection(dp)) { | ||
980 | DRM_DEV_INFO(dp->dev, "Connected without sink. Assert hpd\n"); | ||
981 | dp->connected = false; | ||
982 | |||
983 | /* Enabled and connected with a sink, re-train if requested */ | ||
984 | } else if (!cdn_dp_check_link_status(dp)) { | ||
985 | unsigned int rate = dp->link.rate; | ||
986 | unsigned int lanes = dp->link.num_lanes; | ||
987 | struct drm_display_mode *mode = &dp->mode; | ||
988 | |||
989 | DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n"); | ||
990 | ret = cdn_dp_train_link(dp); | ||
991 | if (ret) { | ||
992 | dp->connected = false; | ||
993 | DRM_DEV_ERROR(dp->dev, "Train link failed %d\n", ret); | ||
994 | goto out; | ||
995 | } | ||
996 | |||
997 | /* If training result is changed, update the video config */ | ||
998 | if (mode->clock && | ||
999 | (rate != dp->link.rate || lanes != dp->link.num_lanes)) { | ||
1000 | ret = cdn_dp_config_video(dp); | ||
1001 | if (ret) { | ||
1002 | dp->connected = false; | ||
1003 | DRM_DEV_ERROR(dp->dev, | ||
1004 | "Failed to config video %d\n", | ||
1005 | ret); | ||
1006 | } | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | out: | ||
1011 | mutex_unlock(&dp->lock); | ||
1012 | |||
1013 | old_status = connector->status; | ||
1014 | connector->status = connector->funcs->detect(connector, false); | ||
1015 | if (old_status != connector->status) | ||
1016 | drm_kms_helper_hotplug_event(dp->drm_dev); | ||
1017 | } | ||
1018 | |||
1019 | static int cdn_dp_pd_event(struct notifier_block *nb, | ||
1020 | unsigned long event, void *priv) | ||
1021 | { | ||
1022 | struct cdn_dp_port *port = container_of(nb, struct cdn_dp_port, | ||
1023 | event_nb); | ||
1024 | struct cdn_dp_device *dp = port->dp; | ||
1025 | |||
1026 | /* | ||
1027 | * It would be nice to be able to just do the work inline right here. | ||
1028 | * However, we need to make a bunch of calls that might sleep in order | ||
1029 | * to turn on the block/phy, so use a worker instead. | ||
1030 | */ | ||
1031 | schedule_work(&dp->event_work); | ||
1032 | |||
1033 | return NOTIFY_DONE; | ||
1034 | } | ||
1035 | |||
1036 | static int cdn_dp_bind(struct device *dev, struct device *master, void *data) | ||
1037 | { | ||
1038 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
1039 | struct drm_encoder *encoder; | ||
1040 | struct drm_connector *connector; | ||
1041 | struct cdn_dp_port *port; | ||
1042 | struct drm_device *drm_dev = data; | ||
1043 | int ret, i; | ||
1044 | |||
1045 | ret = cdn_dp_parse_dt(dp); | ||
1046 | if (ret < 0) | ||
1047 | return ret; | ||
1048 | |||
1049 | dp->drm_dev = drm_dev; | ||
1050 | dp->connected = false; | ||
1051 | dp->active = false; | ||
1052 | dp->active_port = -1; | ||
1053 | |||
1054 | INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); | ||
1055 | |||
1056 | encoder = &dp->encoder; | ||
1057 | |||
1058 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, | ||
1059 | dev->of_node); | ||
1060 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
1061 | |||
1062 | ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs, | ||
1063 | DRM_MODE_ENCODER_TMDS, NULL); | ||
1064 | if (ret) { | ||
1065 | DRM_ERROR("failed to initialize encoder with drm\n"); | ||
1066 | return ret; | ||
1067 | } | ||
1068 | |||
1069 | drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); | ||
1070 | |||
1071 | connector = &dp->connector; | ||
1072 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
1073 | connector->dpms = DRM_MODE_DPMS_OFF; | ||
1074 | |||
1075 | ret = drm_connector_init(drm_dev, connector, | ||
1076 | &cdn_dp_atomic_connector_funcs, | ||
1077 | DRM_MODE_CONNECTOR_DisplayPort); | ||
1078 | if (ret) { | ||
1079 | DRM_ERROR("failed to initialize connector with drm\n"); | ||
1080 | goto err_free_encoder; | ||
1081 | } | ||
1082 | |||
1083 | drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); | ||
1084 | |||
1085 | ret = drm_mode_connector_attach_encoder(connector, encoder); | ||
1086 | if (ret) { | ||
1087 | DRM_ERROR("failed to attach connector and encoder\n"); | ||
1088 | goto err_free_connector; | ||
1089 | } | ||
1090 | |||
1091 | cdn_dp_audio_codec_init(dp, dev); | ||
1092 | |||
1093 | for (i = 0; i < dp->ports; i++) { | ||
1094 | port = dp->port[i]; | ||
1095 | |||
1096 | port->event_nb.notifier_call = cdn_dp_pd_event; | ||
1097 | ret = devm_extcon_register_notifier(dp->dev, port->extcon, | ||
1098 | EXTCON_DISP_DP, | ||
1099 | &port->event_nb); | ||
1100 | if (ret) { | ||
1101 | DRM_DEV_ERROR(dev, | ||
1102 | "register EXTCON_DISP_DP notifier err\n"); | ||
1103 | goto err_free_connector; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | pm_runtime_enable(dev); | ||
1108 | |||
1109 | schedule_work(&dp->event_work); | ||
1110 | |||
1111 | return 0; | ||
1112 | |||
1113 | err_free_connector: | ||
1114 | drm_connector_cleanup(connector); | ||
1115 | err_free_encoder: | ||
1116 | drm_encoder_cleanup(encoder); | ||
1117 | return ret; | ||
1118 | } | ||
1119 | |||
1120 | static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) | ||
1121 | { | ||
1122 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
1123 | struct drm_encoder *encoder = &dp->encoder; | ||
1124 | struct drm_connector *connector = &dp->connector; | ||
1125 | |||
1126 | cancel_work_sync(&dp->event_work); | ||
1127 | platform_device_unregister(dp->audio_pdev); | ||
1128 | cdn_dp_encoder_disable(encoder); | ||
1129 | encoder->funcs->destroy(encoder); | ||
1130 | connector->funcs->destroy(connector); | ||
1131 | |||
1132 | pm_runtime_disable(dev); | ||
1133 | release_firmware(dp->fw); | ||
1134 | kfree(dp->edid); | ||
1135 | dp->edid = NULL; | ||
1136 | } | ||
1137 | |||
1138 | static const struct component_ops cdn_dp_component_ops = { | ||
1139 | .bind = cdn_dp_bind, | ||
1140 | .unbind = cdn_dp_unbind, | ||
1141 | }; | ||
1142 | |||
1143 | int cdn_dp_suspend(struct device *dev) | ||
1144 | { | ||
1145 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
1146 | int ret = 0; | ||
1147 | |||
1148 | mutex_lock(&dp->lock); | ||
1149 | if (dp->active) | ||
1150 | ret = cdn_dp_disable(dp); | ||
1151 | dp->suspended = true; | ||
1152 | mutex_unlock(&dp->lock); | ||
1153 | |||
1154 | return ret; | ||
1155 | } | ||
1156 | |||
1157 | int cdn_dp_resume(struct device *dev) | ||
1158 | { | ||
1159 | struct cdn_dp_device *dp = dev_get_drvdata(dev); | ||
1160 | |||
1161 | mutex_lock(&dp->lock); | ||
1162 | dp->suspended = false; | ||
1163 | if (dp->fw_loaded) | ||
1164 | schedule_work(&dp->event_work); | ||
1165 | mutex_unlock(&dp->lock); | ||
1166 | |||
1167 | return 0; | ||
1168 | } | ||
1169 | |||
1170 | static int cdn_dp_probe(struct platform_device *pdev) | ||
1171 | { | ||
1172 | struct device *dev = &pdev->dev; | ||
1173 | const struct of_device_id *match; | ||
1174 | struct cdn_dp_data *dp_data; | ||
1175 | struct cdn_dp_port *port; | ||
1176 | struct cdn_dp_device *dp; | ||
1177 | struct extcon_dev *extcon; | ||
1178 | struct phy *phy; | ||
1179 | int i; | ||
1180 | |||
1181 | dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); | ||
1182 | if (!dp) | ||
1183 | return -ENOMEM; | ||
1184 | dp->dev = dev; | ||
1185 | |||
1186 | match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); | ||
1187 | dp_data = (struct cdn_dp_data *)match->data; | ||
1188 | |||
1189 | for (i = 0; i < dp_data->max_phy; i++) { | ||
1190 | extcon = extcon_get_edev_by_phandle(dev, i); | ||
1191 | phy = devm_of_phy_get_by_index(dev, dev->of_node, i); | ||
1192 | |||
1193 | if (PTR_ERR(extcon) == -EPROBE_DEFER || | ||
1194 | PTR_ERR(phy) == -EPROBE_DEFER) | ||
1195 | return -EPROBE_DEFER; | ||
1196 | |||
1197 | if (IS_ERR(extcon) || IS_ERR(phy)) | ||
1198 | continue; | ||
1199 | |||
1200 | port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); | ||
1201 | if (!dp) | ||
1202 | return -ENOMEM; | ||
1203 | |||
1204 | port->extcon = extcon; | ||
1205 | port->phy = phy; | ||
1206 | port->dp = dp; | ||
1207 | port->id = i; | ||
1208 | dp->port[dp->ports++] = port; | ||
1209 | } | ||
1210 | |||
1211 | if (!dp->ports) { | ||
1212 | DRM_DEV_ERROR(dev, "missing extcon or phy\n"); | ||
1213 | return -EINVAL; | ||
1214 | } | ||
1215 | |||
1216 | mutex_init(&dp->lock); | ||
1217 | dev_set_drvdata(dev, dp); | ||
1218 | |||
1219 | return component_add(dev, &cdn_dp_component_ops); | ||
1220 | } | ||
1221 | |||
1222 | static int cdn_dp_remove(struct platform_device *pdev) | ||
1223 | { | ||
1224 | struct cdn_dp_device *dp = platform_get_drvdata(pdev); | ||
1225 | |||
1226 | cdn_dp_suspend(dp->dev); | ||
1227 | component_del(&pdev->dev, &cdn_dp_component_ops); | ||
1228 | |||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | static void cdn_dp_shutdown(struct platform_device *pdev) | ||
1233 | { | ||
1234 | struct cdn_dp_device *dp = platform_get_drvdata(pdev); | ||
1235 | |||
1236 | cdn_dp_suspend(dp->dev); | ||
1237 | } | ||
1238 | |||
1239 | static const struct dev_pm_ops cdn_dp_pm_ops = { | ||
1240 | SET_SYSTEM_SLEEP_PM_OPS(cdn_dp_suspend, | ||
1241 | cdn_dp_resume) | ||
1242 | }; | ||
1243 | |||
1244 | static struct platform_driver cdn_dp_driver = { | ||
1245 | .probe = cdn_dp_probe, | ||
1246 | .remove = cdn_dp_remove, | ||
1247 | .shutdown = cdn_dp_shutdown, | ||
1248 | .driver = { | ||
1249 | .name = "cdn-dp", | ||
1250 | .owner = THIS_MODULE, | ||
1251 | .of_match_table = of_match_ptr(cdn_dp_dt_ids), | ||
1252 | .pm = &cdn_dp_pm_ops, | ||
1253 | }, | ||
1254 | }; | ||
1255 | |||
1256 | module_platform_driver(cdn_dp_driver); | ||
1257 | |||
1258 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); | ||
1259 | MODULE_DESCRIPTION("cdn DP Driver"); | ||
1260 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h new file mode 100644 index 000000000000..f57e296401b8 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Chris Zhong <zyw@rock-chips.com> | ||
3 | * Copyright (C) 2016 ROCKCHIP, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef _CDN_DP_CORE_H | ||
16 | #define _CDN_DP_CORE_H | ||
17 | |||
18 | #include <drm/drmP.h> | ||
19 | #include <drm/drm_crtc_helper.h> | ||
20 | #include <drm/drm_dp_helper.h> | ||
21 | #include <drm/drm_panel.h> | ||
22 | #include "rockchip_drm_drv.h" | ||
23 | |||
24 | #define MAX_PHY 2 | ||
25 | |||
26 | enum audio_format { | ||
27 | AFMT_I2S = 0, | ||
28 | AFMT_SPDIF = 1, | ||
29 | AFMT_UNUSED, | ||
30 | }; | ||
31 | |||
32 | struct audio_info { | ||
33 | enum audio_format format; | ||
34 | int sample_rate; | ||
35 | int channels; | ||
36 | int sample_width; | ||
37 | }; | ||
38 | |||
39 | enum vic_pxl_encoding_format { | ||
40 | PXL_RGB = 0x1, | ||
41 | YCBCR_4_4_4 = 0x2, | ||
42 | YCBCR_4_2_2 = 0x4, | ||
43 | YCBCR_4_2_0 = 0x8, | ||
44 | Y_ONLY = 0x10, | ||
45 | }; | ||
46 | |||
47 | struct video_info { | ||
48 | bool h_sync_polarity; | ||
49 | bool v_sync_polarity; | ||
50 | bool interlaced; | ||
51 | int color_depth; | ||
52 | enum vic_pxl_encoding_format color_fmt; | ||
53 | }; | ||
54 | |||
55 | struct cdn_firmware_header { | ||
56 | u32 size_bytes; /* size of the entire header+image(s) in bytes */ | ||
57 | u32 header_size; /* size of just the header in bytes */ | ||
58 | u32 iram_size; /* size of iram */ | ||
59 | u32 dram_size; /* size of dram */ | ||
60 | }; | ||
61 | |||
62 | struct cdn_dp_port { | ||
63 | struct cdn_dp_device *dp; | ||
64 | struct notifier_block event_nb; | ||
65 | struct extcon_dev *extcon; | ||
66 | struct phy *phy; | ||
67 | u8 lanes; | ||
68 | bool phy_enabled; | ||
69 | u8 id; | ||
70 | }; | ||
71 | |||
72 | struct cdn_dp_device { | ||
73 | struct device *dev; | ||
74 | struct drm_device *drm_dev; | ||
75 | struct drm_connector connector; | ||
76 | struct drm_encoder encoder; | ||
77 | struct drm_display_mode mode; | ||
78 | struct platform_device *audio_pdev; | ||
79 | struct work_struct event_work; | ||
80 | struct edid *edid; | ||
81 | |||
82 | struct mutex lock; | ||
83 | bool connected; | ||
84 | bool active; | ||
85 | bool suspended; | ||
86 | |||
87 | const struct firmware *fw; /* cdn dp firmware */ | ||
88 | unsigned int fw_version; /* cdn fw version */ | ||
89 | bool fw_loaded; | ||
90 | |||
91 | void __iomem *regs; | ||
92 | struct regmap *grf; | ||
93 | struct clk *core_clk; | ||
94 | struct clk *pclk; | ||
95 | struct clk *spdif_clk; | ||
96 | struct clk *grf_clk; | ||
97 | struct reset_control *spdif_rst; | ||
98 | struct reset_control *dptx_rst; | ||
99 | struct reset_control *apb_rst; | ||
100 | struct reset_control *core_rst; | ||
101 | struct audio_info audio_info; | ||
102 | struct video_info video_info; | ||
103 | struct drm_dp_link link; | ||
104 | struct cdn_dp_port *port[MAX_PHY]; | ||
105 | u8 ports; | ||
106 | u8 lanes; | ||
107 | int active_port; | ||
108 | |||
109 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; | ||
110 | bool sink_has_audio; | ||
111 | }; | ||
112 | #endif /* _CDN_DP_CORE_H */ | ||
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c new file mode 100644 index 000000000000..3a5b8a4aa1e7 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c | |||
@@ -0,0 +1,979 @@ | |||
1 | /* | ||
2 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | ||
3 | * Author: Chris Zhong <zyw@rock-chips.com> | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/iopoll.h> | ||
20 | #include <linux/reset.h> | ||
21 | |||
22 | #include "cdn-dp-core.h" | ||
23 | #include "cdn-dp-reg.h" | ||
24 | |||
25 | #define CDN_DP_SPDIF_CLK 200000000 | ||
26 | #define FW_ALIVE_TIMEOUT_US 1000000 | ||
27 | #define MAILBOX_RETRY_US 1000 | ||
28 | #define MAILBOX_TIMEOUT_US 5000000 | ||
29 | #define LINK_TRAINING_RETRY_MS 20 | ||
30 | #define LINK_TRAINING_TIMEOUT_MS 500 | ||
31 | |||
32 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk) | ||
33 | { | ||
34 | writel(clk / 1000000, dp->regs + SW_CLK_H); | ||
35 | } | ||
36 | |||
37 | void cdn_dp_clock_reset(struct cdn_dp_device *dp) | ||
38 | { | ||
39 | u32 val; | ||
40 | |||
41 | val = DPTX_FRMR_DATA_CLK_RSTN_EN | | ||
42 | DPTX_FRMR_DATA_CLK_EN | | ||
43 | DPTX_PHY_DATA_RSTN_EN | | ||
44 | DPTX_PHY_DATA_CLK_EN | | ||
45 | DPTX_PHY_CHAR_RSTN_EN | | ||
46 | DPTX_PHY_CHAR_CLK_EN | | ||
47 | SOURCE_AUX_SYS_CLK_RSTN_EN | | ||
48 | SOURCE_AUX_SYS_CLK_EN | | ||
49 | DPTX_SYS_CLK_RSTN_EN | | ||
50 | DPTX_SYS_CLK_EN | | ||
51 | CFG_DPTX_VIF_CLK_RSTN_EN | | ||
52 | CFG_DPTX_VIF_CLK_EN; | ||
53 | writel(val, dp->regs + SOURCE_DPTX_CAR); | ||
54 | |||
55 | val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; | ||
56 | writel(val, dp->regs + SOURCE_PHY_CAR); | ||
57 | |||
58 | val = SOURCE_PKT_SYS_RSTN_EN | | ||
59 | SOURCE_PKT_SYS_CLK_EN | | ||
60 | SOURCE_PKT_DATA_RSTN_EN | | ||
61 | SOURCE_PKT_DATA_CLK_EN; | ||
62 | writel(val, dp->regs + SOURCE_PKT_CAR); | ||
63 | |||
64 | val = SPDIF_CDR_CLK_RSTN_EN | | ||
65 | SPDIF_CDR_CLK_EN | | ||
66 | SOURCE_AIF_SYS_RSTN_EN | | ||
67 | SOURCE_AIF_SYS_CLK_EN | | ||
68 | SOURCE_AIF_CLK_RSTN_EN | | ||
69 | SOURCE_AIF_CLK_EN; | ||
70 | writel(val, dp->regs + SOURCE_AIF_CAR); | ||
71 | |||
72 | val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | | ||
73 | SOURCE_CIPHER_SYS_CLK_EN | | ||
74 | SOURCE_CIPHER_CHAR_CLK_RSTN_EN | | ||
75 | SOURCE_CIPHER_CHAR_CLK_EN; | ||
76 | writel(val, dp->regs + SOURCE_CIPHER_CAR); | ||
77 | |||
78 | val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | | ||
79 | SOURCE_CRYPTO_SYS_CLK_EN; | ||
80 | writel(val, dp->regs + SOURCE_CRYPTO_CAR); | ||
81 | |||
82 | /* enable Mailbox and PIF interrupt */ | ||
83 | writel(0, dp->regs + APB_INT_MASK); | ||
84 | } | ||
85 | |||
86 | static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) | ||
87 | { | ||
88 | int val, ret; | ||
89 | |||
90 | ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR, | ||
91 | val, !val, MAILBOX_RETRY_US, | ||
92 | MAILBOX_TIMEOUT_US); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff; | ||
97 | } | ||
98 | |||
99 | static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val) | ||
100 | { | ||
101 | int ret, full; | ||
102 | |||
103 | ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR, | ||
104 | full, !full, MAILBOX_RETRY_US, | ||
105 | MAILBOX_TIMEOUT_US); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | |||
109 | writel(val, dp->regs + MAILBOX0_WR_DATA); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, | ||
115 | u8 module_id, u8 opcode, | ||
116 | u8 req_size) | ||
117 | { | ||
118 | u32 mbox_size, i; | ||
119 | u8 header[4]; | ||
120 | int ret; | ||
121 | |||
122 | /* read the header of the message */ | ||
123 | for (i = 0; i < 4; i++) { | ||
124 | ret = cdn_dp_mailbox_read(dp); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | header[i] = ret; | ||
129 | } | ||
130 | |||
131 | mbox_size = (header[2] << 8) | header[3]; | ||
132 | |||
133 | if (opcode != header[0] || module_id != header[1] || | ||
134 | req_size != mbox_size) { | ||
135 | /* | ||
136 | * If the message in mailbox is not what we want, we need to | ||
137 | * clear the mailbox by reading its contents. | ||
138 | */ | ||
139 | for (i = 0; i < mbox_size; i++) | ||
140 | if (cdn_dp_mailbox_read(dp) < 0) | ||
141 | break; | ||
142 | |||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, | ||
150 | u8 *buff, u8 buff_size) | ||
151 | { | ||
152 | u32 i; | ||
153 | int ret; | ||
154 | |||
155 | for (i = 0; i < buff_size; i++) { | ||
156 | ret = cdn_dp_mailbox_read(dp); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | buff[i] = ret; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, | ||
167 | u8 opcode, u16 size, u8 *message) | ||
168 | { | ||
169 | u8 header[4]; | ||
170 | int ret, i; | ||
171 | |||
172 | header[0] = opcode; | ||
173 | header[1] = module_id; | ||
174 | header[2] = (size >> 8) & 0xff; | ||
175 | header[3] = size & 0xff; | ||
176 | |||
177 | for (i = 0; i < 4; i++) { | ||
178 | ret = cdp_dp_mailbox_write(dp, header[i]); | ||
179 | if (ret) | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | for (i = 0; i < size; i++) { | ||
184 | ret = cdp_dp_mailbox_write(dp, message[i]); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) | ||
193 | { | ||
194 | u8 msg[6]; | ||
195 | |||
196 | msg[0] = (addr >> 8) & 0xff; | ||
197 | msg[1] = addr & 0xff; | ||
198 | msg[2] = (val >> 24) & 0xff; | ||
199 | msg[3] = (val >> 16) & 0xff; | ||
200 | msg[4] = (val >> 8) & 0xff; | ||
201 | msg[5] = val & 0xff; | ||
202 | return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER, | ||
203 | sizeof(msg), msg); | ||
204 | } | ||
205 | |||
206 | static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, | ||
207 | u8 start_bit, u8 bits_no, u32 val) | ||
208 | { | ||
209 | u8 field[8]; | ||
210 | |||
211 | field[0] = (addr >> 8) & 0xff; | ||
212 | field[1] = addr & 0xff; | ||
213 | field[2] = start_bit; | ||
214 | field[3] = bits_no; | ||
215 | field[4] = (val >> 24) & 0xff; | ||
216 | field[5] = (val >> 16) & 0xff; | ||
217 | field[6] = (val >> 8) & 0xff; | ||
218 | field[7] = val & 0xff; | ||
219 | |||
220 | return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD, | ||
221 | sizeof(field), field); | ||
222 | } | ||
223 | |||
224 | int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) | ||
225 | { | ||
226 | u8 msg[5], reg[5]; | ||
227 | int ret; | ||
228 | |||
229 | msg[0] = (len >> 8) & 0xff; | ||
230 | msg[1] = len & 0xff; | ||
231 | msg[2] = (addr >> 16) & 0xff; | ||
232 | msg[3] = (addr >> 8) & 0xff; | ||
233 | msg[4] = addr & 0xff; | ||
234 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD, | ||
235 | sizeof(msg), msg); | ||
236 | if (ret) | ||
237 | goto err_dpcd_read; | ||
238 | |||
239 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
240 | DPTX_READ_DPCD, | ||
241 | sizeof(reg) + len); | ||
242 | if (ret) | ||
243 | goto err_dpcd_read; | ||
244 | |||
245 | ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); | ||
246 | if (ret) | ||
247 | goto err_dpcd_read; | ||
248 | |||
249 | ret = cdn_dp_mailbox_read_receive(dp, data, len); | ||
250 | |||
251 | err_dpcd_read: | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) | ||
256 | { | ||
257 | u8 msg[6], reg[5]; | ||
258 | int ret; | ||
259 | |||
260 | msg[0] = 0; | ||
261 | msg[1] = 1; | ||
262 | msg[2] = (addr >> 16) & 0xff; | ||
263 | msg[3] = (addr >> 8) & 0xff; | ||
264 | msg[4] = addr & 0xff; | ||
265 | msg[5] = value; | ||
266 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, | ||
267 | sizeof(msg), msg); | ||
268 | if (ret) | ||
269 | goto err_dpcd_write; | ||
270 | |||
271 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
272 | DPTX_WRITE_DPCD, sizeof(reg)); | ||
273 | if (ret) | ||
274 | goto err_dpcd_write; | ||
275 | |||
276 | ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); | ||
277 | if (ret) | ||
278 | goto err_dpcd_write; | ||
279 | |||
280 | if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) | ||
281 | ret = -EINVAL; | ||
282 | |||
283 | err_dpcd_write: | ||
284 | if (ret) | ||
285 | DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, | ||
290 | u32 i_size, const u32 *d_mem, u32 d_size) | ||
291 | { | ||
292 | u32 reg; | ||
293 | int i, ret; | ||
294 | |||
295 | /* reset ucpu before load firmware*/ | ||
296 | writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, | ||
297 | dp->regs + APB_CTRL); | ||
298 | |||
299 | for (i = 0; i < i_size; i += 4) | ||
300 | writel(*i_mem++, dp->regs + ADDR_IMEM + i); | ||
301 | |||
302 | for (i = 0; i < d_size; i += 4) | ||
303 | writel(*d_mem++, dp->regs + ADDR_DMEM + i); | ||
304 | |||
305 | /* un-reset ucpu */ | ||
306 | writel(0, dp->regs + APB_CTRL); | ||
307 | |||
308 | /* check the keep alive register to make sure fw working */ | ||
309 | ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE, | ||
310 | reg, reg, 2000, FW_ALIVE_TIMEOUT_US); | ||
311 | if (ret < 0) { | ||
312 | DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n", | ||
313 | reg); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | reg = readl(dp->regs + VER_L) & 0xff; | ||
318 | dp->fw_version = reg; | ||
319 | reg = readl(dp->regs + VER_H) & 0xff; | ||
320 | dp->fw_version |= reg << 8; | ||
321 | reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff; | ||
322 | dp->fw_version |= reg << 16; | ||
323 | reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; | ||
324 | dp->fw_version |= reg << 24; | ||
325 | |||
326 | dev_dbg(dp->dev, "firmware version: %x\n", dp->fw_version); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable) | ||
332 | { | ||
333 | u8 msg[5]; | ||
334 | int ret, i; | ||
335 | |||
336 | msg[0] = GENERAL_MAIN_CONTROL; | ||
337 | msg[1] = MB_MODULE_ID_GENERAL; | ||
338 | msg[2] = 0; | ||
339 | msg[3] = 1; | ||
340 | msg[4] = enable ? FW_ACTIVE : FW_STANDBY; | ||
341 | |||
342 | for (i = 0; i < sizeof(msg); i++) { | ||
343 | ret = cdp_dp_mailbox_write(dp, msg[i]); | ||
344 | if (ret) | ||
345 | goto err_set_firmware_active; | ||
346 | } | ||
347 | |||
348 | /* read the firmware state */ | ||
349 | for (i = 0; i < sizeof(msg); i++) { | ||
350 | ret = cdn_dp_mailbox_read(dp); | ||
351 | if (ret < 0) | ||
352 | goto err_set_firmware_active; | ||
353 | |||
354 | msg[i] = ret; | ||
355 | } | ||
356 | |||
357 | ret = 0; | ||
358 | |||
359 | err_set_firmware_active: | ||
360 | if (ret < 0) | ||
361 | DRM_DEV_ERROR(dp->dev, "set firmware active failed\n"); | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip) | ||
366 | { | ||
367 | u8 msg[8]; | ||
368 | int ret; | ||
369 | |||
370 | msg[0] = CDN_DP_MAX_LINK_RATE; | ||
371 | msg[1] = lanes | SCRAMBLER_EN; | ||
372 | msg[2] = VOLTAGE_LEVEL_2; | ||
373 | msg[3] = PRE_EMPHASIS_LEVEL_3; | ||
374 | msg[4] = PTS1 | PTS2 | PTS3 | PTS4; | ||
375 | msg[5] = FAST_LT_NOT_SUPPORT; | ||
376 | msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; | ||
377 | msg[7] = ENHANCED; | ||
378 | |||
379 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, | ||
380 | DPTX_SET_HOST_CAPABILITIES, | ||
381 | sizeof(msg), msg); | ||
382 | if (ret) | ||
383 | goto err_set_host_cap; | ||
384 | |||
385 | ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, | ||
386 | AUX_HOST_INVERT); | ||
387 | |||
388 | err_set_host_cap: | ||
389 | if (ret) | ||
390 | DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | int cdn_dp_event_config(struct cdn_dp_device *dp) | ||
395 | { | ||
396 | u8 msg[5]; | ||
397 | int ret; | ||
398 | |||
399 | memset(msg, 0, sizeof(msg)); | ||
400 | |||
401 | msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; | ||
402 | |||
403 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, | ||
404 | sizeof(msg), msg); | ||
405 | if (ret) | ||
406 | DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret); | ||
407 | |||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | u32 cdn_dp_get_event(struct cdn_dp_device *dp) | ||
412 | { | ||
413 | return readl(dp->regs + SW_EVENTS0); | ||
414 | } | ||
415 | |||
416 | int cdn_dp_get_hpd_status(struct cdn_dp_device *dp) | ||
417 | { | ||
418 | u8 status; | ||
419 | int ret; | ||
420 | |||
421 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE, | ||
422 | 0, NULL); | ||
423 | if (ret) | ||
424 | goto err_get_hpd; | ||
425 | |||
426 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
427 | DPTX_HPD_STATE, sizeof(status)); | ||
428 | if (ret) | ||
429 | goto err_get_hpd; | ||
430 | |||
431 | ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); | ||
432 | if (ret) | ||
433 | goto err_get_hpd; | ||
434 | |||
435 | return status; | ||
436 | |||
437 | err_get_hpd: | ||
438 | DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret); | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | int cdn_dp_get_edid_block(void *data, u8 *edid, | ||
443 | unsigned int block, size_t length) | ||
444 | { | ||
445 | struct cdn_dp_device *dp = data; | ||
446 | u8 msg[2], reg[2], i; | ||
447 | int ret; | ||
448 | |||
449 | for (i = 0; i < 4; i++) { | ||
450 | msg[0] = block / 2; | ||
451 | msg[1] = block % 2; | ||
452 | |||
453 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID, | ||
454 | sizeof(msg), msg); | ||
455 | if (ret) | ||
456 | continue; | ||
457 | |||
458 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
459 | DPTX_GET_EDID, | ||
460 | sizeof(reg) + length); | ||
461 | if (ret) | ||
462 | continue; | ||
463 | |||
464 | ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); | ||
465 | if (ret) | ||
466 | continue; | ||
467 | |||
468 | ret = cdn_dp_mailbox_read_receive(dp, edid, length); | ||
469 | if (ret) | ||
470 | continue; | ||
471 | |||
472 | if (reg[0] == length && reg[1] == block / 2) | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | if (ret) | ||
477 | DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block, | ||
478 | ret); | ||
479 | |||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | static int cdn_dp_training_start(struct cdn_dp_device *dp) | ||
484 | { | ||
485 | unsigned long timeout; | ||
486 | u8 msg, event[2]; | ||
487 | int ret; | ||
488 | |||
489 | msg = LINK_TRAINING_RUN; | ||
490 | |||
491 | /* start training */ | ||
492 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL, | ||
493 | sizeof(msg), &msg); | ||
494 | if (ret) | ||
495 | goto err_training_start; | ||
496 | |||
497 | timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); | ||
498 | while (time_before(jiffies, timeout)) { | ||
499 | msleep(LINK_TRAINING_RETRY_MS); | ||
500 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, | ||
501 | DPTX_READ_EVENT, 0, NULL); | ||
502 | if (ret) | ||
503 | goto err_training_start; | ||
504 | |||
505 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
506 | DPTX_READ_EVENT, | ||
507 | sizeof(event)); | ||
508 | if (ret) | ||
509 | goto err_training_start; | ||
510 | |||
511 | ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event)); | ||
512 | if (ret) | ||
513 | goto err_training_start; | ||
514 | |||
515 | if (event[1] & EQ_PHASE_FINISHED) | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | ret = -ETIMEDOUT; | ||
520 | |||
521 | err_training_start: | ||
522 | DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret); | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | static int cdn_dp_get_training_status(struct cdn_dp_device *dp) | ||
527 | { | ||
528 | u8 status[10]; | ||
529 | int ret; | ||
530 | |||
531 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, | ||
532 | 0, NULL); | ||
533 | if (ret) | ||
534 | goto err_get_training_status; | ||
535 | |||
536 | ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, | ||
537 | DPTX_READ_LINK_STAT, | ||
538 | sizeof(status)); | ||
539 | if (ret) | ||
540 | goto err_get_training_status; | ||
541 | |||
542 | ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status)); | ||
543 | if (ret) | ||
544 | goto err_get_training_status; | ||
545 | |||
546 | dp->link.rate = status[0]; | ||
547 | dp->link.num_lanes = status[1]; | ||
548 | |||
549 | err_get_training_status: | ||
550 | if (ret) | ||
551 | DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret); | ||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | int cdn_dp_train_link(struct cdn_dp_device *dp) | ||
556 | { | ||
557 | int ret; | ||
558 | |||
559 | ret = cdn_dp_training_start(dp); | ||
560 | if (ret) { | ||
561 | DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | ret = cdn_dp_get_training_status(dp); | ||
566 | if (ret) { | ||
567 | DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret); | ||
568 | return ret; | ||
569 | } | ||
570 | |||
571 | DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, | ||
572 | dp->link.num_lanes); | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) | ||
577 | { | ||
578 | u8 msg; | ||
579 | int ret; | ||
580 | |||
581 | msg = !!active; | ||
582 | |||
583 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, | ||
584 | sizeof(msg), &msg); | ||
585 | if (ret) | ||
586 | DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret); | ||
587 | |||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | static int cdn_dp_get_msa_misc(struct video_info *video, | ||
592 | struct drm_display_mode *mode) | ||
593 | { | ||
594 | u32 msa_misc; | ||
595 | u8 val[2]; | ||
596 | |||
597 | switch (video->color_fmt) { | ||
598 | case PXL_RGB: | ||
599 | case Y_ONLY: | ||
600 | val[0] = 0; | ||
601 | break; | ||
602 | /* set YUV default color space conversion to BT601 */ | ||
603 | case YCBCR_4_4_4: | ||
604 | val[0] = 6 + BT_601 * 8; | ||
605 | break; | ||
606 | case YCBCR_4_2_2: | ||
607 | val[0] = 5 + BT_601 * 8; | ||
608 | break; | ||
609 | case YCBCR_4_2_0: | ||
610 | val[0] = 5; | ||
611 | break; | ||
612 | }; | ||
613 | |||
614 | switch (video->color_depth) { | ||
615 | case 6: | ||
616 | val[1] = 0; | ||
617 | break; | ||
618 | case 8: | ||
619 | val[1] = 1; | ||
620 | break; | ||
621 | case 10: | ||
622 | val[1] = 2; | ||
623 | break; | ||
624 | case 12: | ||
625 | val[1] = 3; | ||
626 | break; | ||
627 | case 16: | ||
628 | val[1] = 4; | ||
629 | break; | ||
630 | }; | ||
631 | |||
632 | msa_misc = 2 * val[0] + 32 * val[1] + | ||
633 | ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); | ||
634 | |||
635 | return msa_misc; | ||
636 | } | ||
637 | |||
638 | int cdn_dp_config_video(struct cdn_dp_device *dp) | ||
639 | { | ||
640 | struct video_info *video = &dp->video_info; | ||
641 | struct drm_display_mode *mode = &dp->mode; | ||
642 | u64 symbol; | ||
643 | u32 val, link_rate, rem; | ||
644 | u8 bit_per_pix, tu_size_reg = TU_SIZE; | ||
645 | int ret; | ||
646 | |||
647 | bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? | ||
648 | (video->color_depth * 2) : (video->color_depth * 3); | ||
649 | |||
650 | link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000; | ||
651 | |||
652 | ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); | ||
653 | if (ret) | ||
654 | goto err_config_video; | ||
655 | |||
656 | ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0); | ||
657 | if (ret) | ||
658 | goto err_config_video; | ||
659 | |||
660 | /* | ||
661 | * get a best tu_size and valid symbol: | ||
662 | * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 | ||
663 | * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) | ||
664 | * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set | ||
665 | * TU += 2 and repeat 2nd step. | ||
666 | */ | ||
667 | do { | ||
668 | tu_size_reg += 2; | ||
669 | symbol = tu_size_reg * mode->clock * bit_per_pix; | ||
670 | do_div(symbol, dp->link.num_lanes * link_rate * 8); | ||
671 | rem = do_div(symbol, 1000); | ||
672 | if (tu_size_reg > 64) { | ||
673 | ret = -EINVAL; | ||
674 | goto err_config_video; | ||
675 | } | ||
676 | } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || | ||
677 | (rem > 850) || (rem < 100)); | ||
678 | |||
679 | val = symbol + (tu_size_reg << 8); | ||
680 | val |= TU_CNT_RST_EN; | ||
681 | ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val); | ||
682 | if (ret) | ||
683 | goto err_config_video; | ||
684 | |||
685 | /* set the FIFO Buffer size */ | ||
686 | val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; | ||
687 | val /= (dp->link.num_lanes * link_rate); | ||
688 | val = div_u64(8 * (symbol + 1), bit_per_pix) - val; | ||
689 | val += 2; | ||
690 | ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); | ||
691 | |||
692 | switch (video->color_depth) { | ||
693 | case 6: | ||
694 | val = BCS_6; | ||
695 | break; | ||
696 | case 8: | ||
697 | val = BCS_8; | ||
698 | break; | ||
699 | case 10: | ||
700 | val = BCS_10; | ||
701 | break; | ||
702 | case 12: | ||
703 | val = BCS_12; | ||
704 | break; | ||
705 | case 16: | ||
706 | val = BCS_16; | ||
707 | break; | ||
708 | }; | ||
709 | |||
710 | val += video->color_fmt << 8; | ||
711 | ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); | ||
712 | if (ret) | ||
713 | goto err_config_video; | ||
714 | |||
715 | val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; | ||
716 | val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; | ||
717 | ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val); | ||
718 | if (ret) | ||
719 | goto err_config_video; | ||
720 | |||
721 | val = (mode->hsync_start - mode->hdisplay) << 16; | ||
722 | val |= mode->htotal - mode->hsync_end; | ||
723 | ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val); | ||
724 | if (ret) | ||
725 | goto err_config_video; | ||
726 | |||
727 | val = mode->hdisplay * bit_per_pix / 8; | ||
728 | ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val); | ||
729 | if (ret) | ||
730 | goto err_config_video; | ||
731 | |||
732 | val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); | ||
733 | ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val); | ||
734 | if (ret) | ||
735 | goto err_config_video; | ||
736 | |||
737 | val = mode->hsync_end - mode->hsync_start; | ||
738 | val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); | ||
739 | ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val); | ||
740 | if (ret) | ||
741 | goto err_config_video; | ||
742 | |||
743 | val = mode->vtotal; | ||
744 | val |= (mode->vtotal - mode->vsync_start) << 16; | ||
745 | ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val); | ||
746 | if (ret) | ||
747 | goto err_config_video; | ||
748 | |||
749 | val = mode->vsync_end - mode->vsync_start; | ||
750 | val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); | ||
751 | ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val); | ||
752 | if (ret) | ||
753 | goto err_config_video; | ||
754 | |||
755 | val = cdn_dp_get_msa_misc(video, mode); | ||
756 | ret = cdn_dp_reg_write(dp, MSA_MISC, val); | ||
757 | if (ret) | ||
758 | goto err_config_video; | ||
759 | |||
760 | ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1); | ||
761 | if (ret) | ||
762 | goto err_config_video; | ||
763 | |||
764 | val = mode->hsync_end - mode->hsync_start; | ||
765 | val |= mode->hdisplay << 16; | ||
766 | ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val); | ||
767 | if (ret) | ||
768 | goto err_config_video; | ||
769 | |||
770 | val = mode->vdisplay; | ||
771 | val |= (mode->vtotal - mode->vsync_start) << 16; | ||
772 | ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val); | ||
773 | if (ret) | ||
774 | goto err_config_video; | ||
775 | |||
776 | val = mode->vtotal; | ||
777 | ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val); | ||
778 | if (ret) | ||
779 | goto err_config_video; | ||
780 | |||
781 | ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, 0); | ||
782 | |||
783 | err_config_video: | ||
784 | if (ret) | ||
785 | DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret); | ||
786 | return ret; | ||
787 | } | ||
788 | |||
789 | int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) | ||
790 | { | ||
791 | u32 val; | ||
792 | int ret; | ||
793 | |||
794 | ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); | ||
795 | if (ret) { | ||
796 | DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret); | ||
797 | return ret; | ||
798 | } | ||
799 | |||
800 | val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; | ||
801 | val |= SPDIF_FIFO_MID_RANGE(0xe0); | ||
802 | val |= SPDIF_JITTER_THRSH(0xe0); | ||
803 | val |= SPDIF_JITTER_AVG_WIN(7); | ||
804 | writel(val, dp->regs + SPDIF_CTRL_ADDR); | ||
805 | |||
806 | /* clearn the audio config and reset */ | ||
807 | writel(0, dp->regs + AUDIO_SRC_CNTL); | ||
808 | writel(0, dp->regs + AUDIO_SRC_CNFG); | ||
809 | writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL); | ||
810 | writel(0, dp->regs + AUDIO_SRC_CNTL); | ||
811 | |||
812 | /* reset smpl2pckt component */ | ||
813 | writel(0, dp->regs + SMPL2PKT_CNTL); | ||
814 | writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL); | ||
815 | writel(0, dp->regs + SMPL2PKT_CNTL); | ||
816 | |||
817 | /* reset FIFO */ | ||
818 | writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL); | ||
819 | writel(0, dp->regs + FIFO_CNTL); | ||
820 | |||
821 | if (audio->format == AFMT_SPDIF) | ||
822 | clk_disable_unprepare(dp->spdif_clk); | ||
823 | |||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable) | ||
828 | { | ||
829 | int ret; | ||
830 | |||
831 | ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable); | ||
832 | if (ret) | ||
833 | DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret); | ||
834 | |||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, | ||
839 | struct audio_info *audio) | ||
840 | { | ||
841 | int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; | ||
842 | u32 val; | ||
843 | |||
844 | if (audio->channels == 2) { | ||
845 | if (dp->link.num_lanes == 1) | ||
846 | sub_pckt_num = 2; | ||
847 | else | ||
848 | sub_pckt_num = 4; | ||
849 | |||
850 | i2s_port_en_val = 1; | ||
851 | } else if (audio->channels == 4) { | ||
852 | i2s_port_en_val = 3; | ||
853 | } | ||
854 | |||
855 | writel(0x0, dp->regs + SPDIF_CTRL_ADDR); | ||
856 | |||
857 | writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); | ||
858 | |||
859 | val = MAX_NUM_CH(audio->channels); | ||
860 | val |= NUM_OF_I2S_PORTS(audio->channels); | ||
861 | val |= AUDIO_TYPE_LPCM; | ||
862 | val |= CFG_SUB_PCKT_NUM(sub_pckt_num); | ||
863 | writel(val, dp->regs + SMPL2PKT_CNFG); | ||
864 | |||
865 | if (audio->sample_width == 16) | ||
866 | val = 0; | ||
867 | else if (audio->sample_width == 24) | ||
868 | val = 1 << 9; | ||
869 | else | ||
870 | val = 2 << 9; | ||
871 | |||
872 | val |= AUDIO_CH_NUM(audio->channels); | ||
873 | val |= I2S_DEC_PORT_EN(i2s_port_en_val); | ||
874 | val |= TRANS_SMPL_WIDTH_32; | ||
875 | writel(val, dp->regs + AUDIO_SRC_CNFG); | ||
876 | |||
877 | for (i = 0; i < (audio->channels + 1) / 2; i++) { | ||
878 | if (audio->sample_width == 16) | ||
879 | val = (0x02 << 8) | (0x02 << 20); | ||
880 | else if (audio->sample_width == 24) | ||
881 | val = (0x0b << 8) | (0x0b << 20); | ||
882 | |||
883 | val |= ((2 * i) << 4) | ((2 * i + 1) << 16); | ||
884 | writel(val, dp->regs + STTS_BIT_CH(i)); | ||
885 | } | ||
886 | |||
887 | switch (audio->sample_rate) { | ||
888 | case 32000: | ||
889 | val = SAMPLING_FREQ(3) | | ||
890 | ORIGINAL_SAMP_FREQ(0xc); | ||
891 | break; | ||
892 | case 44100: | ||
893 | val = SAMPLING_FREQ(0) | | ||
894 | ORIGINAL_SAMP_FREQ(0xf); | ||
895 | break; | ||
896 | case 48000: | ||
897 | val = SAMPLING_FREQ(2) | | ||
898 | ORIGINAL_SAMP_FREQ(0xd); | ||
899 | break; | ||
900 | case 88200: | ||
901 | val = SAMPLING_FREQ(8) | | ||
902 | ORIGINAL_SAMP_FREQ(0x7); | ||
903 | break; | ||
904 | case 96000: | ||
905 | val = SAMPLING_FREQ(0xa) | | ||
906 | ORIGINAL_SAMP_FREQ(5); | ||
907 | break; | ||
908 | case 176400: | ||
909 | val = SAMPLING_FREQ(0xc) | | ||
910 | ORIGINAL_SAMP_FREQ(3); | ||
911 | break; | ||
912 | case 192000: | ||
913 | val = SAMPLING_FREQ(0xe) | | ||
914 | ORIGINAL_SAMP_FREQ(1); | ||
915 | break; | ||
916 | } | ||
917 | val |= 4; | ||
918 | writel(val, dp->regs + COM_CH_STTS_BITS); | ||
919 | |||
920 | writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); | ||
921 | writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); | ||
922 | } | ||
923 | |||
924 | static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) | ||
925 | { | ||
926 | u32 val; | ||
927 | |||
928 | val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; | ||
929 | val |= SPDIF_FIFO_MID_RANGE(0xe0); | ||
930 | val |= SPDIF_JITTER_THRSH(0xe0); | ||
931 | val |= SPDIF_JITTER_AVG_WIN(7); | ||
932 | writel(val, dp->regs + SPDIF_CTRL_ADDR); | ||
933 | |||
934 | writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); | ||
935 | |||
936 | val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); | ||
937 | writel(val, dp->regs + SMPL2PKT_CNFG); | ||
938 | writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); | ||
939 | |||
940 | val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; | ||
941 | val |= SPDIF_FIFO_MID_RANGE(0xe0); | ||
942 | val |= SPDIF_JITTER_THRSH(0xe0); | ||
943 | val |= SPDIF_JITTER_AVG_WIN(7); | ||
944 | writel(val, dp->regs + SPDIF_CTRL_ADDR); | ||
945 | |||
946 | clk_prepare_enable(dp->spdif_clk); | ||
947 | clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); | ||
948 | } | ||
949 | |||
950 | int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) | ||
951 | { | ||
952 | int ret; | ||
953 | |||
954 | /* reset the spdif clk before config */ | ||
955 | if (audio->format == AFMT_SPDIF) { | ||
956 | reset_control_assert(dp->spdif_rst); | ||
957 | reset_control_deassert(dp->spdif_rst); | ||
958 | } | ||
959 | |||
960 | ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC); | ||
961 | if (ret) | ||
962 | goto err_audio_config; | ||
963 | |||
964 | ret = cdn_dp_reg_write(dp, CM_CTRL, 0); | ||
965 | if (ret) | ||
966 | goto err_audio_config; | ||
967 | |||
968 | if (audio->format == AFMT_I2S) | ||
969 | cdn_dp_audio_config_i2s(dp, audio); | ||
970 | else if (audio->format == AFMT_SPDIF) | ||
971 | cdn_dp_audio_config_spdif(dp); | ||
972 | |||
973 | ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); | ||
974 | |||
975 | err_audio_config: | ||
976 | if (ret) | ||
977 | DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret); | ||
978 | return ret; | ||
979 | } | ||
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h new file mode 100644 index 000000000000..b5f215324694 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h | |||
@@ -0,0 +1,483 @@ | |||
1 | /* | ||
2 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | ||
3 | * Author: Chris Zhong <zyw@rock-chips.com> | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef _CDN_DP_REG_H | ||
16 | #define _CDN_DP_REG_H | ||
17 | |||
18 | #include <linux/bitops.h> | ||
19 | |||
20 | #define ADDR_IMEM 0x10000 | ||
21 | #define ADDR_DMEM 0x20000 | ||
22 | |||
23 | /* APB CFG addr */ | ||
24 | #define APB_CTRL 0 | ||
25 | #define XT_INT_CTRL 0x04 | ||
26 | #define MAILBOX_FULL_ADDR 0x08 | ||
27 | #define MAILBOX_EMPTY_ADDR 0x0c | ||
28 | #define MAILBOX0_WR_DATA 0x10 | ||
29 | #define MAILBOX0_RD_DATA 0x14 | ||
30 | #define KEEP_ALIVE 0x18 | ||
31 | #define VER_L 0x1c | ||
32 | #define VER_H 0x20 | ||
33 | #define VER_LIB_L_ADDR 0x24 | ||
34 | #define VER_LIB_H_ADDR 0x28 | ||
35 | #define SW_DEBUG_L 0x2c | ||
36 | #define SW_DEBUG_H 0x30 | ||
37 | #define MAILBOX_INT_MASK 0x34 | ||
38 | #define MAILBOX_INT_STATUS 0x38 | ||
39 | #define SW_CLK_L 0x3c | ||
40 | #define SW_CLK_H 0x40 | ||
41 | #define SW_EVENTS0 0x44 | ||
42 | #define SW_EVENTS1 0x48 | ||
43 | #define SW_EVENTS2 0x4c | ||
44 | #define SW_EVENTS3 0x50 | ||
45 | #define XT_OCD_CTRL 0x60 | ||
46 | #define APB_INT_MASK 0x6c | ||
47 | #define APB_STATUS_MASK 0x70 | ||
48 | |||
49 | /* audio decoder addr */ | ||
50 | #define AUDIO_SRC_CNTL 0x30000 | ||
51 | #define AUDIO_SRC_CNFG 0x30004 | ||
52 | #define COM_CH_STTS_BITS 0x30008 | ||
53 | #define STTS_BIT_CH(x) (0x3000c + ((x) << 2)) | ||
54 | #define SPDIF_CTRL_ADDR 0x3004c | ||
55 | #define SPDIF_CH1_CS_3100_ADDR 0x30050 | ||
56 | #define SPDIF_CH1_CS_6332_ADDR 0x30054 | ||
57 | #define SPDIF_CH1_CS_9564_ADDR 0x30058 | ||
58 | #define SPDIF_CH1_CS_12796_ADDR 0x3005c | ||
59 | #define SPDIF_CH1_CS_159128_ADDR 0x30060 | ||
60 | #define SPDIF_CH1_CS_191160_ADDR 0x30064 | ||
61 | #define SPDIF_CH2_CS_3100_ADDR 0x30068 | ||
62 | #define SPDIF_CH2_CS_6332_ADDR 0x3006c | ||
63 | #define SPDIF_CH2_CS_9564_ADDR 0x30070 | ||
64 | #define SPDIF_CH2_CS_12796_ADDR 0x30074 | ||
65 | #define SPDIF_CH2_CS_159128_ADDR 0x30078 | ||
66 | #define SPDIF_CH2_CS_191160_ADDR 0x3007c | ||
67 | #define SMPL2PKT_CNTL 0x30080 | ||
68 | #define SMPL2PKT_CNFG 0x30084 | ||
69 | #define FIFO_CNTL 0x30088 | ||
70 | #define FIFO_STTS 0x3008c | ||
71 | |||
72 | /* source pif addr */ | ||
73 | #define SOURCE_PIF_WR_ADDR 0x30800 | ||
74 | #define SOURCE_PIF_WR_REQ 0x30804 | ||
75 | #define SOURCE_PIF_RD_ADDR 0x30808 | ||
76 | #define SOURCE_PIF_RD_REQ 0x3080c | ||
77 | #define SOURCE_PIF_DATA_WR 0x30810 | ||
78 | #define SOURCE_PIF_DATA_RD 0x30814 | ||
79 | #define SOURCE_PIF_FIFO1_FLUSH 0x30818 | ||
80 | #define SOURCE_PIF_FIFO2_FLUSH 0x3081c | ||
81 | #define SOURCE_PIF_STATUS 0x30820 | ||
82 | #define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 | ||
83 | #define SOURCE_PIF_INTERRUPT_MASK 0x30828 | ||
84 | #define SOURCE_PIF_PKT_ALLOC_REG 0x3082c | ||
85 | #define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 | ||
86 | #define SOURCE_PIF_SW_RESET 0x30834 | ||
87 | |||
88 | /* bellow registers need access by mailbox */ | ||
89 | /* source car addr */ | ||
90 | #define SOURCE_HDTX_CAR 0x0900 | ||
91 | #define SOURCE_DPTX_CAR 0x0904 | ||
92 | #define SOURCE_PHY_CAR 0x0908 | ||
93 | #define SOURCE_CEC_CAR 0x090c | ||
94 | #define SOURCE_CBUS_CAR 0x0910 | ||
95 | #define SOURCE_PKT_CAR 0x0918 | ||
96 | #define SOURCE_AIF_CAR 0x091c | ||
97 | #define SOURCE_CIPHER_CAR 0x0920 | ||
98 | #define SOURCE_CRYPTO_CAR 0x0924 | ||
99 | |||
100 | /* clock meters addr */ | ||
101 | #define CM_CTRL 0x0a00 | ||
102 | #define CM_I2S_CTRL 0x0a04 | ||
103 | #define CM_SPDIF_CTRL 0x0a08 | ||
104 | #define CM_VID_CTRL 0x0a0c | ||
105 | #define CM_LANE_CTRL 0x0a10 | ||
106 | #define I2S_NM_STABLE 0x0a14 | ||
107 | #define I2S_NCTS_STABLE 0x0a18 | ||
108 | #define SPDIF_NM_STABLE 0x0a1c | ||
109 | #define SPDIF_NCTS_STABLE 0x0a20 | ||
110 | #define NMVID_MEAS_STABLE 0x0a24 | ||
111 | #define I2S_MEAS 0x0a40 | ||
112 | #define SPDIF_MEAS 0x0a80 | ||
113 | #define NMVID_MEAS 0x0ac0 | ||
114 | |||
115 | /* source vif addr */ | ||
116 | #define BND_HSYNC2VSYNC 0x0b00 | ||
117 | #define HSYNC2VSYNC_F1_L1 0x0b04 | ||
118 | #define HSYNC2VSYNC_F2_L1 0x0b08 | ||
119 | #define HSYNC2VSYNC_STATUS 0x0b0c | ||
120 | #define HSYNC2VSYNC_POL_CTRL 0x0b10 | ||
121 | |||
122 | /* dptx phy addr */ | ||
123 | #define DP_TX_PHY_CONFIG_REG 0x2000 | ||
124 | #define DP_TX_PHY_STATUS_REG 0x2004 | ||
125 | #define DP_TX_PHY_SW_RESET 0x2008 | ||
126 | #define DP_TX_PHY_SCRAMBLER_SEED 0x200c | ||
127 | #define DP_TX_PHY_TRAINING_01_04 0x2010 | ||
128 | #define DP_TX_PHY_TRAINING_05_08 0x2014 | ||
129 | #define DP_TX_PHY_TRAINING_09_10 0x2018 | ||
130 | #define TEST_COR 0x23fc | ||
131 | |||
132 | /* dptx hpd addr */ | ||
133 | #define HPD_IRQ_DET_MIN_TIMER 0x2100 | ||
134 | #define HPD_IRQ_DET_MAX_TIMER 0x2104 | ||
135 | #define HPD_UNPLGED_DET_MIN_TIMER 0x2108 | ||
136 | #define HPD_STABLE_TIMER 0x210c | ||
137 | #define HPD_FILTER_TIMER 0x2110 | ||
138 | #define HPD_EVENT_MASK 0x211c | ||
139 | #define HPD_EVENT_DET 0x2120 | ||
140 | |||
141 | /* dpyx framer addr */ | ||
142 | #define DP_FRAMER_GLOBAL_CONFIG 0x2200 | ||
143 | #define DP_SW_RESET 0x2204 | ||
144 | #define DP_FRAMER_TU 0x2208 | ||
145 | #define DP_FRAMER_PXL_REPR 0x220c | ||
146 | #define DP_FRAMER_SP 0x2210 | ||
147 | #define AUDIO_PACK_CONTROL 0x2214 | ||
148 | #define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) | ||
149 | #define DP_VB_ID 0x2258 | ||
150 | #define DP_MTPH_LVP_CONTROL 0x225c | ||
151 | #define DP_MTPH_SYMBOL_VALUES 0x2260 | ||
152 | #define DP_MTPH_ECF_CONTROL 0x2264 | ||
153 | #define DP_MTPH_ACT_CONTROL 0x2268 | ||
154 | #define DP_MTPH_STATUS 0x226c | ||
155 | #define DP_INTERRUPT_SOURCE 0x2270 | ||
156 | #define DP_INTERRUPT_MASK 0x2274 | ||
157 | #define DP_FRONT_BACK_PORCH 0x2278 | ||
158 | #define DP_BYTE_COUNT 0x227c | ||
159 | |||
160 | /* dptx stream addr */ | ||
161 | #define MSA_HORIZONTAL_0 0x2280 | ||
162 | #define MSA_HORIZONTAL_1 0x2284 | ||
163 | #define MSA_VERTICAL_0 0x2288 | ||
164 | #define MSA_VERTICAL_1 0x228c | ||
165 | #define MSA_MISC 0x2290 | ||
166 | #define STREAM_CONFIG 0x2294 | ||
167 | #define AUDIO_PACK_STATUS 0x2298 | ||
168 | #define VIF_STATUS 0x229c | ||
169 | #define PCK_STUFF_STATUS_0 0x22a0 | ||
170 | #define PCK_STUFF_STATUS_1 0x22a4 | ||
171 | #define INFO_PACK_STATUS 0x22a8 | ||
172 | #define RATE_GOVERNOR_STATUS 0x22ac | ||
173 | #define DP_HORIZONTAL 0x22b0 | ||
174 | #define DP_VERTICAL_0 0x22b4 | ||
175 | #define DP_VERTICAL_1 0x22b8 | ||
176 | #define DP_BLOCK_SDP 0x22bc | ||
177 | |||
178 | /* dptx glbl addr */ | ||
179 | #define DPTX_LANE_EN 0x2300 | ||
180 | #define DPTX_ENHNCD 0x2304 | ||
181 | #define DPTX_INT_MASK 0x2308 | ||
182 | #define DPTX_INT_STATUS 0x230c | ||
183 | |||
184 | /* dp aux addr */ | ||
185 | #define DP_AUX_HOST_CONTROL 0x2800 | ||
186 | #define DP_AUX_INTERRUPT_SOURCE 0x2804 | ||
187 | #define DP_AUX_INTERRUPT_MASK 0x2808 | ||
188 | #define DP_AUX_SWAP_INVERSION_CONTROL 0x280c | ||
189 | #define DP_AUX_SEND_NACK_TRANSACTION 0x2810 | ||
190 | #define DP_AUX_CLEAR_RX 0x2814 | ||
191 | #define DP_AUX_CLEAR_TX 0x2818 | ||
192 | #define DP_AUX_TIMER_STOP 0x281c | ||
193 | #define DP_AUX_TIMER_CLEAR 0x2820 | ||
194 | #define DP_AUX_RESET_SW 0x2824 | ||
195 | #define DP_AUX_DIVIDE_2M 0x2828 | ||
196 | #define DP_AUX_TX_PREACHARGE_LENGTH 0x282c | ||
197 | #define DP_AUX_FREQUENCY_1M_MAX 0x2830 | ||
198 | #define DP_AUX_FREQUENCY_1M_MIN 0x2834 | ||
199 | #define DP_AUX_RX_PRE_MIN 0x2838 | ||
200 | #define DP_AUX_RX_PRE_MAX 0x283c | ||
201 | #define DP_AUX_TIMER_PRESET 0x2840 | ||
202 | #define DP_AUX_NACK_FORMAT 0x2844 | ||
203 | #define DP_AUX_TX_DATA 0x2848 | ||
204 | #define DP_AUX_RX_DATA 0x284c | ||
205 | #define DP_AUX_TX_STATUS 0x2850 | ||
206 | #define DP_AUX_RX_STATUS 0x2854 | ||
207 | #define DP_AUX_RX_CYCLE_COUNTER 0x2858 | ||
208 | #define DP_AUX_MAIN_STATES 0x285c | ||
209 | #define DP_AUX_MAIN_TIMER 0x2860 | ||
210 | #define DP_AUX_AFE_OUT 0x2864 | ||
211 | |||
212 | /* crypto addr */ | ||
213 | #define CRYPTO_HDCP_REVISION 0x5800 | ||
214 | #define HDCP_CRYPTO_CONFIG 0x5804 | ||
215 | #define CRYPTO_INTERRUPT_SOURCE 0x5808 | ||
216 | #define CRYPTO_INTERRUPT_MASK 0x580c | ||
217 | #define CRYPTO22_CONFIG 0x5818 | ||
218 | #define CRYPTO22_STATUS 0x581c | ||
219 | #define SHA_256_DATA_IN 0x583c | ||
220 | #define SHA_256_DATA_OUT_(x) (0x5850 + ((x) << 2)) | ||
221 | #define AES_32_KEY_(x) (0x5870 + ((x) << 2)) | ||
222 | #define AES_32_DATA_IN 0x5880 | ||
223 | #define AES_32_DATA_OUT_(x) (0x5884 + ((x) << 2)) | ||
224 | #define CRYPTO14_CONFIG 0x58a0 | ||
225 | #define CRYPTO14_STATUS 0x58a4 | ||
226 | #define CRYPTO14_PRNM_OUT 0x58a8 | ||
227 | #define CRYPTO14_KM_0 0x58ac | ||
228 | #define CRYPTO14_KM_1 0x58b0 | ||
229 | #define CRYPTO14_AN_0 0x58b4 | ||
230 | #define CRYPTO14_AN_1 0x58b8 | ||
231 | #define CRYPTO14_YOUR_KSV_0 0x58bc | ||
232 | #define CRYPTO14_YOUR_KSV_1 0x58c0 | ||
233 | #define CRYPTO14_MI_0 0x58c4 | ||
234 | #define CRYPTO14_MI_1 0x58c8 | ||
235 | #define CRYPTO14_TI_0 0x58cc | ||
236 | #define CRYPTO14_KI_0 0x58d0 | ||
237 | #define CRYPTO14_KI_1 0x58d4 | ||
238 | #define CRYPTO14_BLOCKS_NUM 0x58d8 | ||
239 | #define CRYPTO14_KEY_MEM_DATA_0 0x58dc | ||
240 | #define CRYPTO14_KEY_MEM_DATA_1 0x58e0 | ||
241 | #define CRYPTO14_SHA1_MSG_DATA 0x58e4 | ||
242 | #define CRYPTO14_SHA1_V_VALUE_(x) (0x58e8 + ((x) << 2)) | ||
243 | #define TRNG_CTRL 0x58fc | ||
244 | #define TRNG_DATA_RDY 0x5900 | ||
245 | #define TRNG_DATA 0x5904 | ||
246 | |||
247 | /* cipher addr */ | ||
248 | #define HDCP_REVISION 0x60000 | ||
249 | #define INTERRUPT_SOURCE 0x60004 | ||
250 | #define INTERRUPT_MASK 0x60008 | ||
251 | #define HDCP_CIPHER_CONFIG 0x6000c | ||
252 | #define AES_128_KEY_0 0x60010 | ||
253 | #define AES_128_KEY_1 0x60014 | ||
254 | #define AES_128_KEY_2 0x60018 | ||
255 | #define AES_128_KEY_3 0x6001c | ||
256 | #define AES_128_RANDOM_0 0x60020 | ||
257 | #define AES_128_RANDOM_1 0x60024 | ||
258 | #define CIPHER14_KM_0 0x60028 | ||
259 | #define CIPHER14_KM_1 0x6002c | ||
260 | #define CIPHER14_STATUS 0x60030 | ||
261 | #define CIPHER14_RI_PJ_STATUS 0x60034 | ||
262 | #define CIPHER_MODE 0x60038 | ||
263 | #define CIPHER14_AN_0 0x6003c | ||
264 | #define CIPHER14_AN_1 0x60040 | ||
265 | #define CIPHER22_AUTH 0x60044 | ||
266 | #define CIPHER14_R0_DP_STATUS 0x60048 | ||
267 | #define CIPHER14_BOOTSTRAP 0x6004c | ||
268 | |||
269 | #define DPTX_FRMR_DATA_CLK_RSTN_EN BIT(11) | ||
270 | #define DPTX_FRMR_DATA_CLK_EN BIT(10) | ||
271 | #define DPTX_PHY_DATA_RSTN_EN BIT(9) | ||
272 | #define DPTX_PHY_DATA_CLK_EN BIT(8) | ||
273 | #define DPTX_PHY_CHAR_RSTN_EN BIT(7) | ||
274 | #define DPTX_PHY_CHAR_CLK_EN BIT(6) | ||
275 | #define SOURCE_AUX_SYS_CLK_RSTN_EN BIT(5) | ||
276 | #define SOURCE_AUX_SYS_CLK_EN BIT(4) | ||
277 | #define DPTX_SYS_CLK_RSTN_EN BIT(3) | ||
278 | #define DPTX_SYS_CLK_EN BIT(2) | ||
279 | #define CFG_DPTX_VIF_CLK_RSTN_EN BIT(1) | ||
280 | #define CFG_DPTX_VIF_CLK_EN BIT(0) | ||
281 | |||
282 | #define SOURCE_PHY_RSTN_EN BIT(1) | ||
283 | #define SOURCE_PHY_CLK_EN BIT(0) | ||
284 | |||
285 | #define SOURCE_PKT_SYS_RSTN_EN BIT(3) | ||
286 | #define SOURCE_PKT_SYS_CLK_EN BIT(2) | ||
287 | #define SOURCE_PKT_DATA_RSTN_EN BIT(1) | ||
288 | #define SOURCE_PKT_DATA_CLK_EN BIT(0) | ||
289 | |||
290 | #define SPDIF_CDR_CLK_RSTN_EN BIT(5) | ||
291 | #define SPDIF_CDR_CLK_EN BIT(4) | ||
292 | #define SOURCE_AIF_SYS_RSTN_EN BIT(3) | ||
293 | #define SOURCE_AIF_SYS_CLK_EN BIT(2) | ||
294 | #define SOURCE_AIF_CLK_RSTN_EN BIT(1) | ||
295 | #define SOURCE_AIF_CLK_EN BIT(0) | ||
296 | |||
297 | #define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN BIT(3) | ||
298 | #define SOURCE_CIPHER_SYS_CLK_EN BIT(2) | ||
299 | #define SOURCE_CIPHER_CHAR_CLK_RSTN_EN BIT(1) | ||
300 | #define SOURCE_CIPHER_CHAR_CLK_EN BIT(0) | ||
301 | |||
302 | #define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1) | ||
303 | #define SOURCE_CRYPTO_SYS_CLK_EN BIT(0) | ||
304 | |||
305 | #define APB_IRAM_PATH BIT(2) | ||
306 | #define APB_DRAM_PATH BIT(1) | ||
307 | #define APB_XT_RESET BIT(0) | ||
308 | |||
309 | #define MAILBOX_INT_MASK_BIT BIT(1) | ||
310 | #define PIF_INT_MASK_BIT BIT(0) | ||
311 | #define ALL_INT_MASK 3 | ||
312 | |||
313 | /* mailbox */ | ||
314 | #define MB_OPCODE_ID 0 | ||
315 | #define MB_MODULE_ID 1 | ||
316 | #define MB_SIZE_MSB_ID 2 | ||
317 | #define MB_SIZE_LSB_ID 3 | ||
318 | #define MB_DATA_ID 4 | ||
319 | |||
320 | #define MB_MODULE_ID_DP_TX 0x01 | ||
321 | #define MB_MODULE_ID_HDCP_TX 0x07 | ||
322 | #define MB_MODULE_ID_HDCP_RX 0x08 | ||
323 | #define MB_MODULE_ID_HDCP_GENERAL 0x09 | ||
324 | #define MB_MODULE_ID_GENERAL 0x0a | ||
325 | |||
326 | /* general opcode */ | ||
327 | #define GENERAL_MAIN_CONTROL 0x01 | ||
328 | #define GENERAL_TEST_ECHO 0x02 | ||
329 | #define GENERAL_BUS_SETTINGS 0x03 | ||
330 | #define GENERAL_TEST_ACCESS 0x04 | ||
331 | |||
332 | #define DPTX_SET_POWER_MNG 0x00 | ||
333 | #define DPTX_SET_HOST_CAPABILITIES 0x01 | ||
334 | #define DPTX_GET_EDID 0x02 | ||
335 | #define DPTX_READ_DPCD 0x03 | ||
336 | #define DPTX_WRITE_DPCD 0x04 | ||
337 | #define DPTX_ENABLE_EVENT 0x05 | ||
338 | #define DPTX_WRITE_REGISTER 0x06 | ||
339 | #define DPTX_READ_REGISTER 0x07 | ||
340 | #define DPTX_WRITE_FIELD 0x08 | ||
341 | #define DPTX_TRAINING_CONTROL 0x09 | ||
342 | #define DPTX_READ_EVENT 0x0a | ||
343 | #define DPTX_READ_LINK_STAT 0x0b | ||
344 | #define DPTX_SET_VIDEO 0x0c | ||
345 | #define DPTX_SET_AUDIO 0x0d | ||
346 | #define DPTX_GET_LAST_AUX_STAUS 0x0e | ||
347 | #define DPTX_SET_LINK_BREAK_POINT 0x0f | ||
348 | #define DPTX_FORCE_LANES 0x10 | ||
349 | #define DPTX_HPD_STATE 0x11 | ||
350 | |||
351 | #define FW_STANDBY 0 | ||
352 | #define FW_ACTIVE 1 | ||
353 | |||
354 | #define DPTX_EVENT_ENABLE_HPD BIT(0) | ||
355 | #define DPTX_EVENT_ENABLE_TRAINING BIT(1) | ||
356 | |||
357 | #define LINK_TRAINING_NOT_ACTIVE 0 | ||
358 | #define LINK_TRAINING_RUN 1 | ||
359 | #define LINK_TRAINING_RESTART 2 | ||
360 | |||
361 | #define CONTROL_VIDEO_IDLE 0 | ||
362 | #define CONTROL_VIDEO_VALID 1 | ||
363 | |||
364 | #define TU_CNT_RST_EN BIT(15) | ||
365 | #define VIF_BYPASS_INTERLACE BIT(13) | ||
366 | #define INTERLACE_FMT_DET BIT(12) | ||
367 | #define INTERLACE_DTCT_WIN 0x20 | ||
368 | |||
369 | #define DP_FRAMER_SP_INTERLACE_EN BIT(2) | ||
370 | #define DP_FRAMER_SP_HSP BIT(1) | ||
371 | #define DP_FRAMER_SP_VSP BIT(0) | ||
372 | |||
373 | /* capability */ | ||
374 | #define AUX_HOST_INVERT 3 | ||
375 | #define FAST_LT_SUPPORT 1 | ||
376 | #define FAST_LT_NOT_SUPPORT 0 | ||
377 | #define LANE_MAPPING_NORMAL 0x1b | ||
378 | #define LANE_MAPPING_FLIPPED 0xe4 | ||
379 | #define ENHANCED 1 | ||
380 | #define SCRAMBLER_EN BIT(4) | ||
381 | |||
382 | #define FULL_LT_STARTED BIT(0) | ||
383 | #define FASE_LT_STARTED BIT(1) | ||
384 | #define CLK_RECOVERY_FINISHED BIT(2) | ||
385 | #define EQ_PHASE_FINISHED BIT(3) | ||
386 | #define FASE_LT_START_FINISHED BIT(4) | ||
387 | #define CLK_RECOVERY_FAILED BIT(5) | ||
388 | #define EQ_PHASE_FAILED BIT(6) | ||
389 | #define FASE_LT_FAILED BIT(7) | ||
390 | |||
391 | #define DPTX_HPD_EVENT BIT(0) | ||
392 | #define DPTX_TRAINING_EVENT BIT(1) | ||
393 | #define HDCP_TX_STATUS_EVENT BIT(4) | ||
394 | #define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) | ||
395 | #define HDCP2_TX_STORE_KM_EVENT BIT(6) | ||
396 | #define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) | ||
397 | |||
398 | #define TU_SIZE 30 | ||
399 | #define CDN_DP_MAX_LINK_RATE DP_LINK_BW_5_4 | ||
400 | |||
401 | /* audio */ | ||
402 | #define AUDIO_PACK_EN BIT(8) | ||
403 | #define SAMPLING_FREQ(x) (((x) & 0xf) << 16) | ||
404 | #define ORIGINAL_SAMP_FREQ(x) (((x) & 0xf) << 24) | ||
405 | #define SYNC_WR_TO_CH_ZERO BIT(1) | ||
406 | #define I2S_DEC_START BIT(1) | ||
407 | #define AUDIO_SW_RST BIT(0) | ||
408 | #define SMPL2PKT_EN BIT(1) | ||
409 | #define MAX_NUM_CH(x) (((x) & 0x1f) - 1) | ||
410 | #define NUM_OF_I2S_PORTS(x) ((((x) / 2 - 1) & 0x3) << 5) | ||
411 | #define AUDIO_TYPE_LPCM (2 << 7) | ||
412 | #define CFG_SUB_PCKT_NUM(x) ((((x) - 1) & 0x7) << 11) | ||
413 | #define AUDIO_CH_NUM(x) ((((x) - 1) & 0x1f) << 2) | ||
414 | #define TRANS_SMPL_WIDTH_16 0 | ||
415 | #define TRANS_SMPL_WIDTH_24 BIT(11) | ||
416 | #define TRANS_SMPL_WIDTH_32 (2 << 11) | ||
417 | #define I2S_DEC_PORT_EN(x) (((x) & 0xf) << 17) | ||
418 | #define SPDIF_ENABLE BIT(21) | ||
419 | #define SPDIF_AVG_SEL BIT(20) | ||
420 | #define SPDIF_JITTER_BYPASS BIT(19) | ||
421 | #define SPDIF_FIFO_MID_RANGE(x) (((x) & 0xff) << 11) | ||
422 | #define SPDIF_JITTER_THRSH(x) (((x) & 0xff) << 3) | ||
423 | #define SPDIF_JITTER_AVG_WIN(x) ((x) & 0x7) | ||
424 | |||
425 | /* Reference cycles when using lane clock as reference */ | ||
426 | #define LANE_REF_CYC 0x8000 | ||
427 | |||
428 | enum voltage_swing_level { | ||
429 | VOLTAGE_LEVEL_0, | ||
430 | VOLTAGE_LEVEL_1, | ||
431 | VOLTAGE_LEVEL_2, | ||
432 | VOLTAGE_LEVEL_3, | ||
433 | }; | ||
434 | |||
435 | enum pre_emphasis_level { | ||
436 | PRE_EMPHASIS_LEVEL_0, | ||
437 | PRE_EMPHASIS_LEVEL_1, | ||
438 | PRE_EMPHASIS_LEVEL_2, | ||
439 | PRE_EMPHASIS_LEVEL_3, | ||
440 | }; | ||
441 | |||
442 | enum pattern_set { | ||
443 | PTS1 = BIT(0), | ||
444 | PTS2 = BIT(1), | ||
445 | PTS3 = BIT(2), | ||
446 | PTS4 = BIT(3), | ||
447 | DP_NONE = BIT(4) | ||
448 | }; | ||
449 | |||
450 | enum vic_color_depth { | ||
451 | BCS_6 = 0x1, | ||
452 | BCS_8 = 0x2, | ||
453 | BCS_10 = 0x4, | ||
454 | BCS_12 = 0x8, | ||
455 | BCS_16 = 0x10, | ||
456 | }; | ||
457 | |||
458 | enum vic_bt_type { | ||
459 | BT_601 = 0x0, | ||
460 | BT_709 = 0x1, | ||
461 | }; | ||
462 | |||
463 | void cdn_dp_clock_reset(struct cdn_dp_device *dp); | ||
464 | |||
465 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk); | ||
466 | int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, | ||
467 | u32 i_size, const u32 *d_mem, u32 d_size); | ||
468 | int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); | ||
469 | int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); | ||
470 | int cdn_dp_event_config(struct cdn_dp_device *dp); | ||
471 | u32 cdn_dp_get_event(struct cdn_dp_device *dp); | ||
472 | int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); | ||
473 | int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value); | ||
474 | int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len); | ||
475 | int cdn_dp_get_edid_block(void *dp, u8 *edid, | ||
476 | unsigned int block, size_t length); | ||
477 | int cdn_dp_train_link(struct cdn_dp_device *dp); | ||
478 | int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active); | ||
479 | int cdn_dp_config_video(struct cdn_dp_device *dp); | ||
480 | int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); | ||
481 | int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); | ||
482 | int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); | ||
483 | #endif /* _CDN_DP_REG_H */ | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index d5e1f8627d38..c9ccdf8f44bb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c | |||
@@ -213,7 +213,7 @@ rockchip_drm_framebuffer_init(struct drm_device *dev, | |||
213 | 213 | ||
214 | rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); | 214 | rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); |
215 | if (IS_ERR(rockchip_fb)) | 215 | if (IS_ERR(rockchip_fb)) |
216 | return NULL; | 216 | return ERR_CAST(rockchip_fb); |
217 | 217 | ||
218 | return &rockchip_fb->fb; | 218 | return &rockchip_fb->fb; |
219 | } | 219 | } |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index fb5f001f51c3..76c79ac57df0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -531,6 +531,8 @@ static int vop_enable(struct drm_crtc *crtc) | |||
531 | } | 531 | } |
532 | 532 | ||
533 | memcpy(vop->regs, vop->regsbak, vop->len); | 533 | memcpy(vop->regs, vop->regsbak, vop->len); |
534 | vop_cfg_done(vop); | ||
535 | |||
534 | /* | 536 | /* |
535 | * At here, vop clock & iommu is enable, R/W vop regs would be safe. | 537 | * At here, vop clock & iommu is enable, R/W vop regs would be safe. |
536 | */ | 538 | */ |
@@ -582,6 +584,8 @@ static void vop_crtc_disable(struct drm_crtc *crtc) | |||
582 | spin_unlock(&vop->reg_lock); | 584 | spin_unlock(&vop->reg_lock); |
583 | } | 585 | } |
584 | 586 | ||
587 | vop_cfg_done(vop); | ||
588 | |||
585 | drm_crtc_vblank_off(crtc); | 589 | drm_crtc_vblank_off(crtc); |
586 | 590 | ||
587 | /* | 591 | /* |
@@ -932,9 +936,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) | |||
932 | vop_dsp_hold_valid_irq_disable(vop); | 936 | vop_dsp_hold_valid_irq_disable(vop); |
933 | } | 937 | } |
934 | 938 | ||
935 | pin_pol = 0x8; | 939 | pin_pol = BIT(DCLK_INVERT); |
936 | pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; | 940 | pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? |
937 | pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); | 941 | 0 : BIT(HSYNC_POSITIVE); |
942 | pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? | ||
943 | 0 : BIT(VSYNC_POSITIVE); | ||
938 | VOP_CTRL_SET(vop, pin_pol, pin_pol); | 944 | VOP_CTRL_SET(vop, pin_pol, pin_pol); |
939 | 945 | ||
940 | switch (s->output_type) { | 946 | switch (s->output_type) { |
@@ -954,6 +960,11 @@ static void vop_crtc_enable(struct drm_crtc *crtc) | |||
954 | VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol); | 960 | VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol); |
955 | VOP_CTRL_SET(vop, mipi_en, 1); | 961 | VOP_CTRL_SET(vop, mipi_en, 1); |
956 | break; | 962 | break; |
963 | case DRM_MODE_CONNECTOR_DisplayPort: | ||
964 | pin_pol &= ~BIT(DCLK_INVERT); | ||
965 | VOP_CTRL_SET(vop, dp_pin_pol, pin_pol); | ||
966 | VOP_CTRL_SET(vop, dp_en, 1); | ||
967 | break; | ||
957 | default: | 968 | default: |
958 | DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", | 969 | DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", |
959 | s->output_type); | 970 | s->output_type); |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 1dbc52615257..5a4faa85dbd2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h | |||
@@ -45,6 +45,7 @@ struct vop_ctrl { | |||
45 | struct vop_reg edp_en; | 45 | struct vop_reg edp_en; |
46 | struct vop_reg hdmi_en; | 46 | struct vop_reg hdmi_en; |
47 | struct vop_reg mipi_en; | 47 | struct vop_reg mipi_en; |
48 | struct vop_reg dp_en; | ||
48 | struct vop_reg out_mode; | 49 | struct vop_reg out_mode; |
49 | struct vop_reg dither_down; | 50 | struct vop_reg dither_down; |
50 | struct vop_reg dither_up; | 51 | struct vop_reg dither_up; |
@@ -53,6 +54,7 @@ struct vop_ctrl { | |||
53 | struct vop_reg hdmi_pin_pol; | 54 | struct vop_reg hdmi_pin_pol; |
54 | struct vop_reg edp_pin_pol; | 55 | struct vop_reg edp_pin_pol; |
55 | struct vop_reg mipi_pin_pol; | 56 | struct vop_reg mipi_pin_pol; |
57 | struct vop_reg dp_pin_pol; | ||
56 | 58 | ||
57 | struct vop_reg htotal_pw; | 59 | struct vop_reg htotal_pw; |
58 | struct vop_reg hact_st_end; | 60 | struct vop_reg hact_st_end; |
@@ -244,6 +246,13 @@ enum scale_down_mode { | |||
244 | SCALE_DOWN_AVG = 0x1 | 246 | SCALE_DOWN_AVG = 0x1 |
245 | }; | 247 | }; |
246 | 248 | ||
249 | enum vop_pol { | ||
250 | HSYNC_POSITIVE = 0, | ||
251 | VSYNC_POSITIVE = 1, | ||
252 | DEN_NEGATIVE = 2, | ||
253 | DCLK_INVERT = 3 | ||
254 | }; | ||
255 | |||
247 | #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) | 256 | #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) |
248 | #define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12 | 257 | #define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12 |
249 | #define SCL_MAX_VSKIPLINES 4 | 258 | #define SCL_MAX_VSKIPLINES 4 |
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 35c51f3402f2..91fbc7b52147 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c | |||
@@ -284,6 +284,7 @@ static const struct vop_data rk3288_vop = { | |||
284 | static const struct vop_ctrl rk3399_ctrl_data = { | 284 | static const struct vop_ctrl rk3399_ctrl_data = { |
285 | .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), | 285 | .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), |
286 | .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), | 286 | .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), |
287 | .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), | ||
287 | .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), | 288 | .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), |
288 | .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), | 289 | .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), |
289 | .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), | 290 | .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), |
@@ -293,6 +294,7 @@ static const struct vop_ctrl rk3399_ctrl_data = { | |||
293 | .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), | 294 | .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), |
294 | .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), | 295 | .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), |
295 | .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), | 296 | .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), |
297 | .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), | ||
296 | .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), | 298 | .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), |
297 | .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), | 299 | .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), |
298 | .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), | 300 | .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), |