Lines Matching +full:hdmi +full:- +full:bridge

1 // SPDX-License-Identifier: GPL-2.0
5 * Author: Chen Shunqing <csq@rock-chips.com>
14 #include <linux/extcon-provider.h>
15 #include <linux/hdmi.h>
28 #include <sound/hdmi-codec.h>
36 #include <linux/extcon-provider.h>
64 u8 pre_emphasis; /* pre-emphasis value */
73 struct drm_bridge bridge; member
108 * R = 1.164*Y + 1.596*V - 204
109 * G = 1.164*Y - 0.391*U - 0.813*V + 154
110 * B = 1.164*Y + 2.018*U - 258
119 * R = Y + 1.402*V - 248
120 * G = Y - 0.344*U - 0.714*V + 135
121 * B = Y + 1.772*U - 227
130 * R = 1.164*Y + 1.793*V - 248
131 * G = 1.164*Y - 0.213*U - 0.534*V + 77
132 * B = 1.164*Y + 2.115*U - 289
142 * Cb = -0.291G - 0.148R + 0.439B + 128
144 * Cr = -0.368G + 0.439R - 0.071B + 128
153 * Cb = - 0.338G - 0.101R + 0.439B + 128
155 * Cr = - 0.399G + 0.439R - 0.040B + 128
164 * R' = R x (235-16)/255 + 16;
165 * G' = G x (235-16)/255 + 16;
166 * B' = B x (235-16)/255 + 16;
177 return container_of(b, struct rk628_hdmi, bridge); in bridge_to_hdmi()
185 static u32 hdmi_readb(struct rk628_hdmi *hdmi, u32 reg) in hdmi_readb() argument
189 rk628_i2c_read(hdmi->rk628, reg, &val); in hdmi_readb()
194 static void hdmi_writeb(struct rk628_hdmi *hdmi, u32 reg, u32 val) in hdmi_writeb() argument
196 rk628_i2c_write(hdmi->rk628, reg, val); in hdmi_writeb()
199 static void hdmi_modb(struct rk628_hdmi *hdmi, u32 offset, in hdmi_modb() argument
202 u8 temp = hdmi_readb(hdmi, offset) & ~msk; in hdmi_modb()
205 hdmi_writeb(hdmi, offset, temp); in hdmi_modb()
208 static void rk628_hdmi_i2c_init(struct rk628_hdmi *hdmi) in rk628_hdmi_i2c_init() argument
212 ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; in rk628_hdmi_i2c_init()
214 hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); in rk628_hdmi_i2c_init()
215 hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); in rk628_hdmi_i2c_init()
218 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); in rk628_hdmi_i2c_init()
219 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, INT_EDID_READY); in rk628_hdmi_i2c_init()
222 static void rk628_hdmi_sys_power(struct rk628_hdmi *hdmi, bool enable) in rk628_hdmi_sys_power() argument
225 hdmi_modb(hdmi, HDMI_SYS_CTRL, POWER_MASK, PWR_OFF(0)); in rk628_hdmi_sys_power()
227 hdmi_modb(hdmi, HDMI_SYS_CTRL, POWER_MASK, PWR_OFF(1)); in rk628_hdmi_sys_power()
231 /* pixelclk pre-emp vlev */
237 static void rk628_hdmi_set_pwr_mode(struct rk628_hdmi *hdmi, int mode) in rk628_hdmi_set_pwr_mode() argument
244 rk628_hdmi_sys_power(hdmi, false); in rk628_hdmi_set_pwr_mode()
245 for (; phy_config->mpixelclock != ~0UL; phy_config++) in rk628_hdmi_set_pwr_mode()
246 if (hdmi->tmds_rate <= phy_config->mpixelclock) in rk628_hdmi_set_pwr_mode()
248 if (!phy_config->mpixelclock) in rk628_hdmi_set_pwr_mode()
250 hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, in rk628_hdmi_set_pwr_mode()
251 phy_config->pre_emphasis); in rk628_hdmi_set_pwr_mode()
252 hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->vlev_ctr); in rk628_hdmi_set_pwr_mode()
254 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); in rk628_hdmi_set_pwr_mode()
255 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); in rk628_hdmi_set_pwr_mode()
256 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); in rk628_hdmi_set_pwr_mode()
257 hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); in rk628_hdmi_set_pwr_mode()
258 hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); in rk628_hdmi_set_pwr_mode()
259 hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); in rk628_hdmi_set_pwr_mode()
261 rk628_hdmi_sys_power(hdmi, true); in rk628_hdmi_set_pwr_mode()
265 rk628_hdmi_sys_power(hdmi, false); in rk628_hdmi_set_pwr_mode()
266 hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); in rk628_hdmi_set_pwr_mode()
267 hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); in rk628_hdmi_set_pwr_mode()
268 hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); in rk628_hdmi_set_pwr_mode()
269 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); in rk628_hdmi_set_pwr_mode()
273 dev_err(hdmi->dev, "Unknown power mode %d\n", mode); in rk628_hdmi_set_pwr_mode()
277 static void rk628_hdmi_reset(struct rk628_hdmi *hdmi) in rk628_hdmi_reset() argument
282 hdmi_modb(hdmi, HDMI_SYS_CTRL, RST_DIGITAL_MASK, NOT_RST_DIGITAL(1)); in rk628_hdmi_reset()
285 hdmi_modb(hdmi, HDMI_SYS_CTRL, RST_ANALOG_MASK, NOT_RST_ANALOG(1)); in rk628_hdmi_reset()
291 hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); in rk628_hdmi_reset()
293 rk628_hdmi_set_pwr_mode(hdmi, NORMAL); in rk628_hdmi_reset()
296 static int rk628_hdmi_upload_frame(struct rk628_hdmi *hdmi, int setup_rc, in rk628_hdmi_upload_frame() argument
301 hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable); in rk628_hdmi_upload_frame()
303 hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); in rk628_hdmi_upload_frame()
315 hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + (i * 4), in rk628_hdmi_upload_frame()
319 hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable); in rk628_hdmi_upload_frame()
325 static int rk628_hdmi_config_video_vsi(struct rk628_hdmi *hdmi, in rk628_hdmi_config_video_vsi() argument
331 rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, in rk628_hdmi_config_video_vsi()
332 &hdmi->connector, in rk628_hdmi_config_video_vsi()
335 return rk628_hdmi_upload_frame(hdmi, rc, &frame, in rk628_hdmi_config_video_vsi()
340 static int rk628_hdmi_config_video_avi(struct rk628_hdmi *hdmi, in rk628_hdmi_config_video_avi() argument
347 &hdmi->connector, mode); in rk628_hdmi_config_video_avi()
349 if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) in rk628_hdmi_config_video_avi()
351 else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422) in rk628_hdmi_config_video_avi()
357 frame.avi.colorimetry = hdmi->hdmi_data.colorimetry; in rk628_hdmi_config_video_avi()
361 return rk628_hdmi_upload_frame(hdmi, rc, &frame, in rk628_hdmi_config_video_avi()
365 static int rk628_hdmi_config_audio_aai(struct rk628_hdmi *hdmi, in rk628_hdmi_config_audio_aai() argument
375 faudio->channels = audio->channels; in rk628_hdmi_config_audio_aai()
377 return rk628_hdmi_upload_frame(hdmi, rc, &frame, in rk628_hdmi_config_audio_aai()
381 static int rk628_hdmi_config_video_csc(struct rk628_hdmi *hdmi) in rk628_hdmi_config_video_csc() argument
383 struct hdmi_data_info *data = &hdmi->hdmi_data; in rk628_hdmi_config_video_csc()
393 hdmi_writeb(hdmi, HDMI_VIDEO_CONTROL1, DE_SOURCE(1) | in rk628_hdmi_config_video_csc()
396 if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) in rk628_hdmi_config_video_csc()
402 hdmi_writeb(hdmi, HDMI_VIDEO_CONTROL2, value); in rk628_hdmi_config_video_csc()
404 if (data->enc_in_format == data->enc_out_format) { in rk628_hdmi_config_video_csc()
405 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) || in rk628_hdmi_config_video_csc()
406 (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) { in rk628_hdmi_config_video_csc()
408 hdmi_writeb(hdmi, HDMI_VIDEO_CONTROL3, value); in rk628_hdmi_config_video_csc()
410 hdmi_modb(hdmi, HDMI_VIDEO_CONTROL, in rk628_hdmi_config_video_csc()
418 if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) { in rk628_hdmi_config_video_csc()
419 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && in rk628_hdmi_config_video_csc()
420 (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { in rk628_hdmi_config_video_csc()
425 } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && in rk628_hdmi_config_video_csc()
426 (data->enc_out_format == HDMI_COLORSPACE_RGB)) { in rk628_hdmi_config_video_csc()
433 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && in rk628_hdmi_config_video_csc()
434 (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { in rk628_hdmi_config_video_csc()
439 } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && in rk628_hdmi_config_video_csc()
440 (data->enc_out_format == HDMI_COLORSPACE_RGB)) { in rk628_hdmi_config_video_csc()
449 hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + (i * 4), in rk628_hdmi_config_video_csc()
453 hdmi_writeb(hdmi, HDMI_VIDEO_CONTROL3, value); in rk628_hdmi_config_video_csc()
454 hdmi_modb(hdmi, HDMI_VIDEO_CONTROL, in rk628_hdmi_config_video_csc()
461 static int rk628_hdmi_config_video_timing(struct rk628_hdmi *hdmi, in rk628_hdmi_config_video_timing() argument
468 value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? in rk628_hdmi_config_video_timing()
470 value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? in rk628_hdmi_config_video_timing()
472 value |= mode->flags & DRM_MODE_FLAG_INTERLACE ? in rk628_hdmi_config_video_timing()
474 hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value); in rk628_hdmi_config_video_timing()
477 value = mode->htotal; in rk628_hdmi_config_video_timing()
478 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF); in rk628_hdmi_config_video_timing()
479 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF); in rk628_hdmi_config_video_timing()
481 value = mode->htotal - mode->hdisplay; in rk628_hdmi_config_video_timing()
482 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); in rk628_hdmi_config_video_timing()
483 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); in rk628_hdmi_config_video_timing()
485 value = mode->htotal - mode->hsync_start; in rk628_hdmi_config_video_timing()
486 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); in rk628_hdmi_config_video_timing()
487 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); in rk628_hdmi_config_video_timing()
489 value = mode->hsync_end - mode->hsync_start; in rk628_hdmi_config_video_timing()
490 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF); in rk628_hdmi_config_video_timing()
491 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF); in rk628_hdmi_config_video_timing()
493 value = mode->vtotal; in rk628_hdmi_config_video_timing()
494 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF); in rk628_hdmi_config_video_timing()
495 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF); in rk628_hdmi_config_video_timing()
497 value = mode->vtotal - mode->vdisplay; in rk628_hdmi_config_video_timing()
498 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); in rk628_hdmi_config_video_timing()
500 value = mode->vtotal - mode->vsync_start; in rk628_hdmi_config_video_timing()
501 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); in rk628_hdmi_config_video_timing()
503 value = mode->vsync_end - mode->vsync_start; in rk628_hdmi_config_video_timing()
504 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF); in rk628_hdmi_config_video_timing()
506 hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e); in rk628_hdmi_config_video_timing()
507 hdmi_writeb(hdmi, PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c); in rk628_hdmi_config_video_timing()
508 hdmi_writeb(hdmi, PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01); in rk628_hdmi_config_video_timing()
513 static int rk628_hdmi_setup(struct rk628_hdmi *hdmi, in rk628_hdmi_setup() argument
516 hdmi->hdmi_data.vic = drm_match_cea_mode(mode); in rk628_hdmi_setup()
518 hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB; in rk628_hdmi_setup()
519 hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; in rk628_hdmi_setup()
521 if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) || in rk628_hdmi_setup()
522 (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) || in rk628_hdmi_setup()
523 (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) || in rk628_hdmi_setup()
524 (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18)) in rk628_hdmi_setup()
525 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; in rk628_hdmi_setup()
527 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; in rk628_hdmi_setup()
530 hdmi_modb(hdmi, HDMI_AV_MUTE, AUDIO_MUTE_MASK | VIDEO_BLACK_MASK, in rk628_hdmi_setup()
533 /* Set HDMI Mode */ in rk628_hdmi_setup()
534 hdmi_writeb(hdmi, HDMI_HDCP_CTRL, in rk628_hdmi_setup()
535 HDMI_DVI(hdmi->hdmi_data.sink_is_hdmi)); in rk628_hdmi_setup()
537 rk628_hdmi_config_video_timing(hdmi, mode); in rk628_hdmi_setup()
539 rk628_hdmi_config_video_csc(hdmi); in rk628_hdmi_setup()
541 if (hdmi->hdmi_data.sink_is_hdmi) { in rk628_hdmi_setup()
542 rk628_hdmi_config_video_avi(hdmi, mode); in rk628_hdmi_setup()
543 rk628_hdmi_config_video_vsi(hdmi, mode); in rk628_hdmi_setup()
552 hdmi->tmds_rate = mode->clock * 1000; in rk628_hdmi_setup()
553 rk628_hdmi_i2c_init(hdmi); in rk628_hdmi_setup()
556 hdmi_modb(hdmi, HDMI_AV_MUTE, VIDEO_BLACK_MASK, VIDEO_MUTE(0)); in rk628_hdmi_setup()
557 if (hdmi->audio_enable) in rk628_hdmi_setup()
558 hdmi_modb(hdmi, HDMI_AV_MUTE, AUDIO_MUTE_MASK, AUDIO_MUTE(0)); in rk628_hdmi_setup()
566 struct rk628_hdmi *hdmi = connector_to_hdmi(connector); in rk628_hdmi_connector_detect() local
569 status = hdmi_readb(hdmi, HDMI_STATUS) & HOTPLUG_STATUS; in rk628_hdmi_connector_detect()
572 extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, true); in rk628_hdmi_connector_detect()
574 extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, false); in rk628_hdmi_connector_detect()
582 struct rk628_hdmi *hdmi = connector_to_hdmi(connector); in rk628_hdmi_connector_get_modes() local
583 struct drm_display_info *info = &connector->display_info; in rk628_hdmi_connector_get_modes()
587 if (!hdmi->ddc) in rk628_hdmi_connector_get_modes()
590 if ((hdmi_readb(hdmi, HDMI_STATUS) & HOTPLUG_STATUS)) in rk628_hdmi_connector_get_modes()
591 edid = drm_get_edid(connector, hdmi->ddc); in rk628_hdmi_connector_get_modes()
594 hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid); in rk628_hdmi_connector_get_modes()
595 hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid); in rk628_hdmi_connector_get_modes()
602 hdmi->hdmi_data.sink_is_hdmi = true; in rk628_hdmi_connector_get_modes()
603 hdmi->hdmi_data.sink_has_audio = true; in rk628_hdmi_connector_get_modes()
607 info->edid_hdmi_dc_modes = 0; in rk628_hdmi_connector_get_modes()
608 info->hdmi.y420_dc_modes = 0; in rk628_hdmi_connector_get_modes()
609 info->color_formats = 0; in rk628_hdmi_connector_get_modes()
611 dev_info(hdmi->dev, "failed to get edid\n"); in rk628_hdmi_connector_get_modes()
621 if ((mode->hdisplay == 1920 && mode->vdisplay == 1080) || in rk628_hdmi_connector_mode_valid()
622 (mode->hdisplay == 1280 && mode->vdisplay == 720)) in rk628_hdmi_connector_mode_valid()
631 struct rk628_hdmi *hdmi = connector_to_hdmi(connector); in rk628_hdmi_connector_best_encoder() local
633 return hdmi->bridge.encoder; in rk628_hdmi_connector_best_encoder()
659 static void rk628_hdmi_bridge_mode_set(struct drm_bridge *bridge, in rk628_hdmi_bridge_mode_set() argument
663 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_mode_set() local
664 struct rk628 *rk628 = hdmi->rk628; in rk628_hdmi_bridge_mode_set()
669 memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); in rk628_hdmi_bridge_mode_set()
670 dst->clock = mode->clock; in rk628_hdmi_bridge_mode_set()
671 dst->hdisplay = mode->hdisplay; in rk628_hdmi_bridge_mode_set()
672 dst->hsync_start = mode->hsync_start; in rk628_hdmi_bridge_mode_set()
673 dst->hsync_end = mode->hsync_end; in rk628_hdmi_bridge_mode_set()
674 dst->htotal = mode->htotal; in rk628_hdmi_bridge_mode_set()
675 dst->vdisplay = mode->vdisplay; in rk628_hdmi_bridge_mode_set()
676 dst->vsync_start = mode->vsync_start; in rk628_hdmi_bridge_mode_set()
677 dst->vsync_end = mode->vsync_end; in rk628_hdmi_bridge_mode_set()
678 dst->vtotal = mode->vtotal; in rk628_hdmi_bridge_mode_set()
679 dst->flags = mode->flags; in rk628_hdmi_bridge_mode_set()
684 rk628_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, in rk628_hdmi_bridge_mode_fixup() argument
688 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_mode_fixup() local
689 struct rk628 *rk628 = hdmi->rk628; in rk628_hdmi_bridge_mode_fixup()
691 if (rk628->sync_pol == MODE_FLAG_NSYNC) { in rk628_hdmi_bridge_mode_fixup()
692 adj->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); in rk628_hdmi_bridge_mode_fixup()
693 adj->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); in rk628_hdmi_bridge_mode_fixup()
695 adj->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); in rk628_hdmi_bridge_mode_fixup()
696 adj->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); in rk628_hdmi_bridge_mode_fixup()
702 static void rk628_hdmi_bridge_enable(struct drm_bridge *bridge) in rk628_hdmi_bridge_enable() argument
704 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_enable() local
706 rk628_post_process_init(hdmi->rk628); in rk628_hdmi_bridge_enable()
707 rk628_post_process_enable(hdmi->rk628); in rk628_hdmi_bridge_enable()
708 rk628_hdmi_setup(hdmi, &hdmi->previous_mode); in rk628_hdmi_bridge_enable()
709 rk628_hdmi_set_pwr_mode(hdmi, NORMAL); in rk628_hdmi_bridge_enable()
712 static void rk628_hdmi_bridge_disable(struct drm_bridge *bridge) in rk628_hdmi_bridge_disable() argument
714 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_disable() local
716 rk628_hdmi_set_pwr_mode(hdmi, LOWER_PWR); in rk628_hdmi_bridge_disable()
719 static int rk628_hdmi_bridge_attach(struct drm_bridge *bridge, in rk628_hdmi_bridge_attach() argument
722 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_attach() local
723 struct drm_connector *connector = &hdmi->connector; in rk628_hdmi_bridge_attach()
724 struct drm_device *drm = bridge->dev; in rk628_hdmi_bridge_attach()
730 connector->polled = DRM_CONNECTOR_POLL_HPD; in rk628_hdmi_bridge_attach()
735 dev_err(hdmi->dev, "Failed to initialize connector with drm\n"); in rk628_hdmi_bridge_attach()
741 drm_connector_attach_encoder(connector, bridge->encoder); in rk628_hdmi_bridge_attach()
743 hdmi->sub_dev.connector = &hdmi->connector; in rk628_hdmi_bridge_attach()
744 hdmi->sub_dev.of_node = hdmi->dev->of_node; in rk628_hdmi_bridge_attach()
745 rockchip_drm_register_sub_dev(&hdmi->sub_dev); in rk628_hdmi_bridge_attach()
750 static void rk628_hdmi_bridge_detach(struct drm_bridge *bridge) in rk628_hdmi_bridge_detach() argument
752 struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge); in rk628_hdmi_bridge_detach() local
754 rockchip_drm_unregister_sub_dev(&hdmi->sub_dev); in rk628_hdmi_bridge_detach()
767 rk628_hdmi_audio_config_set(struct rk628_hdmi *hdmi, struct audio_info *audio) in rk628_hdmi_audio_config_set() argument
771 if (audio->channels < 3) in rk628_hdmi_audio_config_set()
773 else if (audio->channels < 5) in rk628_hdmi_audio_config_set()
775 else if (audio->channels < 7) in rk628_hdmi_audio_config_set()
780 switch (audio->sample_rate) { in rk628_hdmi_audio_config_set()
810 dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", in rk628_hdmi_audio_config_set()
811 __func__, audio->sample_rate); in rk628_hdmi_audio_config_set()
812 return -ENOENT; in rk628_hdmi_audio_config_set()
816 hdmi_writeb(hdmi, HDMI_AUDIO_CTRL1, 0x01); in rk628_hdmi_audio_config_set()
817 hdmi_writeb(hdmi, AUDIO_SAMPLE_RATE, rate); in rk628_hdmi_audio_config_set()
818 hdmi_writeb(hdmi, AUDIO_I2S_MODE, in rk628_hdmi_audio_config_set()
821 hdmi_writeb(hdmi, AUDIO_I2S_MAP, 0x00); in rk628_hdmi_audio_config_set()
822 hdmi_writeb(hdmi, AUDIO_I2S_SWAPS_SPDIF, 0); in rk628_hdmi_audio_config_set()
825 hdmi_writeb(hdmi, AUDIO_N_H, (N >> 16) & 0x0F); in rk628_hdmi_audio_config_set()
826 hdmi_writeb(hdmi, AUDIO_N_M, (N >> 8) & 0xFF); in rk628_hdmi_audio_config_set()
827 hdmi_writeb(hdmi, AUDIO_N_L, N & 0xFF); in rk628_hdmi_audio_config_set()
829 /*Set hdmi nlpcm mode to support hdmi bitstream*/ in rk628_hdmi_audio_config_set()
830 hdmi_writeb(hdmi, HDMI_AUDIO_CHANNEL_STATUS, AUDIO_STATUS_NLPCM(0)); in rk628_hdmi_audio_config_set()
832 return rk628_hdmi_config_audio_aai(hdmi, audio); in rk628_hdmi_audio_config_set()
839 struct rk628_hdmi *hdmi = dev_get_drvdata(dev); in rk628_hdmi_audio_hw_params() local
841 .sample_width = params->sample_width, in rk628_hdmi_audio_hw_params()
842 .sample_rate = params->sample_rate, in rk628_hdmi_audio_hw_params()
843 .channels = params->channels, in rk628_hdmi_audio_hw_params()
846 if (!hdmi->hdmi_data.sink_has_audio) { in rk628_hdmi_audio_hw_params()
847 dev_err(hdmi->dev, "Sink do not support audio!\n"); in rk628_hdmi_audio_hw_params()
848 return -ENODEV; in rk628_hdmi_audio_hw_params()
851 if (!hdmi->bridge.encoder->crtc) in rk628_hdmi_audio_hw_params()
852 return -ENODEV; in rk628_hdmi_audio_hw_params()
854 switch (daifmt->fmt) { in rk628_hdmi_audio_hw_params()
858 dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); in rk628_hdmi_audio_hw_params()
859 return -EINVAL; in rk628_hdmi_audio_hw_params()
862 return rk628_hdmi_audio_config_set(hdmi, &audio); in rk628_hdmi_audio_hw_params()
873 struct rk628_hdmi *hdmi = dev_get_drvdata(dev); in rk628_hdmi_audio_mute() local
875 if (!hdmi->hdmi_data.sink_has_audio) { in rk628_hdmi_audio_mute()
876 dev_err(hdmi->dev, "Sink do not support audio!\n"); in rk628_hdmi_audio_mute()
877 return -ENODEV; in rk628_hdmi_audio_mute()
880 hdmi->audio_enable = !mute; in rk628_hdmi_audio_mute()
883 hdmi_modb(hdmi, HDMI_AV_MUTE, AUDIO_MUTE_MASK | AUDIO_PD_MASK, in rk628_hdmi_audio_mute()
886 hdmi_modb(hdmi, HDMI_AV_MUTE, AUDIO_MUTE_MASK | AUDIO_PD_MASK, in rk628_hdmi_audio_mute()
895 struct rk628_hdmi *hdmi = dev_get_drvdata(dev); in rk628_hdmi_audio_get_eld() local
896 struct drm_mode_config *config = &hdmi->bridge.dev->mode_config; in rk628_hdmi_audio_get_eld()
898 int ret = -ENODEV; in rk628_hdmi_audio_get_eld()
900 mutex_lock(&config->mutex); in rk628_hdmi_audio_get_eld()
901 list_for_each_entry(connector, &config->connector_list, head) { in rk628_hdmi_audio_get_eld()
902 if (hdmi->bridge.encoder == connector->encoder) { in rk628_hdmi_audio_get_eld()
903 memcpy(buf, connector->eld, in rk628_hdmi_audio_get_eld()
904 min(sizeof(connector->eld), len)); in rk628_hdmi_audio_get_eld()
908 mutex_unlock(&config->mutex); in rk628_hdmi_audio_get_eld()
921 static int rk628_hdmi_audio_codec_init(struct rk628_hdmi *hdmi, in rk628_hdmi_audio_codec_init() argument
930 hdmi->audio_enable = false; in rk628_hdmi_audio_codec_init()
931 hdmi->audio_pdev = platform_device_register_data(dev, in rk628_hdmi_audio_codec_init()
935 return PTR_ERR_OR_ZERO(hdmi->audio_pdev); in rk628_hdmi_audio_codec_init()
940 struct rk628_hdmi *hdmi = dev_id; in rk628_hdmi_irq() local
944 rk628_i2c_write(hdmi->rk628, GRF_INTR0_CLR_EN, 0x00040004); in rk628_hdmi_irq()
945 interrupt = hdmi_readb(hdmi, HDMI_STATUS); in rk628_hdmi_irq()
949 hdmi_modb(hdmi, HDMI_STATUS, INT_HOTPLUG, INT_HOTPLUG); in rk628_hdmi_irq()
950 if (hdmi->connector.dev) in rk628_hdmi_irq()
951 drm_helper_hpd_irq_event(hdmi->connector.dev); in rk628_hdmi_irq()
956 static int rk628_hdmi_i2c_read(struct rk628_hdmi *hdmi, struct i2c_msg *msgs) in rk628_hdmi_i2c_read() argument
958 int length = msgs->len; in rk628_hdmi_i2c_read()
959 u8 *buf = msgs->buf; in rk628_hdmi_i2c_read()
965 c = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1); in rk628_hdmi_i2c_read()
970 return -EAGAIN; in rk628_hdmi_i2c_read()
972 while (length--) in rk628_hdmi_i2c_read()
973 *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR); in rk628_hdmi_i2c_read()
978 static int rk628_hdmi_i2c_write(struct rk628_hdmi *hdmi, struct i2c_msg *msgs) in rk628_hdmi_i2c_write() argument
985 if ((msgs->len != 1) || in rk628_hdmi_i2c_write()
986 ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR))) in rk628_hdmi_i2c_write()
987 return -EINVAL; in rk628_hdmi_i2c_write()
989 if (msgs->addr == DDC_ADDR) in rk628_hdmi_i2c_write()
990 hdmi->i2c->ddc_addr = msgs->buf[0]; in rk628_hdmi_i2c_write()
991 if (msgs->addr == DDC_SEGMENT_ADDR) { in rk628_hdmi_i2c_write()
992 hdmi->i2c->segment_addr = msgs->buf[0]; in rk628_hdmi_i2c_write()
997 hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00); in rk628_hdmi_i2c_write()
1000 hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr); in rk628_hdmi_i2c_write()
1003 hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr); in rk628_hdmi_i2c_write()
1011 struct rk628_hdmi *hdmi = i2c_get_adapdata(adap); in rk628_hdmi_i2c_xfer() local
1012 struct rk628_hdmi_i2c *i2c = hdmi->i2c; in rk628_hdmi_i2c_xfer()
1015 mutex_lock(&i2c->lock); in rk628_hdmi_i2c_xfer()
1017 hdmi->i2c->ddc_addr = 0; in rk628_hdmi_i2c_xfer()
1018 hdmi->i2c->segment_addr = 0; in rk628_hdmi_i2c_xfer()
1021 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, INT_EDID_READY); in rk628_hdmi_i2c_xfer()
1022 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, INT_EDID_READY_MASK); in rk628_hdmi_i2c_xfer()
1025 dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", in rk628_hdmi_i2c_xfer()
1029 ret = rk628_hdmi_i2c_read(hdmi, &msgs[i]); in rk628_hdmi_i2c_xfer()
1031 ret = rk628_hdmi_i2c_write(hdmi, &msgs[i]); in rk628_hdmi_i2c_xfer()
1040 /* Mute HDMI EDID interrupt */ in rk628_hdmi_i2c_xfer()
1041 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); in rk628_hdmi_i2c_xfer()
1042 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, INT_EDID_READY); in rk628_hdmi_i2c_xfer()
1044 mutex_unlock(&i2c->lock); in rk628_hdmi_i2c_xfer()
1059 static struct i2c_adapter *rk628_hdmi_i2c_adapter(struct rk628_hdmi *hdmi) in rk628_hdmi_i2c_adapter() argument
1065 i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); in rk628_hdmi_i2c_adapter()
1067 return ERR_PTR(-ENOMEM); in rk628_hdmi_i2c_adapter()
1069 mutex_init(&i2c->lock); in rk628_hdmi_i2c_adapter()
1071 adap = &i2c->adap; in rk628_hdmi_i2c_adapter()
1072 adap->class = I2C_CLASS_DDC; in rk628_hdmi_i2c_adapter()
1073 adap->owner = THIS_MODULE; in rk628_hdmi_i2c_adapter()
1074 adap->dev.parent = hdmi->dev; in rk628_hdmi_i2c_adapter()
1075 adap->dev.of_node = hdmi->dev->of_node; in rk628_hdmi_i2c_adapter()
1076 adap->algo = &rk628_hdmi_algorithm; in rk628_hdmi_i2c_adapter()
1077 strscpy(adap->name, "RK628 HDMI", sizeof(adap->name)); in rk628_hdmi_i2c_adapter()
1078 i2c_set_adapdata(adap, hdmi); in rk628_hdmi_i2c_adapter()
1082 dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); in rk628_hdmi_i2c_adapter()
1083 devm_kfree(hdmi->dev, i2c); in rk628_hdmi_i2c_adapter()
1087 hdmi->i2c = i2c; in rk628_hdmi_i2c_adapter()
1089 dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); in rk628_hdmi_i2c_adapter()
1096 struct device *dev = rk628->dev; in rk628_hdmitx_enable()
1097 struct rk628_hdmi *hdmi; in rk628_hdmitx_enable() local
1101 if (!of_device_is_available(dev->of_node)) in rk628_hdmitx_enable()
1102 return -ENODEV; in rk628_hdmitx_enable()
1104 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); in rk628_hdmitx_enable()
1105 if (!hdmi) in rk628_hdmitx_enable()
1106 return -ENOMEM; in rk628_hdmitx_enable()
1109 hdmi->dev = dev; in rk628_hdmitx_enable()
1110 hdmi->rk628 = rk628; in rk628_hdmitx_enable()
1112 irq = rk628->client->irq; in rk628_hdmitx_enable()
1115 dev_set_drvdata(dev, hdmi); in rk628_hdmitx_enable()
1125 /* set output mode to HDMI */ in rk628_hdmitx_enable()
1129 rk628_hdmi_reset(hdmi); in rk628_hdmitx_enable()
1131 hdmi->ddc = rk628_hdmi_i2c_adapter(hdmi); in rk628_hdmitx_enable()
1132 if (IS_ERR(hdmi->ddc)) { in rk628_hdmitx_enable()
1133 ret = PTR_ERR(hdmi->ddc); in rk628_hdmitx_enable()
1134 hdmi->ddc = NULL; in rk628_hdmitx_enable()
1144 hdmi->tmds_rate = 24000 * 1000; in rk628_hdmitx_enable()
1148 rk628_hdmi_i2c_init(hdmi); in rk628_hdmitx_enable()
1150 rk628_hdmi_audio_codec_init(hdmi, dev); in rk628_hdmitx_enable()
1155 dev_name(dev), hdmi); in rk628_hdmitx_enable()
1157 dev_err(dev, "failed to request hdmi irq: %d\n", ret); in rk628_hdmitx_enable()
1162 hdmi_modb(hdmi, HDMI_STATUS, MASK_INT_HOTPLUG_MASK, in rk628_hdmitx_enable()
1164 hdmi->bridge.funcs = &rk628_hdmi_bridge_funcs; in rk628_hdmitx_enable()
1165 hdmi->bridge.of_node = dev->of_node; in rk628_hdmitx_enable()
1167 drm_bridge_add(&hdmi->bridge); in rk628_hdmitx_enable()
1169 hdmi->extcon = devm_extcon_dev_allocate(hdmi->dev, rk628_hdmi_cable); in rk628_hdmitx_enable()
1170 if (IS_ERR(hdmi->extcon)) { in rk628_hdmitx_enable()
1171 dev_err(hdmi->dev, "allocate extcon failed\n"); in rk628_hdmitx_enable()
1172 ret = PTR_ERR(hdmi->extcon); in rk628_hdmitx_enable()
1176 ret = devm_extcon_dev_register(hdmi->dev, hdmi->extcon); in rk628_hdmitx_enable()
1182 ret = extcon_set_property_capability(hdmi->extcon, EXTCON_DISP_HDMI, in rk628_hdmitx_enable()
1196 MODULE_AUTHOR("Chen Shunqing <csq@rock-chips.com>");
1197 MODULE_DESCRIPTION("Rockchip RK628 HDMI driver");