162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2015, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "dsi.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_cibool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi) 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host); 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci return !(host_flags & MIPI_DSI_MODE_VIDEO); 1362306a36Sopenharmony_ci} 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci return msm_dsi_host_get_dsc_config(msm_dsi->host); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int dsi_get_phy(struct msm_dsi *msm_dsi) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct platform_device *pdev = msm_dsi->pdev; 2362306a36Sopenharmony_ci struct platform_device *phy_pdev; 2462306a36Sopenharmony_ci struct device_node *phy_node; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0); 2762306a36Sopenharmony_ci if (!phy_node) { 2862306a36Sopenharmony_ci DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n"); 2962306a36Sopenharmony_ci return -ENXIO; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci phy_pdev = of_find_device_by_node(phy_node); 3362306a36Sopenharmony_ci if (phy_pdev) { 3462306a36Sopenharmony_ci msm_dsi->phy = platform_get_drvdata(phy_pdev); 3562306a36Sopenharmony_ci msm_dsi->phy_dev = &phy_pdev->dev; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci of_node_put(phy_node); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (!phy_pdev) { 4162306a36Sopenharmony_ci DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__); 4262306a36Sopenharmony_ci return -EPROBE_DEFER; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci if (!msm_dsi->phy) { 4562306a36Sopenharmony_ci put_device(&phy_pdev->dev); 4662306a36Sopenharmony_ci DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__); 4762306a36Sopenharmony_ci return -EPROBE_DEFER; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void dsi_destroy(struct msm_dsi *msm_dsi) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci if (!msm_dsi) 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci msm_dsi_manager_unregister(msm_dsi); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (msm_dsi->phy_dev) { 6162306a36Sopenharmony_ci put_device(msm_dsi->phy_dev); 6262306a36Sopenharmony_ci msm_dsi->phy = NULL; 6362306a36Sopenharmony_ci msm_dsi->phy_dev = NULL; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (msm_dsi->host) { 6762306a36Sopenharmony_ci msm_dsi_host_destroy(msm_dsi->host); 6862306a36Sopenharmony_ci msm_dsi->host = NULL; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci platform_set_drvdata(msm_dsi->pdev, NULL); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct msm_dsi *dsi_init(struct platform_device *pdev) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct msm_dsi *msm_dsi; 7762306a36Sopenharmony_ci int ret; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!pdev) 8062306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL); 8362306a36Sopenharmony_ci if (!msm_dsi) 8462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 8562306a36Sopenharmony_ci DBG("dsi probed=%p", msm_dsi); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci msm_dsi->id = -1; 8862306a36Sopenharmony_ci msm_dsi->pdev = pdev; 8962306a36Sopenharmony_ci platform_set_drvdata(pdev, msm_dsi); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Init dsi host */ 9262306a36Sopenharmony_ci ret = msm_dsi_host_init(msm_dsi); 9362306a36Sopenharmony_ci if (ret) 9462306a36Sopenharmony_ci goto destroy_dsi; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* GET dsi PHY */ 9762306a36Sopenharmony_ci ret = dsi_get_phy(msm_dsi); 9862306a36Sopenharmony_ci if (ret) 9962306a36Sopenharmony_ci goto destroy_dsi; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Register to dsi manager */ 10262306a36Sopenharmony_ci ret = msm_dsi_manager_register(msm_dsi); 10362306a36Sopenharmony_ci if (ret) 10462306a36Sopenharmony_ci goto destroy_dsi; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return msm_dsi; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cidestroy_dsi: 10962306a36Sopenharmony_ci dsi_destroy(msm_dsi); 11062306a36Sopenharmony_ci return ERR_PTR(ret); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int dsi_bind(struct device *dev, struct device *master, void *data) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct msm_drm_private *priv = dev_get_drvdata(master); 11662306a36Sopenharmony_ci struct msm_dsi *msm_dsi = dev_get_drvdata(dev); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci priv->dsi[msm_dsi->id] = msm_dsi; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void dsi_unbind(struct device *dev, struct device *master, 12462306a36Sopenharmony_ci void *data) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct msm_drm_private *priv = dev_get_drvdata(master); 12762306a36Sopenharmony_ci struct msm_dsi *msm_dsi = dev_get_drvdata(dev); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci msm_dsi_tx_buf_free(msm_dsi->host); 13062306a36Sopenharmony_ci priv->dsi[msm_dsi->id] = NULL; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const struct component_ops dsi_ops = { 13462306a36Sopenharmony_ci .bind = dsi_bind, 13562306a36Sopenharmony_ci .unbind = dsi_unbind, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint dsi_dev_attach(struct platform_device *pdev) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return component_add(&pdev->dev, &dsi_ops); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_civoid dsi_dev_detach(struct platform_device *pdev) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci component_del(&pdev->dev, &dsi_ops); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int dsi_dev_probe(struct platform_device *pdev) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct msm_dsi *msm_dsi; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci DBG(""); 15362306a36Sopenharmony_ci msm_dsi = dsi_init(pdev); 15462306a36Sopenharmony_ci if (IS_ERR(msm_dsi)) { 15562306a36Sopenharmony_ci /* Don't fail the bind if the dsi port is not connected */ 15662306a36Sopenharmony_ci if (PTR_ERR(msm_dsi) == -ENODEV) 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci return PTR_ERR(msm_dsi); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int dsi_dev_remove(struct platform_device *pdev) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci DBG(""); 17062306a36Sopenharmony_ci dsi_destroy(msm_dsi); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const struct of_device_id dt_match[] = { 17662306a36Sopenharmony_ci { .compatible = "qcom,mdss-dsi-ctrl" }, 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Deprecated, don't use */ 17962306a36Sopenharmony_ci { .compatible = "qcom,dsi-ctrl-6g-qcm2290" }, 18062306a36Sopenharmony_ci {} 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct dev_pm_ops dsi_pm_ops = { 18462306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL) 18562306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 18662306a36Sopenharmony_ci pm_runtime_force_resume) 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic struct platform_driver dsi_driver = { 19062306a36Sopenharmony_ci .probe = dsi_dev_probe, 19162306a36Sopenharmony_ci .remove = dsi_dev_remove, 19262306a36Sopenharmony_ci .driver = { 19362306a36Sopenharmony_ci .name = "msm_dsi", 19462306a36Sopenharmony_ci .of_match_table = dt_match, 19562306a36Sopenharmony_ci .pm = &dsi_pm_ops, 19662306a36Sopenharmony_ci }, 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid __init msm_dsi_register(void) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci DBG(""); 20262306a36Sopenharmony_ci msm_dsi_phy_driver_register(); 20362306a36Sopenharmony_ci platform_driver_register(&dsi_driver); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_civoid __exit msm_dsi_unregister(void) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci DBG(""); 20962306a36Sopenharmony_ci msm_dsi_phy_driver_unregister(); 21062306a36Sopenharmony_ci platform_driver_unregister(&dsi_driver); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciint msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, 21462306a36Sopenharmony_ci struct drm_encoder *encoder) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 21762306a36Sopenharmony_ci int ret; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { 22062306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "too many bridges\n"); 22162306a36Sopenharmony_ci return -ENOSPC; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci msm_dsi->dev = dev; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ret = msm_dsi_host_modeset_init(msm_dsi->host, dev); 22762306a36Sopenharmony_ci if (ret) { 22862306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "failed to modeset init host: %d\n", ret); 22962306a36Sopenharmony_ci goto fail; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (msm_dsi_is_bonded_dsi(msm_dsi) && 23362306a36Sopenharmony_ci !msm_dsi_is_master_dsi(msm_dsi)) { 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * Do not return an eror here, 23662306a36Sopenharmony_ci * Just skip creating encoder/connector for the slave-DSI. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci msm_dsi->encoder = encoder; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id); 24462306a36Sopenharmony_ci if (IS_ERR(msm_dsi->bridge)) { 24562306a36Sopenharmony_ci ret = PTR_ERR(msm_dsi->bridge); 24662306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "failed to create dsi bridge: %d\n", ret); 24762306a36Sopenharmony_ci msm_dsi->bridge = NULL; 24862306a36Sopenharmony_ci goto fail; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id); 25262306a36Sopenharmony_ci if (ret) { 25362306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, 25462306a36Sopenharmony_ci "failed to create dsi connector: %d\n", ret); 25562306a36Sopenharmony_ci goto fail; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci priv->bridges[priv->num_bridges++] = msm_dsi->bridge; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_cifail: 26262306a36Sopenharmony_ci /* bridge/connector are normally destroyed by drm: */ 26362306a36Sopenharmony_ci if (msm_dsi->bridge) { 26462306a36Sopenharmony_ci msm_dsi_manager_bridge_destroy(msm_dsi->bridge); 26562306a36Sopenharmony_ci msm_dsi->bridge = NULL; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return ret; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci msm_dsi_host_snapshot(disp_state, msm_dsi->host); 27462306a36Sopenharmony_ci msm_dsi_phy_snapshot(disp_state, msm_dsi->phy); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 277