Commit a3376e3e authored by Rob Clark's avatar Rob Clark Committed by Dave Airlie

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: default avatarRob Clark <robdclark@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 3b336ec4
...@@ -7,6 +7,7 @@ msm-y := \ ...@@ -7,6 +7,7 @@ msm-y := \
adreno/adreno_gpu.o \ adreno/adreno_gpu.o \
adreno/a3xx_gpu.o \ adreno/a3xx_gpu.o \
hdmi/hdmi.o \ hdmi/hdmi.o \
hdmi/hdmi_bridge.o \
hdmi/hdmi_connector.o \ hdmi/hdmi_connector.o \
hdmi/hdmi_i2c.o \ hdmi/hdmi_i2c.o \
hdmi/hdmi_phy_8960.o \ hdmi/hdmi_phy_8960.o \
...@@ -17,7 +18,6 @@ msm-y := \ ...@@ -17,7 +18,6 @@ msm-y := \
mdp4/mdp4_irq.o \ mdp4/mdp4_irq.o \
mdp4/mdp4_kms.o \ mdp4/mdp4_kms.o \
mdp4/mdp4_plane.o \ mdp4/mdp4_plane.o \
msm_connector.o \
msm_drv.o \ msm_drv.o \
msm_fb.o \ msm_fb.o \
msm_gem.o \ msm_gem.o \
......
...@@ -56,8 +56,9 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id) ...@@ -56,8 +56,9 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED; 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; struct hdmi_phy *phy = hdmi->phy;
if (phy) if (phy)
...@@ -70,9 +71,10 @@ void hdmi_destroy(struct hdmi *hdmi) ...@@ -70,9 +71,10 @@ void hdmi_destroy(struct hdmi *hdmi)
} }
/* initialize connector */ /* initialize connector */
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev, int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
struct drm_connector *connector)
{ {
struct hdmi *hdmi = NULL;
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = hdmi_pdev; struct platform_device *pdev = hdmi_pdev;
struct hdmi_platform_config *config; struct hdmi_platform_config *config;
int ret; int ret;
...@@ -85,11 +87,19 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev, ...@@ -85,11 +87,19 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
config = pdev->dev.platform_data; 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); get_device(&pdev->dev);
hdmi->dev = dev; hdmi->dev = dev;
hdmi->pdev = pdev; hdmi->pdev = pdev;
hdmi->connector = connector; hdmi->encoder = encoder;
/* not sure about which phy maps to which msm.. probably I miss some */ /* not sure about which phy maps to which msm.. probably I miss some */
if (config->phy_init) if (config->phy_init)
...@@ -152,6 +162,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev, ...@@ -152,6 +162,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
goto fail; 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); hdmi->irq = platform_get_irq(pdev, 0);
if (hdmi->irq < 0) { if (hdmi->irq < 0) {
ret = hdmi->irq; ret = hdmi->irq;
...@@ -168,11 +194,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev, ...@@ -168,11 +194,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
goto fail; goto fail;
} }
encoder->bridge = hdmi->bridge;
priv->bridges[priv->num_bridges++] = hdmi->bridge;
priv->connectors[priv->num_connectors++] = hdmi->connector;
return 0; return 0;
fail: fail:
if (hdmi) if (hdmi) {
hdmi_destroy(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; return ret;
} }
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
struct hdmi_phy; struct hdmi_phy;
struct hdmi { struct hdmi {
struct kref refcount;
struct drm_device *dev; struct drm_device *dev;
struct platform_device *pdev; struct platform_device *pdev;
...@@ -45,6 +47,10 @@ struct hdmi { ...@@ -45,6 +47,10 @@ struct hdmi {
struct hdmi_phy *phy; struct hdmi_phy *phy;
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
struct drm_connector *connector; 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? */ bool hdmi_mode; /* are we in hdmi mode? */
...@@ -58,9 +64,7 @@ struct hdmi_platform_config { ...@@ -58,9 +64,7 @@ struct hdmi_platform_config {
}; };
void hdmi_set_mode(struct hdmi *hdmi, bool power_on); void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
void hdmi_destroy(struct hdmi *hdmi); void hdmi_destroy(struct kref *kref);
int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
struct drm_connector *connector);
static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data) 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) ...@@ -72,6 +76,17 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
return msm_readl(hdmi->mmio + 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, * 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 * so split the phy related functions out and load the correct one at
...@@ -89,17 +104,21 @@ struct hdmi_phy { ...@@ -89,17 +104,21 @@ struct hdmi_phy {
const struct hdmi_phy_funcs *funcs; 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_8960_init(struct hdmi *hdmi);
struct hdmi_phy *hdmi_phy_8x60_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: * hdmi connector:
*/ */
void hdmi_connector_irq(struct drm_connector *connector); void hdmi_connector_irq(struct drm_connector *connector);
struct drm_connector *hdmi_connector_init(struct hdmi *hdmi);
/* /*
* i2c adapter for ddc: * i2c adapter for ddc:
......
/*
* 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 @@ ...@@ -17,14 +17,11 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include "msm_connector.h"
#include "hdmi.h" #include "hdmi.h"
struct hdmi_connector { struct hdmi_connector {
struct msm_connector base; struct drm_connector base;
struct hdmi hdmi; struct hdmi *hdmi;
unsigned long int pixclock;
bool enabled;
}; };
#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) #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) ...@@ -90,8 +87,8 @@ static int gpio_config(struct hdmi *hdmi, bool on)
static int hpd_enable(struct hdmi_connector *hdmi_connector) static int hpd_enable(struct hdmi_connector *hdmi_connector)
{ {
struct hdmi *hdmi = &hdmi_connector->hdmi; struct hdmi *hdmi = hdmi_connector->hdmi;
struct drm_device *dev = hdmi_connector->base.base.dev; struct drm_device *dev = hdmi_connector->base.dev;
struct hdmi_phy *phy = hdmi->phy; struct hdmi_phy *phy = hdmi->phy;
uint32_t hpd_ctrl; uint32_t hpd_ctrl;
int ret; int ret;
...@@ -158,8 +155,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) ...@@ -158,8 +155,8 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
static int hdp_disable(struct hdmi_connector *hdmi_connector) static int hdp_disable(struct hdmi_connector *hdmi_connector)
{ {
struct hdmi *hdmi = &hdmi_connector->hdmi; struct hdmi *hdmi = hdmi_connector->hdmi;
struct drm_device *dev = hdmi_connector->base.base.dev; struct drm_device *dev = hdmi_connector->base.dev;
int ret = 0; int ret = 0;
/* Disable HPD interrupt */ /* Disable HPD interrupt */
...@@ -194,9 +191,8 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector) ...@@ -194,9 +191,8 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector)
void hdmi_connector_irq(struct drm_connector *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(connector);
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); struct hdmi *hdmi = hdmi_connector->hdmi;
struct hdmi *hdmi = &hdmi_connector->hdmi;
uint32_t hpd_int_status, hpd_int_ctrl; uint32_t hpd_int_status, hpd_int_ctrl;
/* Process HPD: */ /* Process HPD: */
...@@ -226,9 +222,8 @@ void hdmi_connector_irq(struct drm_connector *connector) ...@@ -226,9 +222,8 @@ void hdmi_connector_irq(struct drm_connector *connector)
static enum drm_connector_status hdmi_connector_detect( static enum drm_connector_status hdmi_connector_detect(
struct drm_connector *connector, bool force) struct drm_connector *connector, bool force)
{ {
struct msm_connector *msm_connector = to_msm_connector(connector); struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); struct hdmi *hdmi = hdmi_connector->hdmi;
struct hdmi *hdmi = &hdmi_connector->hdmi;
uint32_t hpd_int_status; uint32_t hpd_int_status;
int retry = 20; int retry = 20;
...@@ -249,24 +244,22 @@ static enum drm_connector_status hdmi_connector_detect( ...@@ -249,24 +244,22 @@ static enum drm_connector_status hdmi_connector_detect(
static void hdmi_connector_destroy(struct drm_connector *connector) 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(connector);
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
hdp_disable(hdmi_connector); hdp_disable(hdmi_connector);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
hdmi_destroy(&hdmi_connector->hdmi); hdmi_unreference(hdmi_connector->hdmi);
kfree(hdmi_connector); kfree(hdmi_connector);
} }
static int hdmi_connector_get_modes(struct drm_connector *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(connector);
struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); struct hdmi *hdmi = hdmi_connector->hdmi;
struct hdmi *hdmi = &hdmi_connector->hdmi;
struct edid *edid; struct edid *edid;
uint32_t hdmi_ctrl; uint32_t hdmi_ctrl;
int ret = 0; int ret = 0;
...@@ -291,14 +284,14 @@ static int hdmi_connector_get_modes(struct drm_connector *connector) ...@@ -291,14 +284,14 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
static int hdmi_connector_mode_valid(struct drm_connector *connector, static int hdmi_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) 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_drm_private *priv = connector->dev->dev_private;
struct msm_kms *kms = priv->kms; struct msm_kms *kms = priv->kms;
long actual, requested; long actual, requested;
requested = 1000 * mode->clock; requested = 1000 * mode->clock;
actual = kms->funcs->round_pixclk(kms, actual = kms->funcs->round_pixclk(kms,
requested, msm_connector->encoder); requested, hdmi_connector->hdmi->encoder);
DBG("requested=%ld, actual=%ld", requested, actual); DBG("requested=%ld, actual=%ld", requested, actual);
...@@ -308,6 +301,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector, ...@@ -308,6 +301,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
return 0; 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 = { static const struct drm_connector_funcs hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = drm_helper_connector_dpms,
.detect = hdmi_connector_detect, .detect = hdmi_connector_detect,
...@@ -318,101 +318,11 @@ static const struct drm_connector_funcs hdmi_connector_funcs = { ...@@ -318,101 +318,11 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
.get_modes = hdmi_connector_get_modes, .get_modes = hdmi_connector_get_modes,
.mode_valid = hdmi_connector_mode_valid, .mode_valid = hdmi_connector_mode_valid,
.best_encoder = msm_connector_attached_encoder, .best_encoder = hdmi_connector_best_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,
}; };
/* initialize connector */ /* initialize connector */
struct drm_connector *hdmi_connector_init(struct drm_device *dev, struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
struct drm_encoder *encoder)
{ {
struct drm_connector *connector = NULL; struct drm_connector *connector = NULL;
struct hdmi_connector *hdmi_connector; struct hdmi_connector *hdmi_connector;
...@@ -424,11 +334,11 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev, ...@@ -424,11 +334,11 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
goto fail; goto fail;
} }
connector = &hdmi_connector->base.base; hdmi_connector->hdmi = hdmi_reference(hdmi);
connector = &hdmi_connector->base;
msm_connector_init(&hdmi_connector->base, drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
&msm_connector_funcs, encoder);
drm_connector_init(dev, connector, &hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA); DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
...@@ -439,17 +349,13 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev, ...@@ -439,17 +349,13 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
if (ret)
goto fail;
ret = hpd_enable(hdmi_connector); ret = hpd_enable(hdmi_connector);
if (ret) { 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; goto fail;
} }
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, hdmi->encoder);
return connector; return connector;
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <mach/clk.h> #include <mach/clk.h>
#include "mdp4_kms.h" #include "mdp4_kms.h"
#include "msm_connector.h"
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
...@@ -101,7 +100,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode) ...@@ -101,7 +100,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); 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); struct mdp4_kms *mdp4_kms = get_kms(encoder);
bool enabled = (mode == DRM_MODE_DPMS_ON); bool enabled = (mode == DRM_MODE_DPMS_ON);
...@@ -116,9 +114,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode) ...@@ -116,9 +114,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
bs_set(mdp4_dtv_encoder, 1); bs_set(mdp4_dtv_encoder, 1);
if (msm_connector)
msm_connector->funcs->dpms(msm_connector, mode);
DBG("setting src_clk=%lu", pc); DBG("setting src_clk=%lu", pc);
ret = clk_set_rate(mdp4_dtv_encoder->src_clk, 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) ...@@ -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->hdmi_clk);
clk_disable_unprepare(mdp4_dtv_encoder->mdp_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); bs_set(mdp4_dtv_encoder, 0);
} }
...@@ -171,7 +163,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, ...@@ -171,7 +163,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); 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); struct mdp4_kms *mdp4_kms = get_kms(encoder);
uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
uint32_t display_v_start, display_v_end; uint32_t display_v_start, display_v_end;
...@@ -230,9 +221,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, ...@@ -230,9 +221,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
MDP4_DTV_ACTIVE_HCTL_END(0)); MDP4_DTV_ACTIVE_HCTL_END(0));
mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0); mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 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) static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
......
...@@ -191,7 +191,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms) ...@@ -191,7 +191,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
struct drm_plane *plane; struct drm_plane *plane;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector *connector;
int ret; int ret;
/* /*
...@@ -224,13 +223,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms) ...@@ -224,13 +223,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */ encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */
priv->encoders[priv->num_encoders++] = encoder; priv->encoders[priv->num_encoders++] = encoder;
connector = hdmi_connector_init(dev, encoder); ret = hdmi_init(dev, encoder);
if (IS_ERR(connector)) { if (ret) {
dev_err(dev->dev, "failed to construct HDMI connector\n"); dev_err(dev->dev, "failed to initialize HDMI\n");
ret = PTR_ERR(connector);
goto fail; goto fail;
} }
priv->connectors[priv->num_connectors++] = connector;
return 0; return 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;
}
/*
* 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 { ...@@ -83,6 +83,9 @@ struct msm_drm_private {
unsigned int num_encoders; unsigned int num_encoders;
struct drm_encoder *encoders[8]; struct drm_encoder *encoders[8];
unsigned int num_bridges;
struct drm_bridge *bridges[8];
unsigned int num_connectors; unsigned int num_connectors;
struct drm_connector *connectors[8]; struct drm_connector *connectors[8];
}; };
...@@ -170,8 +173,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, ...@@ -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_fb_helper *msm_fbdev_init(struct drm_device *dev);
struct drm_connector *hdmi_connector_init(struct drm_device *dev, int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
struct drm_encoder *encoder);
void __init hdmi_register(void); void __init hdmi_register(void);
void __exit hdmi_unregister(void); void __exit hdmi_unregister(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment