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