mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 09:59:32 +00:00
drm/msm: convert to drm_bridge
Drop the msm_connector base class, and special calls to base class methods from the encoder, and use instead drm_bridge. This allows for a cleaner division between the hdmi (and in future dsi) blocks, from the mdp block. Signed-off-by: Rob Clark <robdclark@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
3b336ec4c5
commit
a3376e3ec8
10 changed files with 274 additions and 260 deletions
|
@ -7,6 +7,7 @@ msm-y := \
|
|||
adreno/adreno_gpu.o \
|
||||
adreno/a3xx_gpu.o \
|
||||
hdmi/hdmi.o \
|
||||
hdmi/hdmi_bridge.o \
|
||||
hdmi/hdmi_connector.o \
|
||||
hdmi/hdmi_i2c.o \
|
||||
hdmi/hdmi_phy_8960.o \
|
||||
|
@ -17,7 +18,6 @@ msm-y := \
|
|||
mdp4/mdp4_irq.o \
|
||||
mdp4/mdp4_kms.o \
|
||||
mdp4/mdp4_plane.o \
|
||||
msm_connector.o \
|
||||
msm_drv.o \
|
||||
msm_fb.o \
|
||||
msm_gem.o \
|
||||
|
|
|
@ -56,8 +56,9 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void hdmi_destroy(struct hdmi *hdmi)
|
||||
void hdmi_destroy(struct kref *kref)
|
||||
{
|
||||
struct hdmi *hdmi = container_of(kref, struct hdmi, refcount);
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
|
||||
if (phy)
|
||||
|
@ -70,9 +71,10 @@ void hdmi_destroy(struct hdmi *hdmi)
|
|||
}
|
||||
|
||||
/* initialize connector */
|
||||
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
||||
struct drm_connector *connector)
|
||||
int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
|
||||
{
|
||||
struct hdmi *hdmi = NULL;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct platform_device *pdev = hdmi_pdev;
|
||||
struct hdmi_platform_config *config;
|
||||
int ret;
|
||||
|
@ -85,11 +87,19 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
|||
|
||||
config = pdev->dev.platform_data;
|
||||
|
||||
hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
kref_init(&hdmi->refcount);
|
||||
|
||||
get_device(&pdev->dev);
|
||||
|
||||
hdmi->dev = dev;
|
||||
hdmi->pdev = pdev;
|
||||
hdmi->connector = connector;
|
||||
hdmi->encoder = encoder;
|
||||
|
||||
/* not sure about which phy maps to which msm.. probably I miss some */
|
||||
if (config->phy_init)
|
||||
|
@ -152,6 +162,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->bridge = hdmi_bridge_init(hdmi);
|
||||
if (IS_ERR(hdmi->bridge)) {
|
||||
ret = PTR_ERR(hdmi->bridge);
|
||||
dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
|
||||
hdmi->bridge = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->connector = hdmi_connector_init(hdmi);
|
||||
if (IS_ERR(hdmi->connector)) {
|
||||
ret = PTR_ERR(hdmi->connector);
|
||||
dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
|
||||
hdmi->connector = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi->irq = platform_get_irq(pdev, 0);
|
||||
if (hdmi->irq < 0) {
|
||||
ret = hdmi->irq;
|
||||
|
@ -168,11 +194,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
encoder->bridge = hdmi->bridge;
|
||||
|
||||
priv->bridges[priv->num_bridges++] = hdmi->bridge;
|
||||
priv->connectors[priv->num_connectors++] = hdmi->connector;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (hdmi)
|
||||
hdmi_destroy(hdmi);
|
||||
if (hdmi) {
|
||||
/* bridge/connector are normally destroyed by drm: */
|
||||
if (hdmi->bridge)
|
||||
hdmi->bridge->funcs->destroy(hdmi->bridge);
|
||||
if (hdmi->connector)
|
||||
hdmi->connector->funcs->destroy(hdmi->connector);
|
||||
hdmi_destroy(&hdmi->refcount);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
struct hdmi_phy;
|
||||
|
||||
struct hdmi {
|
||||
struct kref refcount;
|
||||
|
||||
struct drm_device *dev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
|
@ -45,6 +47,10 @@ struct hdmi {
|
|||
struct hdmi_phy *phy;
|
||||
struct i2c_adapter *i2c;
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
/* the encoder we are hooked to (outside of hdmi block) */
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
bool hdmi_mode; /* are we in hdmi mode? */
|
||||
|
||||
|
@ -58,9 +64,7 @@ struct hdmi_platform_config {
|
|||
};
|
||||
|
||||
void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
|
||||
void hdmi_destroy(struct hdmi *hdmi);
|
||||
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
|
||||
struct drm_connector *connector);
|
||||
void hdmi_destroy(struct kref *kref);
|
||||
|
||||
static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data)
|
||||
{
|
||||
|
@ -72,6 +76,17 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
|
|||
return msm_readl(hdmi->mmio + reg);
|
||||
}
|
||||
|
||||
static inline struct hdmi * hdmi_reference(struct hdmi *hdmi)
|
||||
{
|
||||
kref_get(&hdmi->refcount);
|
||||
return hdmi;
|
||||
}
|
||||
|
||||
static inline void hdmi_unreference(struct hdmi *hdmi)
|
||||
{
|
||||
kref_put(&hdmi->refcount, hdmi_destroy);
|
||||
}
|
||||
|
||||
/*
|
||||
* The phy appears to be different, for example between 8960 and 8x60,
|
||||
* so split the phy related functions out and load the correct one at
|
||||
|
@ -89,17 +104,21 @@ struct hdmi_phy {
|
|||
const struct hdmi_phy_funcs *funcs;
|
||||
};
|
||||
|
||||
/*
|
||||
* phy can be different on different generations:
|
||||
*/
|
||||
struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
|
||||
struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
|
||||
|
||||
/*
|
||||
* hdmi bridge:
|
||||
*/
|
||||
|
||||
struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
|
||||
|
||||
/*
|
||||
* hdmi connector:
|
||||
*/
|
||||
|
||||
void hdmi_connector_irq(struct drm_connector *connector);
|
||||
struct drm_connector *hdmi_connector_init(struct hdmi *hdmi);
|
||||
|
||||
/*
|
||||
* i2c adapter for ddc:
|
||||
|
|
167
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
Normal file
167
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hdmi.h"
|
||||
|
||||
struct hdmi_bridge {
|
||||
struct drm_bridge base;
|
||||
|
||||
struct hdmi *hdmi;
|
||||
|
||||
unsigned long int pixclock;
|
||||
};
|
||||
#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
|
||||
|
||||
static void hdmi_bridge_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
hdmi_unreference(hdmi_bridge->hdmi);
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(hdmi_bridge);
|
||||
}
|
||||
|
||||
static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
|
||||
DBG("power up");
|
||||
phy->funcs->powerup(phy, hdmi_bridge->pixclock);
|
||||
hdmi_set_mode(hdmi, true);
|
||||
}
|
||||
|
||||
static void hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
static void hdmi_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
|
||||
DBG("power down");
|
||||
hdmi_set_mode(hdmi, false);
|
||||
phy->funcs->powerdown(phy);
|
||||
}
|
||||
|
||||
static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
int hstart, hend, vstart, vend;
|
||||
uint32_t frame_ctrl;
|
||||
|
||||
mode = adjusted_mode;
|
||||
|
||||
hdmi_bridge->pixclock = mode->clock * 1000;
|
||||
|
||||
hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
|
||||
|
||||
hstart = mode->htotal - mode->hsync_start;
|
||||
hend = mode->htotal - mode->hsync_start + mode->hdisplay;
|
||||
|
||||
vstart = mode->vtotal - mode->vsync_start - 1;
|
||||
vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
|
||||
|
||||
DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
|
||||
mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
|
||||
|
||||
hdmi_write(hdmi, REG_HDMI_TOTAL,
|
||||
HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
|
||||
HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
|
||||
|
||||
hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
|
||||
HDMI_ACTIVE_HSYNC_START(hstart) |
|
||||
HDMI_ACTIVE_HSYNC_END(hend));
|
||||
hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
|
||||
HDMI_ACTIVE_VSYNC_START(vstart) |
|
||||
HDMI_ACTIVE_VSYNC_END(vend));
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
|
||||
HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
|
||||
HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
|
||||
HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
|
||||
} else {
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
|
||||
HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
|
||||
HDMI_VSYNC_ACTIVE_F2_START(0) |
|
||||
HDMI_VSYNC_ACTIVE_F2_END(0));
|
||||
}
|
||||
|
||||
frame_ctrl = 0;
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
|
||||
DBG("frame_ctrl=%08x", frame_ctrl);
|
||||
hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
|
||||
|
||||
// TODO until we have audio, this might be safest:
|
||||
if (hdmi->hdmi_mode)
|
||||
hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs hdmi_bridge_funcs = {
|
||||
.pre_enable = hdmi_bridge_pre_enable,
|
||||
.enable = hdmi_bridge_enable,
|
||||
.disable = hdmi_bridge_disable,
|
||||
.post_disable = hdmi_bridge_post_disable,
|
||||
.mode_set = hdmi_bridge_mode_set,
|
||||
.destroy = hdmi_bridge_destroy,
|
||||
};
|
||||
|
||||
|
||||
/* initialize bridge */
|
||||
struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
|
||||
{
|
||||
struct drm_bridge *bridge = NULL;
|
||||
struct hdmi_bridge *hdmi_bridge;
|
||||
int ret;
|
||||
|
||||
hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
|
||||
if (!hdmi_bridge) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdmi_bridge->hdmi = hdmi_reference(hdmi);
|
||||
|
||||
bridge = &hdmi_bridge->base;
|
||||
|
||||
drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
|
||||
|
||||
return bridge;
|
||||
|
||||
fail:
|
||||
if (bridge)
|
||||
hdmi_bridge_destroy(bridge);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
|
@ -17,14 +17,11 @@
|
|||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "msm_connector.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
struct hdmi_connector {
|
||||
struct msm_connector base;
|
||||
struct hdmi hdmi;
|
||||
unsigned long int pixclock;
|
||||
bool enabled;
|
||||
struct drm_connector base;
|
||||
struct hdmi *hdmi;
|
||||
};
|
||||
#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
|
||||
|
||||
|
@ -90,8 +87,8 @@ static int gpio_config(struct hdmi *hdmi, bool on)
|
|||
|
||||
static int hpd_enable(struct hdmi_connector *hdmi_connector)
|
||||
{
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct drm_device *dev = hdmi_connector->base.base.dev;
|
||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||
struct drm_device *dev = hdmi_connector->base.dev;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
uint32_t hpd_ctrl;
|
||||
int ret;
|
||||
|
@ -158,8 +155,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
|
|||
|
||||
static int hdp_disable(struct hdmi_connector *hdmi_connector)
|
||||
{
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct drm_device *dev = hdmi_connector->base.base.dev;
|
||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||
struct drm_device *dev = hdmi_connector->base.dev;
|
||||
int ret = 0;
|
||||
|
||||
/* Disable HPD interrupt */
|
||||
|
@ -194,9 +191,8 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector)
|
|||
|
||||
void hdmi_connector_irq(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||
uint32_t hpd_int_status, hpd_int_ctrl;
|
||||
|
||||
/* Process HPD: */
|
||||
|
@ -226,9 +222,8 @@ void hdmi_connector_irq(struct drm_connector *connector)
|
|||
static enum drm_connector_status hdmi_connector_detect(
|
||||
struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||
uint32_t hpd_int_status;
|
||||
int retry = 20;
|
||||
|
||||
|
@ -249,24 +244,22 @@ static enum drm_connector_status hdmi_connector_detect(
|
|||
|
||||
static void hdmi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
|
||||
hdp_disable(hdmi_connector);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
hdmi_destroy(&hdmi_connector->hdmi);
|
||||
hdmi_unreference(hdmi_connector->hdmi);
|
||||
|
||||
kfree(hdmi_connector);
|
||||
}
|
||||
|
||||
static int hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
struct hdmi *hdmi = hdmi_connector->hdmi;
|
||||
struct edid *edid;
|
||||
uint32_t hdmi_ctrl;
|
||||
int ret = 0;
|
||||
|
@ -291,14 +284,14 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
|
|||
static int hdmi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
struct msm_drm_private *priv = connector->dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
long actual, requested;
|
||||
|
||||
requested = 1000 * mode->clock;
|
||||
actual = kms->funcs->round_pixclk(kms,
|
||||
requested, msm_connector->encoder);
|
||||
requested, hdmi_connector->hdmi->encoder);
|
||||
|
||||
DBG("requested=%ld, actual=%ld", requested, actual);
|
||||
|
||||
|
@ -308,6 +301,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
hdmi_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
|
||||
return hdmi_connector->hdmi->encoder;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs hdmi_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = hdmi_connector_detect,
|
||||
|
@ -318,101 +318,11 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
|
|||
static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
|
||||
.get_modes = hdmi_connector_get_modes,
|
||||
.mode_valid = hdmi_connector_mode_valid,
|
||||
.best_encoder = msm_connector_attached_encoder,
|
||||
};
|
||||
|
||||
static void hdmi_connector_dpms(struct msm_connector *msm_connector, int mode)
|
||||
{
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
struct hdmi_phy *phy = hdmi->phy;
|
||||
bool enabled = (mode == DRM_MODE_DPMS_ON);
|
||||
|
||||
DBG("mode=%d", mode);
|
||||
|
||||
if (enabled == hdmi_connector->enabled)
|
||||
return;
|
||||
|
||||
if (enabled) {
|
||||
phy->funcs->powerup(phy, hdmi_connector->pixclock);
|
||||
hdmi_set_mode(hdmi, true);
|
||||
} else {
|
||||
hdmi_set_mode(hdmi, false);
|
||||
phy->funcs->powerdown(phy);
|
||||
}
|
||||
|
||||
hdmi_connector->enabled = enabled;
|
||||
}
|
||||
|
||||
static void hdmi_connector_mode_set(struct msm_connector *msm_connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
|
||||
struct hdmi *hdmi = &hdmi_connector->hdmi;
|
||||
int hstart, hend, vstart, vend;
|
||||
uint32_t frame_ctrl;
|
||||
|
||||
hdmi_connector->pixclock = mode->clock * 1000;
|
||||
|
||||
hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
|
||||
|
||||
hstart = mode->htotal - mode->hsync_start;
|
||||
hend = mode->htotal - mode->hsync_start + mode->hdisplay;
|
||||
|
||||
vstart = mode->vtotal - mode->vsync_start - 1;
|
||||
vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
|
||||
|
||||
DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
|
||||
mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
|
||||
|
||||
hdmi_write(hdmi, REG_HDMI_TOTAL,
|
||||
HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
|
||||
HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
|
||||
|
||||
hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
|
||||
HDMI_ACTIVE_HSYNC_START(hstart) |
|
||||
HDMI_ACTIVE_HSYNC_END(hend));
|
||||
hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
|
||||
HDMI_ACTIVE_VSYNC_START(vstart) |
|
||||
HDMI_ACTIVE_VSYNC_END(vend));
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
|
||||
HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
|
||||
HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
|
||||
HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
|
||||
} else {
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
|
||||
HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
|
||||
hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
|
||||
HDMI_VSYNC_ACTIVE_F2_START(0) |
|
||||
HDMI_VSYNC_ACTIVE_F2_END(0));
|
||||
}
|
||||
|
||||
frame_ctrl = 0;
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
|
||||
DBG("frame_ctrl=%08x", frame_ctrl);
|
||||
hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
|
||||
|
||||
// TODO until we have audio, this might be safest:
|
||||
if (hdmi->hdmi_mode)
|
||||
hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
|
||||
}
|
||||
|
||||
static const struct msm_connector_funcs msm_connector_funcs = {
|
||||
.dpms = hdmi_connector_dpms,
|
||||
.mode_set = hdmi_connector_mode_set,
|
||||
.best_encoder = hdmi_connector_best_encoder,
|
||||
};
|
||||
|
||||
/* initialize connector */
|
||||
struct drm_connector *hdmi_connector_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
|
||||
{
|
||||
struct drm_connector *connector = NULL;
|
||||
struct hdmi_connector *hdmi_connector;
|
||||
|
@ -424,11 +334,11 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
connector = &hdmi_connector->base.base;
|
||||
hdmi_connector->hdmi = hdmi_reference(hdmi);
|
||||
|
||||
msm_connector_init(&hdmi_connector->base,
|
||||
&msm_connector_funcs, encoder);
|
||||
drm_connector_init(dev, connector, &hdmi_connector_funcs,
|
||||
connector = &hdmi_connector->base;
|
||||
|
||||
drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
|
||||
|
||||
|
@ -439,17 +349,13 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
|
|||
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = hpd_enable(hdmi_connector);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable HPD: %d\n", ret);
|
||||
dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
drm_mode_connector_attach_encoder(connector, hdmi->encoder);
|
||||
|
||||
return connector;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <mach/clk.h>
|
||||
|
||||
#include "mdp4_kms.h"
|
||||
#include "msm_connector.h"
|
||||
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
@ -101,7 +100,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
|
||||
struct msm_connector *msm_connector = get_connector(encoder);
|
||||
struct mdp4_kms *mdp4_kms = get_kms(encoder);
|
||||
bool enabled = (mode == DRM_MODE_DPMS_ON);
|
||||
|
||||
|
@ -116,9 +114,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
|
||||
bs_set(mdp4_dtv_encoder, 1);
|
||||
|
||||
if (msm_connector)
|
||||
msm_connector->funcs->dpms(msm_connector, mode);
|
||||
|
||||
DBG("setting src_clk=%lu", pc);
|
||||
|
||||
ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
|
||||
|
@ -150,9 +145,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
|
||||
clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
|
||||
|
||||
if (msm_connector)
|
||||
msm_connector->funcs->dpms(msm_connector, mode);
|
||||
|
||||
bs_set(mdp4_dtv_encoder, 0);
|
||||
}
|
||||
|
||||
|
@ -171,7 +163,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
|
|||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
|
||||
struct msm_connector *msm_connector = get_connector(encoder);
|
||||
struct mdp4_kms *mdp4_kms = get_kms(encoder);
|
||||
uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
|
||||
uint32_t display_v_start, display_v_end;
|
||||
|
@ -230,9 +221,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
|
|||
MDP4_DTV_ACTIVE_HCTL_END(0));
|
||||
mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
|
||||
mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
|
||||
|
||||
if (msm_connector)
|
||||
msm_connector->funcs->mode_set(msm_connector, mode);
|
||||
}
|
||||
|
||||
static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
|
||||
|
|
|
@ -191,7 +191,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
|
|||
struct drm_plane *plane;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -224,13 +223,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
|
|||
encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */
|
||||
priv->encoders[priv->num_encoders++] = encoder;
|
||||
|
||||
connector = hdmi_connector_init(dev, encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
dev_err(dev->dev, "failed to construct HDMI connector\n");
|
||||
ret = PTR_ERR(connector);
|
||||
ret = hdmi_init(dev, encoder);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to initialize HDMI\n");
|
||||
goto fail;
|
||||
}
|
||||
priv->connectors[priv->num_connectors++] = connector;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_connector.h"
|
||||
|
||||
void msm_connector_init(struct msm_connector *connector,
|
||||
const struct msm_connector_funcs *funcs,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
connector->funcs = funcs;
|
||||
connector->encoder = encoder;
|
||||
}
|
||||
|
||||
struct drm_encoder *msm_connector_attached_encoder(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct msm_connector *msm_connector = to_msm_connector(connector);
|
||||
return msm_connector->encoder;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MSM_CONNECTOR_H__
|
||||
#define __MSM_CONNECTOR_H__
|
||||
|
||||
#include "msm_drv.h"
|
||||
|
||||
/*
|
||||
* Base class for MSM connectors. Typically a connector is a bit more
|
||||
* passive. But with the split between (for example) DTV within MDP4,
|
||||
* and HDMI encoder, we really need two parts to an encoder. Instead
|
||||
* what we do is have the part external to the display controller block
|
||||
* in the connector, which is called from the encoder to delegate the
|
||||
* appropriate parts of modeset.
|
||||
*/
|
||||
|
||||
struct msm_connector;
|
||||
|
||||
struct msm_connector_funcs {
|
||||
void (*dpms)(struct msm_connector *connector, int mode);
|
||||
void (*mode_set)(struct msm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
};
|
||||
|
||||
struct msm_connector {
|
||||
struct drm_connector base;
|
||||
struct drm_encoder *encoder;
|
||||
const struct msm_connector_funcs *funcs;
|
||||
};
|
||||
#define to_msm_connector(x) container_of(x, struct msm_connector, base)
|
||||
|
||||
void msm_connector_init(struct msm_connector *connector,
|
||||
const struct msm_connector_funcs *funcs,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
struct drm_encoder *msm_connector_attached_encoder(
|
||||
struct drm_connector *connector);
|
||||
|
||||
static inline struct msm_connector *get_connector(struct drm_encoder *encoder)
|
||||
{
|
||||
struct msm_drm_private *priv = encoder->dev->dev_private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_connectors; i++) {
|
||||
struct drm_connector *connector = priv->connectors[i];
|
||||
if (msm_connector_attached_encoder(connector) == encoder)
|
||||
return to_msm_connector(connector);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* __MSM_CONNECTOR_H__ */
|
|
@ -83,6 +83,9 @@ struct msm_drm_private {
|
|||
unsigned int num_encoders;
|
||||
struct drm_encoder *encoders[8];
|
||||
|
||||
unsigned int num_bridges;
|
||||
struct drm_bridge *bridges[8];
|
||||
|
||||
unsigned int num_connectors;
|
||||
struct drm_connector *connectors[8];
|
||||
};
|
||||
|
@ -170,8 +173,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
|
|||
|
||||
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
|
||||
|
||||
struct drm_connector *hdmi_connector_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
|
||||
void __init hdmi_register(void);
|
||||
void __exit hdmi_unregister(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue