Commit 0a26daaa authored by Dmitry Baryshkov's avatar Dmitry Baryshkov Committed by Rob Clark

drm/msm/edp: drop old eDP support

MSM DRM driver has support for eDP block present on MSM 8x74/8x84 SoC
families. However since addition back in 2015 this driver received only
generic fixes. No actual devices with these SoCs supported upstream (or
by the community) seem to support eDP panels. Judging from downstream
kernels the eDP was present only on MSM8974 LIQUID or on APQ8084 CDP.
Remove this driver.
Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20211001165011.441945-3-dmitry.baryshkov@linaro.orgSigned-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
[rob: Rebased on "drm: msm: fix building without CONFIG_COMMON_CLK"]
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 9ab3d271
......@@ -27,12 +27,6 @@ msm-y := \
hdmi/hdmi_phy_8x60.o \
hdmi/hdmi_phy_8x74.o \
hdmi/hdmi_pll_8960.o \
edp/edp.o \
edp/edp_aux.o \
edp/edp_bridge.o \
edp/edp_connector.o \
edp/edp_ctrl.o \
edp/edp_phy.o \
disp/mdp_format.o \
disp/mdp_kms.o \
disp/mdp4/mdp4_crtc.o \
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include <linux/of_irq.h>
#include "edp.h"
static irqreturn_t edp_irq(int irq, void *dev_id)
{
struct msm_edp *edp = dev_id;
/* Process eDP irq */
return msm_edp_ctrl_irq(edp->ctrl);
}
static void edp_destroy(struct platform_device *pdev)
{
struct msm_edp *edp = platform_get_drvdata(pdev);
if (!edp)
return;
if (edp->ctrl) {
msm_edp_ctrl_destroy(edp->ctrl);
edp->ctrl = NULL;
}
platform_set_drvdata(pdev, NULL);
}
/* construct eDP at bind/probe time, grab all the resources. */
static struct msm_edp *edp_init(struct platform_device *pdev)
{
struct msm_edp *edp = NULL;
int ret;
if (!pdev) {
pr_err("no eDP device\n");
ret = -ENXIO;
goto fail;
}
edp = devm_kzalloc(&pdev->dev, sizeof(*edp), GFP_KERNEL);
if (!edp) {
ret = -ENOMEM;
goto fail;
}
DBG("eDP probed=%p", edp);
edp->pdev = pdev;
platform_set_drvdata(pdev, edp);
ret = msm_edp_ctrl_init(edp);
if (ret)
goto fail;
return edp;
fail:
if (edp)
edp_destroy(pdev);
return ERR_PTR(ret);
}
static int edp_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = dev_get_drvdata(master);
struct msm_drm_private *priv = drm->dev_private;
struct msm_edp *edp;
DBG("");
edp = edp_init(to_platform_device(dev));
if (IS_ERR(edp))
return PTR_ERR(edp);
priv->edp = edp;
return 0;
}
static void edp_unbind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = dev_get_drvdata(master);
struct msm_drm_private *priv = drm->dev_private;
DBG("");
if (priv->edp) {
edp_destroy(to_platform_device(dev));
priv->edp = NULL;
}
}
static const struct component_ops edp_ops = {
.bind = edp_bind,
.unbind = edp_unbind,
};
static int edp_dev_probe(struct platform_device *pdev)
{
DBG("");
return component_add(&pdev->dev, &edp_ops);
}
static int edp_dev_remove(struct platform_device *pdev)
{
DBG("");
component_del(&pdev->dev, &edp_ops);
return 0;
}
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,mdss-edp" },
{}
};
static struct platform_driver edp_driver = {
.probe = edp_dev_probe,
.remove = edp_dev_remove,
.driver = {
.name = "msm_edp",
.of_match_table = dt_match,
},
};
void __init msm_edp_register(void)
{
DBG("");
platform_driver_register(&edp_driver);
}
void __exit msm_edp_unregister(void)
{
DBG("");
platform_driver_unregister(&edp_driver);
}
/* Second part of initialization, the drm/kms level modeset_init */
int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
struct drm_encoder *encoder)
{
struct platform_device *pdev = edp->pdev;
struct msm_drm_private *priv = dev->dev_private;
int ret;
edp->encoder = encoder;
edp->dev = dev;
edp->bridge = msm_edp_bridge_init(edp);
if (IS_ERR(edp->bridge)) {
ret = PTR_ERR(edp->bridge);
DRM_DEV_ERROR(dev->dev, "failed to create eDP bridge: %d\n", ret);
edp->bridge = NULL;
goto fail;
}
edp->connector = msm_edp_connector_init(edp);
if (IS_ERR(edp->connector)) {
ret = PTR_ERR(edp->connector);
DRM_DEV_ERROR(dev->dev, "failed to create eDP connector: %d\n", ret);
edp->connector = NULL;
goto fail;
}
edp->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (edp->irq < 0) {
ret = edp->irq;
DRM_DEV_ERROR(dev->dev, "failed to get IRQ: %d\n", ret);
goto fail;
}
ret = devm_request_irq(&pdev->dev, edp->irq,
edp_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"edp_isr", edp);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n",
edp->irq, ret);
goto fail;
}
priv->bridges[priv->num_bridges++] = edp->bridge;
priv->connectors[priv->num_connectors++] = edp->connector;
return 0;
fail:
/* bridge/connector are normally destroyed by drm */
if (edp->bridge) {
edp_bridge_destroy(edp->bridge);
edp->bridge = NULL;
}
if (edp->connector) {
edp->connector->funcs->destroy(edp->connector);
edp->connector = NULL;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#ifndef __EDP_CONNECTOR_H__
#define __EDP_CONNECTOR_H__
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include "msm_drv.h"
#define edp_read(offset) msm_readl((offset))
#define edp_write(offset, data) msm_writel((data), (offset))
struct edp_ctrl;
struct edp_aux;
struct edp_phy;
struct msm_edp {
struct drm_device *dev;
struct platform_device *pdev;
struct drm_connector *connector;
struct drm_bridge *bridge;
/* the encoder we are hooked to (outside of eDP block) */
struct drm_encoder *encoder;
struct edp_ctrl *ctrl;
int irq;
};
/* eDP bridge */
struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp);
void edp_bridge_destroy(struct drm_bridge *bridge);
/* eDP connector */
struct drm_connector *msm_edp_connector_init(struct msm_edp *edp);
/* AUX */
void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux);
void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux);
irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr);
void msm_edp_aux_ctrl(struct edp_aux *aux, int enable);
/* Phy */
bool msm_edp_phy_ready(struct edp_phy *phy);
void msm_edp_phy_ctrl(struct edp_phy *phy, int enable);
void msm_edp_phy_vm_pe_init(struct edp_phy *phy);
void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1);
void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane);
void *msm_edp_phy_init(struct device *dev, void __iomem *regbase);
/* Ctrl */
irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl);
void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on);
int msm_edp_ctrl_init(struct msm_edp *edp);
void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl);
bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl);
int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl,
struct drm_connector *connector, struct edid **edid);
int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl,
const struct drm_display_mode *mode,
const struct drm_display_info *info);
/* @pixel_rate is in kHz */
bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl,
u32 pixel_rate, u32 *pm, u32 *pn);
#endif /* __EDP_CONNECTOR_H__ */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include "edp.h"
#include "edp.xml.h"
#define AUX_CMD_FIFO_LEN 144
#define AUX_CMD_NATIVE_MAX 16
#define AUX_CMD_I2C_MAX 128
#define EDP_INTR_AUX_I2C_ERR \
(EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER)
#define EDP_INTR_TRANS_STATUS \
(EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR)
struct edp_aux {
void __iomem *base;
bool msg_err;
struct completion msg_comp;
/* To prevent the message transaction routine from reentry. */
struct mutex msg_mutex;
struct drm_dp_aux drm_aux;
};
#define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux)
static int edp_msg_fifo_tx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
{
u32 data[4];
u32 reg, len;
bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
u8 *msgdata = msg->buffer;
int i;
if (read)
len = 4;
else
len = msg->size + 4;
/*
* cmd fifo only has depth of 144 bytes
*/
if (len > AUX_CMD_FIFO_LEN)
return -EINVAL;
/* Pack cmd and write to HW */
data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
if (read)
data[0] |= BIT(4); /* R/W */
data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */
data[2] = msg->address & 0xff; /* addr[7:0] */
data[3] = (msg->size - 1) & 0xff; /* len[7:0] */
for (i = 0; i < len; i++) {
reg = (i < 4) ? data[i] : msgdata[i - 4];
reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
if (i == 0)
reg |= EDP_AUX_DATA_INDEX_WRITE;
edp_write(aux->base + REG_EDP_AUX_DATA, reg);
}
reg = 0; /* Transaction number is always 1 */
if (!native) /* i2c */
reg |= EDP_AUX_TRANS_CTRL_I2C;
reg |= EDP_AUX_TRANS_CTRL_GO;
edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, reg);
return 0;
}
static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
{
u32 data;
u8 *dp;
int i;
u32 len = msg->size;
edp_write(aux->base + REG_EDP_AUX_DATA,
EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
dp = msg->buffer;
/* discard first byte */
data = edp_read(aux->base + REG_EDP_AUX_DATA);
for (i = 0; i < len; i++) {
data = edp_read(aux->base + REG_EDP_AUX_DATA);
dp[i] = (u8)((data >> 8) & 0xff);
}
return 0;
}
/*
* This function does the real job to process an AUX transaction.
* It will call msm_edp_aux_ctrl() function to reset the AUX channel,
* if the waiting is timeout.
* The caller who triggers the transaction should avoid the
* msm_edp_aux_ctrl() running concurrently in other threads, i.e.
* start transaction only when AUX channel is fully enabled.
*/
static ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux,
struct drm_dp_aux_msg *msg)
{
struct edp_aux *aux = to_edp_aux(drm_aux);
ssize_t ret;
unsigned long time_left;
bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
/* Ignore address only message */
if ((msg->size == 0) || (msg->buffer == NULL)) {
msg->reply = native ?
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
return msg->size;
}
/* msg sanity check */
if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
(msg->size > AUX_CMD_I2C_MAX)) {
pr_err("%s: invalid msg: size(%zu), request(%x)\n",
__func__, msg->size, msg->request);
return -EINVAL;
}
mutex_lock(&aux->msg_mutex);
aux->msg_err = false;
reinit_completion(&aux->msg_comp);
ret = edp_msg_fifo_tx(aux, msg);
if (ret < 0)
goto unlock_exit;
DBG("wait_for_completion");
time_left = wait_for_completion_timeout(&aux->msg_comp,
msecs_to_jiffies(300));
if (!time_left) {
/*
* Clear GO and reset AUX channel
* to cancel the current transaction.
*/
edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
msm_edp_aux_ctrl(aux, 1);
pr_err("%s: aux timeout,\n", __func__);
ret = -ETIMEDOUT;
goto unlock_exit;
}
DBG("completion");
if (!aux->msg_err) {
if (read) {
ret = edp_msg_fifo_rx(aux, msg);
if (ret < 0)
goto unlock_exit;
}
msg->reply = native ?
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
} else {
/* Reply defer to retry */
msg->reply = native ?
DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
/*
* The sleep time in caller is not long enough to make sure
* our H/W completes transactions. Add more defer time here.
*/
msleep(100);
}
/* Return requested size for success or retry */
ret = msg->size;
unlock_exit:
mutex_unlock(&aux->msg_mutex);
return ret;
}
void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux)
{
struct device *dev = &edp->pdev->dev;
struct edp_aux *aux = NULL;
int ret;
DBG("");
aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
if (!aux)
return NULL;
aux->base = regbase;
mutex_init(&aux->msg_mutex);
init_completion(&aux->msg_comp);
aux->drm_aux.name = "msm_edp_aux";
aux->drm_aux.dev = dev;
aux->drm_aux.drm_dev = edp->dev;
aux->drm_aux.transfer = edp_aux_transfer;
ret = drm_dp_aux_register(&aux->drm_aux);
if (ret) {
pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
mutex_destroy(&aux->msg_mutex);
}
if (drm_aux && aux)
*drm_aux = &aux->drm_aux;
return aux;
}
void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux)
{
if (aux) {
drm_dp_aux_unregister(&aux->drm_aux);
mutex_destroy(&aux->msg_mutex);
}
}
irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr)
{
if (isr & EDP_INTR_TRANS_STATUS) {
DBG("isr=%x", isr);
edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
if (isr & EDP_INTR_AUX_I2C_ERR)
aux->msg_err = true;
else
aux->msg_err = false;
complete(&aux->msg_comp);
}
return IRQ_HANDLED;
}
void msm_edp_aux_ctrl(struct edp_aux *aux, int enable)
{
u32 data;
DBG("enable=%d", enable);
data = edp_read(aux->base + REG_EDP_AUX_CTRL);
if (enable) {
data |= EDP_AUX_CTRL_RESET;
edp_write(aux->base + REG_EDP_AUX_CTRL, data);
/* Make sure full reset */
wmb();
usleep_range(500, 1000);
data &= ~EDP_AUX_CTRL_RESET;
data |= EDP_AUX_CTRL_ENABLE;
edp_write(aux->base + REG_EDP_AUX_CTRL, data);
} else {
data &= ~EDP_AUX_CTRL_ENABLE;
edp_write(aux->base + REG_EDP_AUX_CTRL, data);
}
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include "edp.h"
struct edp_bridge {
struct drm_bridge base;
struct msm_edp *edp;
};
#define to_edp_bridge(x) container_of(x, struct edp_bridge, base)
void edp_bridge_destroy(struct drm_bridge *bridge)
{
}
static void edp_bridge_pre_enable(struct drm_bridge *bridge)
{
struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
struct msm_edp *edp = edp_bridge->edp;
DBG("");
msm_edp_ctrl_power(edp->ctrl, true);
}
static void edp_bridge_enable(struct drm_bridge *bridge)
{
DBG("");
}
static void edp_bridge_disable(struct drm_bridge *bridge)
{
DBG("");
}
static void edp_bridge_post_disable(struct drm_bridge *bridge)
{
struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
struct msm_edp *edp = edp_bridge->edp;
DBG("");
msm_edp_ctrl_power(edp->ctrl, false);
}
static void edp_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = bridge->dev;
struct drm_connector *connector;
struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
struct msm_edp *edp = edp_bridge->edp;
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct drm_encoder *encoder = connector->encoder;
struct drm_bridge *first_bridge;
if (!connector->encoder)
continue;
first_bridge = drm_bridge_chain_get_first_bridge(encoder);
if (bridge == first_bridge) {
msm_edp_ctrl_timing_cfg(edp->ctrl,
adjusted_mode, &connector->display_info);
break;
}
}
}
static const struct drm_bridge_funcs edp_bridge_funcs = {
.pre_enable = edp_bridge_pre_enable,
.enable = edp_bridge_enable,
.disable = edp_bridge_disable,
.post_disable = edp_bridge_post_disable,
.mode_set = edp_bridge_mode_set,
};
/* initialize bridge */
struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
{
struct drm_bridge *bridge = NULL;
struct edp_bridge *edp_bridge;
int ret;
edp_bridge = devm_kzalloc(edp->dev->dev,
sizeof(*edp_bridge), GFP_KERNEL);
if (!edp_bridge) {
ret = -ENOMEM;
goto fail;
}
edp_bridge->edp = edp;
bridge = &edp_bridge->base;
bridge->funcs = &edp_bridge_funcs;
ret = drm_bridge_attach(edp->encoder, bridge, NULL, 0);
if (ret)
goto fail;
return bridge;
fail:
if (bridge)
edp_bridge_destroy(bridge);
return ERR_PTR(ret);
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include "drm/drm_edid.h"
#include "msm_kms.h"
#include "edp.h"
struct edp_connector {
struct drm_connector base;
struct msm_edp *edp;
};
#define to_edp_connector(x) container_of(x, struct edp_connector, base)
static enum drm_connector_status edp_connector_detect(
struct drm_connector *connector, bool force)
{
struct edp_connector *edp_connector = to_edp_connector(connector);
struct msm_edp *edp = edp_connector->edp;
DBG("");
return msm_edp_ctrl_panel_connected(edp->ctrl) ?
connector_status_connected : connector_status_disconnected;
}
static void edp_connector_destroy(struct drm_connector *connector)
{
struct edp_connector *edp_connector = to_edp_connector(connector);
DBG("");
drm_connector_cleanup(connector);
kfree(edp_connector);
}
static int edp_connector_get_modes(struct drm_connector *connector)
{
struct edp_connector *edp_connector = to_edp_connector(connector);
struct msm_edp *edp = edp_connector->edp;
struct edid *drm_edid = NULL;
int ret = 0;
DBG("");
ret = msm_edp_ctrl_get_panel_info(edp->ctrl, connector, &drm_edid);
if (ret)
return ret;
drm_connector_update_edid_property(connector, drm_edid);
if (drm_edid)
ret = drm_add_edid_modes(connector, drm_edid);
return ret;
}
static int edp_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct edp_connector *edp_connector = to_edp_connector(connector);
struct msm_edp *edp = edp_connector->edp;
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, edp_connector->edp->encoder);
DBG("requested=%ld, actual=%ld", requested, actual);
if (actual != requested)
return MODE_CLOCK_RANGE;
if (!msm_edp_ctrl_pixel_clock_valid(
edp->ctrl, mode->clock, NULL, NULL))
return MODE_CLOCK_RANGE;
/* Invalidate all modes if color format is not supported */
if (connector->display_info.bpc > 8)
return MODE_BAD;
return MODE_OK;
}
static const struct drm_connector_funcs edp_connector_funcs = {
.detect = edp_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = edp_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs edp_connector_helper_funcs = {
.get_modes = edp_connector_get_modes,
.mode_valid = edp_connector_mode_valid,
};
/* initialize connector */
struct drm_connector *msm_edp_connector_init(struct msm_edp *edp)
{
struct drm_connector *connector = NULL;
struct edp_connector *edp_connector;
int ret;
edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL);
if (!edp_connector)
return ERR_PTR(-ENOMEM);
edp_connector->edp = edp;
connector = &edp_connector->base;
ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs,
DRM_MODE_CONNECTOR_eDP);
if (ret)
return ERR_PTR(ret);
drm_connector_helper_add(connector, &edp_connector_helper_funcs);
/* We don't support HPD, so only poll status until connected. */
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
/* Display driver doesn't support interlace now. */
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
drm_connector_attach_encoder(connector, edp->encoder);
return connector;
}
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#include "edp.h"
#include "edp.xml.h"
#define EDP_MAX_LANE 4
struct edp_phy {
void __iomem *base;
};
bool msm_edp_phy_ready(struct edp_phy *phy)
{
u32 status;
int cnt = 100;
while (--cnt) {
status = edp_read(phy->base +
REG_EDP_PHY_GLB_PHY_STATUS);
if (status & 0x01)
break;
usleep_range(500, 1000);
}
if (cnt == 0) {
pr_err("%s: PHY NOT ready\n", __func__);
return false;
} else {
return true;
}
}
void msm_edp_phy_ctrl(struct edp_phy *phy, int enable)
{
DBG("enable=%d", enable);
if (enable) {
/* Reset */
edp_write(phy->base + REG_EDP_PHY_CTRL,
EDP_PHY_CTRL_SW_RESET | EDP_PHY_CTRL_SW_RESET_PLL);
/* Make sure fully reset */
wmb();
usleep_range(500, 1000);
edp_write(phy->base + REG_EDP_PHY_CTRL, 0x000);
edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0x3f);
edp_write(phy->base + REG_EDP_PHY_GLB_CFG, 0x1);
} else {
edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0xc0);
}
}
/* voltage mode and pre emphasis cfg */
void msm_edp_phy_vm_pe_init(struct edp_phy *phy)
{
edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, 0x3);
edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, 0x64);
edp_write(phy->base + REG_EDP_PHY_GLB_MISC9, 0x6c);
}
void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1)
{
edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, v0);
edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, v1);
}
void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane)
{
u32 i;
u32 data;
if (up)
data = 0; /* power up */
else
data = 0x7; /* power down */
for (i = 0; i < max_lane; i++)
edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
/* power down unused lane */
data = 0x7; /* power down */
for (i = max_lane; i < EDP_MAX_LANE; i++)
edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
}
void *msm_edp_phy_init(struct device *dev, void __iomem *regbase)
{
struct edp_phy *phy = NULL;
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy)
return NULL;
phy->base = regbase;
return phy;
}
......@@ -1478,7 +1478,6 @@ static int __init msm_drm_register(void)
msm_mdp_register();
msm_dpu_register();
msm_dsi_register();
msm_edp_register();
msm_hdmi_register();
msm_dp_register();
adreno_register();
......@@ -1492,7 +1491,6 @@ static void __exit msm_drm_unregister(void)
msm_dp_unregister();
msm_hdmi_unregister();
adreno_unregister();
msm_edp_unregister();
msm_dsi_unregister();
msm_mdp_unregister();
msm_dpu_unregister();
......
......@@ -151,12 +151,6 @@ struct msm_drm_private {
*/
struct hdmi *hdmi;
/* eDP is for mdp5 only, but kms has not been created
* when edp_bind() and edp_init() are called. Here is the only
* place to keep the edp instance.
*/
struct msm_edp *edp;
/* DSI is shared by mdp4 and mdp5 */
struct msm_dsi *dsi[2];
......@@ -335,12 +329,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
void __init msm_hdmi_register(void);
void __exit msm_hdmi_unregister(void);
struct msm_edp;
void __init msm_edp_register(void);
void __exit msm_edp_unregister(void);
int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
struct drm_encoder *encoder);
struct msm_dsi;
#ifdef CONFIG_DRM_MSM_DSI
void __init msm_dsi_register(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