1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27eb8f069SAndrzej Hajda /* 3*e7447128SJagan 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> 119a320415SYoungJun Cho #include <linux/of_device.h> 122bda34d7SSam Ravnborg 13*e7447128SJagan Teki #include <drm/bridge/samsung-dsim.h> 142bda34d7SSam Ravnborg #include <drm/drm_probe_helper.h> 153e1fe32dSThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 162bda34d7SSam Ravnborg 17e17ddeccSYoungJun Cho #include "exynos_drm_crtc.h" 187eb8f069SAndrzej Hajda #include "exynos_drm_drv.h" 197eb8f069SAndrzej Hajda 207eb8f069SAndrzej Hajda struct exynos_dsi { 2170e360f9SJagan Teki struct drm_encoder encoder; 227eb8f069SAndrzej Hajda }; 237eb8f069SAndrzej Hajda 24*e7447128SJagan Teki static irqreturn_t exynos_dsi_te_irq_handler(struct samsung_dsim *dsim) 255cd5db80SAndrzej Hajda { 26*e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv; 27*e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder; 2848b64ba8SJagan Teki 2948b64ba8SJagan Teki if (dsim->state & DSIM_STATE_VIDOUT_AVAILABLE) 3048b64ba8SJagan Teki exynos_drm_crtc_te_handler(encoder->crtc); 3148b64ba8SJagan Teki 3248b64ba8SJagan Teki return IRQ_HANDLED; 3348b64ba8SJagan Teki } 3448b64ba8SJagan Teki 35*e7447128SJagan Teki static int exynos_dsi_host_attach(struct samsung_dsim *dsim, 3670e360f9SJagan Teki struct mipi_dsi_device *device) 3770e360f9SJagan Teki { 38*e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv; 39*e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder; 4070e360f9SJagan Teki struct drm_device *drm = encoder->dev; 4170e360f9SJagan Teki 4270e360f9SJagan Teki drm_bridge_attach(encoder, &dsim->bridge, 4370e360f9SJagan Teki list_first_entry_or_null(&encoder->bridge_chain, 4470e360f9SJagan Teki struct drm_bridge, 4570e360f9SJagan Teki chain_node), 0); 4670e360f9SJagan Teki 4770e360f9SJagan Teki mutex_lock(&drm->mode_config.mutex); 4870e360f9SJagan Teki 4970e360f9SJagan Teki dsim->lanes = device->lanes; 5070e360f9SJagan Teki dsim->format = device->format; 5170e360f9SJagan Teki dsim->mode_flags = device->mode_flags; 5270e360f9SJagan Teki exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode = 5370e360f9SJagan Teki !(dsim->mode_flags & MIPI_DSI_MODE_VIDEO); 5470e360f9SJagan Teki 5570e360f9SJagan Teki mutex_unlock(&drm->mode_config.mutex); 5670e360f9SJagan Teki 5770e360f9SJagan Teki if (drm->mode_config.poll_enabled) 5870e360f9SJagan Teki drm_kms_helper_hotplug_event(drm); 5970e360f9SJagan Teki 6070e360f9SJagan Teki return 0; 6170e360f9SJagan Teki } 6270e360f9SJagan Teki 63*e7447128SJagan Teki static void exynos_dsi_host_detach(struct samsung_dsim *dsim, 6470e360f9SJagan Teki struct mipi_dsi_device *device) 6570e360f9SJagan Teki { 66*e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv; 67*e7447128SJagan Teki struct drm_device *drm = dsi->encoder.dev; 6870e360f9SJagan Teki 6970e360f9SJagan Teki if (drm->mode_config.poll_enabled) 7070e360f9SJagan Teki drm_kms_helper_hotplug_event(drm); 7170e360f9SJagan Teki } 7270e360f9SJagan Teki 73*e7447128SJagan Teki static int exynos_dsi_bind(struct device *dev, struct device *master, void *data) 74f37cd5e8SInki Dae { 75*e7447128SJagan Teki struct samsung_dsim *dsim = dev_get_drvdata(dev); 76*e7447128SJagan Teki struct exynos_dsi *dsi = dsim->priv; 77*e7447128SJagan Teki struct drm_encoder *encoder = &dsi->encoder; 78f37cd5e8SInki Dae struct drm_device *drm_dev = data; 79f37cd5e8SInki Dae int ret; 80f37cd5e8SInki Dae 813e1fe32dSThomas Zimmermann drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS); 822b8376c8SGustavo Padovan 831ca582f1SAndrzej Hajda ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); 841ca582f1SAndrzej Hajda if (ret < 0) 851ca582f1SAndrzej Hajda return ret; 861ca582f1SAndrzej Hajda 87*e7447128SJagan Teki return mipi_dsi_host_register(&dsim->dsi_host); 88f37cd5e8SInki Dae } 89f37cd5e8SInki Dae 90*e7447128SJagan Teki static void exynos_dsi_unbind(struct device *dev, struct device *master, void *data) 91f37cd5e8SInki Dae { 92*e7447128SJagan Teki struct samsung_dsim *dsim = dev_get_drvdata(dev); 93f37cd5e8SInki Dae 94*e7447128SJagan Teki dsim->bridge.funcs->atomic_disable(&dsim->bridge, NULL); 95f37cd5e8SInki Dae 96*e7447128SJagan Teki mipi_dsi_host_unregister(&dsim->dsi_host); 97f37cd5e8SInki Dae } 98f37cd5e8SInki Dae 99f37cd5e8SInki Dae static const struct component_ops exynos_dsi_component_ops = { 100f37cd5e8SInki Dae .bind = exynos_dsi_bind, 101f37cd5e8SInki Dae .unbind = exynos_dsi_unbind, 102f37cd5e8SInki Dae }; 103f37cd5e8SInki Dae 104*e7447128SJagan Teki static int exynos_dsi_register_host(struct samsung_dsim *dsim) 10570e360f9SJagan Teki { 106*e7447128SJagan Teki struct exynos_dsi *dsi; 10770e360f9SJagan Teki 108*e7447128SJagan Teki dsi = devm_kzalloc(dsim->dev, sizeof(*dsi), GFP_KERNEL); 109*e7447128SJagan Teki if (!dsi) 11070e360f9SJagan Teki return -ENOMEM; 11170e360f9SJagan Teki 112*e7447128SJagan Teki dsim->priv = dsi; 11370e360f9SJagan Teki dsim->bridge.pre_enable_prev_first = true; 11470e360f9SJagan Teki 11570e360f9SJagan Teki return component_add(dsim->dev, &exynos_dsi_component_ops); 11670e360f9SJagan Teki } 11770e360f9SJagan Teki 118*e7447128SJagan Teki static void exynos_dsi_unregister_host(struct samsung_dsim *dsim) 11970e360f9SJagan Teki { 12070e360f9SJagan Teki component_del(dsim->dev, &exynos_dsi_component_ops); 12170e360f9SJagan Teki } 12270e360f9SJagan Teki 123*e7447128SJagan Teki static const struct samsung_dsim_host_ops exynos_dsi_exynos_host_ops = { 12470e360f9SJagan Teki .register_host = exynos_dsi_register_host, 12570e360f9SJagan Teki .unregister_host = exynos_dsi_unregister_host, 126*e7447128SJagan Teki .attach = exynos_dsi_host_attach, 127*e7447128SJagan Teki .detach = exynos_dsi_host_detach, 128*e7447128SJagan Teki .te_irq_handler = exynos_dsi_te_irq_handler, 12970e360f9SJagan Teki }; 13070e360f9SJagan Teki 131*e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos3250_dsi_pdata = { 1327e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS3250, 133*e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops, 1347e9f0d32SJagan Teki }; 1357e9f0d32SJagan Teki 136*e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos4210_dsi_pdata = { 1377e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS4210, 138*e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops, 1397e9f0d32SJagan Teki }; 1407e9f0d32SJagan Teki 141*e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5410_dsi_pdata = { 1427e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5410, 143*e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops, 1447e9f0d32SJagan Teki }; 1457e9f0d32SJagan Teki 146*e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5422_dsi_pdata = { 1477e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5422, 148*e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops, 1497e9f0d32SJagan Teki }; 1507e9f0d32SJagan Teki 151*e7447128SJagan Teki static const struct samsung_dsim_plat_data exynos5433_dsi_pdata = { 1527e9f0d32SJagan Teki .hw_type = DSIM_TYPE_EXYNOS5433, 153*e7447128SJagan Teki .host_ops = &exynos_dsi_exynos_host_ops, 1547e9f0d32SJagan Teki }; 1557e9f0d32SJagan Teki 1567e9f0d32SJagan Teki static const struct of_device_id exynos_dsi_of_match[] = { 1577e9f0d32SJagan Teki { 1587e9f0d32SJagan Teki .compatible = "samsung,exynos3250-mipi-dsi", 1597e9f0d32SJagan Teki .data = &exynos3250_dsi_pdata, 1607e9f0d32SJagan Teki }, 1617e9f0d32SJagan Teki { 1627e9f0d32SJagan Teki .compatible = "samsung,exynos4210-mipi-dsi", 1637e9f0d32SJagan Teki .data = &exynos4210_dsi_pdata, 1647e9f0d32SJagan Teki }, 1657e9f0d32SJagan Teki { 1667e9f0d32SJagan Teki .compatible = "samsung,exynos5410-mipi-dsi", 1677e9f0d32SJagan Teki .data = &exynos5410_dsi_pdata, 1687e9f0d32SJagan Teki }, 1697e9f0d32SJagan Teki { 1707e9f0d32SJagan Teki .compatible = "samsung,exynos5422-mipi-dsi", 1717e9f0d32SJagan Teki .data = &exynos5422_dsi_pdata, 1727e9f0d32SJagan Teki }, 1737e9f0d32SJagan Teki { 1747e9f0d32SJagan Teki .compatible = "samsung,exynos5433-mipi-dsi", 1757e9f0d32SJagan Teki .data = &exynos5433_dsi_pdata, 1767e9f0d32SJagan Teki }, 1777e9f0d32SJagan Teki { /* sentinel. */ } 1787e9f0d32SJagan Teki }; 1797e9f0d32SJagan Teki MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); 1807e9f0d32SJagan Teki 1817eb8f069SAndrzej Hajda struct platform_driver dsi_driver = { 182*e7447128SJagan Teki .probe = samsung_dsim_probe, 183*e7447128SJagan Teki .remove = samsung_dsim_remove, 1847eb8f069SAndrzej Hajda .driver = { 1857eb8f069SAndrzej Hajda .name = "exynos-dsi", 1867eb8f069SAndrzej Hajda .owner = THIS_MODULE, 187*e7447128SJagan Teki .pm = &samsung_dsim_pm_ops, 1887eb8f069SAndrzej Hajda .of_match_table = exynos_dsi_of_match, 1897eb8f069SAndrzej Hajda }, 1907eb8f069SAndrzej Hajda }; 1917eb8f069SAndrzej Hajda 1927eb8f069SAndrzej Hajda MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); 1937eb8f069SAndrzej Hajda MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 1947eb8f069SAndrzej Hajda MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); 1957eb8f069SAndrzej Hajda MODULE_LICENSE("GPL v2"); 196