1*a689554bSHai Li /* 2*a689554bSHai Li * Copyright (c) 2015, The Linux Foundation. All rights reserved. 3*a689554bSHai Li * 4*a689554bSHai Li * This program is free software; you can redistribute it and/or modify 5*a689554bSHai Li * it under the terms of the GNU General Public License version 2 and 6*a689554bSHai Li * only version 2 as published by the Free Software Foundation. 7*a689554bSHai Li * 8*a689554bSHai Li * This program is distributed in the hope that it will be useful, 9*a689554bSHai Li * but WITHOUT ANY WARRANTY; without even the implied warranty of 10*a689554bSHai Li * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*a689554bSHai Li * GNU General Public License for more details. 12*a689554bSHai Li */ 13*a689554bSHai Li 14*a689554bSHai Li #include "dsi.h" 15*a689554bSHai Li 16*a689554bSHai Li struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi) 17*a689554bSHai Li { 18*a689554bSHai Li if (!msm_dsi || !msm_dsi->panel) 19*a689554bSHai Li return NULL; 20*a689554bSHai Li 21*a689554bSHai Li return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ? 22*a689554bSHai Li msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] : 23*a689554bSHai Li msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID]; 24*a689554bSHai Li } 25*a689554bSHai Li 26*a689554bSHai Li static void dsi_destroy(struct msm_dsi *msm_dsi) 27*a689554bSHai Li { 28*a689554bSHai Li if (!msm_dsi) 29*a689554bSHai Li return; 30*a689554bSHai Li 31*a689554bSHai Li msm_dsi_manager_unregister(msm_dsi); 32*a689554bSHai Li if (msm_dsi->host) { 33*a689554bSHai Li msm_dsi_host_destroy(msm_dsi->host); 34*a689554bSHai Li msm_dsi->host = NULL; 35*a689554bSHai Li } 36*a689554bSHai Li 37*a689554bSHai Li platform_set_drvdata(msm_dsi->pdev, NULL); 38*a689554bSHai Li } 39*a689554bSHai Li 40*a689554bSHai Li static struct msm_dsi *dsi_init(struct platform_device *pdev) 41*a689554bSHai Li { 42*a689554bSHai Li struct msm_dsi *msm_dsi = NULL; 43*a689554bSHai Li int ret; 44*a689554bSHai Li 45*a689554bSHai Li if (!pdev) { 46*a689554bSHai Li dev_err(&pdev->dev, "no dsi device\n"); 47*a689554bSHai Li ret = -ENXIO; 48*a689554bSHai Li goto fail; 49*a689554bSHai Li } 50*a689554bSHai Li 51*a689554bSHai Li msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL); 52*a689554bSHai Li if (!msm_dsi) { 53*a689554bSHai Li ret = -ENOMEM; 54*a689554bSHai Li goto fail; 55*a689554bSHai Li } 56*a689554bSHai Li DBG("dsi probed=%p", msm_dsi); 57*a689554bSHai Li 58*a689554bSHai Li msm_dsi->pdev = pdev; 59*a689554bSHai Li platform_set_drvdata(pdev, msm_dsi); 60*a689554bSHai Li 61*a689554bSHai Li /* Init dsi host */ 62*a689554bSHai Li ret = msm_dsi_host_init(msm_dsi); 63*a689554bSHai Li if (ret) 64*a689554bSHai Li goto fail; 65*a689554bSHai Li 66*a689554bSHai Li /* Register to dsi manager */ 67*a689554bSHai Li ret = msm_dsi_manager_register(msm_dsi); 68*a689554bSHai Li if (ret) 69*a689554bSHai Li goto fail; 70*a689554bSHai Li 71*a689554bSHai Li return msm_dsi; 72*a689554bSHai Li 73*a689554bSHai Li fail: 74*a689554bSHai Li if (msm_dsi) 75*a689554bSHai Li dsi_destroy(msm_dsi); 76*a689554bSHai Li 77*a689554bSHai Li return ERR_PTR(ret); 78*a689554bSHai Li } 79*a689554bSHai Li 80*a689554bSHai Li static int dsi_bind(struct device *dev, struct device *master, void *data) 81*a689554bSHai Li { 82*a689554bSHai Li struct drm_device *drm = dev_get_drvdata(master); 83*a689554bSHai Li struct msm_drm_private *priv = drm->dev_private; 84*a689554bSHai Li struct platform_device *pdev = to_platform_device(dev); 85*a689554bSHai Li struct msm_dsi *msm_dsi; 86*a689554bSHai Li 87*a689554bSHai Li DBG(""); 88*a689554bSHai Li msm_dsi = dsi_init(pdev); 89*a689554bSHai Li if (IS_ERR(msm_dsi)) 90*a689554bSHai Li return PTR_ERR(msm_dsi); 91*a689554bSHai Li 92*a689554bSHai Li priv->dsi[msm_dsi->id] = msm_dsi; 93*a689554bSHai Li 94*a689554bSHai Li return 0; 95*a689554bSHai Li } 96*a689554bSHai Li 97*a689554bSHai Li static void dsi_unbind(struct device *dev, struct device *master, 98*a689554bSHai Li void *data) 99*a689554bSHai Li { 100*a689554bSHai Li struct drm_device *drm = dev_get_drvdata(master); 101*a689554bSHai Li struct msm_drm_private *priv = drm->dev_private; 102*a689554bSHai Li struct msm_dsi *msm_dsi = dev_get_drvdata(dev); 103*a689554bSHai Li int id = msm_dsi->id; 104*a689554bSHai Li 105*a689554bSHai Li if (priv->dsi[id]) { 106*a689554bSHai Li dsi_destroy(msm_dsi); 107*a689554bSHai Li priv->dsi[id] = NULL; 108*a689554bSHai Li } 109*a689554bSHai Li } 110*a689554bSHai Li 111*a689554bSHai Li static const struct component_ops dsi_ops = { 112*a689554bSHai Li .bind = dsi_bind, 113*a689554bSHai Li .unbind = dsi_unbind, 114*a689554bSHai Li }; 115*a689554bSHai Li 116*a689554bSHai Li static int dsi_dev_probe(struct platform_device *pdev) 117*a689554bSHai Li { 118*a689554bSHai Li return component_add(&pdev->dev, &dsi_ops); 119*a689554bSHai Li } 120*a689554bSHai Li 121*a689554bSHai Li static int dsi_dev_remove(struct platform_device *pdev) 122*a689554bSHai Li { 123*a689554bSHai Li DBG(""); 124*a689554bSHai Li component_del(&pdev->dev, &dsi_ops); 125*a689554bSHai Li return 0; 126*a689554bSHai Li } 127*a689554bSHai Li 128*a689554bSHai Li static const struct of_device_id dt_match[] = { 129*a689554bSHai Li { .compatible = "qcom,mdss-dsi-ctrl" }, 130*a689554bSHai Li {} 131*a689554bSHai Li }; 132*a689554bSHai Li 133*a689554bSHai Li static struct platform_driver dsi_driver = { 134*a689554bSHai Li .probe = dsi_dev_probe, 135*a689554bSHai Li .remove = dsi_dev_remove, 136*a689554bSHai Li .driver = { 137*a689554bSHai Li .name = "msm_dsi", 138*a689554bSHai Li .of_match_table = dt_match, 139*a689554bSHai Li }, 140*a689554bSHai Li }; 141*a689554bSHai Li 142*a689554bSHai Li void __init msm_dsi_register(void) 143*a689554bSHai Li { 144*a689554bSHai Li DBG(""); 145*a689554bSHai Li platform_driver_register(&dsi_driver); 146*a689554bSHai Li } 147*a689554bSHai Li 148*a689554bSHai Li void __exit msm_dsi_unregister(void) 149*a689554bSHai Li { 150*a689554bSHai Li DBG(""); 151*a689554bSHai Li platform_driver_unregister(&dsi_driver); 152*a689554bSHai Li } 153*a689554bSHai Li 154*a689554bSHai Li int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, 155*a689554bSHai Li struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM]) 156*a689554bSHai Li { 157*a689554bSHai Li struct msm_drm_private *priv = dev->dev_private; 158*a689554bSHai Li int ret, i; 159*a689554bSHai Li 160*a689554bSHai Li if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] || 161*a689554bSHai Li !encoders[MSM_DSI_CMD_ENCODER_ID])) 162*a689554bSHai Li return -EINVAL; 163*a689554bSHai Li 164*a689554bSHai Li msm_dsi->dev = dev; 165*a689554bSHai Li 166*a689554bSHai Li ret = msm_dsi_host_modeset_init(msm_dsi->host, dev); 167*a689554bSHai Li if (ret) { 168*a689554bSHai Li dev_err(dev->dev, "failed to modeset init host: %d\n", ret); 169*a689554bSHai Li goto fail; 170*a689554bSHai Li } 171*a689554bSHai Li 172*a689554bSHai Li msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id); 173*a689554bSHai Li if (IS_ERR(msm_dsi->bridge)) { 174*a689554bSHai Li ret = PTR_ERR(msm_dsi->bridge); 175*a689554bSHai Li dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret); 176*a689554bSHai Li msm_dsi->bridge = NULL; 177*a689554bSHai Li goto fail; 178*a689554bSHai Li } 179*a689554bSHai Li 180*a689554bSHai Li msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id); 181*a689554bSHai Li if (IS_ERR(msm_dsi->connector)) { 182*a689554bSHai Li ret = PTR_ERR(msm_dsi->connector); 183*a689554bSHai Li dev_err(dev->dev, "failed to create dsi connector: %d\n", ret); 184*a689554bSHai Li msm_dsi->connector = NULL; 185*a689554bSHai Li goto fail; 186*a689554bSHai Li } 187*a689554bSHai Li 188*a689554bSHai Li for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) { 189*a689554bSHai Li encoders[i]->bridge = msm_dsi->bridge; 190*a689554bSHai Li msm_dsi->encoders[i] = encoders[i]; 191*a689554bSHai Li } 192*a689554bSHai Li 193*a689554bSHai Li priv->bridges[priv->num_bridges++] = msm_dsi->bridge; 194*a689554bSHai Li priv->connectors[priv->num_connectors++] = msm_dsi->connector; 195*a689554bSHai Li 196*a689554bSHai Li return 0; 197*a689554bSHai Li fail: 198*a689554bSHai Li if (msm_dsi) { 199*a689554bSHai Li /* bridge/connector are normally destroyed by drm: */ 200*a689554bSHai Li if (msm_dsi->bridge) { 201*a689554bSHai Li msm_dsi_manager_bridge_destroy(msm_dsi->bridge); 202*a689554bSHai Li msm_dsi->bridge = NULL; 203*a689554bSHai Li } 204*a689554bSHai Li if (msm_dsi->connector) { 205*a689554bSHai Li msm_dsi->connector->funcs->destroy(msm_dsi->connector); 206*a689554bSHai Li msm_dsi->connector = NULL; 207*a689554bSHai Li } 208*a689554bSHai Li } 209*a689554bSHai Li 210*a689554bSHai Li return ret; 211*a689554bSHai Li } 212*a689554bSHai Li 213