Skip to content

Commit 1e4d58c

Browse files
committed
drm/bridge: adv7533: Create a MIPI DSI device
In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host. Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host. Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now. Select DRM_MIPI_DSI config option only when ADV7533 support is enabled. Signed-off-by: Archit Taneja <[email protected]>
1 parent 2437e7c commit 1e4d58c

File tree

4 files changed

+147
-8
lines changed

4 files changed

+147
-8
lines changed

drivers/gpu/drm/bridge/adv7511/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ config DRM_I2C_ADV7511
99
config DRM_I2C_ADV7533
1010
bool "ADV7533 encoder"
1111
depends on DRM_I2C_ADV7511
12+
select DRM_MIPI_DSI
1213
default y
1314
help
1415
Support for the Analog Devices ADV7533 DSI to HDMI encoder.

drivers/gpu/drm/bridge/adv7511/adv7511.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/regmap.h>
1515

1616
#include <drm/drm_crtc_helper.h>
17+
#include <drm/drm_mipi_dsi.h>
1718

1819
#define ADV7511_REG_CHIP_REVISION 0x00
1920
#define ADV7511_REG_N0 0x01
@@ -324,6 +325,11 @@ struct adv7511 {
324325

325326
struct gpio_desc *gpio_pd;
326327

328+
/* ADV7533 DSI RX related params */
329+
struct device_node *host_node;
330+
struct mipi_dsi_device *dsi;
331+
u8 num_dsi_lanes;
332+
327333
enum adv7511_type type;
328334
};
329335

@@ -333,6 +339,9 @@ void adv7533_dsi_power_off(struct adv7511 *adv);
333339
int adv7533_patch_registers(struct adv7511 *adv);
334340
void adv7533_uninit_cec(struct adv7511 *adv);
335341
int adv7533_init_cec(struct adv7511 *adv);
342+
int adv7533_attach_dsi(struct adv7511 *adv);
343+
void adv7533_detach_dsi(struct adv7511 *adv);
344+
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
336345
#else
337346
static inline void adv7533_dsi_power_on(struct adv7511 *adv)
338347
{
@@ -355,6 +364,20 @@ static inline int adv7533_init_cec(struct adv7511 *adv)
355364
{
356365
return -ENODEV;
357366
}
367+
368+
static inline int adv7533_attach_dsi(struct adv7511 *adv)
369+
{
370+
return -ENODEV;
371+
}
372+
373+
static inline void adv7533_detach_dsi(struct adv7511 *adv)
374+
{
375+
}
376+
377+
static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
378+
{
379+
return -ENODEV;
380+
}
358381
#endif
359382

360383
#endif /* __DRM_I2C_ADV7511_H__ */

drivers/gpu/drm/bridge/adv7511/adv7511_drv.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
817817
&adv7511_connector_helper_funcs);
818818
drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
819819

820+
if (adv->type == ADV7533)
821+
ret = adv7533_attach_dsi(adv);
822+
820823
return ret;
821824
}
822825

@@ -943,11 +946,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
943946

944947
memset(&link_config, 0, sizeof(link_config));
945948

946-
if (adv7511->type == ADV7511) {
949+
if (adv7511->type == ADV7511)
947950
ret = adv7511_parse_dt(dev->of_node, &link_config);
948-
if (ret)
949-
return ret;
950-
}
951+
else
952+
ret = adv7533_parse_dt(dev->of_node, adv7511);
953+
if (ret)
954+
return ret;
951955

952956
/*
953957
* The power down GPIO is optional. If present, toggle it from active to
@@ -1042,9 +1046,13 @@ static int adv7511_remove(struct i2c_client *i2c)
10421046
{
10431047
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
10441048

1049+
if (adv7511->type == ADV7533) {
1050+
adv7533_detach_dsi(adv7511);
1051+
adv7533_uninit_cec(adv7511);
1052+
}
1053+
10451054
drm_bridge_remove(&adv7511->bridge);
10461055

1047-
adv7533_uninit_cec(adv7511);
10481056
i2c_unregister_device(adv7511->i2c_edid);
10491057

10501058
kfree(adv7511->edid);
@@ -1074,6 +1082,10 @@ static const struct of_device_id adv7511_of_ids[] = {
10741082
};
10751083
MODULE_DEVICE_TABLE(of, adv7511_of_ids);
10761084

1085+
static struct mipi_dsi_driver adv7533_dsi_driver = {
1086+
.driver.name = "adv7533",
1087+
};
1088+
10771089
static struct i2c_driver adv7511_driver = {
10781090
.driver = {
10791091
.name = "adv7511",
@@ -1084,7 +1096,23 @@ static struct i2c_driver adv7511_driver = {
10841096
.remove = adv7511_remove,
10851097
};
10861098

1087-
module_i2c_driver(adv7511_driver);
1099+
static int __init adv7511_init(void)
1100+
{
1101+
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
1102+
mipi_dsi_driver_register(&adv7533_dsi_driver);
1103+
1104+
return i2c_add_driver(&adv7511_driver);
1105+
}
1106+
module_init(adv7511_init);
1107+
1108+
static void __exit adv7511_exit(void)
1109+
{
1110+
i2c_del_driver(&adv7511_driver);
1111+
1112+
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
1113+
mipi_dsi_driver_unregister(&adv7533_dsi_driver);
1114+
}
1115+
module_exit(adv7511_exit);
10881116

10891117
MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
10901118
MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");

drivers/gpu/drm/bridge/adv7511/adv7533.c

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* GNU General Public License for more details.
1212
*/
1313

