1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27eb8f069SAndrzej Hajda /*
3e7447128SJagan Teki * Samsung MIPI DSIM glue for Exynos SoCs.
47eb8f069SAndrzej Hajda *
57eb8f069SAndrzej Hajda * Copyright (c) 2014 Samsung Electronics Co., Ltd
67eb8f069SAndrzej Hajda *
77eb8f069SAndrzej Hajda * Contacts: Tomasz Figa <t.figa@samsung.com>
87eb8f069SAndrzej Hajda */
97eb8f069SAndrzej Hajda
102bda34d7SSam Ravnborg #include <linux/component.h>
11*722d4f06SRob Herring #include <linux/of.h>
12*722d4f06SRob Herring #include <linux/platform_device.h>
132bda34d7SSam Ravnborg
14e7447128SJagan Teki #include <drm/bridge/samsung-dsim.h>
152bda34d7SSam Ravnborg #include <drm/drm_probe_helper.h>
163e1fe32dSThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
172bda34d7SSam Ravnborg
18e17ddeccSYoungJun Cho #include "exynos_drm_crtc.h"
197eb8f069SAndrzej Hajda #include "exynos_drm_drv.h"
207eb8f069SAndrzej Hajda
217eb8f069SAndrzej Hajda struct exynos_dsi {
2270e360f9SJagan Teki struct drm_encoder encoder;
237eb8f069SAndrzej Hajda };
247eb8f069SAndrzej Hajda
exynos_dsi_te_irq_handler(struct samsung_dsim * dsim)25e7447128SJagan Teki static irqreturn_t exynos_dsi_te_irq_handler(struct samsung_dsim *dsim)
265cd5db80SAndrzej Hajda {
27e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv;
28e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder;
2948b64ba8SJagan Teki
3048b64ba8SJagan Teki if (dsim->state & DSIM_STATE_VIDOUT_AVAILABLE)
3148b64ba8SJagan Teki exynos_drm_crtc_te_handler(encoder->crtc);
3248b64ba8SJagan Teki
3348b64ba8SJagan Teki return IRQ_HANDLED;
3448b64ba8SJagan Teki }
3548b64ba8SJagan Teki
exynos_dsi_host_attach(struct samsung_dsim * dsim,struct mipi_dsi_device * device)36e7447128SJagan Teki static int exynos_dsi_host_attach(struct samsung_dsim *dsim,
3770e360f9SJagan Teki struct mipi_dsi_device *device)
3870e360f9SJagan Teki {
39e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv;
40e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder;
4170e360f9SJagan Teki struct drm_device *drm = encoder->dev;
4270e360f9SJagan Teki
4370e360f9SJagan Teki drm_bridge_attach(encoder, &dsim->bridge,
4470e360f9SJagan Teki list_first_entry_or_null(&encoder->bridge_chain,
4570e360f9SJagan Teki struct drm_bridge,
4670e360f9SJagan Teki chain_node), 0);
4770e360f9SJagan Teki
4870e360f9SJagan Teki mutex_lock(&drm->mode_config.mutex);
4970e360f9SJagan Teki
5070e360f9SJagan Teki dsim->lanes = device->lanes;
5170e360f9SJagan Teki dsim->format = device->format;
5270e360f9SJagan Teki dsim->mode_flags = device->mode_flags;
5370e360f9SJagan Teki exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
5470e360f9SJagan Teki !(dsim->mode_flags & MIPI_DSI_MODE_VIDEO);
5570e360f9SJagan Teki
5670e360f9SJagan Teki mutex_unlock(&drm->mode_config.mutex);
5770e360f9SJagan Teki
5870e360f9SJagan Teki if (drm->mode_config.poll_enabled)
5970e360f9SJagan Teki drm_kms_helper_hotplug_event(drm);
6070e360f9SJagan Teki
6170e360f9SJagan Teki return 0;
6270e360f9SJagan Teki }
6370e360f9SJagan Teki
exynos_dsi_host_detach(struct samsung_dsim * dsim,struct mipi_dsi_device * device)64e7447128SJagan Teki static void exynos_dsi_host_detach(struct samsung_dsim *dsim,
6570e360f9SJagan Teki struct mipi_dsi_device *device)
6670e360f9SJagan Teki {
67e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv;
68e7447128SJagan Teki struct drm_device *drm = dsi->encoder.dev;
6970e360f9SJagan Teki
7070e360f9SJagan Teki if (drm->mode_config.poll_enabled)
7170e360f9SJagan Teki drm_kms_helper_hotplug_event(drm);
7270e360f9SJagan Teki }
7370e360f9SJagan Teki
exynos_dsi_bind(struct device * dev,struct device * master,void * data)74e7447128SJagan Teki static int exynos_dsi_bind(struct device *dev, struct device *master, void *data)
75f37cd5e8SInki Dae {
76e7447128SJagan Teki struct samsung_dsim *dsim = dev_get_drvdata(dev);
77e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv;
78e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder;
79f37cd5e8SInki Dae struct drm_device *drm_dev = data;
80f37cd5e8SInki Dae int ret;
81f37cd5e8SInki Dae
823e1fe32dSThomas Zimmermann drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
832b8376c8SGustavo Padovan
841ca582f1SAndrzej Hajda ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
851ca582f1SAndrzej Hajda if (ret < 0)
861ca582f1SAndrzej Hajda return ret;
871ca582f1SAndrzej Hajda
88e7447128SJagan Teki return mipi_dsi_host_register(&dsim->dsi_host);
89f37cd5e8SInki Dae }
90f37cd5e8SInki Dae
exynos_dsi_unbind(struct device * dev,struct device * master,void * data)91e7447128SJagan Teki static void exynos_dsi_unbind(struct device *dev, struct device *master, void *data)
92f37cd5e8SInki Dae {
93e7447128SJagan Teki struct samsung_dsim *dsim = dev_get_drvdata(dev);
94f37cd5e8SInki Dae
95e7447128SJagan Teki dsim->bridge.funcs->atomic_disable(&dsim->bridge, NULL);
96f37cd5e8SInki Dae
97e7447128SJagan Teki mipi_dsi_host_unregister(&dsim->dsi_host);
98f37cd5e8SInki Dae }
99f37cd5e8SInki Dae
100f37cd5e8SInki Dae static const struct component_ops exynos_dsi_component_ops = {
101f37cd5e8SInki Dae .bind = exynos_dsi_bind,
102f37cd5e8SInki Dae .unbind = exynos_dsi_unbind,
103f37cd5e8SInki Dae };
104f37cd5e8SInki Dae
exynos_dsi_register_host(struct samsung_dsim * dsim)105e7447128SJagan Teki static int exynos_dsi_register_host(struct samsung_dsim *dsim)
10670e360f9SJagan Teki {
107e7447128SJagan Teki struct exynos_dsi *dsi;
10870e360f9SJagan Teki
109e7447128SJagan Teki dsi = devm_kzalloc(dsim->dev, sizeof(*dsi), GFP_KERNEL);
110e7447128SJagan Teki if (!dsi)
11170e360f9SJagan Teki return -ENOMEM;
11270e360f9SJagan Teki
113e7447128SJagan Teki dsim->priv = dsi;
11470e360f9SJagan Teki dsim->bridge.pre_enable_prev_first = true;
11570e360f9SJagan Teki
11670e360f9SJagan Teki return component_add(dsim->dev, &exynos_dsi_component_ops);
11770e360f9SJagan Teki }
11870e360f9SJagan Teki
exynos_dsi_unregister_host(struct samsung_dsim * dsim)119e7447128SJagan Teki static void exynos_dsi_unregister_host(struct samsung_dsim *dsim)
12070e360f9SJagan Teki {
12170e360f9SJagan Teki component_del(dsim->dev, &exynos_dsi_component_ops);
12270e360f9SJagan Teki }
12370e360f9SJagan Teki
124e7447128SJagan Teki static const struct samsung_dsim_host_ops exynos_dsi_exynos_host_ops = {
12570e360f9SJagan Teki .register_host = exynos_dsi_register_host,
12670e360f9SJagan Teki .unregister_host = exynos_dsi_unregister_host,
127e7447128SJagan Teki .attach = exynos_dsi_host_attach,
128e7447128SJagan Teki .detach = exynos_dsi_host_detach,
129e7447128SJagan Teki .te_irq_handler = exynos_dsi_te_irq_handler,
13070e360f9SJagan Teki };
13170e360f9SJagan Teki
132e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos3250_dsi_pdata = {
1337e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS3250,
134e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops,
1357e9f0d32SJagan Teki };
1367e9f0d32SJagan Teki
137e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos4210_dsi_pdata = {
1387e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS4210,
139e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops,
1407e9f0d32SJagan Teki };
1417e9f0d32SJagan Teki
142e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5410_dsi_pdata = {
1437e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5410,
144e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops,
1457e9f0d32SJagan Teki };
1467e9f0d32SJagan Teki
147e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5422_dsi_pdata = {
1487e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5422,
149e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops,
1507e9f0d32SJagan Teki };
1517e9f0d32SJagan Teki
152e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5433_dsi_pdata = {
1537e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5433,
154e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops,
1557e9f0d32SJagan Teki };
1567e9f0d32SJagan Teki
1577e9f0d32SJagan Teki static const struct of_device_id exynos_dsi_of_match[] = {
1587e9f0d32SJagan Teki {
1597e9f0d32SJagan Teki .compatible = "samsung,exynos3250-mipi-dsi",
1607e9f0d32SJagan Teki .data = &exynos3250_dsi_pdata,
1617e9f0d32SJagan Teki },
1627e9f0d32SJagan Teki {
1637e9f0d32SJagan Teki .compatible = "samsung,exynos4210-mipi-dsi",
1647e9f0d32SJagan Teki .data = &exynos4210_dsi_pdata,
1657e9f0d32SJagan Teki },
1667e9f0d32SJagan Teki {
1677e9f0d32SJagan Teki .compatible = "samsung,exynos5410-mipi-dsi",
1687e9f0d32SJagan Teki .data = &exynos5410_dsi_pdata,
1697e9f0d32SJagan Teki },
1707e9f0d32SJagan Teki {
1717e9f0d32SJagan Teki .compatible = "samsung,exynos5422-mipi-dsi",
1727e9f0d32SJagan Teki .data = &exynos5422_dsi_pdata,
1737e9f0d32SJagan Teki },
1747e9f0d32SJagan Teki {
1757e9f0d32SJagan Teki .compatible = "samsung,exynos5433-mipi-dsi",
1767e9f0d32SJagan Teki .data = &exynos5433_dsi_pdata,
1777e9f0d32SJagan Teki },
1787e9f0d32SJagan Teki { /* sentinel. */ }
1797e9f0d32SJagan Teki };
1807e9f0d32SJagan Teki MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
1817e9f0d32SJagan Teki
1827eb8f069SAndrzej Hajda struct platform_driver dsi_driver = {
183e7447128SJagan Teki .probe = samsung_dsim_probe,
184e7447128SJagan Teki .remove = samsung_dsim_remove,
1857eb8f069SAndrzej Hajda .driver = {
1867eb8f069SAndrzej Hajda .name = "exynos-dsi",
1877eb8f069SAndrzej Hajda .owner = THIS_MODULE,
188e7447128SJagan Teki .pm = &samsung_dsim_pm_ops,
1897eb8f069SAndrzej Hajda .of_match_table = exynos_dsi_of_match,
1907eb8f069SAndrzej Hajda },
1917eb8f069SAndrzej Hajda };
1927eb8f069SAndrzej Hajda
1937eb8f069SAndrzej Hajda MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
1947eb8f069SAndrzej Hajda MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
1957eb8f069SAndrzej Hajda MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
1967eb8f069SAndrzej Hajda MODULE_LICENSE("GPL v2");
197