From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755228AbbCRH43 (ORCPT ); Wed, 18 Mar 2015 03:56:29 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:55313 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755061AbbCRH40 (ORCPT ); Wed, 18 Mar 2015 03:56:26 -0400 Message-ID: <55092F9C.3050004@codeaurora.org> Date: Wed, 18 Mar 2015 13:26:12 +0530 From: Archit Taneja User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Hai Li CC: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 3/4] drm/msm: Initial add DSI connector support References: <1426289058-6663-1-git-send-email-hali@codeaurora.org> <1426289058-6663-4-git-send-email-hali@codeaurora.org> In-Reply-To: <1426289058-6663-4-git-send-email-hali@codeaurora.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, On 03/14/2015 04:54 AM, Hai Li wrote: > This change adds the DSI connector support in msm drm driver. > > Signed-off-by: Hai Li > --- > drivers/gpu/drm/msm/Kconfig | 11 + > drivers/gpu/drm/msm/Makefile | 4 + > drivers/gpu/drm/msm/dsi/dsi.c | 203 ++++ > drivers/gpu/drm/msm/dsi/dsi.h | 115 ++ > drivers/gpu/drm/msm/dsi/dsi_host.c | 1997 +++++++++++++++++++++++++++++++++ > drivers/gpu/drm/msm/dsi/dsi_manager.c | 706 ++++++++++++ > drivers/gpu/drm/msm/dsi/dsi_phy.c | 352 ++++++ > drivers/gpu/drm/msm/msm_drv.h | 20 + > 8 files changed, 3408 insertions(+) > create mode 100644 drivers/gpu/drm/msm/dsi/dsi.c > create mode 100644 drivers/gpu/drm/msm/dsi/dsi.h > create mode 100644 drivers/gpu/drm/msm/dsi/dsi_host.c > create mode 100644 drivers/gpu/drm/msm/dsi/dsi_manager.c > create mode 100644 drivers/gpu/drm/msm/dsi/dsi_phy.c > > diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig > index 1e6a907..5ba5631 100644 > --- a/drivers/gpu/drm/msm/Kconfig > +++ b/drivers/gpu/drm/msm/Kconfig > @@ -35,3 +35,14 @@ config DRM_MSM_REGISTER_LOGGING > Compile in support for logging register reads/writes in a format > that can be parsed by envytools demsm tool. If enabled, register > logging can be switched on via msm.reglog=y module param. > + > +config DRM_MSM_DSI > + bool "Enable DSI support in MSM DRM driver" > + depends on DRM_MSM > + select DRM_PANEL > + select DRM_MIPI_DSI > + default y > + help > + Choose this option if you have a need for MIPI DSI connector > + support. > + > diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile > index 674a132..5c144cc 100644 > --- a/drivers/gpu/drm/msm/Makefile > +++ b/drivers/gpu/drm/msm/Makefile > @@ -50,5 +50,9 @@ msm-y := \ > > msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o > msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o > +msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ > + dsi/dsi_host.o \ > + dsi/dsi_manager.o \ > + dsi/dsi_phy.o > > obj-$(CONFIG_DRM_MSM) += msm.o > diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c > new file mode 100644 > index 0000000..de77260 > --- /dev/null > +++ b/drivers/gpu/drm/msm/dsi/dsi.c > @@ -0,0 +1,203 @@ > +/* > + * Copyright (c) 2015, The Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only 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. > + */ > + > +#include "dsi.h" > + > +int msm_dsi_modeset_init(struct msm_drm_sub_dev *base, struct drm_device *dev) > +{ > + struct msm_dsi *msm_dsi = container_of(base, struct msm_dsi, base); > + struct msm_drm_private *priv = dev->dev_private; > + int ret, i; > + > + if (WARN_ON((base->num_encoders != MSM_DSI_ENCODER_NUM) || > + !base->encoders[MSM_DSI_VIDEO_ENCODER_ID] || > + !base->encoders[MSM_DSI_CMD_ENCODER_ID])) > + return -EINVAL; > + > + msm_dsi->dev = dev; > + > + ret = msm_dsi_host_modeset_init(msm_dsi->host, dev); > + if (ret) { > + dev_err(dev->dev, "failed to modeset init host: %d\n", ret); > + goto fail; > + } > + > + msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id); > + if (IS_ERR(msm_dsi->bridge)) { > + ret = PTR_ERR(msm_dsi->bridge); > + dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret); > + msm_dsi->bridge = NULL; > + goto fail; > + } > + > + msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id); > + if (IS_ERR(msm_dsi->connector)) { > + ret = PTR_ERR(msm_dsi->connector); > + dev_err(dev->dev, "failed to create dsi connector: %d\n", ret); > + msm_dsi->connector = NULL; > + goto fail; > + } > + > + for (i = 0; i < base->num_encoders; i++) > + base->encoders[i]->bridge = msm_dsi->bridge; > + > + priv->bridges[priv->num_bridges++] = msm_dsi->bridge; > + priv->connectors[priv->num_connectors++] = msm_dsi->connector; > + > + return 0; > +fail: > + if (msm_dsi) { > + /* bridge/connector are normally destroyed by drm: */ > + if (msm_dsi->bridge) { > + msm_dsi_manager_bridge_destroy(msm_dsi->bridge); > + msm_dsi->bridge = NULL; > + } > + if (msm_dsi->connector) { > + msm_dsi->connector->funcs->destroy(msm_dsi->connector); > + msm_dsi->connector = NULL; > + } > + } > + > + return ret; > +} > + > +static void dsi_destroy(struct msm_dsi *msm_dsi) > +{ > + if (!msm_dsi) > + return; > + > + msm_dsi_manager_unregister(msm_dsi); > + if (msm_dsi->host) { > + msm_dsi_host_destroy(msm_dsi->host); > + msm_dsi->host = NULL; > + } > + > + platform_set_drvdata(msm_dsi->pdev, NULL); > +} > + > +static struct msm_dsi *dsi_init(struct platform_device *pdev) > +{ > + struct msm_dsi *msm_dsi = NULL; > + int ret; > + > + if (!pdev) { > + dev_err(&pdev->dev, "no dsi device\n"); > + ret = -ENXIO; > + goto fail; > + } > + > + msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL); > + if (!msm_dsi) { > + ret = -ENOMEM; > + goto fail; > + } > + DBG("dsi probed=%p", msm_dsi); > + > + msm_dsi->pdev = pdev; > + platform_set_drvdata(pdev, msm_dsi); > + > + /* Init dsi host */ > + ret = msm_dsi_host_init(msm_dsi); > + if (ret) > + goto fail; > + > + /* Register to dsi manager */ > + ret = msm_dsi_manager_register(msm_dsi); > + if (ret) > + goto fail; > + > + msm_dsi->base.modeset_init = msm_dsi_modeset_init; > + > + return msm_dsi; > + > +fail: > + if (msm_dsi) > + dsi_destroy(msm_dsi); > + > + return ERR_PTR(ret); > +} > + > +static int dsi_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 platform_device *pdev = to_platform_device(dev); > + struct msm_dsi *msm_dsi; > + > + DBG(""); > + msm_dsi = dsi_init(pdev); > + if (IS_ERR(msm_dsi)) > + return PTR_ERR(msm_dsi); > + > + priv->dsi[msm_dsi->id] = &msm_dsi->base; > + > + return 0; > +} > + > +static void dsi_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; > + struct msm_dsi *msm_dsi = dev_get_drvdata(dev); > + int id = msm_dsi->id; > + > + if (priv->dsi[id]) { > + dsi_destroy(msm_dsi); > + priv->dsi[id] = NULL; > + } > +} > + > +static const struct component_ops dsi_ops = { > + .bind = dsi_bind, > + .unbind = dsi_unbind, > +}; > + > +static int dsi_dev_probe(struct platform_device *pdev) > +{ > + return component_add(&pdev->dev, &dsi_ops); > +} > + > +static int dsi_dev_remove(struct platform_device *pdev) > +{ > + DBG(""); > + component_del(&pdev->dev, &dsi_ops); > + return 0; > +} > + > +static const struct of_device_id dt_match[] = { > + { .compatible = "qcom,mdss-dsi-ctrl" }, > + {} > +}; > + > +static struct platform_driver dsi_driver = { > + .probe = dsi_dev_probe, > + .remove = dsi_dev_remove, > + .driver = { > + .name = "msm_dsi", > + .of_match_table = dt_match, > + }, > +}; > + > +void __init msm_dsi_register(void) > +{ > + DBG(""); > + platform_driver_register(&dsi_driver); > +} > + > +void __exit msm_dsi_unregister(void) > +{ > + DBG(""); > + platform_driver_unregister(&dsi_driver); > +} > + > diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h > new file mode 100644 > index 0000000..1d24409 > --- /dev/null > +++ b/drivers/gpu/drm/msm/dsi/dsi.h > @@ -0,0 +1,115 @@ > +/* > + * Copyright (c) 2015, The Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only 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. > + */ > + > +#ifndef __DSI_CONNECTOR_H__ > +#define __DSI_CONNECTOR_H__ > + > +#include > + > +#include "drm_crtc.h" > +#include "drm_mipi_dsi.h" > +#include "drm_panel.h" > + > +#include "msm_drv.h" > + > +#define DSI_0 0 > +#define DSI_1 1 > +#define DSI_MAX 2 > + > +#define DSI_CLOCK_MASTER DSI_0 > +#define DSI_CLOCK_SLAVE DSI_1 > + > +#define DSI_LEFT DSI_0 > +#define DSI_RIGHT DSI_1 > + > +/* According to the current drm framework sequence, take the encoder of > + * DSI_1 as master encoder > + */ > +#define DSI_ENCODER_MASTER DSI_1 > +#define DSI_ENCODER_SLAVE DSI_0 > + > +struct msm_dsi { > + struct msm_drm_sub_dev base; > + struct drm_device *dev; > + struct platform_device *pdev; > + > + struct drm_connector *connector; > + struct drm_bridge *bridge; > + > + struct mipi_dsi_host *host; > + struct msm_dsi_phy *phy; > + struct drm_panel *panel; > + unsigned long panel_flags; > + bool phy_enabled; > + > + /* the encoder we are hooked to (outside of dsi block) */ > + struct drm_encoder *encoder; > + > + int id; > +}; > + > +/* dsi manager */ > +struct drm_bridge *msm_dsi_manager_bridge_init(u8 id); > +void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge); > +struct drm_connector *msm_dsi_manager_connector_init(u8 id); > +int msm_dsi_manager_phy_enable(int id, > + const unsigned long bit_rate, const unsigned long esc_rate, > + u32 *clk_pre, u32 *clk_post); > +void msm_dsi_manager_phy_disable(int id); > +int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); > +bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len); > +int msm_dsi_manager_register(struct msm_dsi *msm_dsi); > +void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); > + > +/* dsi host */ > +int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg); > +void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg); > +int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg); > +int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, > + const struct mipi_dsi_msg *msg); > +void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, > + u32 iova, u32 len); > +int msm_dsi_host_enable(struct mipi_dsi_host *host); > +int msm_dsi_host_disable(struct mipi_dsi_host *host); > +int msm_dsi_host_power_on(struct mipi_dsi_host *host); > +int msm_dsi_host_power_off(struct mipi_dsi_host *host); > +int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, > + struct drm_display_mode *mode); > +struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, > + unsigned long *panel_flags); > +int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer); > +void msm_dsi_host_unregister(struct mipi_dsi_host *host); > +void msm_dsi_host_destroy(struct mipi_dsi_host *host); > +int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, > + struct drm_device *dev); > +int msm_dsi_host_init(struct msm_dsi *msm_dsi); > + > +/* dsi phy */ > +struct msm_dsi_phy; > +enum msm_dsi_phy_type { > + MSM_DSI_PHY_UNKNOWN, > + MSM_DSI_PHY_28NM, > + MSM_DSI_PHY_MAX > +}; > +struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev, > + enum msm_dsi_phy_type type, int id); > +int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel, > + const unsigned long bit_rate, const unsigned long esc_rate); > +int msm_dsi_phy_disable(struct msm_dsi_phy *phy); > +void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, > + u32 *clk_pre, u32 *clk_post); > +#endif /* __DSI_CONNECTOR_H__ */ > + > diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c > new file mode 100644 > index 0000000..8db11eb > --- /dev/null > +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c > @@ -0,0 +1,1997 @@ > +/* > + * Copyright (c) 2015, The Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only 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. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include