Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
0004  *    Zheng Yang <zhengyang@rock-chips.com>
0005  *    Yakir Yang <ykk@rock-chips.com>
0006  */
0007 
0008 #include <linux/irq.h>
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/err.h>
0012 #include <linux/hdmi.h>
0013 #include <linux/mfd/syscon.h>
0014 #include <linux/module.h>
0015 #include <linux/mutex.h>
0016 #include <linux/of_device.h>
0017 
0018 #include <drm/drm_atomic_helper.h>
0019 #include <drm/drm_edid.h>
0020 #include <drm/drm_of.h>
0021 #include <drm/drm_probe_helper.h>
0022 #include <drm/drm_simple_kms_helper.h>
0023 
0024 #include "rockchip_drm_drv.h"
0025 #include "rockchip_drm_vop.h"
0026 
0027 #include "inno_hdmi.h"
0028 
0029 struct hdmi_data_info {
0030     int vic;
0031     bool sink_has_audio;
0032     unsigned int enc_in_format;
0033     unsigned int enc_out_format;
0034     unsigned int colorimetry;
0035 };
0036 
0037 struct inno_hdmi_i2c {
0038     struct i2c_adapter adap;
0039 
0040     u8 ddc_addr;
0041     u8 segment_addr;
0042 
0043     struct mutex lock;
0044     struct completion cmp;
0045 };
0046 
0047 struct inno_hdmi {
0048     struct device *dev;
0049     struct drm_device *drm_dev;
0050 
0051     int irq;
0052     struct clk *pclk;
0053     void __iomem *regs;
0054 
0055     struct drm_connector    connector;
0056     struct rockchip_encoder encoder;
0057 
0058     struct inno_hdmi_i2c *i2c;
0059     struct i2c_adapter *ddc;
0060 
0061     unsigned int tmds_rate;
0062 
0063     struct hdmi_data_info   hdmi_data;
0064     struct drm_display_mode previous_mode;
0065 };
0066 
0067 static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
0068 {
0069     struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
0070 
0071     return container_of(rkencoder, struct inno_hdmi, encoder);
0072 }
0073 
0074 static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector)
0075 {
0076     return container_of(connector, struct inno_hdmi, connector);
0077 }
0078 
0079 enum {
0080     CSC_ITU601_16_235_TO_RGB_0_255_8BIT,
0081     CSC_ITU601_0_255_TO_RGB_0_255_8BIT,
0082     CSC_ITU709_16_235_TO_RGB_0_255_8BIT,
0083     CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
0084     CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
0085     CSC_RGB_0_255_TO_RGB_16_235_8BIT,
0086 };
0087 
0088 static const char coeff_csc[][24] = {
0089     /*
0090      * YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]):
0091      *   R = 1.164*Y + 1.596*V - 204
0092      *   G = 1.164*Y - 0.391*U - 0.813*V + 154
0093      *   B = 1.164*Y + 2.018*U - 258
0094      */
0095     {
0096         0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc,
0097         0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a,
0098         0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02
0099     },
0100     /*
0101      * YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]):
0102      *   R = Y + 1.402*V - 248
0103      *   G = Y - 0.344*U - 0.714*V + 135
0104      *   B = Y + 1.772*U - 227
0105      */
0106     {
0107         0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8,
0108         0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87,
0109         0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3
0110     },
0111     /*
0112      * YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]):
0113      *   R = 1.164*Y + 1.793*V - 248
0114      *   G = 1.164*Y - 0.213*U - 0.534*V + 77
0115      *   B = 1.164*Y + 2.115*U - 289
0116      */
0117     {
0118         0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8,
0119         0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d,
0120         0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21
0121     },
0122 
0123     /*
0124      * RGB2YUV:601 SD mode:
0125      *   Cb = -0.291G - 0.148R + 0.439B + 128
0126      *   Y  = 0.504G  + 0.257R + 0.098B + 16
0127      *   Cr = -0.368G + 0.439R - 0.071B + 128
0128      */
0129     {
0130         0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
0131         0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
0132         0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
0133     },
0134     /*
0135      * RGB2YUV:709 HD mode:
0136      *   Cb = - 0.338G - 0.101R + 0.439B + 128
0137      *   Y  = 0.614G   + 0.183R + 0.062B + 16
0138      *   Cr = - 0.399G + 0.439R - 0.040B + 128
0139      */
0140     {
0141         0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
0142         0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
0143         0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
0144     },
0145     /*
0146      * RGB[0:255]2RGB[16:235]:
0147      *   R' = R x (235-16)/255 + 16;
0148      *   G' = G x (235-16)/255 + 16;
0149      *   B' = B x (235-16)/255 + 16;
0150      */
0151     {
0152         0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
0153         0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0154         0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
0155     },
0156 };
0157 
0158 static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
0159 {
0160     return readl_relaxed(hdmi->regs + (offset) * 0x04);
0161 }
0162 
0163 static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val)
0164 {
0165     writel_relaxed(val, hdmi->regs + (offset) * 0x04);
0166 }
0167 
0168 static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset,
0169                  u32 msk, u32 val)
0170 {
0171     u8 temp = hdmi_readb(hdmi, offset) & ~msk;
0172 
0173     temp |= val & msk;
0174     hdmi_writeb(hdmi, offset, temp);
0175 }
0176 
0177 static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi)
0178 {
0179     int ddc_bus_freq;
0180 
0181     ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE;
0182 
0183     hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
0184     hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
0185 
0186     /* Clear the EDID interrupt flag and mute the interrupt */
0187     hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
0188     hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
0189 }
0190 
0191 static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
0192 {
0193     if (enable)
0194         hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON);
0195     else
0196         hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
0197 }
0198 
0199 static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
0200 {
0201     switch (mode) {
0202     case NORMAL:
0203         inno_hdmi_sys_power(hdmi, false);
0204 
0205         hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f);
0206         hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb);
0207 
0208         hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
0209         hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
0210         hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
0211         hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
0212         hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
0213         hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
0214 
0215         inno_hdmi_sys_power(hdmi, true);
0216         break;
0217 
0218     case LOWER_PWR:
0219         inno_hdmi_sys_power(hdmi, false);
0220         hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
0221         hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
0222         hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
0223         hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
0224 
0225         break;
0226 
0227     default:
0228         DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode);
0229     }
0230 }
0231 
0232 static void inno_hdmi_reset(struct inno_hdmi *hdmi)
0233 {
0234     u32 val;
0235     u32 msk;
0236 
0237     hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
0238     udelay(100);
0239 
0240     hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
0241     udelay(100);
0242 
0243     msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
0244     val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
0245     hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
0246 
0247     inno_hdmi_set_pwr_mode(hdmi, NORMAL);
0248 }
0249 
0250 static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc,
0251                   union hdmi_infoframe *frame, u32 frame_index,
0252                   u32 mask, u32 disable, u32 enable)
0253 {
0254     if (mask)
0255         hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable);
0256 
0257     hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index);
0258 
0259     if (setup_rc >= 0) {
0260         u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
0261         ssize_t rc, i;
0262 
0263         rc = hdmi_infoframe_pack(frame, packed_frame,
0264                      sizeof(packed_frame));
0265         if (rc < 0)
0266             return rc;
0267 
0268         for (i = 0; i < rc; i++)
0269             hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
0270                     packed_frame[i]);
0271 
0272         if (mask)
0273             hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable);
0274     }
0275 
0276     return setup_rc;
0277 }
0278 
0279 static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi,
0280                       struct drm_display_mode *mode)
0281 {
0282     union hdmi_infoframe frame;
0283     int rc;
0284 
0285     rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
0286                              &hdmi->connector,
0287                              mode);
0288 
0289     return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI,
0290         m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1));
0291 }
0292 
0293 static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
0294                       struct drm_display_mode *mode)
0295 {
0296     union hdmi_infoframe frame;
0297     int rc;
0298 
0299     rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
0300                               &hdmi->connector,
0301                               mode);
0302 
0303     if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
0304         frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
0305     else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
0306         frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
0307     else
0308         frame.avi.colorspace = HDMI_COLORSPACE_RGB;
0309 
0310     return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
0311 }
0312 
0313 static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
0314 {
0315     struct hdmi_data_info *data = &hdmi->hdmi_data;
0316     int c0_c2_change = 0;
0317     int csc_enable = 0;
0318     int csc_mode = 0;
0319     int auto_csc = 0;
0320     int value;
0321     int i;
0322 
0323     /* Input video mode is SDR RGB24bit, data enable signal from external */
0324     hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
0325             v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
0326 
0327     /* Input color hardcode to RGB, and output color hardcode to RGB888 */
0328     value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
0329         v_VIDEO_OUTPUT_COLOR(0) |
0330         v_VIDEO_INPUT_CSP(0);
0331     hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
0332 
0333     if (data->enc_in_format == data->enc_out_format) {
0334         if ((data->enc_in_format == HDMI_COLORSPACE_RGB) ||
0335             (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) {
0336             value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
0337             hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
0338 
0339             hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
0340                   m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
0341                   v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
0342                   v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
0343             return 0;
0344         }
0345     }
0346 
0347     if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) {
0348         if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
0349             (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
0350             csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
0351             auto_csc = AUTO_CSC_DISABLE;
0352             c0_c2_change = C0_C2_CHANGE_DISABLE;
0353             csc_enable = v_CSC_ENABLE;
0354         } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
0355                (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
0356             csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
0357             auto_csc = AUTO_CSC_ENABLE;
0358             c0_c2_change = C0_C2_CHANGE_DISABLE;
0359             csc_enable = v_CSC_DISABLE;
0360         }
0361     } else {
0362         if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
0363             (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
0364             csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
0365             auto_csc = AUTO_CSC_DISABLE;
0366             c0_c2_change = C0_C2_CHANGE_DISABLE;
0367             csc_enable = v_CSC_ENABLE;
0368         } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
0369                (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
0370             csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT;
0371             auto_csc = AUTO_CSC_ENABLE;
0372             c0_c2_change = C0_C2_CHANGE_DISABLE;
0373             csc_enable = v_CSC_DISABLE;
0374         }
0375     }
0376 
0377     for (i = 0; i < 24; i++)
0378         hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
0379                 coeff_csc[csc_mode][i]);
0380 
0381     value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
0382     hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
0383     hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
0384           m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
0385           v_VIDEO_C0_C2_SWAP(c0_c2_change));
0386 
0387     return 0;
0388 }
0389 
0390 static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
0391                      struct drm_display_mode *mode)
0392 {
0393     int value;
0394 
0395     /* Set detail external video timing polarity and interlace mode */
0396     value = v_EXTERANL_VIDEO(1);
0397     value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
0398          v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
0399     value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
0400          v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
0401     value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
0402          v_INETLACE(1) : v_INETLACE(0);
0403     hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
0404 
0405     /* Set detail external video timing */
0406     value = mode->htotal;
0407     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
0408     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
0409 
0410     value = mode->htotal - mode->hdisplay;
0411     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
0412     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
0413 
0414     value = mode->hsync_start - mode->hdisplay;
0415     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
0416     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
0417 
0418     value = mode->hsync_end - mode->hsync_start;
0419     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
0420     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
0421 
0422     value = mode->vtotal;
0423     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
0424     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
0425 
0426     value = mode->vtotal - mode->vdisplay;
0427     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
0428 
0429     value = mode->vsync_start - mode->vdisplay;
0430     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
0431 
0432     value = mode->vsync_end - mode->vsync_start;
0433     hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
0434 
0435     hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e);
0436     hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
0437     hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
0438 
0439     return 0;
0440 }
0441 
0442 static int inno_hdmi_setup(struct inno_hdmi *hdmi,
0443                struct drm_display_mode *mode)
0444 {
0445     struct drm_display_info *display = &hdmi->connector.display_info;
0446 
0447     hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
0448 
0449     hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB;
0450     hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
0451 
0452     if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) ||
0453         (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) ||
0454         (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) ||
0455         (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18))
0456         hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
0457     else
0458         hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
0459 
0460     /* Mute video and audio output */
0461     hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
0462           v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
0463 
0464     /* Set HDMI Mode */
0465     hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
0466             v_HDMI_DVI(display->is_hdmi));
0467 
0468     inno_hdmi_config_video_timing(hdmi, mode);
0469 
0470     inno_hdmi_config_video_csc(hdmi);
0471 
0472     if (display->is_hdmi) {
0473         inno_hdmi_config_video_avi(hdmi, mode);
0474         inno_hdmi_config_video_vsi(hdmi, mode);
0475     }
0476 
0477     /*
0478      * When IP controller have configured to an accurate video
0479      * timing, then the TMDS clock source would be switched to
0480      * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
0481      * clock rate, and reconfigure the DDC clock.
0482      */
0483     hdmi->tmds_rate = mode->clock * 1000;
0484     inno_hdmi_i2c_init(hdmi);
0485 
0486     /* Unmute video and audio output */
0487     hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
0488           v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
0489 
0490     return 0;
0491 }
0492 
0493 static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
0494                        struct drm_display_mode *mode,
0495                        struct drm_display_mode *adj_mode)
0496 {
0497     struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
0498 
0499     inno_hdmi_setup(hdmi, adj_mode);
0500 
0501     /* Store the display mode for plugin/DPMS poweron events */
0502     memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
0503 }
0504 
0505 static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
0506 {
0507     struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
0508 
0509     inno_hdmi_set_pwr_mode(hdmi, NORMAL);
0510 }
0511 
0512 static void inno_hdmi_encoder_disable(struct drm_encoder *encoder)
0513 {
0514     struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
0515 
0516     inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
0517 }
0518 
0519 static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
0520                      const struct drm_display_mode *mode,
0521                      struct drm_display_mode *adj_mode)
0522 {
0523     return true;
0524 }
0525 
0526 static int
0527 inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
0528                    struct drm_crtc_state *crtc_state,
0529                    struct drm_connector_state *conn_state)
0530 {
0531     struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
0532 
0533     s->output_mode = ROCKCHIP_OUT_MODE_P888;
0534     s->output_type = DRM_MODE_CONNECTOR_HDMIA;
0535 
0536     return 0;
0537 }
0538 
0539 static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = {
0540     .enable     = inno_hdmi_encoder_enable,
0541     .disable    = inno_hdmi_encoder_disable,
0542     .mode_fixup = inno_hdmi_encoder_mode_fixup,
0543     .mode_set   = inno_hdmi_encoder_mode_set,
0544     .atomic_check = inno_hdmi_encoder_atomic_check,
0545 };
0546 
0547 static enum drm_connector_status
0548 inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
0549 {
0550     struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
0551 
0552     return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
0553         connector_status_connected : connector_status_disconnected;
0554 }
0555 
0556 static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
0557 {
0558     struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
0559     struct edid *edid;
0560     int ret = 0;
0561 
0562     if (!hdmi->ddc)
0563         return 0;
0564 
0565     edid = drm_get_edid(connector, hdmi->ddc);
0566     if (edid) {
0567         hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
0568         drm_connector_update_edid_property(connector, edid);
0569         ret = drm_add_edid_modes(connector, edid);
0570         kfree(edid);
0571     }
0572 
0573     return ret;
0574 }
0575 
0576 static enum drm_mode_status
0577 inno_hdmi_connector_mode_valid(struct drm_connector *connector,
0578                    struct drm_display_mode *mode)
0579 {
0580     return MODE_OK;
0581 }
0582 
0583 static int
0584 inno_hdmi_probe_single_connector_modes(struct drm_connector *connector,
0585                        uint32_t maxX, uint32_t maxY)
0586 {
0587     return drm_helper_probe_single_connector_modes(connector, 1920, 1080);
0588 }
0589 
0590 static void inno_hdmi_connector_destroy(struct drm_connector *connector)
0591 {
0592     drm_connector_unregister(connector);
0593     drm_connector_cleanup(connector);
0594 }
0595 
0596 static const struct drm_connector_funcs inno_hdmi_connector_funcs = {
0597     .fill_modes = inno_hdmi_probe_single_connector_modes,
0598     .detect = inno_hdmi_connector_detect,
0599     .destroy = inno_hdmi_connector_destroy,
0600     .reset = drm_atomic_helper_connector_reset,
0601     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0602     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0603 };
0604 
0605 static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
0606     .get_modes = inno_hdmi_connector_get_modes,
0607     .mode_valid = inno_hdmi_connector_mode_valid,
0608 };
0609 
0610 static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
0611 {
0612     struct drm_encoder *encoder = &hdmi->encoder.encoder;
0613     struct device *dev = hdmi->dev;
0614 
0615     encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
0616 
0617     /*
0618      * If we failed to find the CRTC(s) which this encoder is
0619      * supposed to be connected to, it's because the CRTC has
0620      * not been registered yet.  Defer probing, and hope that
0621      * the required CRTC is added later.
0622      */
0623     if (encoder->possible_crtcs == 0)
0624         return -EPROBE_DEFER;
0625 
0626     drm_encoder_helper_add(encoder, &inno_hdmi_encoder_helper_funcs);
0627     drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
0628 
0629     hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
0630 
0631     drm_connector_helper_add(&hdmi->connector,
0632                  &inno_hdmi_connector_helper_funcs);
0633     drm_connector_init_with_ddc(drm, &hdmi->connector,
0634                     &inno_hdmi_connector_funcs,
0635                     DRM_MODE_CONNECTOR_HDMIA,
0636                     hdmi->ddc);
0637 
0638     drm_connector_attach_encoder(&hdmi->connector, encoder);
0639 
0640     return 0;
0641 }
0642 
0643 static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi)
0644 {
0645     struct inno_hdmi_i2c *i2c = hdmi->i2c;
0646     u8 stat;
0647 
0648     stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1);
0649     if (!(stat & m_INT_EDID_READY))
0650         return IRQ_NONE;
0651 
0652     /* Clear HDMI EDID interrupt flag */
0653     hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
0654 
0655     complete(&i2c->cmp);
0656 
0657     return IRQ_HANDLED;
0658 }
0659 
0660 static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id)
0661 {
0662     struct inno_hdmi *hdmi = dev_id;
0663     irqreturn_t ret = IRQ_NONE;
0664     u8 interrupt;
0665 
0666     if (hdmi->i2c)
0667         ret = inno_hdmi_i2c_irq(hdmi);
0668 
0669     interrupt = hdmi_readb(hdmi, HDMI_STATUS);
0670     if (interrupt & m_INT_HOTPLUG) {
0671         hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG);
0672         ret = IRQ_WAKE_THREAD;
0673     }
0674 
0675     return ret;
0676 }
0677 
0678 static irqreturn_t inno_hdmi_irq(int irq, void *dev_id)
0679 {
0680     struct inno_hdmi *hdmi = dev_id;
0681 
0682     drm_helper_hpd_irq_event(hdmi->connector.dev);
0683 
0684     return IRQ_HANDLED;
0685 }
0686 
0687 static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
0688 {
0689     int length = msgs->len;
0690     u8 *buf = msgs->buf;
0691     int ret;
0692 
0693     ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10);
0694     if (!ret)
0695         return -EAGAIN;
0696 
0697     while (length--)
0698         *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR);
0699 
0700     return 0;
0701 }
0702 
0703 static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
0704 {
0705     /*
0706      * The DDC module only support read EDID message, so
0707      * we assume that each word write to this i2c adapter
0708      * should be the offset of EDID word address.
0709      */
0710     if ((msgs->len != 1) ||
0711         ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR)))
0712         return -EINVAL;
0713 
0714     reinit_completion(&hdmi->i2c->cmp);
0715 
0716     if (msgs->addr == DDC_SEGMENT_ADDR)
0717         hdmi->i2c->segment_addr = msgs->buf[0];
0718     if (msgs->addr == DDC_ADDR)
0719         hdmi->i2c->ddc_addr = msgs->buf[0];
0720 
0721     /* Set edid fifo first addr */
0722     hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00);
0723 
0724     /* Set edid word address 0x00/0x80 */
0725     hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
0726 
0727     /* Set edid segment pointer */
0728     hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr);
0729 
0730     return 0;
0731 }
0732 
0733 static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap,
0734                   struct i2c_msg *msgs, int num)
0735 {
0736     struct inno_hdmi *hdmi = i2c_get_adapdata(adap);
0737     struct inno_hdmi_i2c *i2c = hdmi->i2c;
0738     int i, ret = 0;
0739 
0740     mutex_lock(&i2c->lock);
0741 
0742     /* Clear the EDID interrupt flag and unmute the interrupt */
0743     hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY);
0744     hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
0745 
0746     for (i = 0; i < num; i++) {
0747         DRM_DEV_DEBUG(hdmi->dev,
0748                   "xfer: num: %d/%d, len: %d, flags: %#x\n",
0749                   i + 1, num, msgs[i].len, msgs[i].flags);
0750 
0751         if (msgs[i].flags & I2C_M_RD)
0752             ret = inno_hdmi_i2c_read(hdmi, &msgs[i]);
0753         else
0754             ret = inno_hdmi_i2c_write(hdmi, &msgs[i]);
0755 
0756         if (ret < 0)
0757             break;
0758     }
0759 
0760     if (!ret)
0761         ret = num;
0762 
0763     /* Mute HDMI EDID interrupt */
0764     hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
0765 
0766     mutex_unlock(&i2c->lock);
0767 
0768     return ret;
0769 }
0770 
0771 static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter)
0772 {
0773     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
0774 }
0775 
0776 static const struct i2c_algorithm inno_hdmi_algorithm = {
0777     .master_xfer    = inno_hdmi_i2c_xfer,
0778     .functionality  = inno_hdmi_i2c_func,
0779 };
0780 
0781 static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
0782 {
0783     struct i2c_adapter *adap;
0784     struct inno_hdmi_i2c *i2c;
0785     int ret;
0786 
0787     i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
0788     if (!i2c)
0789         return ERR_PTR(-ENOMEM);
0790 
0791     mutex_init(&i2c->lock);
0792     init_completion(&i2c->cmp);
0793 
0794     adap = &i2c->adap;
0795     adap->class = I2C_CLASS_DDC;
0796     adap->owner = THIS_MODULE;
0797     adap->dev.parent = hdmi->dev;
0798     adap->dev.of_node = hdmi->dev->of_node;
0799     adap->algo = &inno_hdmi_algorithm;
0800     strlcpy(adap->name, "Inno HDMI", sizeof(adap->name));
0801     i2c_set_adapdata(adap, hdmi);
0802 
0803     ret = i2c_add_adapter(adap);
0804     if (ret) {
0805         dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
0806         devm_kfree(hdmi->dev, i2c);
0807         return ERR_PTR(ret);
0808     }
0809 
0810     hdmi->i2c = i2c;
0811 
0812     DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
0813 
0814     return adap;
0815 }
0816 
0817 static int inno_hdmi_bind(struct device *dev, struct device *master,
0818                  void *data)
0819 {
0820     struct platform_device *pdev = to_platform_device(dev);
0821     struct drm_device *drm = data;
0822     struct inno_hdmi *hdmi;
0823     int irq;
0824     int ret;
0825 
0826     hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
0827     if (!hdmi)
0828         return -ENOMEM;
0829 
0830     hdmi->dev = dev;
0831     hdmi->drm_dev = drm;
0832 
0833     hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
0834     if (IS_ERR(hdmi->regs))
0835         return PTR_ERR(hdmi->regs);
0836 
0837     hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
0838     if (IS_ERR(hdmi->pclk)) {
0839         DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n");
0840         return PTR_ERR(hdmi->pclk);
0841     }
0842 
0843     ret = clk_prepare_enable(hdmi->pclk);
0844     if (ret) {
0845         DRM_DEV_ERROR(hdmi->dev,
0846                   "Cannot enable HDMI pclk clock: %d\n", ret);
0847         return ret;
0848     }
0849 
0850     irq = platform_get_irq(pdev, 0);
0851     if (irq < 0) {
0852         ret = irq;
0853         goto err_disable_clk;
0854     }
0855 
0856     inno_hdmi_reset(hdmi);
0857 
0858     hdmi->ddc = inno_hdmi_i2c_adapter(hdmi);
0859     if (IS_ERR(hdmi->ddc)) {
0860         ret = PTR_ERR(hdmi->ddc);
0861         hdmi->ddc = NULL;
0862         goto err_disable_clk;
0863     }
0864 
0865     /*
0866      * When IP controller haven't configured to an accurate video
0867      * timing, then the TMDS clock source would be switched to
0868      * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate,
0869      * and reconfigure the DDC clock.
0870      */
0871     hdmi->tmds_rate = clk_get_rate(hdmi->pclk);
0872     inno_hdmi_i2c_init(hdmi);
0873 
0874     ret = inno_hdmi_register(drm, hdmi);
0875     if (ret)
0876         goto err_put_adapter;
0877 
0878     dev_set_drvdata(dev, hdmi);
0879 
0880     /* Unmute hotplug interrupt */
0881     hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
0882 
0883     ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
0884                     inno_hdmi_irq, IRQF_SHARED,
0885                     dev_name(dev), hdmi);
0886     if (ret < 0)
0887         goto err_cleanup_hdmi;
0888 
0889     return 0;
0890 err_cleanup_hdmi:
0891     hdmi->connector.funcs->destroy(&hdmi->connector);
0892     hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
0893 err_put_adapter:
0894     i2c_put_adapter(hdmi->ddc);
0895 err_disable_clk:
0896     clk_disable_unprepare(hdmi->pclk);
0897     return ret;
0898 }
0899 
0900 static void inno_hdmi_unbind(struct device *dev, struct device *master,
0901                  void *data)
0902 {
0903     struct inno_hdmi *hdmi = dev_get_drvdata(dev);
0904 
0905     hdmi->connector.funcs->destroy(&hdmi->connector);
0906     hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
0907 
0908     i2c_put_adapter(hdmi->ddc);
0909     clk_disable_unprepare(hdmi->pclk);
0910 }
0911 
0912 static const struct component_ops inno_hdmi_ops = {
0913     .bind   = inno_hdmi_bind,
0914     .unbind = inno_hdmi_unbind,
0915 };
0916 
0917 static int inno_hdmi_probe(struct platform_device *pdev)
0918 {
0919     return component_add(&pdev->dev, &inno_hdmi_ops);
0920 }
0921 
0922 static int inno_hdmi_remove(struct platform_device *pdev)
0923 {
0924     component_del(&pdev->dev, &inno_hdmi_ops);
0925 
0926     return 0;
0927 }
0928 
0929 static const struct of_device_id inno_hdmi_dt_ids[] = {
0930     { .compatible = "rockchip,rk3036-inno-hdmi",
0931     },
0932     {},
0933 };
0934 MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
0935 
0936 struct platform_driver inno_hdmi_driver = {
0937     .probe  = inno_hdmi_probe,
0938     .remove = inno_hdmi_remove,
0939     .driver = {
0940         .name = "innohdmi-rockchip",
0941         .of_match_table = inno_hdmi_dt_ids,
0942     },
0943 };