14+
#include <linux/of_graph.h>
15+
1416
#include "adv7511.h"
1517

1618
static const struct reg_sequence adv7533_fixed_registers[] = {
@@ -39,8 +41,10 @@ static const struct regmap_config adv7533_cec_regmap_config = {
3941

4042
void adv7533_dsi_power_on(struct adv7511 *adv)
4143
{
42-
/* set number of dsi lanes (hardcoded to 4 for now) */
43-
regmap_write(adv->regmap_cec, 0x1c, 4 << 4);
44+
struct mipi_dsi_device *dsi = adv->dsi;
45+
46+
/* set number of dsi lanes */
47+
regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
4448
/* disable internal timing generator */
4549
regmap_write(adv->regmap_cec, 0x27, 0x0b);
4650
/* enable hdmi */
@@ -98,3 +102,86 @@ int adv7533_init_cec(struct adv7511 *adv)
98102
adv7533_uninit_cec(adv);
99103
return ret;
100104
}
105+
106+
int adv7533_attach_dsi(struct adv7511 *adv)
107+
{
108+
struct device *dev = &adv->i2c_main->dev;
109+
struct mipi_dsi_host *host;
110+
struct mipi_dsi_device *dsi;
111+
int ret = 0;
112+
const struct mipi_dsi_device_info info = { .type = "adv7533",
113+
.channel = 0,
114+
.node = NULL,
115+
};
116+
117+
host = of_find_mipi_dsi_host_by_node(adv->host_node);
118+
if (!host) {
119+
dev_err(dev, "failed to find dsi host\n");
120+
return -EPROBE_DEFER;
121+
}
122+
123+
dsi = mipi_dsi_device_register_full(host, &info);
124+
if (IS_ERR(dsi)) {
125+
dev_err(dev, "failed to create dsi device\n");
126+
ret = PTR_ERR(dsi);
127+
goto err_dsi_device;
128+
}
129+
130+
adv->dsi = dsi;
131+
132+
dsi->lanes = adv->num_dsi_lanes;
133+
dsi->format = MIPI_DSI_FMT_RGB888;
134+
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
135+
MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
136+
137+
ret = mipi_dsi_attach(dsi);
138+
if (ret < 0) {
139+
dev_err(dev, "failed to attach dsi to host\n");
140+
goto err_dsi_attach;
141+
}
142+
143+
return 0;
144+
145+
err_dsi_attach:
146+
mipi_dsi_device_unregister(dsi);
147+
err_dsi_device:
148+
return ret;
149+
}
150+
151+
void adv7533_detach_dsi(struct adv7511 *adv)
152+
{
153+
mipi_dsi_detach(adv->dsi);
154+
mipi_dsi_device_unregister(adv->dsi);
155+
}
156+
157+
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
158+
{
159+
u32 num_lanes;
160+
struct device_node *endpoint;
161+
162+
of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
163+
164+
if (num_lanes < 1 || num_lanes > 4)
165+
return -EINVAL;
166+
167+
adv->num_dsi_lanes = num_lanes;
168+
169+
endpoint = of_graph_get_next_endpoint(np, NULL);
170+
if (!endpoint)
171+
return -ENODEV;
172+
173+
adv->host_node = of_graph_get_remote_port_parent(endpoint);
174+
if (!adv->host_node) {
175+
of_node_put(endpoint);
176+
return -ENODEV;
177+
}
178+
179+
of_node_put(endpoint);
180+
of_node_put(adv->host_node);
181+
182+
/* TODO: Check if these need to be parsed by DT or not */
183+
adv->rgb = true;
184+
adv->embedded_sync = false;
185+
186+
return 0;
187+
}

0 commit comments

Comments
 (0)