Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2013 Red Hat
0004  * Author: Rob Clark <robdclark@gmail.com>
0005  */
0006 
0007 #include <linux/delay.h>
0008 #include <drm/drm_bridge_connector.h>
0009 #include <drm/drm_edid.h>
0010 
0011 #include "msm_kms.h"
0012 #include "hdmi.h"
0013 
0014 void msm_hdmi_bridge_destroy(struct drm_bridge *bridge)
0015 {
0016     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0017 
0018     msm_hdmi_hpd_disable(hdmi_bridge);
0019     drm_bridge_remove(bridge);
0020 }
0021 
0022 static void msm_hdmi_power_on(struct drm_bridge *bridge)
0023 {
0024     struct drm_device *dev = bridge->dev;
0025     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0026     struct hdmi *hdmi = hdmi_bridge->hdmi;
0027     const struct hdmi_platform_config *config = hdmi->config;
0028     int i, ret;
0029 
0030     pm_runtime_get_sync(&hdmi->pdev->dev);
0031 
0032     ret = regulator_bulk_enable(config->pwr_reg_cnt, hdmi->pwr_regs);
0033     if (ret)
0034         DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %d\n", ret);
0035 
0036     if (config->pwr_clk_cnt > 0) {
0037         DBG("pixclock: %lu", hdmi->pixclock);
0038         ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
0039         if (ret) {
0040             DRM_DEV_ERROR(dev->dev, "failed to set pixel clk: %s (%d)\n",
0041                     config->pwr_clk_names[0], ret);
0042         }
0043     }
0044 
0045     for (i = 0; i < config->pwr_clk_cnt; i++) {
0046         ret = clk_prepare_enable(hdmi->pwr_clks[i]);
0047         if (ret) {
0048             DRM_DEV_ERROR(dev->dev, "failed to enable pwr clk: %s (%d)\n",
0049                     config->pwr_clk_names[i], ret);
0050         }
0051     }
0052 }
0053 
0054 static void power_off(struct drm_bridge *bridge)
0055 {
0056     struct drm_device *dev = bridge->dev;
0057     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0058     struct hdmi *hdmi = hdmi_bridge->hdmi;
0059     const struct hdmi_platform_config *config = hdmi->config;
0060     int i, ret;
0061 
0062     /* TODO do we need to wait for final vblank somewhere before
0063      * cutting the clocks?
0064      */
0065     mdelay(16 + 4);
0066 
0067     for (i = 0; i < config->pwr_clk_cnt; i++)
0068         clk_disable_unprepare(hdmi->pwr_clks[i]);
0069 
0070     ret = regulator_bulk_disable(config->pwr_reg_cnt, hdmi->pwr_regs);
0071     if (ret)
0072         DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %d\n", ret);
0073 
0074     pm_runtime_put(&hdmi->pdev->dev);
0075 }
0076 
0077 #define AVI_IFRAME_LINE_NUMBER 1
0078 
0079 static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
0080 {
0081     struct drm_crtc *crtc = hdmi->encoder->crtc;
0082     const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
0083     union hdmi_infoframe frame;
0084     u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
0085     u32 val;
0086     int len;
0087 
0088     drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
0089                          hdmi->connector, mode);
0090 
0091     len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
0092     if (len < 0) {
0093         DRM_DEV_ERROR(&hdmi->pdev->dev,
0094             "failed to configure avi infoframe\n");
0095         return;
0096     }
0097 
0098     /*
0099      * the AVI_INFOx registers don't map exactly to how the AVI infoframes
0100      * are packed according to the spec. The checksum from the header is
0101      * written to the LSB byte of AVI_INFO0 and the version is written to
0102      * the third byte from the LSB of AVI_INFO3
0103      */
0104     hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
0105            buffer[3] |
0106            buffer[4] << 8 |
0107            buffer[5] << 16 |
0108            buffer[6] << 24);
0109 
0110     hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
0111            buffer[7] |
0112            buffer[8] << 8 |
0113            buffer[9] << 16 |
0114            buffer[10] << 24);
0115 
0116     hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
0117            buffer[11] |
0118            buffer[12] << 8 |
0119            buffer[13] << 16 |
0120            buffer[14] << 24);
0121 
0122     hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
0123            buffer[15] |
0124            buffer[16] << 8 |
0125            buffer[1] << 24);
0126 
0127     hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
0128            HDMI_INFOFRAME_CTRL0_AVI_SEND |
0129            HDMI_INFOFRAME_CTRL0_AVI_CONT);
0130 
0131     val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
0132     val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
0133     val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
0134     hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
0135 }
0136 
0137 static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
0138 {
0139     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0140     struct hdmi *hdmi = hdmi_bridge->hdmi;
0141     struct hdmi_phy *phy = hdmi->phy;
0142 
0143     DBG("power up");
0144 
0145     if (!hdmi->power_on) {
0146         msm_hdmi_phy_resource_enable(phy);
0147         msm_hdmi_power_on(bridge);
0148         hdmi->power_on = true;
0149         if (hdmi->hdmi_mode) {
0150             msm_hdmi_config_avi_infoframe(hdmi);
0151             msm_hdmi_audio_update(hdmi);
0152         }
0153     }
0154 
0155     msm_hdmi_phy_powerup(phy, hdmi->pixclock);
0156 
0157     msm_hdmi_set_mode(hdmi, true);
0158 
0159     if (hdmi->hdcp_ctrl)
0160         msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
0161 }
0162 
0163 static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge)
0164 {
0165     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0166     struct hdmi *hdmi = hdmi_bridge->hdmi;
0167     struct hdmi_phy *phy = hdmi->phy;
0168 
0169     if (hdmi->hdcp_ctrl)
0170         msm_hdmi_hdcp_off(hdmi->hdcp_ctrl);
0171 
0172     DBG("power down");
0173     msm_hdmi_set_mode(hdmi, false);
0174 
0175     msm_hdmi_phy_powerdown(phy);
0176 
0177     if (hdmi->power_on) {
0178         power_off(bridge);
0179         hdmi->power_on = false;
0180         if (hdmi->hdmi_mode)
0181             msm_hdmi_audio_update(hdmi);
0182         msm_hdmi_phy_resource_disable(phy);
0183     }
0184 }
0185 
0186 static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
0187          const struct drm_display_mode *mode,
0188          const struct drm_display_mode *adjusted_mode)
0189 {
0190     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0191     struct hdmi *hdmi = hdmi_bridge->hdmi;
0192     int hstart, hend, vstart, vend;
0193     uint32_t frame_ctrl;
0194 
0195     mode = adjusted_mode;
0196 
0197     hdmi->pixclock = mode->clock * 1000;
0198 
0199     hstart = mode->htotal - mode->hsync_start;
0200     hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
0201 
0202     vstart = mode->vtotal - mode->vsync_start - 1;
0203     vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
0204 
0205     DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
0206             mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
0207 
0208     hdmi_write(hdmi, REG_HDMI_TOTAL,
0209             HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
0210             HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
0211 
0212     hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
0213             HDMI_ACTIVE_HSYNC_START(hstart) |
0214             HDMI_ACTIVE_HSYNC_END(hend));
0215     hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
0216             HDMI_ACTIVE_VSYNC_START(vstart) |
0217             HDMI_ACTIVE_VSYNC_END(vend));
0218 
0219     if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
0220         hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
0221                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
0222         hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
0223                 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
0224                 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
0225     } else {
0226         hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
0227                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
0228         hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
0229                 HDMI_VSYNC_ACTIVE_F2_START(0) |
0230                 HDMI_VSYNC_ACTIVE_F2_END(0));
0231     }
0232 
0233     frame_ctrl = 0;
0234     if (mode->flags & DRM_MODE_FLAG_NHSYNC)
0235         frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
0236     if (mode->flags & DRM_MODE_FLAG_NVSYNC)
0237         frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
0238     if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0239         frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
0240     DBG("frame_ctrl=%08x", frame_ctrl);
0241     hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
0242 
0243     if (hdmi->hdmi_mode)
0244         msm_hdmi_audio_update(hdmi);
0245 }
0246 
0247 static struct edid *msm_hdmi_bridge_get_edid(struct drm_bridge *bridge,
0248         struct drm_connector *connector)
0249 {
0250     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0251     struct hdmi *hdmi = hdmi_bridge->hdmi;
0252     struct edid *edid;
0253     uint32_t hdmi_ctrl;
0254 
0255     hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
0256     hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
0257 
0258     edid = drm_get_edid(connector, hdmi->i2c);
0259 
0260     hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
0261 
0262     hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
0263 
0264     return edid;
0265 }
0266 
0267 static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
0268         const struct drm_display_info *info,
0269         const struct drm_display_mode *mode)
0270 {
0271     struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
0272     struct hdmi *hdmi = hdmi_bridge->hdmi;
0273     const struct hdmi_platform_config *config = hdmi->config;
0274     struct msm_drm_private *priv = bridge->dev->dev_private;
0275     struct msm_kms *kms = priv->kms;
0276     long actual, requested;
0277 
0278     requested = 1000 * mode->clock;
0279 
0280     /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
0281      * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
0282      * instead):
0283      */
0284     if (kms->funcs->round_pixclk)
0285         actual = kms->funcs->round_pixclk(kms,
0286             requested, hdmi_bridge->hdmi->encoder);
0287     else if (config->pwr_clk_cnt > 0)
0288         actual = clk_round_rate(hdmi->pwr_clks[0], requested);
0289     else
0290         actual = requested;
0291 
0292     DBG("requested=%ld, actual=%ld", requested, actual);
0293 
0294     if (actual != requested)
0295         return MODE_CLOCK_RANGE;
0296 
0297     return 0;
0298 }
0299 
0300 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
0301         .pre_enable = msm_hdmi_bridge_pre_enable,
0302         .post_disable = msm_hdmi_bridge_post_disable,
0303         .mode_set = msm_hdmi_bridge_mode_set,
0304         .mode_valid = msm_hdmi_bridge_mode_valid,
0305         .get_edid = msm_hdmi_bridge_get_edid,
0306         .detect = msm_hdmi_bridge_detect,
0307 };
0308 
0309 static void
0310 msm_hdmi_hotplug_work(struct work_struct *work)
0311 {
0312     struct hdmi_bridge *hdmi_bridge =
0313         container_of(work, struct hdmi_bridge, hpd_work);
0314     struct drm_bridge *bridge = &hdmi_bridge->base;
0315 
0316     drm_bridge_hpd_notify(bridge, drm_bridge_detect(bridge));
0317 }
0318 
0319 /* initialize bridge */
0320 struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
0321 {
0322     struct drm_bridge *bridge = NULL;
0323     struct hdmi_bridge *hdmi_bridge;
0324     int ret;
0325 
0326     hdmi_bridge = devm_kzalloc(hdmi->dev->dev,
0327             sizeof(*hdmi_bridge), GFP_KERNEL);
0328     if (!hdmi_bridge) {
0329         ret = -ENOMEM;
0330         goto fail;
0331     }
0332 
0333     hdmi_bridge->hdmi = hdmi;
0334     INIT_WORK(&hdmi_bridge->hpd_work, msm_hdmi_hotplug_work);
0335 
0336     bridge = &hdmi_bridge->base;
0337     bridge->funcs = &msm_hdmi_bridge_funcs;
0338     bridge->ddc = hdmi->i2c;
0339     bridge->type = DRM_MODE_CONNECTOR_HDMIA;
0340     bridge->ops = DRM_BRIDGE_OP_HPD |
0341         DRM_BRIDGE_OP_DETECT |
0342         DRM_BRIDGE_OP_EDID;
0343 
0344     drm_bridge_add(bridge);
0345 
0346     ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0347     if (ret)
0348         goto fail;
0349 
0350     return bridge;
0351 
0352 fail:
0353     if (bridge)
0354         msm_hdmi_bridge_destroy(bridge);
0355 
0356     return ERR_PTR(ret);
0357 }