Skip to content

Commit a689554

Browse files
Hai Lirobclark
authored andcommitted
drm/msm: Initial add DSI connector support
This change adds the DSI connector support in msm drm driver. v1: Initial change v2: - Address comments from Archit + minor clean-ups - Rebase to not depend on msm_drm_sub_dev change [Rob's comment] v3: Fix issues when initialization is failed Signed-off-by: Hai Li <[email protected]> Signed-off-by: Rob Clark <[email protected]>
1 parent 7a6dc95 commit a689554

File tree

8 files changed

+3423
-0
lines changed

8 files changed

+3423
-0
lines changed

drivers/gpu/drm/msm/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,14 @@ config DRM_MSM_REGISTER_LOGGING
3535
Compile in support for logging register reads/writes in a format
3636
that can be parsed by envytools demsm tool. If enabled, register
3737
logging can be switched on via msm.reglog=y module param.
38+
39+
config DRM_MSM_DSI
40+
bool "Enable DSI support in MSM DRM driver"
41+
depends on DRM_MSM
42+
select DRM_PANEL
43+
select DRM_MIPI_DSI
44+
default y
45+
help
46+
Choose this option if you have a need for MIPI DSI connector
47+
support.
48+

drivers/gpu/drm/msm/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,9 @@ msm-y := \
5050

5151
msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
5252
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
53+
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
54+
dsi/dsi_host.o \
55+
dsi/dsi_manager.o \
56+
dsi/dsi_phy.o
5357

5458
obj-$(CONFIG_DRM_MSM) += msm.o

drivers/gpu/drm/msm/dsi/dsi.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 and
6+
* only version 2 as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include "dsi.h"
15+
16+
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
17+
{
18+
if (!msm_dsi || !msm_dsi->panel)
19+
return NULL;
20+
21+
return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
22+
msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
23+
msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
24+
}
25+
26+
static void dsi_destroy(struct msm_dsi *msm_dsi)
27+
{
28+
if (!msm_dsi)
29+
return;
30+
31+
msm_dsi_manager_unregister(msm_dsi);
32+
if (msm_dsi->host) {
33+
msm_dsi_host_destroy(msm_dsi->host);
34+
msm_dsi->host = NULL;
35+
}
36+
37+
platform_set_drvdata(msm_dsi->pdev, NULL);
38+
}
39+
40+
static struct msm_dsi *dsi_init(struct platform_device *pdev)
41+
{
42+
struct msm_dsi *msm_dsi = NULL;
43+
int ret;
44+
45+
if (!pdev) {
46+
dev_err(&pdev->dev, "no dsi device\n");
47+
ret = -ENXIO;
48+
goto fail;
49+
}
50+
51+
msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
52+
if (!msm_dsi) {
53+
ret = -ENOMEM;
54+
goto fail;
55+
}
56+
DBG("dsi probed=%p", msm_dsi);
57+
58+
msm_dsi->pdev = pdev;
59+
platform_set_drvdata(pdev, msm_dsi);
60+
61+
/* Init dsi host */
62+
ret = msm_dsi_host_init(msm_dsi);
63+
if (ret)
64+
goto fail;
65+
66+
/* Register to dsi manager */
67+
ret = msm_dsi_manager_register(msm_dsi);
68+
if (ret)
69+
goto fail;
70+
71+
return msm_dsi;
72+
73+
fail:
74+
if (msm_dsi)
75+
dsi_destroy(msm_dsi);
76+
77+
return ERR_PTR(ret);
78+
}
79+
80+
static int dsi_bind(struct device *dev, struct device *master, void *data)
81+
{
82+
struct drm_device *drm = dev_get_drvdata(master);
83+
struct msm_drm_private *priv = drm->dev_private;
84+
struct platform_device *pdev = to_platform_device(dev);
85+
struct msm_dsi *msm_dsi;
86+
87+
DBG("");
88+
msm_dsi = dsi_init(pdev);
89+
if (IS_ERR(msm_dsi))
90+
return PTR_ERR(msm_dsi);
91+
92+
priv->dsi[msm_dsi->id] = msm_dsi;
93+
94+
return 0;
95+
}
96+
97+
static void dsi_unbind(struct device *dev, struct device *master,
98+
void *data)
99+
{
100+
struct drm_device *drm = dev_get_drvdata(master);
101+
struct msm_drm_private *priv = drm->dev_private;
102+
struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
103+
int id = msm_dsi->id;
104+
105+
if (priv->dsi[id]) {
106+
dsi_destroy(msm_dsi);
107+
priv->dsi[id] = NULL;
108+
}
109+
}
110+
111+
static const struct component_ops dsi_ops = {
112+
.bind = dsi_bind,
113+
.unbind = dsi_unbind,
114+
};
115+
116+
static int dsi_dev_probe(struct platform_device *pdev)
117+
{
118+
return component_add(&pdev->dev, &dsi_ops);
119+
}
120+
121+
static int dsi_dev_remove(struct platform_device *pdev)
122+
{
123+
DBG("");
124+
component_del(&pdev->dev, &dsi_ops);
125+
return 0;
126+
}
127+
128+
static const struct of_device_id dt_match[] = {
129+
{ .compatible = "qcom,mdss-dsi-ctrl" },
130+
{}
131+
};
132+
133+
static struct platform_driver dsi_driver = {
134+
.probe = dsi_dev_probe,
135+
.remove = dsi_dev_remove,
136+
.driver = {
137+
.name = "msm_dsi",
138+
.of_match_table = dt_match,
139+
},
140+
};
141+
142+
void __init msm_dsi_register(void)
143+
{
144+
DBG("");
145+
platform_driver_register(&dsi_driver);
146+
}
147+
148+
void __exit msm_dsi_unregister(void)
149+
{
150+
DBG("");
151+
platform_driver_unregister(&dsi_driver);
152+
}
153+
154+
int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
155+
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
156+
{
157+
struct msm_drm_private *priv = dev->dev_private;
158+
int ret, i;
159+
160+
if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
161+
!encoders[MSM_DSI_CMD_ENCODER_ID]))
162+
return -EINVAL;
163+
164+
msm_dsi->dev = dev;
165+
166+
ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
167+
if (ret) {
168+
dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
169+
goto fail;
170+
}
171+
172+
msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
173+
if (IS_ERR(msm_dsi->bridge)) {
174+
ret = PTR_ERR(msm_dsi->bridge);
175+
dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
176+
msm_dsi->bridge = NULL;
177+
goto fail;
178+
}
179+
180+
msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
181+
if (IS_ERR(msm_dsi->connector)) {
182+
ret = PTR_ERR(msm_dsi->connector);
183+
dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
184+
msm_dsi->connector = NULL;
185+
goto fail;
186+
}
187+
188+
for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
189+
encoders[i]->bridge = msm_dsi->bridge;
190+
msm_dsi->encoders[i] = encoders[i];
191+
}
192+
193+
priv->bridges[priv->num_bridges++] = msm_dsi->bridge;
194+
priv->connectors[priv->num_connectors++] = msm_dsi->connector;
195+
196+
return 0;
197+
fail:
198+
if (msm_dsi) {
199+
/* bridge/connector are normally destroyed by drm: */
200+
if (msm_dsi->bridge) {
201+
msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
202+
msm_dsi->bridge = NULL;
203+
}
204+
if (msm_dsi->connector) {
205+
msm_dsi->connector->funcs->destroy(msm_dsi->connector);
206+
msm_dsi->connector = NULL;
207+
}
208+
}
209+
210+
return ret;
211+
}
212+

