1a689554bSHai Li /* 2a689554bSHai Li * Copyright (c) 2015, The Linux Foundation. All rights reserved. 3a689554bSHai Li * 4a689554bSHai Li * This program is free software; you can redistribute it and/or modify 5a689554bSHai Li * it under the terms of the GNU General Public License version 2 and 6a689554bSHai Li * only version 2 as published by the Free Software Foundation. 7a689554bSHai Li * 8a689554bSHai Li * This program is distributed in the hope that it will be useful, 9a689554bSHai Li * but WITHOUT ANY WARRANTY; without even the implied warranty of 10a689554bSHai Li * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11a689554bSHai Li * GNU General Public License for more details. 12a689554bSHai Li */ 13a689554bSHai Li 14a689554bSHai Li #include <linux/clk.h> 15a689554bSHai Li #include <linux/delay.h> 16a689554bSHai Li #include <linux/err.h> 17a689554bSHai Li #include <linux/gpio.h> 18964a0754SBrian Norris #include <linux/gpio/consumer.h> 19a689554bSHai Li #include <linux/interrupt.h> 20a689554bSHai Li #include <linux/of_device.h> 21a689554bSHai Li #include <linux/of_gpio.h> 22a689554bSHai Li #include <linux/of_irq.h> 23ab8909b0SHai Li #include <linux/pinctrl/consumer.h> 24f7009d26SArchit Taneja #include <linux/of_graph.h> 25a689554bSHai Li #include <linux/regulator/consumer.h> 26a689554bSHai Li #include <linux/spinlock.h> 27a689554bSHai Li #include <video/mipi_display.h> 28a689554bSHai Li 29a689554bSHai Li #include "dsi.h" 30a689554bSHai Li #include "dsi.xml.h" 31d248b61fSHai Li #include "dsi_cfg.h" 32a689554bSHai Li 33a689554bSHai Li static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) 34a689554bSHai Li { 35a689554bSHai Li u32 ver; 36a689554bSHai Li 37a689554bSHai Li if (!major || !minor) 38a689554bSHai Li return -EINVAL; 39a689554bSHai Li 40648d5063SArchit Taneja /* 41648d5063SArchit Taneja * From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0 42a689554bSHai Li * makes all other registers 4-byte shifted down. 43648d5063SArchit Taneja * 44648d5063SArchit Taneja * In order to identify between DSI6G(v3) and beyond, and DSIv2 and 45648d5063SArchit Taneja * older, we read the DSI_VERSION register without any shift(offset 46648d5063SArchit Taneja * 0x1f0). In the case of DSIv2, this hast to be a non-zero value. In 47648d5063SArchit Taneja * the case of DSI6G, this has to be zero (the offset points to a 48648d5063SArchit Taneja * scratch register which we never touch) 49a689554bSHai Li */ 50648d5063SArchit Taneja 51a689554bSHai Li ver = msm_readl(base + REG_DSI_VERSION); 52648d5063SArchit Taneja if (ver) { 53648d5063SArchit Taneja /* older dsi host, there is no register shift */ 54a689554bSHai Li ver = FIELD(ver, DSI_VERSION_MAJOR); 55a689554bSHai Li if (ver <= MSM_DSI_VER_MAJOR_V2) { 56a689554bSHai Li /* old versions */ 57a689554bSHai Li *major = ver; 58a689554bSHai Li *minor = 0; 59a689554bSHai Li return 0; 60a689554bSHai Li } else { 61a689554bSHai Li return -EINVAL; 62a689554bSHai Li } 63a689554bSHai Li } else { 64648d5063SArchit Taneja /* 65648d5063SArchit Taneja * newer host, offset 0 has 6G_HW_VERSION, the rest of the 66648d5063SArchit Taneja * registers are shifted down, read DSI_VERSION again with 67648d5063SArchit Taneja * the shifted offset 68648d5063SArchit Taneja */ 69a689554bSHai Li ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION); 70a689554bSHai Li ver = FIELD(ver, DSI_VERSION_MAJOR); 71a689554bSHai Li if (ver == MSM_DSI_VER_MAJOR_6G) { 72a689554bSHai Li /* 6G version */ 73a689554bSHai Li *major = ver; 74648d5063SArchit Taneja *minor = msm_readl(base + REG_DSI_6G_HW_VERSION); 75a689554bSHai Li return 0; 76a689554bSHai Li } else { 77a689554bSHai Li return -EINVAL; 78a689554bSHai Li } 79a689554bSHai Li } 80a689554bSHai Li } 81a689554bSHai Li 82a689554bSHai Li #define DSI_ERR_STATE_ACK 0x0000 83a689554bSHai Li #define DSI_ERR_STATE_TIMEOUT 0x0001 84a689554bSHai Li #define DSI_ERR_STATE_DLN0_PHY 0x0002 85a689554bSHai Li #define DSI_ERR_STATE_FIFO 0x0004 86a689554bSHai Li #define DSI_ERR_STATE_MDP_FIFO_UNDERFLOW 0x0008 87a689554bSHai Li #define DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION 0x0010 88a689554bSHai Li #define DSI_ERR_STATE_PLL_UNLOCKED 0x0020 89a689554bSHai Li 90a689554bSHai Li #define DSI_CLK_CTRL_ENABLE_CLKS \ 91a689554bSHai Li (DSI_CLK_CTRL_AHBS_HCLK_ON | DSI_CLK_CTRL_AHBM_SCLK_ON | \ 92a689554bSHai Li DSI_CLK_CTRL_PCLK_ON | DSI_CLK_CTRL_DSICLK_ON | \ 93a689554bSHai Li DSI_CLK_CTRL_BYTECLK_ON | DSI_CLK_CTRL_ESCCLK_ON | \ 94a689554bSHai Li DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK) 95a689554bSHai Li 96a689554bSHai Li struct msm_dsi_host { 97a689554bSHai Li struct mipi_dsi_host base; 98a689554bSHai Li 99a689554bSHai Li struct platform_device *pdev; 100a689554bSHai Li struct drm_device *dev; 101a689554bSHai Li 102a689554bSHai Li int id; 103a689554bSHai Li 104a689554bSHai Li void __iomem *ctrl_base; 105ec31abf6SHai Li struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; 1066e0eb52eSArchit Taneja 1076e0eb52eSArchit Taneja struct clk *bus_clks[DSI_BUS_CLK_MAX]; 1086e0eb52eSArchit Taneja 109a689554bSHai Li struct clk *byte_clk; 110a689554bSHai Li struct clk *esc_clk; 111a689554bSHai Li struct clk *pixel_clk; 1129d32c498SHai Li struct clk *byte_clk_src; 1139d32c498SHai Li struct clk *pixel_clk_src; 1149d32c498SHai Li 115a689554bSHai Li u32 byte_clk_rate; 1164bfa9748SArchit Taneja u32 esc_clk_rate; 1174bfa9748SArchit Taneja 1184bfa9748SArchit Taneja /* DSI v2 specific clocks */ 1194bfa9748SArchit Taneja struct clk *src_clk; 1204bfa9748SArchit Taneja struct clk *esc_clk_src; 1214bfa9748SArchit Taneja struct clk *dsi_clk_src; 1224bfa9748SArchit Taneja 1234bfa9748SArchit Taneja u32 src_clk_rate; 124a689554bSHai Li 125a689554bSHai Li struct gpio_desc *disp_en_gpio; 126a689554bSHai Li struct gpio_desc *te_gpio; 127a689554bSHai Li 128d248b61fSHai Li const struct msm_dsi_cfg_handler *cfg_hnd; 129a689554bSHai Li 130a689554bSHai Li struct completion dma_comp; 131a689554bSHai Li struct completion video_comp; 132a689554bSHai Li struct mutex dev_mutex; 133a689554bSHai Li struct mutex cmd_mutex; 134a689554bSHai Li struct mutex clk_mutex; 135a689554bSHai Li spinlock_t intr_lock; /* Protect interrupt ctrl register */ 136a689554bSHai Li 137a689554bSHai Li u32 err_work_state; 138a689554bSHai Li struct work_struct err_work; 139a689554bSHai Li struct workqueue_struct *workqueue; 140a689554bSHai Li 1414ff9d4cbSArchit Taneja /* DSI 6G TX buffer*/ 142a689554bSHai Li struct drm_gem_object *tx_gem_obj; 1434ff9d4cbSArchit Taneja 1444ff9d4cbSArchit Taneja /* DSI v2 TX buffer */ 1454ff9d4cbSArchit Taneja void *tx_buf; 1464ff9d4cbSArchit Taneja dma_addr_t tx_buf_paddr; 1474ff9d4cbSArchit Taneja 1484ff9d4cbSArchit Taneja int tx_size; 1494ff9d4cbSArchit Taneja 150a689554bSHai Li u8 *rx_buf; 151a689554bSHai Li 152a689554bSHai Li struct drm_display_mode *mode; 153a689554bSHai Li 154a9ddac9cSArchit Taneja /* connected device info */ 155a9ddac9cSArchit Taneja struct device_node *device_node; 156a689554bSHai Li unsigned int channel; 157a689554bSHai Li unsigned int lanes; 158a689554bSHai Li enum mipi_dsi_pixel_format format; 159a689554bSHai Li unsigned long mode_flags; 160a689554bSHai Li 161a689554bSHai Li u32 dma_cmd_ctrl_restore; 162a689554bSHai Li 163a689554bSHai Li bool registered; 164a689554bSHai Li bool power_on; 165a689554bSHai Li int irq; 166a689554bSHai Li }; 167a689554bSHai Li 168a689554bSHai Li static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt) 169a689554bSHai Li { 170a689554bSHai Li switch (fmt) { 171a689554bSHai Li case MIPI_DSI_FMT_RGB565: return 16; 172a689554bSHai Li case MIPI_DSI_FMT_RGB666_PACKED: return 18; 173a689554bSHai Li case MIPI_DSI_FMT_RGB666: 174a689554bSHai Li case MIPI_DSI_FMT_RGB888: 175a689554bSHai Li default: return 24; 176a689554bSHai Li } 177a689554bSHai Li } 178a689554bSHai Li 179a689554bSHai Li static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg) 180a689554bSHai Li { 181d248b61fSHai Li return msm_readl(msm_host->ctrl_base + reg); 182a689554bSHai Li } 183a689554bSHai Li static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data) 184a689554bSHai Li { 185d248b61fSHai Li msm_writel(data, msm_host->ctrl_base + reg); 186a689554bSHai Li } 187a689554bSHai Li 188a689554bSHai Li static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host); 189a689554bSHai Li static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host); 190a689554bSHai Li 191d248b61fSHai Li static const struct msm_dsi_cfg_handler *dsi_get_config( 192d248b61fSHai Li struct msm_dsi_host *msm_host) 193a689554bSHai Li { 194d248b61fSHai Li const struct msm_dsi_cfg_handler *cfg_hnd = NULL; 19531c92767SArchit Taneja struct device *dev = &msm_host->pdev->dev; 196a689554bSHai Li struct regulator *gdsc_reg; 19731c92767SArchit Taneja struct clk *ahb_clk; 198d248b61fSHai Li int ret; 199a689554bSHai Li u32 major = 0, minor = 0; 200a689554bSHai Li 20131c92767SArchit Taneja gdsc_reg = regulator_get(dev, "gdsc"); 202bdc80de2SFabian Frederick if (IS_ERR(gdsc_reg)) { 203a689554bSHai Li pr_err("%s: cannot get gdsc\n", __func__); 204d248b61fSHai Li goto exit; 205a689554bSHai Li } 20631c92767SArchit Taneja 20731c92767SArchit Taneja ahb_clk = clk_get(dev, "iface_clk"); 20831c92767SArchit Taneja if (IS_ERR(ahb_clk)) { 20931c92767SArchit Taneja pr_err("%s: cannot get interface clock\n", __func__); 21031c92767SArchit Taneja goto put_gdsc; 21131c92767SArchit Taneja } 21231c92767SArchit Taneja 213a689554bSHai Li ret = regulator_enable(gdsc_reg); 214a689554bSHai Li if (ret) { 215a689554bSHai Li pr_err("%s: unable to enable gdsc\n", __func__); 21631c92767SArchit Taneja goto put_clk; 217a689554bSHai Li } 21831c92767SArchit Taneja 21931c92767SArchit Taneja ret = clk_prepare_enable(ahb_clk); 220a689554bSHai Li if (ret) { 221a689554bSHai Li pr_err("%s: unable to enable ahb_clk\n", __func__); 222d248b61fSHai Li goto disable_gdsc; 223a689554bSHai Li } 224a689554bSHai Li 225a689554bSHai Li ret = dsi_get_version(msm_host->ctrl_base, &major, &minor); 226a689554bSHai Li if (ret) { 227a689554bSHai Li pr_err("%s: Invalid version\n", __func__); 228d248b61fSHai Li goto disable_clks; 229a689554bSHai Li } 230a689554bSHai Li 231d248b61fSHai Li cfg_hnd = msm_dsi_cfg_get(major, minor); 232a689554bSHai Li 233d248b61fSHai Li DBG("%s: Version %x:%x\n", __func__, major, minor); 234d248b61fSHai Li 235d248b61fSHai Li disable_clks: 23631c92767SArchit Taneja clk_disable_unprepare(ahb_clk); 237d248b61fSHai Li disable_gdsc: 238d248b61fSHai Li regulator_disable(gdsc_reg); 23931c92767SArchit Taneja put_clk: 24031c92767SArchit Taneja clk_put(ahb_clk); 241d248b61fSHai Li put_gdsc: 242d248b61fSHai Li regulator_put(gdsc_reg); 243d248b61fSHai Li exit: 244d248b61fSHai Li return cfg_hnd; 245a689554bSHai Li } 246a689554bSHai Li 247a689554bSHai Li static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host) 248a689554bSHai Li { 249a689554bSHai Li return container_of(host, struct msm_dsi_host, base); 250a689554bSHai Li } 251a689554bSHai Li 252a689554bSHai Li static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host) 253a689554bSHai Li { 254a689554bSHai Li struct regulator_bulk_data *s = msm_host->supplies; 255d248b61fSHai Li const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; 256d248b61fSHai Li int num = msm_host->cfg_hnd->cfg->reg_cfg.num; 257a689554bSHai Li int i; 258a689554bSHai Li 259a689554bSHai Li DBG(""); 260a689554bSHai Li for (i = num - 1; i >= 0; i--) 261a689554bSHai Li if (regs[i].disable_load >= 0) 2622c33ce00SDave Airlie regulator_set_load(s[i].consumer, 263a689554bSHai Li regs[i].disable_load); 264a689554bSHai Li 265a689554bSHai Li regulator_bulk_disable(num, s); 266a689554bSHai Li } 267a689554bSHai Li 268a689554bSHai Li static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host) 269a689554bSHai Li { 270a689554bSHai Li struct regulator_bulk_data *s = msm_host->supplies; 271d248b61fSHai Li const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; 272d248b61fSHai Li int num = msm_host->cfg_hnd->cfg->reg_cfg.num; 273a689554bSHai Li int ret, i; 274a689554bSHai Li 275a689554bSHai Li DBG(""); 276a689554bSHai Li for (i = 0; i < num; i++) { 277a689554bSHai Li if (regs[i].enable_load >= 0) { 2782c33ce00SDave Airlie ret = regulator_set_load(s[i].consumer, 279a689554bSHai Li regs[i].enable_load); 280a689554bSHai Li if (ret < 0) { 281a689554bSHai Li pr_err("regulator %d set op mode failed, %d\n", 282a689554bSHai Li i, ret); 283a689554bSHai Li goto fail; 284a689554bSHai Li } 285a689554bSHai Li } 286a689554bSHai Li } 287a689554bSHai Li 288a689554bSHai Li ret = regulator_bulk_enable(num, s); 289a689554bSHai Li if (ret < 0) { 290a689554bSHai Li pr_err("regulator enable failed, %d\n", ret); 291a689554bSHai Li goto fail; 292a689554bSHai Li } 293a689554bSHai Li 294a689554bSHai Li return 0; 295a689554bSHai Li 296a689554bSHai Li fail: 297a689554bSHai Li for (i--; i >= 0; i--) 2982c33ce00SDave Airlie regulator_set_load(s[i].consumer, regs[i].disable_load); 299a689554bSHai Li return ret; 300a689554bSHai Li } 301a689554bSHai Li 302a689554bSHai Li static int dsi_regulator_init(struct msm_dsi_host *msm_host) 303a689554bSHai Li { 304a689554bSHai Li struct regulator_bulk_data *s = msm_host->supplies; 305d248b61fSHai Li const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; 306d248b61fSHai Li int num = msm_host->cfg_hnd->cfg->reg_cfg.num; 307a689554bSHai Li int i, ret; 308a689554bSHai Li 309a689554bSHai Li for (i = 0; i < num; i++) 310a689554bSHai Li s[i].supply = regs[i].name; 311a689554bSHai Li 312a689554bSHai Li ret = devm_regulator_bulk_get(&msm_host->pdev->dev, num, s); 313a689554bSHai Li if (ret < 0) { 314a689554bSHai Li pr_err("%s: failed to init regulator, ret=%d\n", 315a689554bSHai Li __func__, ret); 316a689554bSHai Li return ret; 317a689554bSHai Li } 318a689554bSHai Li 319a689554bSHai Li for (i = 0; i < num; i++) { 320556a76e5SBjorn Andersson if (regulator_can_change_voltage(s[i].consumer)) { 321a689554bSHai Li ret = regulator_set_voltage(s[i].consumer, 322a689554bSHai Li regs[i].min_voltage, regs[i].max_voltage); 323a689554bSHai Li if (ret < 0) { 324a689554bSHai Li pr_err("regulator %d set voltage failed, %d\n", 325a689554bSHai Li i, ret); 326a689554bSHai Li return ret; 327a689554bSHai Li } 328a689554bSHai Li } 329a689554bSHai Li } 330a689554bSHai Li 331a689554bSHai Li return 0; 332a689554bSHai Li } 333a689554bSHai Li 334a689554bSHai Li static int dsi_clk_init(struct msm_dsi_host *msm_host) 335a689554bSHai Li { 336a689554bSHai Li struct device *dev = &msm_host->pdev->dev; 3374bfa9748SArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 3384bfa9748SArchit Taneja const struct msm_dsi_config *cfg = cfg_hnd->cfg; 3396e0eb52eSArchit Taneja int i, ret = 0; 340a689554bSHai Li 3416e0eb52eSArchit Taneja /* get bus clocks */ 3426e0eb52eSArchit Taneja for (i = 0; i < cfg->num_bus_clks; i++) { 3436e0eb52eSArchit Taneja msm_host->bus_clks[i] = devm_clk_get(dev, 3446e0eb52eSArchit Taneja cfg->bus_clk_names[i]); 3456e0eb52eSArchit Taneja if (IS_ERR(msm_host->bus_clks[i])) { 3466e0eb52eSArchit Taneja ret = PTR_ERR(msm_host->bus_clks[i]); 3476e0eb52eSArchit Taneja pr_err("%s: Unable to get %s, ret = %d\n", 3486e0eb52eSArchit Taneja __func__, cfg->bus_clk_names[i], ret); 349a689554bSHai Li goto exit; 350a689554bSHai Li } 351a689554bSHai Li } 352a689554bSHai Li 3536e0eb52eSArchit Taneja /* get link and source clocks */ 354a689554bSHai Li msm_host->byte_clk = devm_clk_get(dev, "byte_clk"); 355a689554bSHai Li if (IS_ERR(msm_host->byte_clk)) { 356a689554bSHai Li ret = PTR_ERR(msm_host->byte_clk); 357a689554bSHai Li pr_err("%s: can't find dsi_byte_clk. ret=%d\n", 358a689554bSHai Li __func__, ret); 359a689554bSHai Li msm_host->byte_clk = NULL; 360a689554bSHai Li goto exit; 361a689554bSHai Li } 362a689554bSHai Li 363a689554bSHai Li msm_host->pixel_clk = devm_clk_get(dev, "pixel_clk"); 364a689554bSHai Li if (IS_ERR(msm_host->pixel_clk)) { 365a689554bSHai Li ret = PTR_ERR(msm_host->pixel_clk); 366a689554bSHai Li pr_err("%s: can't find dsi_pixel_clk. ret=%d\n", 367a689554bSHai Li __func__, ret); 368a689554bSHai Li msm_host->pixel_clk = NULL; 369a689554bSHai Li goto exit; 370a689554bSHai Li } 371a689554bSHai Li 372a689554bSHai Li msm_host->esc_clk = devm_clk_get(dev, "core_clk"); 373a689554bSHai Li if (IS_ERR(msm_host->esc_clk)) { 374a689554bSHai Li ret = PTR_ERR(msm_host->esc_clk); 375a689554bSHai Li pr_err("%s: can't find dsi_esc_clk. ret=%d\n", 376a689554bSHai Li __func__, ret); 377a689554bSHai Li msm_host->esc_clk = NULL; 378a689554bSHai Li goto exit; 379a689554bSHai Li } 380a689554bSHai Li 381e6c4c78cSArchit Taneja msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); 382e6c4c78cSArchit Taneja if (!msm_host->byte_clk_src) { 383e6c4c78cSArchit Taneja ret = -ENODEV; 3849d32c498SHai Li pr_err("%s: can't find byte_clk_src. ret=%d\n", __func__, ret); 3859d32c498SHai Li goto exit; 3869d32c498SHai Li } 3879d32c498SHai Li 388e6c4c78cSArchit Taneja msm_host->pixel_clk_src = clk_get_parent(msm_host->pixel_clk); 389e6c4c78cSArchit Taneja if (!msm_host->pixel_clk_src) { 390e6c4c78cSArchit Taneja ret = -ENODEV; 3919d32c498SHai Li pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret); 3924bfa9748SArchit Taneja goto exit; 3939d32c498SHai Li } 3949d32c498SHai Li 3954bfa9748SArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { 3964bfa9748SArchit Taneja msm_host->src_clk = devm_clk_get(dev, "src_clk"); 3974bfa9748SArchit Taneja if (IS_ERR(msm_host->src_clk)) { 3984bfa9748SArchit Taneja ret = PTR_ERR(msm_host->src_clk); 3994bfa9748SArchit Taneja pr_err("%s: can't find dsi_src_clk. ret=%d\n", 4004bfa9748SArchit Taneja __func__, ret); 4014bfa9748SArchit Taneja msm_host->src_clk = NULL; 4024bfa9748SArchit Taneja goto exit; 4034bfa9748SArchit Taneja } 4044bfa9748SArchit Taneja 4054bfa9748SArchit Taneja msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk); 4064bfa9748SArchit Taneja if (!msm_host->esc_clk_src) { 4074bfa9748SArchit Taneja ret = -ENODEV; 4084bfa9748SArchit Taneja pr_err("%s: can't get esc_clk_src. ret=%d\n", 4094bfa9748SArchit Taneja __func__, ret); 4104bfa9748SArchit Taneja goto exit; 4114bfa9748SArchit Taneja } 4124bfa9748SArchit Taneja 4134bfa9748SArchit Taneja msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk); 4144bfa9748SArchit Taneja if (!msm_host->dsi_clk_src) { 4154bfa9748SArchit Taneja ret = -ENODEV; 4164bfa9748SArchit Taneja pr_err("%s: can't get dsi_clk_src. ret=%d\n", 4174bfa9748SArchit Taneja __func__, ret); 4184bfa9748SArchit Taneja } 4194bfa9748SArchit Taneja } 420a689554bSHai Li exit: 421a689554bSHai Li return ret; 422a689554bSHai Li } 423a689554bSHai Li 424a689554bSHai Li static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host) 425a689554bSHai Li { 4266e0eb52eSArchit Taneja const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; 4276e0eb52eSArchit Taneja int i, ret; 428a689554bSHai Li 429a689554bSHai Li DBG("id=%d", msm_host->id); 430a689554bSHai Li 4316e0eb52eSArchit Taneja for (i = 0; i < cfg->num_bus_clks; i++) { 4326e0eb52eSArchit Taneja ret = clk_prepare_enable(msm_host->bus_clks[i]); 433a689554bSHai Li if (ret) { 4346e0eb52eSArchit Taneja pr_err("%s: failed to enable bus clock %d ret %d\n", 4356e0eb52eSArchit Taneja __func__, i, ret); 4366e0eb52eSArchit Taneja goto err; 437a689554bSHai Li } 438a689554bSHai Li } 439a689554bSHai Li 440a689554bSHai Li return 0; 4416e0eb52eSArchit Taneja err: 4426e0eb52eSArchit Taneja for (; i > 0; i--) 4436e0eb52eSArchit Taneja clk_disable_unprepare(msm_host->bus_clks[i]); 444a689554bSHai Li 445a689554bSHai Li return ret; 446a689554bSHai Li } 447a689554bSHai Li 448a689554bSHai Li static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host) 449a689554bSHai Li { 4506e0eb52eSArchit Taneja const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; 4516e0eb52eSArchit Taneja int i; 4526e0eb52eSArchit Taneja 453a689554bSHai Li DBG(""); 4546e0eb52eSArchit Taneja 4556e0eb52eSArchit Taneja for (i = cfg->num_bus_clks - 1; i >= 0; i--) 4566e0eb52eSArchit Taneja clk_disable_unprepare(msm_host->bus_clks[i]); 457a689554bSHai Li } 458a689554bSHai Li 4594bfa9748SArchit Taneja static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) 460a689554bSHai Li { 461a689554bSHai Li int ret; 462a689554bSHai Li 463a689554bSHai Li DBG("Set clk rates: pclk=%d, byteclk=%d", 464a689554bSHai Li msm_host->mode->clock, msm_host->byte_clk_rate); 465a689554bSHai Li 466a689554bSHai Li ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); 467a689554bSHai Li if (ret) { 468a689554bSHai Li pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); 469a689554bSHai Li goto error; 470a689554bSHai Li } 471a689554bSHai Li 472a689554bSHai Li ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000); 473a689554bSHai Li if (ret) { 474a689554bSHai Li pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); 475a689554bSHai Li goto error; 476a689554bSHai Li } 477a689554bSHai Li 478a689554bSHai Li ret = clk_prepare_enable(msm_host->esc_clk); 479a689554bSHai Li if (ret) { 480a689554bSHai Li pr_err("%s: Failed to enable dsi esc clk\n", __func__); 481a689554bSHai Li goto error; 482a689554bSHai Li } 483a689554bSHai Li 484a689554bSHai Li ret = clk_prepare_enable(msm_host->byte_clk); 485a689554bSHai Li if (ret) { 486a689554bSHai Li pr_err("%s: Failed to enable dsi byte clk\n", __func__); 487a689554bSHai Li goto byte_clk_err; 488a689554bSHai Li } 489a689554bSHai Li 490a689554bSHai Li ret = clk_prepare_enable(msm_host->pixel_clk); 491a689554bSHai Li if (ret) { 492a689554bSHai Li pr_err("%s: Failed to enable dsi pixel clk\n", __func__); 493a689554bSHai Li goto pixel_clk_err; 494a689554bSHai Li } 495a689554bSHai Li 496a689554bSHai Li return 0; 497a689554bSHai Li 498a689554bSHai Li pixel_clk_err: 499a689554bSHai Li clk_disable_unprepare(msm_host->byte_clk); 500a689554bSHai Li byte_clk_err: 501a689554bSHai Li clk_disable_unprepare(msm_host->esc_clk); 502a689554bSHai Li error: 503a689554bSHai Li return ret; 504a689554bSHai Li } 505a689554bSHai Li 5064bfa9748SArchit Taneja static int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) 5074bfa9748SArchit Taneja { 5084bfa9748SArchit Taneja int ret; 5094bfa9748SArchit Taneja 5104bfa9748SArchit Taneja DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d", 5114bfa9748SArchit Taneja msm_host->mode->clock, msm_host->byte_clk_rate, 5124bfa9748SArchit Taneja msm_host->esc_clk_rate, msm_host->src_clk_rate); 5134bfa9748SArchit Taneja 5144bfa9748SArchit Taneja ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); 5154bfa9748SArchit Taneja if (ret) { 5164bfa9748SArchit Taneja pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); 5174bfa9748SArchit Taneja goto error; 5184bfa9748SArchit Taneja } 5194bfa9748SArchit Taneja 5204bfa9748SArchit Taneja ret = clk_set_rate(msm_host->esc_clk, msm_host->esc_clk_rate); 5214bfa9748SArchit Taneja if (ret) { 5224bfa9748SArchit Taneja pr_err("%s: Failed to set rate esc clk, %d\n", __func__, ret); 5234bfa9748SArchit Taneja goto error; 5244bfa9748SArchit Taneja } 5254bfa9748SArchit Taneja 5264bfa9748SArchit Taneja ret = clk_set_rate(msm_host->src_clk, msm_host->src_clk_rate); 5274bfa9748SArchit Taneja if (ret) { 5284bfa9748SArchit Taneja pr_err("%s: Failed to set rate src clk, %d\n", __func__, ret); 5294bfa9748SArchit Taneja goto error; 5304bfa9748SArchit Taneja } 5314bfa9748SArchit Taneja 5324bfa9748SArchit Taneja ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000); 5334bfa9748SArchit Taneja if (ret) { 5344bfa9748SArchit Taneja pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); 5354bfa9748SArchit Taneja goto error; 5364bfa9748SArchit Taneja } 5374bfa9748SArchit Taneja 5384bfa9748SArchit Taneja ret = clk_prepare_enable(msm_host->byte_clk); 5394bfa9748SArchit Taneja if (ret) { 5404bfa9748SArchit Taneja pr_err("%s: Failed to enable dsi byte clk\n", __func__); 5414bfa9748SArchit Taneja goto error; 5424bfa9748SArchit Taneja } 5434bfa9748SArchit Taneja 5444bfa9748SArchit Taneja ret = clk_prepare_enable(msm_host->esc_clk); 5454bfa9748SArchit Taneja if (ret) { 5464bfa9748SArchit Taneja pr_err("%s: Failed to enable dsi esc clk\n", __func__); 5474bfa9748SArchit Taneja goto esc_clk_err; 5484bfa9748SArchit Taneja } 5494bfa9748SArchit Taneja 5504bfa9748SArchit Taneja ret = clk_prepare_enable(msm_host->src_clk); 5514bfa9748SArchit Taneja if (ret) { 5524bfa9748SArchit Taneja pr_err("%s: Failed to enable dsi src clk\n", __func__); 5534bfa9748SArchit Taneja goto src_clk_err; 5544bfa9748SArchit Taneja } 5554bfa9748SArchit Taneja 5564bfa9748SArchit Taneja ret = clk_prepare_enable(msm_host->pixel_clk); 5574bfa9748SArchit Taneja if (ret) { 5584bfa9748SArchit Taneja pr_err("%s: Failed to enable dsi pixel clk\n", __func__); 5594bfa9748SArchit Taneja goto pixel_clk_err; 5604bfa9748SArchit Taneja } 5614bfa9748SArchit Taneja 5624bfa9748SArchit Taneja return 0; 5634bfa9748SArchit Taneja 5644bfa9748SArchit Taneja pixel_clk_err: 5654bfa9748SArchit Taneja clk_disable_unprepare(msm_host->src_clk); 5664bfa9748SArchit Taneja src_clk_err: 5674bfa9748SArchit Taneja clk_disable_unprepare(msm_host->esc_clk); 5684bfa9748SArchit Taneja esc_clk_err: 5694bfa9748SArchit Taneja clk_disable_unprepare(msm_host->byte_clk); 5704bfa9748SArchit Taneja error: 5714bfa9748SArchit Taneja return ret; 5724bfa9748SArchit Taneja } 5734bfa9748SArchit Taneja 5744bfa9748SArchit Taneja static int dsi_link_clk_enable(struct msm_dsi_host *msm_host) 5754bfa9748SArchit Taneja { 5764bfa9748SArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 5774bfa9748SArchit Taneja 5784bfa9748SArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) 5794bfa9748SArchit Taneja return dsi_link_clk_enable_6g(msm_host); 5804bfa9748SArchit Taneja else 5814bfa9748SArchit Taneja return dsi_link_clk_enable_v2(msm_host); 5824bfa9748SArchit Taneja } 5834bfa9748SArchit Taneja 584a689554bSHai Li static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) 585a689554bSHai Li { 5864bfa9748SArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 5874bfa9748SArchit Taneja 5884bfa9748SArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { 589a689554bSHai Li clk_disable_unprepare(msm_host->esc_clk); 590a689554bSHai Li clk_disable_unprepare(msm_host->pixel_clk); 591a689554bSHai Li clk_disable_unprepare(msm_host->byte_clk); 5924bfa9748SArchit Taneja } else { 5934bfa9748SArchit Taneja clk_disable_unprepare(msm_host->pixel_clk); 5944bfa9748SArchit Taneja clk_disable_unprepare(msm_host->src_clk); 5954bfa9748SArchit Taneja clk_disable_unprepare(msm_host->esc_clk); 5964bfa9748SArchit Taneja clk_disable_unprepare(msm_host->byte_clk); 5974bfa9748SArchit Taneja } 598a689554bSHai Li } 599a689554bSHai Li 600a689554bSHai Li static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable) 601a689554bSHai Li { 602a689554bSHai Li int ret = 0; 603a689554bSHai Li 604a689554bSHai Li mutex_lock(&msm_host->clk_mutex); 605a689554bSHai Li if (enable) { 606a689554bSHai Li ret = dsi_bus_clk_enable(msm_host); 607a689554bSHai Li if (ret) { 608a689554bSHai Li pr_err("%s: Can not enable bus clk, %d\n", 609a689554bSHai Li __func__, ret); 610a689554bSHai Li goto unlock_ret; 611a689554bSHai Li } 612a689554bSHai Li ret = dsi_link_clk_enable(msm_host); 613a689554bSHai Li if (ret) { 614a689554bSHai Li pr_err("%s: Can not enable link clk, %d\n", 615a689554bSHai Li __func__, ret); 616a689554bSHai Li dsi_bus_clk_disable(msm_host); 617a689554bSHai Li goto unlock_ret; 618a689554bSHai Li } 619a689554bSHai Li } else { 620a689554bSHai Li dsi_link_clk_disable(msm_host); 621a689554bSHai Li dsi_bus_clk_disable(msm_host); 622a689554bSHai Li } 623a689554bSHai Li 624a689554bSHai Li unlock_ret: 625a689554bSHai Li mutex_unlock(&msm_host->clk_mutex); 626a689554bSHai Li return ret; 627a689554bSHai Li } 628a689554bSHai Li 629a689554bSHai Li static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) 630a689554bSHai Li { 631a689554bSHai Li struct drm_display_mode *mode = msm_host->mode; 6324bfa9748SArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 633a689554bSHai Li u8 lanes = msm_host->lanes; 634a689554bSHai Li u32 bpp = dsi_get_bpp(msm_host->format); 635a689554bSHai Li u32 pclk_rate; 636a689554bSHai Li 637a689554bSHai Li if (!mode) { 638a689554bSHai Li pr_err("%s: mode not set\n", __func__); 639a689554bSHai Li return -EINVAL; 640a689554bSHai Li } 641a689554bSHai Li 642a689554bSHai Li pclk_rate = mode->clock * 1000; 643a689554bSHai Li if (lanes > 0) { 644a689554bSHai Li msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); 645a689554bSHai Li } else { 646a689554bSHai Li pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); 647a689554bSHai Li msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; 648a689554bSHai Li } 649a689554bSHai Li 650a689554bSHai Li DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); 651a689554bSHai Li 6524bfa9748SArchit Taneja msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); 6534bfa9748SArchit Taneja 6544bfa9748SArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { 6554bfa9748SArchit Taneja unsigned int esc_mhz, esc_div; 6564bfa9748SArchit Taneja unsigned long byte_mhz; 6574bfa9748SArchit Taneja 6584bfa9748SArchit Taneja msm_host->src_clk_rate = (pclk_rate * bpp) / 8; 6594bfa9748SArchit Taneja 6604bfa9748SArchit Taneja /* 6614bfa9748SArchit Taneja * esc clock is byte clock followed by a 4 bit divider, 6624bfa9748SArchit Taneja * we need to find an escape clock frequency within the 6634bfa9748SArchit Taneja * mipi DSI spec range within the maximum divider limit 6644bfa9748SArchit Taneja * We iterate here between an escape clock frequencey 6654bfa9748SArchit Taneja * between 20 Mhz to 5 Mhz and pick up the first one 6664bfa9748SArchit Taneja * that can be supported by our divider 6674bfa9748SArchit Taneja */ 6684bfa9748SArchit Taneja 6694bfa9748SArchit Taneja byte_mhz = msm_host->byte_clk_rate / 1000000; 6704bfa9748SArchit Taneja 6714bfa9748SArchit Taneja for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) { 6724bfa9748SArchit Taneja esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz); 6734bfa9748SArchit Taneja 6744bfa9748SArchit Taneja /* 6754bfa9748SArchit Taneja * TODO: Ideally, we shouldn't know what sort of divider 6764bfa9748SArchit Taneja * is available in mmss_cc, we're just assuming that 6774bfa9748SArchit Taneja * it'll always be a 4 bit divider. Need to come up with 6784bfa9748SArchit Taneja * a better way here. 6794bfa9748SArchit Taneja */ 6804bfa9748SArchit Taneja if (esc_div >= 1 && esc_div <= 16) 6814bfa9748SArchit Taneja break; 6824bfa9748SArchit Taneja } 6834bfa9748SArchit Taneja 6844bfa9748SArchit Taneja if (esc_mhz < 5) 6854bfa9748SArchit Taneja return -EINVAL; 6864bfa9748SArchit Taneja 6874bfa9748SArchit Taneja msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; 6884bfa9748SArchit Taneja 6894bfa9748SArchit Taneja DBG("esc=%d, src=%d", msm_host->esc_clk_rate, 6904bfa9748SArchit Taneja msm_host->src_clk_rate); 6914bfa9748SArchit Taneja } 6924bfa9748SArchit Taneja 693a689554bSHai Li return 0; 694a689554bSHai Li } 695a689554bSHai Li 696a689554bSHai Li static void dsi_phy_sw_reset(struct msm_dsi_host *msm_host) 697a689554bSHai Li { 698a689554bSHai Li DBG(""); 699a689554bSHai Li dsi_write(msm_host, REG_DSI_PHY_RESET, DSI_PHY_RESET_RESET); 700a689554bSHai Li /* Make sure fully reset */ 701a689554bSHai Li wmb(); 702a689554bSHai Li udelay(1000); 703a689554bSHai Li dsi_write(msm_host, REG_DSI_PHY_RESET, 0); 704a689554bSHai Li udelay(100); 705a689554bSHai Li } 706a689554bSHai Li 707a689554bSHai Li static void dsi_intr_ctrl(struct msm_dsi_host *msm_host, u32 mask, int enable) 708a689554bSHai Li { 709a689554bSHai Li u32 intr; 710a689554bSHai Li unsigned long flags; 711a689554bSHai Li 712a689554bSHai Li spin_lock_irqsave(&msm_host->intr_lock, flags); 713a689554bSHai Li intr = dsi_read(msm_host, REG_DSI_INTR_CTRL); 714a689554bSHai Li 715a689554bSHai Li if (enable) 716a689554bSHai Li intr |= mask; 717a689554bSHai Li else 718a689554bSHai Li intr &= ~mask; 719a689554bSHai Li 720a689554bSHai Li DBG("intr=%x enable=%d", intr, enable); 721a689554bSHai Li 722a689554bSHai Li dsi_write(msm_host, REG_DSI_INTR_CTRL, intr); 723a689554bSHai Li spin_unlock_irqrestore(&msm_host->intr_lock, flags); 724a689554bSHai Li } 725a689554bSHai Li 726a689554bSHai Li static inline enum dsi_traffic_mode dsi_get_traffic_mode(const u32 mode_flags) 727a689554bSHai Li { 728a689554bSHai Li if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) 729a689554bSHai Li return BURST_MODE; 730a689554bSHai Li else if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 731a689554bSHai Li return NON_BURST_SYNCH_PULSE; 732a689554bSHai Li 733a689554bSHai Li return NON_BURST_SYNCH_EVENT; 734a689554bSHai Li } 735a689554bSHai Li 736a689554bSHai Li static inline enum dsi_vid_dst_format dsi_get_vid_fmt( 737a689554bSHai Li const enum mipi_dsi_pixel_format mipi_fmt) 738a689554bSHai Li { 739a689554bSHai Li switch (mipi_fmt) { 740a689554bSHai Li case MIPI_DSI_FMT_RGB888: return VID_DST_FORMAT_RGB888; 741a689554bSHai Li case MIPI_DSI_FMT_RGB666: return VID_DST_FORMAT_RGB666_LOOSE; 742a689554bSHai Li case MIPI_DSI_FMT_RGB666_PACKED: return VID_DST_FORMAT_RGB666; 743a689554bSHai Li case MIPI_DSI_FMT_RGB565: return VID_DST_FORMAT_RGB565; 744a689554bSHai Li default: return VID_DST_FORMAT_RGB888; 745a689554bSHai Li } 746a689554bSHai Li } 747a689554bSHai Li 748a689554bSHai Li static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt( 749a689554bSHai Li const enum mipi_dsi_pixel_format mipi_fmt) 750a689554bSHai Li { 751a689554bSHai Li switch (mipi_fmt) { 752a689554bSHai Li case MIPI_DSI_FMT_RGB888: return CMD_DST_FORMAT_RGB888; 753a689554bSHai Li case MIPI_DSI_FMT_RGB666_PACKED: 754a689554bSHai Li case MIPI_DSI_FMT_RGB666: return VID_DST_FORMAT_RGB666; 755a689554bSHai Li case MIPI_DSI_FMT_RGB565: return CMD_DST_FORMAT_RGB565; 756a689554bSHai Li default: return CMD_DST_FORMAT_RGB888; 757a689554bSHai Li } 758a689554bSHai Li } 759a689554bSHai Li 760a689554bSHai Li static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, 761a689554bSHai Li u32 clk_pre, u32 clk_post) 762a689554bSHai Li { 763a689554bSHai Li u32 flags = msm_host->mode_flags; 764a689554bSHai Li enum mipi_dsi_pixel_format mipi_fmt = msm_host->format; 765d248b61fSHai Li const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 766a689554bSHai Li u32 data = 0; 767a689554bSHai Li 768a689554bSHai Li if (!enable) { 769a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, 0); 770a689554bSHai Li return; 771a689554bSHai Li } 772a689554bSHai Li 773a689554bSHai Li if (flags & MIPI_DSI_MODE_VIDEO) { 774a689554bSHai Li if (flags & MIPI_DSI_MODE_VIDEO_HSE) 775a689554bSHai Li data |= DSI_VID_CFG0_PULSE_MODE_HSA_HE; 776a689554bSHai Li if (flags & MIPI_DSI_MODE_VIDEO_HFP) 777a689554bSHai Li data |= DSI_VID_CFG0_HFP_POWER_STOP; 778a689554bSHai Li if (flags & MIPI_DSI_MODE_VIDEO_HBP) 779a689554bSHai Li data |= DSI_VID_CFG0_HBP_POWER_STOP; 780a689554bSHai Li if (flags & MIPI_DSI_MODE_VIDEO_HSA) 781a689554bSHai Li data |= DSI_VID_CFG0_HSA_POWER_STOP; 782a689554bSHai Li /* Always set low power stop mode for BLLP 783a689554bSHai Li * to let command engine send packets 784a689554bSHai Li */ 785a689554bSHai Li data |= DSI_VID_CFG0_EOF_BLLP_POWER_STOP | 786a689554bSHai Li DSI_VID_CFG0_BLLP_POWER_STOP; 787a689554bSHai Li data |= DSI_VID_CFG0_TRAFFIC_MODE(dsi_get_traffic_mode(flags)); 788a689554bSHai Li data |= DSI_VID_CFG0_DST_FORMAT(dsi_get_vid_fmt(mipi_fmt)); 789a689554bSHai Li data |= DSI_VID_CFG0_VIRT_CHANNEL(msm_host->channel); 790a689554bSHai Li dsi_write(msm_host, REG_DSI_VID_CFG0, data); 791a689554bSHai Li 792a689554bSHai Li /* Do not swap RGB colors */ 793a689554bSHai Li data = DSI_VID_CFG1_RGB_SWAP(SWAP_RGB); 794a689554bSHai Li dsi_write(msm_host, REG_DSI_VID_CFG1, 0); 795a689554bSHai Li } else { 796a689554bSHai Li /* Do not swap RGB colors */ 797a689554bSHai Li data = DSI_CMD_CFG0_RGB_SWAP(SWAP_RGB); 798a689554bSHai Li data |= DSI_CMD_CFG0_DST_FORMAT(dsi_get_cmd_fmt(mipi_fmt)); 799a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_CFG0, data); 800a689554bSHai Li 801a689554bSHai Li data = DSI_CMD_CFG1_WR_MEM_START(MIPI_DCS_WRITE_MEMORY_START) | 802a689554bSHai Li DSI_CMD_CFG1_WR_MEM_CONTINUE( 803a689554bSHai Li MIPI_DCS_WRITE_MEMORY_CONTINUE); 804a689554bSHai Li /* Always insert DCS command */ 805a689554bSHai Li data |= DSI_CMD_CFG1_INSERT_DCS_COMMAND; 806a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_CFG1, data); 807a689554bSHai Li } 808a689554bSHai Li 809a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, 810a689554bSHai Li DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER | 811a689554bSHai Li DSI_CMD_DMA_CTRL_LOW_POWER); 812a689554bSHai Li 813a689554bSHai Li data = 0; 814a689554bSHai Li /* Always assume dedicated TE pin */ 815a689554bSHai Li data |= DSI_TRIG_CTRL_TE; 816a689554bSHai Li data |= DSI_TRIG_CTRL_MDP_TRIGGER(TRIGGER_NONE); 817a689554bSHai Li data |= DSI_TRIG_CTRL_DMA_TRIGGER(TRIGGER_SW); 818a689554bSHai Li data |= DSI_TRIG_CTRL_STREAM(msm_host->channel); 819d248b61fSHai Li if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) && 820d248b61fSHai Li (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_2)) 821a689554bSHai Li data |= DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME; 822a689554bSHai Li dsi_write(msm_host, REG_DSI_TRIG_CTRL, data); 823a689554bSHai Li 824a689554bSHai Li data = DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(clk_post) | 825a689554bSHai Li DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE(clk_pre); 826a689554bSHai Li dsi_write(msm_host, REG_DSI_CLKOUT_TIMING_CTRL, data); 827a689554bSHai Li 828a689554bSHai Li data = 0; 829a689554bSHai Li if (!(flags & MIPI_DSI_MODE_EOT_PACKET)) 830a689554bSHai Li data |= DSI_EOT_PACKET_CTRL_TX_EOT_APPEND; 831a689554bSHai Li dsi_write(msm_host, REG_DSI_EOT_PACKET_CTRL, data); 832a689554bSHai Li 833a689554bSHai Li /* allow only ack-err-status to generate interrupt */ 834a689554bSHai Li dsi_write(msm_host, REG_DSI_ERR_INT_MASK0, 0x13ff3fe0); 835a689554bSHai Li 836a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1); 837a689554bSHai Li 838a689554bSHai Li dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS); 839a689554bSHai Li 840a689554bSHai Li data = DSI_CTRL_CLK_EN; 841a689554bSHai Li 842a689554bSHai Li DBG("lane number=%d", msm_host->lanes); 843a689554bSHai Li if (msm_host->lanes == 2) { 844a689554bSHai Li data |= DSI_CTRL_LANE1 | DSI_CTRL_LANE2; 845a689554bSHai Li /* swap lanes for 2-lane panel for better performance */ 846a689554bSHai Li dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL, 847a689554bSHai Li DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_1230)); 848a689554bSHai Li } else { 849a689554bSHai Li /* Take 4 lanes as default */ 850a689554bSHai Li data |= DSI_CTRL_LANE0 | DSI_CTRL_LANE1 | DSI_CTRL_LANE2 | 851a689554bSHai Li DSI_CTRL_LANE3; 852a689554bSHai Li /* Do not swap lanes for 4-lane panel */ 853a689554bSHai Li dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL, 854a689554bSHai Li DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_0123)); 855a689554bSHai Li } 85665c5e542SArchit Taneja 85765c5e542SArchit Taneja if (!(flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) 85865c5e542SArchit Taneja dsi_write(msm_host, REG_DSI_LANE_CTRL, 85965c5e542SArchit Taneja DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST); 86065c5e542SArchit Taneja 861a689554bSHai Li data |= DSI_CTRL_ENABLE; 862a689554bSHai Li 863a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, data); 864a689554bSHai Li } 865a689554bSHai Li 866a689554bSHai Li static void dsi_timing_setup(struct msm_dsi_host *msm_host) 867a689554bSHai Li { 868a689554bSHai Li struct drm_display_mode *mode = msm_host->mode; 869a689554bSHai Li u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */ 870a689554bSHai Li u32 h_total = mode->htotal; 871a689554bSHai Li u32 v_total = mode->vtotal; 872a689554bSHai Li u32 hs_end = mode->hsync_end - mode->hsync_start; 873a689554bSHai Li u32 vs_end = mode->vsync_end - mode->vsync_start; 874a689554bSHai Li u32 ha_start = h_total - mode->hsync_start; 875a689554bSHai Li u32 ha_end = ha_start + mode->hdisplay; 876a689554bSHai Li u32 va_start = v_total - mode->vsync_start; 877a689554bSHai Li u32 va_end = va_start + mode->vdisplay; 878a689554bSHai Li u32 wc; 879a689554bSHai Li 880a689554bSHai Li DBG(""); 881a689554bSHai Li 882a689554bSHai Li if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) { 883a689554bSHai Li dsi_write(msm_host, REG_DSI_ACTIVE_H, 884a689554bSHai Li DSI_ACTIVE_H_START(ha_start) | 885a689554bSHai Li DSI_ACTIVE_H_END(ha_end)); 886a689554bSHai Li dsi_write(msm_host, REG_DSI_ACTIVE_V, 887a689554bSHai Li DSI_ACTIVE_V_START(va_start) | 888a689554bSHai Li DSI_ACTIVE_V_END(va_end)); 889a689554bSHai Li dsi_write(msm_host, REG_DSI_TOTAL, 890a689554bSHai Li DSI_TOTAL_H_TOTAL(h_total - 1) | 891a689554bSHai Li DSI_TOTAL_V_TOTAL(v_total - 1)); 892a689554bSHai Li 893a689554bSHai Li dsi_write(msm_host, REG_DSI_ACTIVE_HSYNC, 894a689554bSHai Li DSI_ACTIVE_HSYNC_START(hs_start) | 895a689554bSHai Li DSI_ACTIVE_HSYNC_END(hs_end)); 896a689554bSHai Li dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_HPOS, 0); 897a689554bSHai Li dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_VPOS, 898a689554bSHai Li DSI_ACTIVE_VSYNC_VPOS_START(vs_start) | 899a689554bSHai Li DSI_ACTIVE_VSYNC_VPOS_END(vs_end)); 900a689554bSHai Li } else { /* command mode */ 901a689554bSHai Li /* image data and 1 byte write_memory_start cmd */ 902a689554bSHai Li wc = mode->hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1; 903a689554bSHai Li 904a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_CTRL, 905a689554bSHai Li DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(wc) | 906a689554bSHai Li DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL( 907a689554bSHai Li msm_host->channel) | 908a689554bSHai Li DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE( 909a689554bSHai Li MIPI_DSI_DCS_LONG_WRITE)); 910a689554bSHai Li 911a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_TOTAL, 912a689554bSHai Li DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(mode->hdisplay) | 913a689554bSHai Li DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(mode->vdisplay)); 914a689554bSHai Li } 915a689554bSHai Li } 916a689554bSHai Li 917a689554bSHai Li static void dsi_sw_reset(struct msm_dsi_host *msm_host) 918a689554bSHai Li { 919a689554bSHai Li dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS); 920a689554bSHai Li wmb(); /* clocks need to be enabled before reset */ 921a689554bSHai Li 922a689554bSHai Li dsi_write(msm_host, REG_DSI_RESET, 1); 923a689554bSHai Li wmb(); /* make sure reset happen */ 924a689554bSHai Li dsi_write(msm_host, REG_DSI_RESET, 0); 925a689554bSHai Li } 926a689554bSHai Li 927a689554bSHai Li static void dsi_op_mode_config(struct msm_dsi_host *msm_host, 928a689554bSHai Li bool video_mode, bool enable) 929a689554bSHai Li { 930a689554bSHai Li u32 dsi_ctrl; 931a689554bSHai Li 932a689554bSHai Li dsi_ctrl = dsi_read(msm_host, REG_DSI_CTRL); 933a689554bSHai Li 934a689554bSHai Li if (!enable) { 935a689554bSHai Li dsi_ctrl &= ~(DSI_CTRL_ENABLE | DSI_CTRL_VID_MODE_EN | 936a689554bSHai Li DSI_CTRL_CMD_MODE_EN); 937a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE | 938a689554bSHai Li DSI_IRQ_MASK_VIDEO_DONE, 0); 939a689554bSHai Li } else { 940a689554bSHai Li if (video_mode) { 941a689554bSHai Li dsi_ctrl |= DSI_CTRL_VID_MODE_EN; 942a689554bSHai Li } else { /* command mode */ 943a689554bSHai Li dsi_ctrl |= DSI_CTRL_CMD_MODE_EN; 944a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE, 1); 945a689554bSHai Li } 946a689554bSHai Li dsi_ctrl |= DSI_CTRL_ENABLE; 947a689554bSHai Li } 948a689554bSHai Li 949a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, dsi_ctrl); 950a689554bSHai Li } 951a689554bSHai Li 952a689554bSHai Li static void dsi_set_tx_power_mode(int mode, struct msm_dsi_host *msm_host) 953a689554bSHai Li { 954a689554bSHai Li u32 data; 955a689554bSHai Li 956a689554bSHai Li data = dsi_read(msm_host, REG_DSI_CMD_DMA_CTRL); 957a689554bSHai Li 958a689554bSHai Li if (mode == 0) 959a689554bSHai Li data &= ~DSI_CMD_DMA_CTRL_LOW_POWER; 960a689554bSHai Li else 961a689554bSHai Li data |= DSI_CMD_DMA_CTRL_LOW_POWER; 962a689554bSHai Li 963a689554bSHai Li dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, data); 964a689554bSHai Li } 965a689554bSHai Li 966a689554bSHai Li static void dsi_wait4video_done(struct msm_dsi_host *msm_host) 967a689554bSHai Li { 968a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 1); 969a689554bSHai Li 970a689554bSHai Li reinit_completion(&msm_host->video_comp); 971a689554bSHai Li 972a689554bSHai Li wait_for_completion_timeout(&msm_host->video_comp, 973a689554bSHai Li msecs_to_jiffies(70)); 974a689554bSHai Li 975a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0); 976a689554bSHai Li } 977a689554bSHai Li 978a689554bSHai Li static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host) 979a689554bSHai Li { 980a689554bSHai Li if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)) 981a689554bSHai Li return; 982a689554bSHai Li 983a689554bSHai Li if (msm_host->power_on) { 984a689554bSHai Li dsi_wait4video_done(msm_host); 985a689554bSHai Li /* delay 4 ms to skip BLLP */ 986a689554bSHai Li usleep_range(2000, 4000); 987a689554bSHai Li } 988a689554bSHai Li } 989a689554bSHai Li 990a689554bSHai Li /* dsi_cmd */ 991a689554bSHai Li static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) 992a689554bSHai Li { 993a689554bSHai Li struct drm_device *dev = msm_host->dev; 9944ff9d4cbSArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 995a689554bSHai Li int ret; 996a689554bSHai Li u32 iova; 997a689554bSHai Li 9984ff9d4cbSArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { 999a689554bSHai Li mutex_lock(&dev->struct_mutex); 1000a689554bSHai Li msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED); 1001a689554bSHai Li if (IS_ERR(msm_host->tx_gem_obj)) { 1002a689554bSHai Li ret = PTR_ERR(msm_host->tx_gem_obj); 10034ff9d4cbSArchit Taneja pr_err("%s: failed to allocate gem, %d\n", 10044ff9d4cbSArchit Taneja __func__, ret); 1005a689554bSHai Li msm_host->tx_gem_obj = NULL; 1006a689554bSHai Li mutex_unlock(&dev->struct_mutex); 1007a689554bSHai Li return ret; 1008a689554bSHai Li } 1009a689554bSHai Li 1010a689554bSHai Li ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova); 1011a689554bSHai Li if (ret) { 1012a689554bSHai Li pr_err("%s: failed to get iova, %d\n", __func__, ret); 1013a689554bSHai Li return ret; 1014a689554bSHai Li } 1015a689554bSHai Li mutex_unlock(&dev->struct_mutex); 1016a689554bSHai Li 1017a689554bSHai Li if (iova & 0x07) { 1018a689554bSHai Li pr_err("%s: buf NOT 8 bytes aligned\n", __func__); 1019a689554bSHai Li return -EINVAL; 1020a689554bSHai Li } 1021a689554bSHai Li 10224ff9d4cbSArchit Taneja msm_host->tx_size = msm_host->tx_gem_obj->size; 10234ff9d4cbSArchit Taneja } else { 10244ff9d4cbSArchit Taneja msm_host->tx_buf = dma_alloc_coherent(dev->dev, size, 10254ff9d4cbSArchit Taneja &msm_host->tx_buf_paddr, GFP_KERNEL); 10264ff9d4cbSArchit Taneja if (!msm_host->tx_buf) { 10274ff9d4cbSArchit Taneja ret = -ENOMEM; 10284ff9d4cbSArchit Taneja pr_err("%s: failed to allocate tx buf, %d\n", 10294ff9d4cbSArchit Taneja __func__, ret); 10304ff9d4cbSArchit Taneja return ret; 10314ff9d4cbSArchit Taneja } 10324ff9d4cbSArchit Taneja 10334ff9d4cbSArchit Taneja msm_host->tx_size = size; 10344ff9d4cbSArchit Taneja } 10354ff9d4cbSArchit Taneja 1036a689554bSHai Li return 0; 1037a689554bSHai Li } 1038a689554bSHai Li 1039a689554bSHai Li static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) 1040a689554bSHai Li { 1041a689554bSHai Li struct drm_device *dev = msm_host->dev; 1042a689554bSHai Li 1043a689554bSHai Li if (msm_host->tx_gem_obj) { 1044a689554bSHai Li msm_gem_put_iova(msm_host->tx_gem_obj, 0); 1045a689554bSHai Li mutex_lock(&dev->struct_mutex); 1046a689554bSHai Li msm_gem_free_object(msm_host->tx_gem_obj); 1047a689554bSHai Li msm_host->tx_gem_obj = NULL; 1048a689554bSHai Li mutex_unlock(&dev->struct_mutex); 1049a689554bSHai Li } 10504ff9d4cbSArchit Taneja 10514ff9d4cbSArchit Taneja if (msm_host->tx_buf) 10524ff9d4cbSArchit Taneja dma_free_coherent(dev->dev, msm_host->tx_size, msm_host->tx_buf, 10534ff9d4cbSArchit Taneja msm_host->tx_buf_paddr); 1054a689554bSHai Li } 1055a689554bSHai Li 1056a689554bSHai Li /* 1057a689554bSHai Li * prepare cmd buffer to be txed 1058a689554bSHai Li */ 10594ff9d4cbSArchit Taneja static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, 1060a689554bSHai Li const struct mipi_dsi_msg *msg) 1061a689554bSHai Li { 10624ff9d4cbSArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 1063a689554bSHai Li struct mipi_dsi_packet packet; 1064a689554bSHai Li int len; 1065a689554bSHai Li int ret; 1066a689554bSHai Li u8 *data; 1067a689554bSHai Li 1068a689554bSHai Li ret = mipi_dsi_create_packet(&packet, msg); 1069a689554bSHai Li if (ret) { 1070a689554bSHai Li pr_err("%s: create packet failed, %d\n", __func__, ret); 1071a689554bSHai Li return ret; 1072a689554bSHai Li } 1073a689554bSHai Li len = (packet.size + 3) & (~0x3); 1074a689554bSHai Li 10754ff9d4cbSArchit Taneja if (len > msm_host->tx_size) { 1076a689554bSHai Li pr_err("%s: packet size is too big\n", __func__); 1077a689554bSHai Li return -EINVAL; 1078a689554bSHai Li } 1079a689554bSHai Li 10804ff9d4cbSArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { 10814ff9d4cbSArchit Taneja data = msm_gem_vaddr(msm_host->tx_gem_obj); 1082a689554bSHai Li if (IS_ERR(data)) { 1083a689554bSHai Li ret = PTR_ERR(data); 1084a689554bSHai Li pr_err("%s: get vaddr failed, %d\n", __func__, ret); 1085a689554bSHai Li return ret; 1086a689554bSHai Li } 10874ff9d4cbSArchit Taneja } else { 10884ff9d4cbSArchit Taneja data = msm_host->tx_buf; 10894ff9d4cbSArchit Taneja } 1090a689554bSHai Li 1091a689554bSHai Li /* MSM specific command format in memory */ 1092a689554bSHai Li data[0] = packet.header[1]; 1093a689554bSHai Li data[1] = packet.header[2]; 1094a689554bSHai Li data[2] = packet.header[0]; 1095a689554bSHai Li data[3] = BIT(7); /* Last packet */ 1096a689554bSHai Li if (mipi_dsi_packet_format_is_long(msg->type)) 1097a689554bSHai Li data[3] |= BIT(6); 1098a689554bSHai Li if (msg->rx_buf && msg->rx_len) 1099a689554bSHai Li data[3] |= BIT(5); 1100a689554bSHai Li 1101a689554bSHai Li /* Long packet */ 1102a689554bSHai Li if (packet.payload && packet.payload_length) 1103a689554bSHai Li memcpy(data + 4, packet.payload, packet.payload_length); 1104a689554bSHai Li 1105a689554bSHai Li /* Append 0xff to the end */ 1106a689554bSHai Li if (packet.size < len) 1107a689554bSHai Li memset(data + packet.size, 0xff, len - packet.size); 1108a689554bSHai Li 1109a689554bSHai Li return len; 1110a689554bSHai Li } 1111a689554bSHai Li 1112a689554bSHai Li /* 1113a689554bSHai Li * dsi_short_read1_resp: 1 parameter 1114a689554bSHai Li */ 1115a689554bSHai Li static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg) 1116a689554bSHai Li { 1117a689554bSHai Li u8 *data = msg->rx_buf; 1118a689554bSHai Li if (data && (msg->rx_len >= 1)) { 1119a689554bSHai Li *data = buf[1]; /* strip out dcs type */ 1120a689554bSHai Li return 1; 1121a689554bSHai Li } else { 1122981371f3SStephane Viau pr_err("%s: read data does not match with rx_buf len %zu\n", 1123a689554bSHai Li __func__, msg->rx_len); 1124a689554bSHai Li return -EINVAL; 1125a689554bSHai Li } 1126a689554bSHai Li } 1127a689554bSHai Li 1128a689554bSHai Li /* 1129a689554bSHai Li * dsi_short_read2_resp: 2 parameter 1130a689554bSHai Li */ 1131a689554bSHai Li static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg) 1132a689554bSHai Li { 1133a689554bSHai Li u8 *data = msg->rx_buf; 1134a689554bSHai Li if (data && (msg->rx_len >= 2)) { 1135a689554bSHai Li data[0] = buf[1]; /* strip out dcs type */ 1136a689554bSHai Li data[1] = buf[2]; 1137a689554bSHai Li return 2; 1138a689554bSHai Li } else { 1139981371f3SStephane Viau pr_err("%s: read data does not match with rx_buf len %zu\n", 1140a689554bSHai Li __func__, msg->rx_len); 1141a689554bSHai Li return -EINVAL; 1142a689554bSHai Li } 1143a689554bSHai Li } 1144a689554bSHai Li 1145a689554bSHai Li static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg) 1146a689554bSHai Li { 1147a689554bSHai Li /* strip out 4 byte dcs header */ 1148a689554bSHai Li if (msg->rx_buf && msg->rx_len) 1149a689554bSHai Li memcpy(msg->rx_buf, buf + 4, msg->rx_len); 1150a689554bSHai Li 1151a689554bSHai Li return msg->rx_len; 1152a689554bSHai Li } 1153a689554bSHai Li 1154a689554bSHai Li static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) 1155a689554bSHai Li { 11564ff9d4cbSArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 1157a689554bSHai Li int ret; 11584ff9d4cbSArchit Taneja u32 dma_base; 1159a689554bSHai Li bool triggered; 1160a689554bSHai Li 11614ff9d4cbSArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { 11624ff9d4cbSArchit Taneja ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &dma_base); 1163a689554bSHai Li if (ret) { 1164a689554bSHai Li pr_err("%s: failed to get iova: %d\n", __func__, ret); 1165a689554bSHai Li return ret; 1166a689554bSHai Li } 11674ff9d4cbSArchit Taneja } else { 11684ff9d4cbSArchit Taneja dma_base = msm_host->tx_buf_paddr; 11694ff9d4cbSArchit Taneja } 1170a689554bSHai Li 1171a689554bSHai Li reinit_completion(&msm_host->dma_comp); 1172a689554bSHai Li 1173a689554bSHai Li dsi_wait4video_eng_busy(msm_host); 1174a689554bSHai Li 1175a689554bSHai Li triggered = msm_dsi_manager_cmd_xfer_trigger( 11764ff9d4cbSArchit Taneja msm_host->id, dma_base, len); 1177a689554bSHai Li if (triggered) { 1178a689554bSHai Li ret = wait_for_completion_timeout(&msm_host->dma_comp, 1179a689554bSHai Li msecs_to_jiffies(200)); 1180a689554bSHai Li DBG("ret=%d", ret); 1181a689554bSHai Li if (ret == 0) 1182a689554bSHai Li ret = -ETIMEDOUT; 1183a689554bSHai Li else 1184a689554bSHai Li ret = len; 1185a689554bSHai Li } else 1186a689554bSHai Li ret = len; 1187a689554bSHai Li 1188a689554bSHai Li return ret; 1189a689554bSHai Li } 1190a689554bSHai Li 1191a689554bSHai Li static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host, 1192a689554bSHai Li u8 *buf, int rx_byte, int pkt_size) 1193a689554bSHai Li { 1194a689554bSHai Li u32 *lp, *temp, data; 1195a689554bSHai Li int i, j = 0, cnt; 1196a689554bSHai Li u32 read_cnt; 1197a689554bSHai Li u8 reg[16]; 1198a689554bSHai Li int repeated_bytes = 0; 1199a689554bSHai Li int buf_offset = buf - msm_host->rx_buf; 1200a689554bSHai Li 1201a689554bSHai Li lp = (u32 *)buf; 1202a689554bSHai Li temp = (u32 *)reg; 1203a689554bSHai Li cnt = (rx_byte + 3) >> 2; 1204a689554bSHai Li if (cnt > 4) 1205a689554bSHai Li cnt = 4; /* 4 x 32 bits registers only */ 1206a689554bSHai Li 1207ec1936ebSHai Li if (rx_byte == 4) 1208ec1936ebSHai Li read_cnt = 4; 1209ec1936ebSHai Li else 1210ec1936ebSHai Li read_cnt = pkt_size + 6; 1211a689554bSHai Li 1212a689554bSHai Li /* 1213a689554bSHai Li * In case of multiple reads from the panel, after the first read, there 1214a689554bSHai Li * is possibility that there are some bytes in the payload repeating in 1215a689554bSHai Li * the RDBK_DATA registers. Since we read all the parameters from the 1216a689554bSHai Li * panel right from the first byte for every pass. We need to skip the 1217a689554bSHai Li * repeating bytes and then append the new parameters to the rx buffer. 1218a689554bSHai Li */ 1219a689554bSHai Li if (read_cnt > 16) { 1220a689554bSHai Li int bytes_shifted; 1221a689554bSHai Li /* Any data more than 16 bytes will be shifted out. 1222a689554bSHai Li * The temp read buffer should already contain these bytes. 1223a689554bSHai Li * The remaining bytes in read buffer are the repeated bytes. 1224a689554bSHai Li */ 1225a689554bSHai Li bytes_shifted = read_cnt - 16; 1226a689554bSHai Li repeated_bytes = buf_offset - bytes_shifted; 1227a689554bSHai Li } 1228a689554bSHai Li 1229a689554bSHai Li for (i = cnt - 1; i >= 0; i--) { 1230a689554bSHai Li data = dsi_read(msm_host, REG_DSI_RDBK_DATA(i)); 1231a689554bSHai Li *temp++ = ntohl(data); /* to host byte order */ 1232a689554bSHai Li DBG("data = 0x%x and ntohl(data) = 0x%x", data, ntohl(data)); 1233a689554bSHai Li } 1234a689554bSHai Li 1235a689554bSHai Li for (i = repeated_bytes; i < 16; i++) 1236a689554bSHai Li buf[j++] = reg[i]; 1237a689554bSHai Li 1238a689554bSHai Li return j; 1239a689554bSHai Li } 1240a689554bSHai Li 1241a689554bSHai Li static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host, 1242a689554bSHai Li const struct mipi_dsi_msg *msg) 1243a689554bSHai Li { 1244a689554bSHai Li int len, ret; 1245a689554bSHai Li int bllp_len = msm_host->mode->hdisplay * 1246a689554bSHai Li dsi_get_bpp(msm_host->format) / 8; 1247a689554bSHai Li 12484ff9d4cbSArchit Taneja len = dsi_cmd_dma_add(msm_host, msg); 1249a689554bSHai Li if (!len) { 1250a689554bSHai Li pr_err("%s: failed to add cmd type = 0x%x\n", 1251a689554bSHai Li __func__, msg->type); 1252a689554bSHai Li return -EINVAL; 1253a689554bSHai Li } 1254a689554bSHai Li 1255a689554bSHai Li /* for video mode, do not send cmds more than 1256a689554bSHai Li * one pixel line, since it only transmit it 1257a689554bSHai Li * during BLLP. 1258a689554bSHai Li */ 1259a689554bSHai Li /* TODO: if the command is sent in LP mode, the bit rate is only 1260a689554bSHai Li * half of esc clk rate. In this case, if the video is already 1261a689554bSHai Li * actively streaming, we need to check more carefully if the 1262a689554bSHai Li * command can be fit into one BLLP. 1263a689554bSHai Li */ 1264a689554bSHai Li if ((msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) && (len > bllp_len)) { 1265a689554bSHai Li pr_err("%s: cmd cannot fit into BLLP period, len=%d\n", 1266a689554bSHai Li __func__, len); 1267a689554bSHai Li return -EINVAL; 1268a689554bSHai Li } 1269a689554bSHai Li 1270a689554bSHai Li ret = dsi_cmd_dma_tx(msm_host, len); 1271a689554bSHai Li if (ret < len) { 1272a689554bSHai Li pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d\n", 1273a689554bSHai Li __func__, msg->type, (*(u8 *)(msg->tx_buf)), len); 1274a689554bSHai Li return -ECOMM; 1275a689554bSHai Li } 1276a689554bSHai Li 1277a689554bSHai Li return len; 1278a689554bSHai Li } 1279a689554bSHai Li 1280a689554bSHai Li static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host) 1281a689554bSHai Li { 1282a689554bSHai Li u32 data0, data1; 1283a689554bSHai Li 1284a689554bSHai Li data0 = dsi_read(msm_host, REG_DSI_CTRL); 1285a689554bSHai Li data1 = data0; 1286a689554bSHai Li data1 &= ~DSI_CTRL_ENABLE; 1287a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, data1); 1288a689554bSHai Li /* 1289a689554bSHai Li * dsi controller need to be disabled before 1290a689554bSHai Li * clocks turned on 1291a689554bSHai Li */ 1292a689554bSHai Li wmb(); 1293a689554bSHai Li 1294a689554bSHai Li dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS); 1295a689554bSHai Li wmb(); /* make sure clocks enabled */ 1296a689554bSHai Li 1297a689554bSHai Li /* dsi controller can only be reset while clocks are running */ 1298a689554bSHai Li dsi_write(msm_host, REG_DSI_RESET, 1); 1299a689554bSHai Li wmb(); /* make sure reset happen */ 1300a689554bSHai Li dsi_write(msm_host, REG_DSI_RESET, 0); 1301a689554bSHai Li wmb(); /* controller out of reset */ 1302a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, data0); 1303a689554bSHai Li wmb(); /* make sure dsi controller enabled again */ 1304a689554bSHai Li } 1305a689554bSHai Li 1306a689554bSHai Li static void dsi_err_worker(struct work_struct *work) 1307a689554bSHai Li { 1308a689554bSHai Li struct msm_dsi_host *msm_host = 1309a689554bSHai Li container_of(work, struct msm_dsi_host, err_work); 1310a689554bSHai Li u32 status = msm_host->err_work_state; 1311a689554bSHai Li 1312ff431fa4SRob Clark pr_err_ratelimited("%s: status=%x\n", __func__, status); 1313a689554bSHai Li if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW) 1314a689554bSHai Li dsi_sw_reset_restore(msm_host); 1315a689554bSHai Li 1316a689554bSHai Li /* It is safe to clear here because error irq is disabled. */ 1317a689554bSHai Li msm_host->err_work_state = 0; 1318a689554bSHai Li 1319a689554bSHai Li /* enable dsi error interrupt */ 1320a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1); 1321a689554bSHai Li } 1322a689554bSHai Li 1323a689554bSHai Li static void dsi_ack_err_status(struct msm_dsi_host *msm_host) 1324a689554bSHai Li { 1325a689554bSHai Li u32 status; 1326a689554bSHai Li 1327a689554bSHai Li status = dsi_read(msm_host, REG_DSI_ACK_ERR_STATUS); 1328a689554bSHai Li 1329a689554bSHai Li if (status) { 1330a689554bSHai Li dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, status); 1331a689554bSHai Li /* Writing of an extra 0 needed to clear error bits */ 1332a689554bSHai Li dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, 0); 1333a689554bSHai Li msm_host->err_work_state |= DSI_ERR_STATE_ACK; 1334a689554bSHai Li } 1335a689554bSHai Li } 1336a689554bSHai Li 1337a689554bSHai Li static void dsi_timeout_status(struct msm_dsi_host *msm_host) 1338a689554bSHai Li { 1339a689554bSHai Li u32 status; 1340a689554bSHai Li 1341a689554bSHai Li status = dsi_read(msm_host, REG_DSI_TIMEOUT_STATUS); 1342a689554bSHai Li 1343a689554bSHai Li if (status) { 1344a689554bSHai Li dsi_write(msm_host, REG_DSI_TIMEOUT_STATUS, status); 1345a689554bSHai Li msm_host->err_work_state |= DSI_ERR_STATE_TIMEOUT; 1346a689554bSHai Li } 1347a689554bSHai Li } 1348a689554bSHai Li 1349a689554bSHai Li static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host) 1350a689554bSHai Li { 1351a689554bSHai Li u32 status; 1352a689554bSHai Li 1353a689554bSHai Li status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR); 1354a689554bSHai Li 135501199361SArchit Taneja if (status & (DSI_DLN0_PHY_ERR_DLN0_ERR_ESC | 135601199361SArchit Taneja DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC | 135701199361SArchit Taneja DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL | 135801199361SArchit Taneja DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0 | 135901199361SArchit Taneja DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1)) { 1360a689554bSHai Li dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, status); 1361a689554bSHai Li msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY; 1362a689554bSHai Li } 1363a689554bSHai Li } 1364a689554bSHai Li 1365a689554bSHai Li static void dsi_fifo_status(struct msm_dsi_host *msm_host) 1366a689554bSHai Li { 1367a689554bSHai Li u32 status; 1368a689554bSHai Li 1369a689554bSHai Li status = dsi_read(msm_host, REG_DSI_FIFO_STATUS); 1370a689554bSHai Li 1371a689554bSHai Li /* fifo underflow, overflow */ 1372a689554bSHai Li if (status) { 1373a689554bSHai Li dsi_write(msm_host, REG_DSI_FIFO_STATUS, status); 1374a689554bSHai Li msm_host->err_work_state |= DSI_ERR_STATE_FIFO; 1375a689554bSHai Li if (status & DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW) 1376a689554bSHai Li msm_host->err_work_state |= 1377a689554bSHai Li DSI_ERR_STATE_MDP_FIFO_UNDERFLOW; 1378a689554bSHai Li } 1379a689554bSHai Li } 1380a689554bSHai Li 1381a689554bSHai Li static void dsi_status(struct msm_dsi_host *msm_host) 1382a689554bSHai Li { 1383a689554bSHai Li u32 status; 1384a689554bSHai Li 1385a689554bSHai Li status = dsi_read(msm_host, REG_DSI_STATUS0); 1386a689554bSHai Li 1387a689554bSHai Li if (status & DSI_STATUS0_INTERLEAVE_OP_CONTENTION) { 1388a689554bSHai Li dsi_write(msm_host, REG_DSI_STATUS0, status); 1389a689554bSHai Li msm_host->err_work_state |= 1390a689554bSHai Li DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION; 1391a689554bSHai Li } 1392a689554bSHai Li } 1393a689554bSHai Li 1394a689554bSHai Li static void dsi_clk_status(struct msm_dsi_host *msm_host) 1395a689554bSHai Li { 1396a689554bSHai Li u32 status; 1397a689554bSHai Li 1398a689554bSHai Li status = dsi_read(msm_host, REG_DSI_CLK_STATUS); 1399a689554bSHai Li 1400a689554bSHai Li if (status & DSI_CLK_STATUS_PLL_UNLOCKED) { 1401a689554bSHai Li dsi_write(msm_host, REG_DSI_CLK_STATUS, status); 1402a689554bSHai Li msm_host->err_work_state |= DSI_ERR_STATE_PLL_UNLOCKED; 1403a689554bSHai Li } 1404a689554bSHai Li } 1405a689554bSHai Li 1406a689554bSHai Li static void dsi_error(struct msm_dsi_host *msm_host) 1407a689554bSHai Li { 1408a689554bSHai Li /* disable dsi error interrupt */ 1409a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 0); 1410a689554bSHai Li 1411a689554bSHai Li dsi_clk_status(msm_host); 1412a689554bSHai Li dsi_fifo_status(msm_host); 1413a689554bSHai Li dsi_ack_err_status(msm_host); 1414a689554bSHai Li dsi_timeout_status(msm_host); 1415a689554bSHai Li dsi_status(msm_host); 1416a689554bSHai Li dsi_dln0_phy_err(msm_host); 1417a689554bSHai Li 1418a689554bSHai Li queue_work(msm_host->workqueue, &msm_host->err_work); 1419a689554bSHai Li } 1420a689554bSHai Li 1421a689554bSHai Li static irqreturn_t dsi_host_irq(int irq, void *ptr) 1422a689554bSHai Li { 1423a689554bSHai Li struct msm_dsi_host *msm_host = ptr; 1424a689554bSHai Li u32 isr; 1425a689554bSHai Li unsigned long flags; 1426a689554bSHai Li 1427a689554bSHai Li if (!msm_host->ctrl_base) 1428a689554bSHai Li return IRQ_HANDLED; 1429a689554bSHai Li 1430a689554bSHai Li spin_lock_irqsave(&msm_host->intr_lock, flags); 1431a689554bSHai Li isr = dsi_read(msm_host, REG_DSI_INTR_CTRL); 1432a689554bSHai Li dsi_write(msm_host, REG_DSI_INTR_CTRL, isr); 1433a689554bSHai Li spin_unlock_irqrestore(&msm_host->intr_lock, flags); 1434a689554bSHai Li 1435a689554bSHai Li DBG("isr=0x%x, id=%d", isr, msm_host->id); 1436a689554bSHai Li 1437a689554bSHai Li if (isr & DSI_IRQ_ERROR) 1438a689554bSHai Li dsi_error(msm_host); 1439a689554bSHai Li 1440a689554bSHai Li if (isr & DSI_IRQ_VIDEO_DONE) 1441a689554bSHai Li complete(&msm_host->video_comp); 1442a689554bSHai Li 1443a689554bSHai Li if (isr & DSI_IRQ_CMD_DMA_DONE) 1444a689554bSHai Li complete(&msm_host->dma_comp); 1445a689554bSHai Li 1446a689554bSHai Li return IRQ_HANDLED; 1447a689554bSHai Li } 1448a689554bSHai Li 1449a689554bSHai Li static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host, 1450a689554bSHai Li struct device *panel_device) 1451a689554bSHai Li { 14529590e69dSUwe Kleine-König msm_host->disp_en_gpio = devm_gpiod_get_optional(panel_device, 14539590e69dSUwe Kleine-König "disp-enable", 14549590e69dSUwe Kleine-König GPIOD_OUT_LOW); 1455a689554bSHai Li if (IS_ERR(msm_host->disp_en_gpio)) { 1456a689554bSHai Li DBG("cannot get disp-enable-gpios %ld", 1457a689554bSHai Li PTR_ERR(msm_host->disp_en_gpio)); 14589590e69dSUwe Kleine-König return PTR_ERR(msm_host->disp_en_gpio); 1459a689554bSHai Li } 1460a689554bSHai Li 146160d05cb4SArchit Taneja msm_host->te_gpio = devm_gpiod_get_optional(panel_device, "disp-te", 146260d05cb4SArchit Taneja GPIOD_IN); 1463a689554bSHai Li if (IS_ERR(msm_host->te_gpio)) { 1464a689554bSHai Li DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio)); 14659590e69dSUwe Kleine-König return PTR_ERR(msm_host->te_gpio); 1466a689554bSHai Li } 1467a689554bSHai Li 1468a689554bSHai Li return 0; 1469a689554bSHai Li } 1470a689554bSHai Li 1471a689554bSHai Li static int dsi_host_attach(struct mipi_dsi_host *host, 1472a689554bSHai Li struct mipi_dsi_device *dsi) 1473a689554bSHai Li { 1474a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1475a689554bSHai Li int ret; 1476a689554bSHai Li 1477a689554bSHai Li msm_host->channel = dsi->channel; 1478a689554bSHai Li msm_host->lanes = dsi->lanes; 1479a689554bSHai Li msm_host->format = dsi->format; 1480a689554bSHai Li msm_host->mode_flags = dsi->mode_flags; 1481a689554bSHai Li 1482a9ddac9cSArchit Taneja WARN_ON(dsi->dev.of_node != msm_host->device_node); 1483a689554bSHai Li 1484a689554bSHai Li /* Some gpios defined in panel DT need to be controlled by host */ 1485a689554bSHai Li ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev); 1486a689554bSHai Li if (ret) 1487a689554bSHai Li return ret; 1488a689554bSHai Li 1489a689554bSHai Li DBG("id=%d", msm_host->id); 1490a689554bSHai Li if (msm_host->dev) 1491a689554bSHai Li drm_helper_hpd_irq_event(msm_host->dev); 1492a689554bSHai Li 1493a689554bSHai Li return 0; 1494a689554bSHai Li } 1495a689554bSHai Li 1496a689554bSHai Li static int dsi_host_detach(struct mipi_dsi_host *host, 1497a689554bSHai Li struct mipi_dsi_device *dsi) 1498a689554bSHai Li { 1499a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1500a689554bSHai Li 1501a9ddac9cSArchit Taneja msm_host->device_node = NULL; 1502a689554bSHai Li 1503a689554bSHai Li DBG("id=%d", msm_host->id); 1504a689554bSHai Li if (msm_host->dev) 1505a689554bSHai Li drm_helper_hpd_irq_event(msm_host->dev); 1506a689554bSHai Li 1507a689554bSHai Li return 0; 1508a689554bSHai Li } 1509a689554bSHai Li 1510a689554bSHai Li static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, 1511a689554bSHai Li const struct mipi_dsi_msg *msg) 1512a689554bSHai Li { 1513a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1514a689554bSHai Li int ret; 1515a689554bSHai Li 1516a689554bSHai Li if (!msg || !msm_host->power_on) 1517a689554bSHai Li return -EINVAL; 1518a689554bSHai Li 1519a689554bSHai Li mutex_lock(&msm_host->cmd_mutex); 1520a689554bSHai Li ret = msm_dsi_manager_cmd_xfer(msm_host->id, msg); 1521a689554bSHai Li mutex_unlock(&msm_host->cmd_mutex); 1522a689554bSHai Li 1523a689554bSHai Li return ret; 1524a689554bSHai Li } 1525a689554bSHai Li 1526a689554bSHai Li static struct mipi_dsi_host_ops dsi_host_ops = { 1527a689554bSHai Li .attach = dsi_host_attach, 1528a689554bSHai Li .detach = dsi_host_detach, 1529a689554bSHai Li .transfer = dsi_host_transfer, 1530a689554bSHai Li }; 1531a689554bSHai Li 1532f7009d26SArchit Taneja static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) 1533f7009d26SArchit Taneja { 1534f7009d26SArchit Taneja struct device *dev = &msm_host->pdev->dev; 1535f7009d26SArchit Taneja struct device_node *np = dev->of_node; 1536a9ddac9cSArchit Taneja struct device_node *endpoint, *device_node; 1537f7009d26SArchit Taneja int ret; 1538f7009d26SArchit Taneja 1539f7009d26SArchit Taneja ret = of_property_read_u32(np, "qcom,dsi-host-index", &msm_host->id); 1540f7009d26SArchit Taneja if (ret) { 1541f7009d26SArchit Taneja dev_err(dev, "%s: host index not specified, ret=%d\n", 1542f7009d26SArchit Taneja __func__, ret); 1543f7009d26SArchit Taneja return ret; 1544f7009d26SArchit Taneja } 1545f7009d26SArchit Taneja 1546f7009d26SArchit Taneja /* 1547f7009d26SArchit Taneja * Get the first endpoint node. In our case, dsi has one output port 1548f7009d26SArchit Taneja * to which the panel is connected. Don't return an error if a port 1549f7009d26SArchit Taneja * isn't defined. It's possible that there is nothing connected to 1550f7009d26SArchit Taneja * the dsi output. 1551f7009d26SArchit Taneja */ 1552f7009d26SArchit Taneja endpoint = of_graph_get_next_endpoint(np, NULL); 1553f7009d26SArchit Taneja if (!endpoint) { 1554f7009d26SArchit Taneja dev_dbg(dev, "%s: no endpoint\n", __func__); 1555f7009d26SArchit Taneja return 0; 1556f7009d26SArchit Taneja } 1557f7009d26SArchit Taneja 1558f7009d26SArchit Taneja /* Get panel node from the output port's endpoint data */ 1559a9ddac9cSArchit Taneja device_node = of_graph_get_remote_port_parent(endpoint); 1560a9ddac9cSArchit Taneja if (!device_node) { 1561f7009d26SArchit Taneja dev_err(dev, "%s: no valid device\n", __func__); 1562f7009d26SArchit Taneja of_node_put(endpoint); 1563f7009d26SArchit Taneja return -ENODEV; 1564f7009d26SArchit Taneja } 1565f7009d26SArchit Taneja 1566f7009d26SArchit Taneja of_node_put(endpoint); 1567a9ddac9cSArchit Taneja of_node_put(device_node); 1568f7009d26SArchit Taneja 1569a9ddac9cSArchit Taneja msm_host->device_node = device_node; 1570f7009d26SArchit Taneja 1571f7009d26SArchit Taneja return 0; 1572f7009d26SArchit Taneja } 1573f7009d26SArchit Taneja 1574a689554bSHai Li int msm_dsi_host_init(struct msm_dsi *msm_dsi) 1575a689554bSHai Li { 1576a689554bSHai Li struct msm_dsi_host *msm_host = NULL; 1577a689554bSHai Li struct platform_device *pdev = msm_dsi->pdev; 1578a689554bSHai Li int ret; 1579a689554bSHai Li 1580a689554bSHai Li msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); 1581a689554bSHai Li if (!msm_host) { 1582a689554bSHai Li pr_err("%s: FAILED: cannot alloc dsi host\n", 1583a689554bSHai Li __func__); 1584a689554bSHai Li ret = -ENOMEM; 1585a689554bSHai Li goto fail; 1586a689554bSHai Li } 1587a689554bSHai Li 1588f7009d26SArchit Taneja msm_host->pdev = pdev; 1589f7009d26SArchit Taneja 1590f7009d26SArchit Taneja ret = dsi_host_parse_dt(msm_host); 1591a689554bSHai Li if (ret) { 1592f7009d26SArchit Taneja pr_err("%s: failed to parse dt\n", __func__); 1593a689554bSHai Li goto fail; 1594a689554bSHai Li } 1595a689554bSHai Li 1596a689554bSHai Li msm_host->ctrl_base = msm_ioremap(pdev, "dsi_ctrl", "DSI CTRL"); 1597a689554bSHai Li if (IS_ERR(msm_host->ctrl_base)) { 1598a689554bSHai Li pr_err("%s: unable to map Dsi ctrl base\n", __func__); 1599a689554bSHai Li ret = PTR_ERR(msm_host->ctrl_base); 1600a689554bSHai Li goto fail; 1601a689554bSHai Li } 1602a689554bSHai Li 1603d248b61fSHai Li msm_host->cfg_hnd = dsi_get_config(msm_host); 1604d248b61fSHai Li if (!msm_host->cfg_hnd) { 1605a689554bSHai Li ret = -EINVAL; 1606a689554bSHai Li pr_err("%s: get config failed\n", __func__); 1607a689554bSHai Li goto fail; 1608a689554bSHai Li } 1609a689554bSHai Li 1610d248b61fSHai Li /* fixup base address by io offset */ 1611d248b61fSHai Li msm_host->ctrl_base += msm_host->cfg_hnd->cfg->io_offset; 1612d248b61fSHai Li 1613a689554bSHai Li ret = dsi_regulator_init(msm_host); 1614a689554bSHai Li if (ret) { 1615a689554bSHai Li pr_err("%s: regulator init failed\n", __func__); 1616a689554bSHai Li goto fail; 1617a689554bSHai Li } 1618a689554bSHai Li 161931c92767SArchit Taneja ret = dsi_clk_init(msm_host); 162031c92767SArchit Taneja if (ret) { 162131c92767SArchit Taneja pr_err("%s: unable to initialize dsi clks\n", __func__); 162231c92767SArchit Taneja goto fail; 162331c92767SArchit Taneja } 162431c92767SArchit Taneja 1625a689554bSHai Li msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL); 1626a689554bSHai Li if (!msm_host->rx_buf) { 1627a689554bSHai Li pr_err("%s: alloc rx temp buf failed\n", __func__); 1628a689554bSHai Li goto fail; 1629a689554bSHai Li } 1630a689554bSHai Li 1631a689554bSHai Li init_completion(&msm_host->dma_comp); 1632a689554bSHai Li init_completion(&msm_host->video_comp); 1633a689554bSHai Li mutex_init(&msm_host->dev_mutex); 1634a689554bSHai Li mutex_init(&msm_host->cmd_mutex); 1635a689554bSHai Li mutex_init(&msm_host->clk_mutex); 1636a689554bSHai Li spin_lock_init(&msm_host->intr_lock); 1637a689554bSHai Li 1638a689554bSHai Li /* setup workqueue */ 1639a689554bSHai Li msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); 1640a689554bSHai Li INIT_WORK(&msm_host->err_work, dsi_err_worker); 1641a689554bSHai Li 1642a689554bSHai Li msm_dsi->host = &msm_host->base; 1643a689554bSHai Li msm_dsi->id = msm_host->id; 1644a689554bSHai Li 1645a689554bSHai Li DBG("Dsi Host %d initialized", msm_host->id); 1646a689554bSHai Li return 0; 1647a689554bSHai Li 1648a689554bSHai Li fail: 1649a689554bSHai Li return ret; 1650a689554bSHai Li } 1651a689554bSHai Li 1652a689554bSHai Li void msm_dsi_host_destroy(struct mipi_dsi_host *host) 1653a689554bSHai Li { 1654a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1655a689554bSHai Li 1656a689554bSHai Li DBG(""); 1657a689554bSHai Li dsi_tx_buf_free(msm_host); 1658a689554bSHai Li if (msm_host->workqueue) { 1659a689554bSHai Li flush_workqueue(msm_host->workqueue); 1660a689554bSHai Li destroy_workqueue(msm_host->workqueue); 1661a689554bSHai Li msm_host->workqueue = NULL; 1662a689554bSHai Li } 1663a689554bSHai Li 1664a689554bSHai Li mutex_destroy(&msm_host->clk_mutex); 1665a689554bSHai Li mutex_destroy(&msm_host->cmd_mutex); 1666a689554bSHai Li mutex_destroy(&msm_host->dev_mutex); 1667a689554bSHai Li } 1668a689554bSHai Li 1669a689554bSHai Li int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, 1670a689554bSHai Li struct drm_device *dev) 1671a689554bSHai Li { 1672a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1673a689554bSHai Li struct platform_device *pdev = msm_host->pdev; 1674a689554bSHai Li int ret; 1675a689554bSHai Li 1676a689554bSHai Li msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 1677a689554bSHai Li if (msm_host->irq < 0) { 1678a689554bSHai Li ret = msm_host->irq; 1679a689554bSHai Li dev_err(dev->dev, "failed to get irq: %d\n", ret); 1680a689554bSHai Li return ret; 1681a689554bSHai Li } 1682a689554bSHai Li 1683a689554bSHai Li ret = devm_request_irq(&pdev->dev, msm_host->irq, 1684a689554bSHai Li dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 1685a689554bSHai Li "dsi_isr", msm_host); 1686a689554bSHai Li if (ret < 0) { 1687a689554bSHai Li dev_err(&pdev->dev, "failed to request IRQ%u: %d\n", 1688a689554bSHai Li msm_host->irq, ret); 1689a689554bSHai Li return ret; 1690a689554bSHai Li } 1691a689554bSHai Li 1692a689554bSHai Li msm_host->dev = dev; 1693a689554bSHai Li ret = dsi_tx_buf_alloc(msm_host, SZ_4K); 1694a689554bSHai Li if (ret) { 1695a689554bSHai Li pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret); 1696a689554bSHai Li return ret; 1697a689554bSHai Li } 1698a689554bSHai Li 1699a689554bSHai Li return 0; 1700a689554bSHai Li } 1701a689554bSHai Li 1702a689554bSHai Li int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer) 1703a689554bSHai Li { 1704a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1705a689554bSHai Li int ret; 1706a689554bSHai Li 1707a689554bSHai Li /* Register mipi dsi host */ 1708a689554bSHai Li if (!msm_host->registered) { 1709a689554bSHai Li host->dev = &msm_host->pdev->dev; 1710a689554bSHai Li host->ops = &dsi_host_ops; 1711a689554bSHai Li ret = mipi_dsi_host_register(host); 1712a689554bSHai Li if (ret) 1713a689554bSHai Li return ret; 1714a689554bSHai Li 1715a689554bSHai Li msm_host->registered = true; 1716a689554bSHai Li 1717a689554bSHai Li /* If the panel driver has not been probed after host register, 1718a689554bSHai Li * we should defer the host's probe. 1719a689554bSHai Li * It makes sure panel is connected when fbcon detects 1720a689554bSHai Li * connector status and gets the proper display mode to 1721a689554bSHai Li * create framebuffer. 1722f7009d26SArchit Taneja * Don't try to defer if there is nothing connected to the dsi 1723f7009d26SArchit Taneja * output 1724a689554bSHai Li */ 1725a9ddac9cSArchit Taneja if (check_defer && msm_host->device_node) { 1726a9ddac9cSArchit Taneja if (!of_drm_find_panel(msm_host->device_node)) 1727c118e290SArchit Taneja if (!of_drm_find_bridge(msm_host->device_node)) 1728a689554bSHai Li return -EPROBE_DEFER; 1729a689554bSHai Li } 1730a689554bSHai Li } 1731a689554bSHai Li 1732a689554bSHai Li return 0; 1733a689554bSHai Li } 1734a689554bSHai Li 1735a689554bSHai Li void msm_dsi_host_unregister(struct mipi_dsi_host *host) 1736a689554bSHai Li { 1737a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1738a689554bSHai Li 1739a689554bSHai Li if (msm_host->registered) { 1740a689554bSHai Li mipi_dsi_host_unregister(host); 1741a689554bSHai Li host->dev = NULL; 1742a689554bSHai Li host->ops = NULL; 1743a689554bSHai Li msm_host->registered = false; 1744a689554bSHai Li } 1745a689554bSHai Li } 1746a689554bSHai Li 1747a689554bSHai Li int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, 1748a689554bSHai Li const struct mipi_dsi_msg *msg) 1749a689554bSHai Li { 1750a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1751a689554bSHai Li 1752a689554bSHai Li /* TODO: make sure dsi_cmd_mdp is idle. 1753a689554bSHai Li * Since DSI6G v1.2.0, we can set DSI_TRIG_CTRL.BLOCK_DMA_WITHIN_FRAME 1754a689554bSHai Li * to ask H/W to wait until cmd mdp is idle. S/W wait is not needed. 1755a689554bSHai Li * How to handle the old versions? Wait for mdp cmd done? 1756a689554bSHai Li */ 1757a689554bSHai Li 1758a689554bSHai Li /* 1759a689554bSHai Li * mdss interrupt is generated in mdp core clock domain 1760a689554bSHai Li * mdp clock need to be enabled to receive dsi interrupt 1761a689554bSHai Li */ 1762a689554bSHai Li dsi_clk_ctrl(msm_host, 1); 1763a689554bSHai Li 1764a689554bSHai Li /* TODO: vote for bus bandwidth */ 1765a689554bSHai Li 1766a689554bSHai Li if (!(msg->flags & MIPI_DSI_MSG_USE_LPM)) 1767a689554bSHai Li dsi_set_tx_power_mode(0, msm_host); 1768a689554bSHai Li 1769a689554bSHai Li msm_host->dma_cmd_ctrl_restore = dsi_read(msm_host, REG_DSI_CTRL); 1770a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, 1771a689554bSHai Li msm_host->dma_cmd_ctrl_restore | 1772a689554bSHai Li DSI_CTRL_CMD_MODE_EN | 1773a689554bSHai Li DSI_CTRL_ENABLE); 1774a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 1); 1775a689554bSHai Li 1776a689554bSHai Li return 0; 1777a689554bSHai Li } 1778a689554bSHai Li 1779a689554bSHai Li void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, 1780a689554bSHai Li const struct mipi_dsi_msg *msg) 1781a689554bSHai Li { 1782a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1783a689554bSHai Li 1784a689554bSHai Li dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 0); 1785a689554bSHai Li dsi_write(msm_host, REG_DSI_CTRL, msm_host->dma_cmd_ctrl_restore); 1786a689554bSHai Li 1787a689554bSHai Li if (!(msg->flags & MIPI_DSI_MSG_USE_LPM)) 1788a689554bSHai Li dsi_set_tx_power_mode(1, msm_host); 1789a689554bSHai Li 1790a689554bSHai Li /* TODO: unvote for bus bandwidth */ 1791a689554bSHai Li 1792a689554bSHai Li dsi_clk_ctrl(msm_host, 0); 1793a689554bSHai Li } 1794a689554bSHai Li 1795a689554bSHai Li int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, 1796a689554bSHai Li const struct mipi_dsi_msg *msg) 1797a689554bSHai Li { 1798a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1799a689554bSHai Li 1800a689554bSHai Li return dsi_cmds2buf_tx(msm_host, msg); 1801a689554bSHai Li } 1802a689554bSHai Li 1803a689554bSHai Li int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, 1804a689554bSHai Li const struct mipi_dsi_msg *msg) 1805a689554bSHai Li { 1806a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1807d248b61fSHai Li const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 1808a689554bSHai Li int data_byte, rx_byte, dlen, end; 1809a689554bSHai Li int short_response, diff, pkt_size, ret = 0; 1810a689554bSHai Li char cmd; 1811a689554bSHai Li int rlen = msg->rx_len; 1812a689554bSHai Li u8 *buf; 1813a689554bSHai Li 1814a689554bSHai Li if (rlen <= 2) { 1815a689554bSHai Li short_response = 1; 1816a689554bSHai Li pkt_size = rlen; 1817a689554bSHai Li rx_byte = 4; 1818a689554bSHai Li } else { 1819a689554bSHai Li short_response = 0; 1820a689554bSHai Li data_byte = 10; /* first read */ 1821a689554bSHai Li if (rlen < data_byte) 1822a689554bSHai Li pkt_size = rlen; 1823a689554bSHai Li else 1824a689554bSHai Li pkt_size = data_byte; 1825a689554bSHai Li rx_byte = data_byte + 6; /* 4 header + 2 crc */ 1826a689554bSHai Li } 1827a689554bSHai Li 1828a689554bSHai Li buf = msm_host->rx_buf; 1829a689554bSHai Li end = 0; 1830a689554bSHai Li while (!end) { 1831a689554bSHai Li u8 tx[2] = {pkt_size & 0xff, pkt_size >> 8}; 1832a689554bSHai Li struct mipi_dsi_msg max_pkt_size_msg = { 1833a689554bSHai Li .channel = msg->channel, 1834a689554bSHai Li .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 1835a689554bSHai Li .tx_len = 2, 1836a689554bSHai Li .tx_buf = tx, 1837a689554bSHai Li }; 1838a689554bSHai Li 1839a689554bSHai Li DBG("rlen=%d pkt_size=%d rx_byte=%d", 1840a689554bSHai Li rlen, pkt_size, rx_byte); 1841a689554bSHai Li 1842a689554bSHai Li ret = dsi_cmds2buf_tx(msm_host, &max_pkt_size_msg); 1843a689554bSHai Li if (ret < 2) { 1844a689554bSHai Li pr_err("%s: Set max pkt size failed, %d\n", 1845a689554bSHai Li __func__, ret); 1846a689554bSHai Li return -EINVAL; 1847a689554bSHai Li } 1848a689554bSHai Li 1849d248b61fSHai Li if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) && 1850d248b61fSHai Li (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) { 1851a689554bSHai Li /* Clear the RDBK_DATA registers */ 1852a689554bSHai Li dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, 1853a689554bSHai Li DSI_RDBK_DATA_CTRL_CLR); 1854a689554bSHai Li wmb(); /* make sure the RDBK registers are cleared */ 1855a689554bSHai Li dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, 0); 1856a689554bSHai Li wmb(); /* release cleared status before transfer */ 1857a689554bSHai Li } 1858a689554bSHai Li 1859a689554bSHai Li ret = dsi_cmds2buf_tx(msm_host, msg); 1860a689554bSHai Li if (ret < msg->tx_len) { 1861a689554bSHai Li pr_err("%s: Read cmd Tx failed, %d\n", __func__, ret); 1862a689554bSHai Li return ret; 1863a689554bSHai Li } 1864a689554bSHai Li 1865a689554bSHai Li /* 1866a689554bSHai Li * once cmd_dma_done interrupt received, 1867a689554bSHai Li * return data from client is ready and stored 1868a689554bSHai Li * at RDBK_DATA register already 1869a689554bSHai Li * since rx fifo is 16 bytes, dcs header is kept at first loop, 1870a689554bSHai Li * after that dcs header lost during shift into registers 1871a689554bSHai Li */ 1872a689554bSHai Li dlen = dsi_cmd_dma_rx(msm_host, buf, rx_byte, pkt_size); 1873a689554bSHai Li 1874a689554bSHai Li if (dlen <= 0) 1875a689554bSHai Li return 0; 1876a689554bSHai Li 1877a689554bSHai Li if (short_response) 1878a689554bSHai Li break; 1879a689554bSHai Li 1880a689554bSHai Li if (rlen <= data_byte) { 1881a689554bSHai Li diff = data_byte - rlen; 1882a689554bSHai Li end = 1; 1883a689554bSHai Li } else { 1884a689554bSHai Li diff = 0; 1885a689554bSHai Li rlen -= data_byte; 1886a689554bSHai Li } 1887a689554bSHai Li 1888a689554bSHai Li if (!end) { 1889a689554bSHai Li dlen -= 2; /* 2 crc */ 1890a689554bSHai Li dlen -= diff; 1891a689554bSHai Li buf += dlen; /* next start position */ 1892a689554bSHai Li data_byte = 14; /* NOT first read */ 1893a689554bSHai Li if (rlen < data_byte) 1894a689554bSHai Li pkt_size += rlen; 1895a689554bSHai Li else 1896a689554bSHai Li pkt_size += data_byte; 1897a689554bSHai Li DBG("buf=%p dlen=%d diff=%d", buf, dlen, diff); 1898a689554bSHai Li } 1899a689554bSHai Li } 1900a689554bSHai Li 1901a689554bSHai Li /* 1902a689554bSHai Li * For single Long read, if the requested rlen < 10, 1903a689554bSHai Li * we need to shift the start position of rx 1904a689554bSHai Li * data buffer to skip the bytes which are not 1905a689554bSHai Li * updated. 1906a689554bSHai Li */ 1907a689554bSHai Li if (pkt_size < 10 && !short_response) 1908a689554bSHai Li buf = msm_host->rx_buf + (10 - rlen); 1909a689554bSHai Li else 1910a689554bSHai Li buf = msm_host->rx_buf; 1911a689554bSHai Li 1912a689554bSHai Li cmd = buf[0]; 1913a689554bSHai Li switch (cmd) { 1914a689554bSHai Li case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: 1915a689554bSHai Li pr_err("%s: rx ACK_ERR_PACLAGE\n", __func__); 1916a689554bSHai Li ret = 0; 1917651ad3f5SHai Li break; 1918a689554bSHai Li case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: 1919a689554bSHai Li case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: 1920a689554bSHai Li ret = dsi_short_read1_resp(buf, msg); 1921a689554bSHai Li break; 1922a689554bSHai Li case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: 1923a689554bSHai Li case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: 1924a689554bSHai Li ret = dsi_short_read2_resp(buf, msg); 1925a689554bSHai Li break; 1926a689554bSHai Li case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: 1927a689554bSHai Li case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: 1928a689554bSHai Li ret = dsi_long_read_resp(buf, msg); 1929a689554bSHai Li break; 1930a689554bSHai Li default: 1931a689554bSHai Li pr_warn("%s:Invalid response cmd\n", __func__); 1932a689554bSHai Li ret = 0; 1933a689554bSHai Li } 1934a689554bSHai Li 1935a689554bSHai Li return ret; 1936a689554bSHai Li } 1937a689554bSHai Li 19384ff9d4cbSArchit Taneja void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base, 19394ff9d4cbSArchit Taneja u32 len) 1940a689554bSHai Li { 1941a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1942a689554bSHai Li 19434ff9d4cbSArchit Taneja dsi_write(msm_host, REG_DSI_DMA_BASE, dma_base); 1944a689554bSHai Li dsi_write(msm_host, REG_DSI_DMA_LEN, len); 1945a689554bSHai Li dsi_write(msm_host, REG_DSI_TRIG_DMA, 1); 1946a689554bSHai Li 1947a689554bSHai Li /* Make sure trigger happens */ 1948a689554bSHai Li wmb(); 1949a689554bSHai Li } 1950a689554bSHai Li 19519d32c498SHai Li int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, 19529d32c498SHai Li struct msm_dsi_pll *src_pll) 19539d32c498SHai Li { 19549d32c498SHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 19554bfa9748SArchit Taneja const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 19569d32c498SHai Li struct clk *byte_clk_provider, *pixel_clk_provider; 19579d32c498SHai Li int ret; 19589d32c498SHai Li 19599d32c498SHai Li ret = msm_dsi_pll_get_clk_provider(src_pll, 19609d32c498SHai Li &byte_clk_provider, &pixel_clk_provider); 19619d32c498SHai Li if (ret) { 19629d32c498SHai Li pr_info("%s: can't get provider from pll, don't set parent\n", 19639d32c498SHai Li __func__); 19649d32c498SHai Li return 0; 19659d32c498SHai Li } 19669d32c498SHai Li 19679d32c498SHai Li ret = clk_set_parent(msm_host->byte_clk_src, byte_clk_provider); 19689d32c498SHai Li if (ret) { 19699d32c498SHai Li pr_err("%s: can't set parent to byte_clk_src. ret=%d\n", 19709d32c498SHai Li __func__, ret); 19719d32c498SHai Li goto exit; 19729d32c498SHai Li } 19739d32c498SHai Li 19749d32c498SHai Li ret = clk_set_parent(msm_host->pixel_clk_src, pixel_clk_provider); 19759d32c498SHai Li if (ret) { 19769d32c498SHai Li pr_err("%s: can't set parent to pixel_clk_src. ret=%d\n", 19779d32c498SHai Li __func__, ret); 19789d32c498SHai Li goto exit; 19799d32c498SHai Li } 19809d32c498SHai Li 19814bfa9748SArchit Taneja if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { 19824bfa9748SArchit Taneja ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider); 19834bfa9748SArchit Taneja if (ret) { 19844bfa9748SArchit Taneja pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n", 19854bfa9748SArchit Taneja __func__, ret); 19864bfa9748SArchit Taneja goto exit; 19874bfa9748SArchit Taneja } 19884bfa9748SArchit Taneja 19894bfa9748SArchit Taneja ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider); 19904bfa9748SArchit Taneja if (ret) { 19914bfa9748SArchit Taneja pr_err("%s: can't set parent to esc_clk_src. ret=%d\n", 19924bfa9748SArchit Taneja __func__, ret); 19934bfa9748SArchit Taneja goto exit; 19944bfa9748SArchit Taneja } 19954bfa9748SArchit Taneja } 19964bfa9748SArchit Taneja 19979d32c498SHai Li exit: 19989d32c498SHai Li return ret; 19999d32c498SHai Li } 20009d32c498SHai Li 2001a689554bSHai Li int msm_dsi_host_enable(struct mipi_dsi_host *host) 2002a689554bSHai Li { 2003a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2004a689554bSHai Li 2005a689554bSHai Li dsi_op_mode_config(msm_host, 2006a689554bSHai Li !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), true); 2007a689554bSHai Li 2008a689554bSHai Li /* TODO: clock should be turned off for command mode, 2009a689554bSHai Li * and only turned on before MDP START. 2010a689554bSHai Li * This part of code should be enabled once mdp driver support it. 2011a689554bSHai Li */ 2012a689554bSHai Li /* if (msm_panel->mode == MSM_DSI_CMD_MODE) 2013a689554bSHai Li dsi_clk_ctrl(msm_host, 0); */ 2014a689554bSHai Li 2015a689554bSHai Li return 0; 2016a689554bSHai Li } 2017a689554bSHai Li 2018a689554bSHai Li int msm_dsi_host_disable(struct mipi_dsi_host *host) 2019a689554bSHai Li { 2020a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2021a689554bSHai Li 2022a689554bSHai Li dsi_op_mode_config(msm_host, 2023a689554bSHai Li !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), false); 2024a689554bSHai Li 2025a689554bSHai Li /* Since we have disabled INTF, the video engine won't stop so that 2026a689554bSHai Li * the cmd engine will be blocked. 2027a689554bSHai Li * Reset to disable video engine so that we can send off cmd. 2028a689554bSHai Li */ 2029a689554bSHai Li dsi_sw_reset(msm_host); 2030a689554bSHai Li 2031a689554bSHai Li return 0; 2032a689554bSHai Li } 2033a689554bSHai Li 2034a689554bSHai Li int msm_dsi_host_power_on(struct mipi_dsi_host *host) 2035a689554bSHai Li { 2036a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2037a689554bSHai Li u32 clk_pre = 0, clk_post = 0; 2038a689554bSHai Li int ret = 0; 2039a689554bSHai Li 2040a689554bSHai Li mutex_lock(&msm_host->dev_mutex); 2041a689554bSHai Li if (msm_host->power_on) { 2042a689554bSHai Li DBG("dsi host already on"); 2043a689554bSHai Li goto unlock_ret; 2044a689554bSHai Li } 2045a689554bSHai Li 2046a689554bSHai Li ret = dsi_calc_clk_rate(msm_host); 2047a689554bSHai Li if (ret) { 2048a689554bSHai Li pr_err("%s: unable to calc clk rate, %d\n", __func__, ret); 2049a689554bSHai Li goto unlock_ret; 2050a689554bSHai Li } 2051a689554bSHai Li 2052a689554bSHai Li ret = dsi_host_regulator_enable(msm_host); 2053a689554bSHai Li if (ret) { 2054a689554bSHai Li pr_err("%s:Failed to enable vregs.ret=%d\n", 2055a689554bSHai Li __func__, ret); 2056a689554bSHai Li goto unlock_ret; 2057a689554bSHai Li } 2058a689554bSHai Li 2059a689554bSHai Li ret = dsi_bus_clk_enable(msm_host); 2060a689554bSHai Li if (ret) { 2061a689554bSHai Li pr_err("%s: failed to enable bus clocks, %d\n", __func__, ret); 2062a689554bSHai Li goto fail_disable_reg; 2063a689554bSHai Li } 2064a689554bSHai Li 2065a689554bSHai Li dsi_phy_sw_reset(msm_host); 2066a689554bSHai Li ret = msm_dsi_manager_phy_enable(msm_host->id, 2067a689554bSHai Li msm_host->byte_clk_rate * 8, 20684bfa9748SArchit Taneja msm_host->esc_clk_rate, 2069a689554bSHai Li &clk_pre, &clk_post); 2070a689554bSHai Li dsi_bus_clk_disable(msm_host); 2071a689554bSHai Li if (ret) { 2072a689554bSHai Li pr_err("%s: failed to enable phy, %d\n", __func__, ret); 2073a689554bSHai Li goto fail_disable_reg; 2074a689554bSHai Li } 2075a689554bSHai Li 2076a689554bSHai Li ret = dsi_clk_ctrl(msm_host, 1); 2077a689554bSHai Li if (ret) { 2078a689554bSHai Li pr_err("%s: failed to enable clocks. ret=%d\n", __func__, ret); 2079a689554bSHai Li goto fail_disable_reg; 2080a689554bSHai Li } 2081a689554bSHai Li 2082ab8909b0SHai Li ret = pinctrl_pm_select_default_state(&msm_host->pdev->dev); 2083ab8909b0SHai Li if (ret) { 2084ab8909b0SHai Li pr_err("%s: failed to set pinctrl default state, %d\n", 2085ab8909b0SHai Li __func__, ret); 2086ab8909b0SHai Li goto fail_disable_clk; 2087ab8909b0SHai Li } 2088ab8909b0SHai Li 2089a689554bSHai Li dsi_timing_setup(msm_host); 2090a689554bSHai Li dsi_sw_reset(msm_host); 2091a689554bSHai Li dsi_ctrl_config(msm_host, true, clk_pre, clk_post); 2092a689554bSHai Li 2093a689554bSHai Li if (msm_host->disp_en_gpio) 2094a689554bSHai Li gpiod_set_value(msm_host->disp_en_gpio, 1); 2095a689554bSHai Li 2096a689554bSHai Li msm_host->power_on = true; 2097a689554bSHai Li mutex_unlock(&msm_host->dev_mutex); 2098a689554bSHai Li 2099a689554bSHai Li return 0; 2100a689554bSHai Li 2101ab8909b0SHai Li fail_disable_clk: 2102ab8909b0SHai Li dsi_clk_ctrl(msm_host, 0); 2103a689554bSHai Li fail_disable_reg: 2104a689554bSHai Li dsi_host_regulator_disable(msm_host); 2105a689554bSHai Li unlock_ret: 2106a689554bSHai Li mutex_unlock(&msm_host->dev_mutex); 2107a689554bSHai Li return ret; 2108a689554bSHai Li } 2109a689554bSHai Li 2110a689554bSHai Li int msm_dsi_host_power_off(struct mipi_dsi_host *host) 2111a689554bSHai Li { 2112a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2113a689554bSHai Li 2114a689554bSHai Li mutex_lock(&msm_host->dev_mutex); 2115a689554bSHai Li if (!msm_host->power_on) { 2116a689554bSHai Li DBG("dsi host already off"); 2117a689554bSHai Li goto unlock_ret; 2118a689554bSHai Li } 2119a689554bSHai Li 2120a689554bSHai Li dsi_ctrl_config(msm_host, false, 0, 0); 2121a689554bSHai Li 2122a689554bSHai Li if (msm_host->disp_en_gpio) 2123a689554bSHai Li gpiod_set_value(msm_host->disp_en_gpio, 0); 2124a689554bSHai Li 2125ab8909b0SHai Li pinctrl_pm_select_sleep_state(&msm_host->pdev->dev); 2126ab8909b0SHai Li 2127a689554bSHai Li msm_dsi_manager_phy_disable(msm_host->id); 2128a689554bSHai Li 2129a689554bSHai Li dsi_clk_ctrl(msm_host, 0); 2130a689554bSHai Li 2131a689554bSHai Li dsi_host_regulator_disable(msm_host); 2132a689554bSHai Li 2133a689554bSHai Li DBG("-"); 2134a689554bSHai Li 2135a689554bSHai Li msm_host->power_on = false; 2136a689554bSHai Li 2137a689554bSHai Li unlock_ret: 2138a689554bSHai Li mutex_unlock(&msm_host->dev_mutex); 2139a689554bSHai Li return 0; 2140a689554bSHai Li } 2141a689554bSHai Li 2142a689554bSHai Li int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, 2143a689554bSHai Li struct drm_display_mode *mode) 2144a689554bSHai Li { 2145a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2146a689554bSHai Li 2147a689554bSHai Li if (msm_host->mode) { 2148a689554bSHai Li drm_mode_destroy(msm_host->dev, msm_host->mode); 2149a689554bSHai Li msm_host->mode = NULL; 2150a689554bSHai Li } 2151a689554bSHai Li 2152a689554bSHai Li msm_host->mode = drm_mode_duplicate(msm_host->dev, mode); 2153a689554bSHai Li if (IS_ERR(msm_host->mode)) { 2154a689554bSHai Li pr_err("%s: cannot duplicate mode\n", __func__); 2155a689554bSHai Li return PTR_ERR(msm_host->mode); 2156a689554bSHai Li } 2157a689554bSHai Li 2158a689554bSHai Li return 0; 2159a689554bSHai Li } 2160a689554bSHai Li 2161a689554bSHai Li struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, 2162a689554bSHai Li unsigned long *panel_flags) 2163a689554bSHai Li { 2164a689554bSHai Li struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2165a689554bSHai Li struct drm_panel *panel; 2166a689554bSHai Li 2167a9ddac9cSArchit Taneja panel = of_drm_find_panel(msm_host->device_node); 2168a689554bSHai Li if (panel_flags) 2169a689554bSHai Li *panel_flags = msm_host->mode_flags; 2170a689554bSHai Li 2171a689554bSHai Li return panel; 2172a689554bSHai Li } 2173a689554bSHai Li 2174c118e290SArchit Taneja struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host) 2175c118e290SArchit Taneja { 2176c118e290SArchit Taneja struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2177c118e290SArchit Taneja 2178c118e290SArchit Taneja return of_drm_find_bridge(msm_host->device_node); 2179c118e290SArchit Taneja } 2180