drivers/gpu/drm/msm/dsi/dsi.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 and
6+
* only version 2 as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#ifndef __DSI_CONNECTOR_H__
15+
#define __DSI_CONNECTOR_H__
16+
17+
#include <linux/platform_device.h>
18+
19+
#include "drm_crtc.h"
20+
#include "drm_mipi_dsi.h"
21+
#include "drm_panel.h"
22+
23+
#include "msm_drv.h"
24+
25+
#define DSI_0 0
26+
#define DSI_1 1
27+
#define DSI_MAX 2
28+
29+
#define DSI_CLOCK_MASTER DSI_0
30+
#define DSI_CLOCK_SLAVE DSI_1
31+
32+
#define DSI_LEFT DSI_0
33+
#define DSI_RIGHT DSI_1
34+
35+
/* According to the current drm framework sequence, take the encoder of
36+
* DSI_1 as master encoder
37+
*/
38+
#define DSI_ENCODER_MASTER DSI_1
39+
#define DSI_ENCODER_SLAVE DSI_0
40+
41+
struct msm_dsi {
42+
struct drm_device *dev;
43+
struct platform_device *pdev;
44+
45+
struct drm_connector *connector;
46+
struct drm_bridge *bridge;
47+
48+
struct mipi_dsi_host *host;
49+
struct msm_dsi_phy *phy;
50+
struct drm_panel *panel;
51+
unsigned long panel_flags;
52+
bool phy_enabled;
53+
54+
/* the encoders we are hooked to (outside of dsi block) */
55+
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM];
56+
57+
int id;
58+
};
59+
60+
/* dsi manager */
61+
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
62+
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
63+
struct drm_connector *msm_dsi_manager_connector_init(u8 id);
64+
int msm_dsi_manager_phy_enable(int id,
65+
const unsigned long bit_rate, const unsigned long esc_rate,
66+
u32 *clk_pre, u32 *clk_post);
67+
void msm_dsi_manager_phy_disable(int id);
68+
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
69+
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len);
70+
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
71+
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
72+
73+
/* msm dsi */
74+
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
75+
76+
/* dsi host */
77+
int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
78+
const struct mipi_dsi_msg *msg);
79+
void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
80+
const struct mipi_dsi_msg *msg);
81+
int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
82+
const struct mipi_dsi_msg *msg);
83+
int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
84+
const struct mipi_dsi_msg *msg);
85+
void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
86+
u32 iova, u32 len);
87+
int msm_dsi_host_enable(struct mipi_dsi_host *host);
88+
int msm_dsi_host_disable(struct mipi_dsi_host *host);
89+
int msm_dsi_host_power_on(struct mipi_dsi_host *host);
90+
int msm_dsi_host_power_off(struct mipi_dsi_host *host);
91+
int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
92+
struct drm_display_mode *mode);
93+
struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
94+
unsigned long *panel_flags);
95+
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
96+
void msm_dsi_host_unregister(struct mipi_dsi_host *host);
97+
void msm_dsi_host_destroy(struct mipi_dsi_host *host);
98+
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
99+
struct drm_device *dev);
100+
int msm_dsi_host_init(struct msm_dsi *msm_dsi);
101+
102+
/* dsi phy */
103+
struct msm_dsi_phy;
104+
enum msm_dsi_phy_type {
105+
MSM_DSI_PHY_UNKNOWN,
106+
MSM_DSI_PHY_28NM,
107+
MSM_DSI_PHY_MAX
108+
};
109+
struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
110+
enum msm_dsi_phy_type type, int id);
111+
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
112+
const unsigned long bit_rate, const unsigned long esc_rate);
113+
int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
114+
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
115+
u32 *clk_pre, u32 *clk_post);
116+
#endif /* __DSI_CONNECTOR_H__ */
117+

0 commit comments

Comments
 (0)