2024-09-09 08:57:42 +00:00
|
|
|
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
2024-09-09 08:52:07 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
|
|
* only version 2 as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/io.h>
|
2024-09-09 08:57:42 +00:00
|
|
|
#include <linux/clk/msm-clk.h>
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
#include "mdss_dsi.h"
|
|
|
|
#include "mdss_edp.h"
|
2024-09-09 08:57:42 +00:00
|
|
|
#include "mdss_dsi_phy.h"
|
|
|
|
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CTRL_0 0x00
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CTRL_1 0x04
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CTRL_2 0x08
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CTRL_3 0x0c
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CTRL_4 0x10
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_CAL_PWR_CFG 0x18
|
|
|
|
#define MDSS_DSI_DSIPHY_LDO_CNTRL 0x1dc
|
|
|
|
#define MDSS_DSI_DSIPHY_REGULATOR_TEST 0x294
|
|
|
|
#define MDSS_DSI_DSIPHY_STRENGTH_CTRL_0 0x184
|
|
|
|
#define MDSS_DSI_DSIPHY_STRENGTH_CTRL_1 0x188
|
|
|
|
#define MDSS_DSI_DSIPHY_STRENGTH_CTRL_2 0x18c
|
|
|
|
#define MDSS_DSI_DSIPHY_TIMING_CTRL_0 0x140
|
|
|
|
#define MDSS_DSI_DSIPHY_GLBL_TEST_CTRL 0x1d4
|
|
|
|
#define MDSS_DSI_DSIPHY_CTRL_0 0x170
|
|
|
|
#define MDSS_DSI_DSIPHY_CTRL_1 0x174
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
#define SW_RESET BIT(2)
|
|
|
|
#define SW_RESET_PLL BIT(0)
|
|
|
|
#define PWRDN_B BIT(7)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* 8996 */
|
|
|
|
#define DATALANE_OFFSET_FROM_BASE_8996 0x100
|
|
|
|
#define DSIPHY_CMN_PLL_CNTRL 0x0048
|
|
|
|
#define DATALANE_SIZE_8996 0x80
|
|
|
|
|
|
|
|
#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
|
|
|
|
#define DSIPHY_CMN_CTRL_0 0x001c
|
|
|
|
#define DSIPHY_CMN_CTRL_1 0x0020
|
|
|
|
#define DSIPHY_CMN_LDO_CNTRL 0x004c
|
|
|
|
#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
|
|
|
|
#define DSIPHY_PLL_PLL_BANDGAP 0x0508
|
|
|
|
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 0x214
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 0x218
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 0x21C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 0x220
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 0x224
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 0x228
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 0x22C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 0x230
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 0x234
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 0x238
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 0x23C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 0x240
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 0x244
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 0x248
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 0x24C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 0x250
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 0x254
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 0x258
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 0x25C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 0x260
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 0x260
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 0x264
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 0x268
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 0x26C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 0x270
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 0x274
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 0x278
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 0x27C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 0x280
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 0x284
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 0x288
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 0x28C
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 0x290
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR 0x294
|
|
|
|
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 0x298
|
|
|
|
|
|
|
|
#define DSIPHY_DLN0_CFG1 0x0104
|
|
|
|
#define DSIPHY_DLN0_TIMING_CTRL_4 0x0118
|
|
|
|
#define DSIPHY_DLN0_TIMING_CTRL_5 0x011C
|
|
|
|
#define DSIPHY_DLN0_TIMING_CTRL_6 0x0120
|
|
|
|
#define DSIPHY_DLN0_TIMING_CTRL_7 0x0124
|
|
|
|
#define DSIPHY_DLN0_TIMING_CTRL_8 0x0128
|
|
|
|
|
|
|
|
#define DSIPHY_DLN1_CFG1 0x0184
|
|
|
|
#define DSIPHY_DLN1_TIMING_CTRL_4 0x0198
|
|
|
|
#define DSIPHY_DLN1_TIMING_CTRL_5 0x019C
|
|
|
|
#define DSIPHY_DLN1_TIMING_CTRL_6 0x01A0
|
|
|
|
#define DSIPHY_DLN1_TIMING_CTRL_7 0x01A4
|
|
|
|
#define DSIPHY_DLN1_TIMING_CTRL_8 0x01A8
|
|
|
|
|
|
|
|
#define DSIPHY_DLN2_CFG1 0x0204
|
|
|
|
#define DSIPHY_DLN2_TIMING_CTRL_4 0x0218
|
|
|
|
#define DSIPHY_DLN2_TIMING_CTRL_5 0x021C
|
|
|
|
#define DSIPHY_DLN2_TIMING_CTRL_6 0x0220
|
|
|
|
#define DSIPHY_DLN2_TIMING_CTRL_7 0x0224
|
|
|
|
#define DSIPHY_DLN2_TIMING_CTRL_8 0x0228
|
|
|
|
|
|
|
|
#define DSIPHY_DLN3_CFG1 0x0284
|
|
|
|
#define DSIPHY_DLN3_TIMING_CTRL_4 0x0298
|
|
|
|
#define DSIPHY_DLN3_TIMING_CTRL_5 0x029C
|
|
|
|
#define DSIPHY_DLN3_TIMING_CTRL_6 0x02A0
|
|
|
|
#define DSIPHY_DLN3_TIMING_CTRL_7 0x02A4
|
|
|
|
#define DSIPHY_DLN3_TIMING_CTRL_8 0x02A8
|
|
|
|
|
|
|
|
#define DSIPHY_CKLN_CFG1 0x0304
|
|
|
|
#define DSIPHY_CKLN_TIMING_CTRL_4 0x0318
|
|
|
|
#define DSIPHY_CKLN_TIMING_CTRL_5 0x031C
|
|
|
|
#define DSIPHY_CKLN_TIMING_CTRL_6 0x0320
|
|
|
|
#define DSIPHY_CKLN_TIMING_CTRL_7 0x0324
|
|
|
|
#define DSIPHY_CKLN_TIMING_CTRL_8 0x0328
|
|
|
|
|
|
|
|
#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
|
|
|
|
|
|
|
|
#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
|
|
|
|
(((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \
|
|
|
|
((data0) << 8) | (((addr0)/4) & 0xFF))
|
|
|
|
|
|
|
|
#define MDSS_DYN_REF_REG_W(base, offset, addr0, addr1, data0, data1) \
|
|
|
|
writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
|
|
|
|
(base) + (offset))
|
|
|
|
|
|
|
|
void mdss_dsi_dfps_config_8996(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct mdss_panel_data *pdata;
|
|
|
|
struct mdss_panel_info *pinfo;
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
int glbl_tst_cntrl =
|
|
|
|
MIPI_INP(ctrl->phy_io.base + DSIPHY_CMN_GLBL_TEST_CTRL);
|
|
|
|
|
|
|
|
pdata = &ctrl->panel_data;
|
|
|
|
if (!pdata) {
|
|
|
|
pr_err("%s: Invalid panel data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pinfo = &pdata->panel_info;
|
|
|
|
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
if (mdss_dsi_is_ctrl_clk_slave(ctrl)) {
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL0,
|
|
|
|
DSIPHY_DLN0_CFG1, DSIPHY_DLN1_CFG1,
|
|
|
|
0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL1,
|
|
|
|
DSIPHY_DLN2_CFG1, DSIPHY_DLN3_CFG1,
|
|
|
|
0x0, 0x0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL2,
|
|
|
|
DSIPHY_CKLN_CFG1, DSIPHY_DLN0_TIMING_CTRL_4,
|
|
|
|
0x0, pd->timing_8996[0]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL3,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_4,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_4,
|
|
|
|
pd->timing_8996[8],
|
|
|
|
pd->timing_8996[16]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL4,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_4,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_4,
|
|
|
|
pd->timing_8996[24],
|
|
|
|
pd->timing_8996[32]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL5,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_5,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_5,
|
|
|
|
pd->timing_8996[1],
|
|
|
|
pd->timing_8996[9]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL6,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_5,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_5,
|
|
|
|
pd->timing_8996[17],
|
|
|
|
pd->timing_8996[25]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL7,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_5,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_6,
|
|
|
|
pd->timing_8996[33],
|
|
|
|
pd->timing_8996[2]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL8,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_6,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_6,
|
|
|
|
pd->timing_8996[10],
|
|
|
|
pd->timing_8996[18]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL9,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_6,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_6,
|
|
|
|
pd->timing_8996[26],
|
|
|
|
pd->timing_8996[34]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL10,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_7,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_7,
|
|
|
|
pd->timing_8996[3],
|
|
|
|
pd->timing_8996[11]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL11,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_7,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_7,
|
|
|
|
pd->timing_8996[19],
|
|
|
|
pd->timing_8996[27]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL12,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_7,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_8,
|
|
|
|
pd->timing_8996[35],
|
|
|
|
pd->timing_8996[4]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL13,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_8,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_8,
|
|
|
|
pd->timing_8996[12],
|
|
|
|
pd->timing_8996[20]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL14,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_8,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_8,
|
|
|
|
pd->timing_8996[28],
|
|
|
|
pd->timing_8996[36]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL15,
|
|
|
|
0x0110, 0x0110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL16,
|
|
|
|
0x0110, 0x0110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL17,
|
|
|
|
0x0110, 0x0110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL18,
|
|
|
|
0x0110, 0x0110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL19,
|
|
|
|
0x0110, 0x0110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL20,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL21,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL22,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL23,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL24,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL25,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL26,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL27,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL28,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL29,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL30,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL31,
|
|
|
|
0x110, 0x110, 0, 0);
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base +
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, 0x0);
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base +
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0x0);
|
|
|
|
} else {
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL0,
|
|
|
|
DSIPHY_CMN_GLBL_TEST_CTRL,
|
|
|
|
DSIPHY_PLL_PLL_BANDGAP,
|
|
|
|
glbl_tst_cntrl | BIT(1), 0x1);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL1,
|
|
|
|
DSIPHY_PLL_RESETSM_CNTRL5,
|
|
|
|
DSIPHY_PLL_PLL_BANDGAP,
|
|
|
|
0x0D, 0x03);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL2,
|
|
|
|
DSIPHY_PLL_RESETSM_CNTRL5,
|
|
|
|
DSIPHY_CMN_PLL_CNTRL,
|
|
|
|
0x1D, 0x00);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL3,
|
|
|
|
DSIPHY_CMN_CTRL_1, DSIPHY_DLN0_CFG1,
|
|
|
|
0x20, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL4,
|
|
|
|
DSIPHY_DLN1_CFG1, DSIPHY_DLN2_CFG1,
|
|
|
|
0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL5,
|
|
|
|
DSIPHY_DLN3_CFG1, DSIPHY_CKLN_CFG1,
|
|
|
|
0, 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL6,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_4,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_4,
|
|
|
|
pd->timing_8996[0],
|
|
|
|
pd->timing_8996[8]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL7,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_4,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_4,
|
|
|
|
pd->timing_8996[16],
|
|
|
|
pd->timing_8996[24]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL8,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_4,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_5,
|
|
|
|
pd->timing_8996[32],
|
|
|
|
pd->timing_8996[1]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL9,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_5,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_5,
|
|
|
|
pd->timing_8996[9],
|
|
|
|
pd->timing_8996[17]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL10,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_5,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_5,
|
|
|
|
pd->timing_8996[25],
|
|
|
|
pd->timing_8996[33]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL11,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_6,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_6,
|
|
|
|
pd->timing_8996[2],
|
|
|
|
pd->timing_8996[10]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL12,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_6,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_6,
|
|
|
|
pd->timing_8996[18],
|
|
|
|
pd->timing_8996[26]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL13,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_6,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_7,
|
|
|
|
pd->timing_8996[34],
|
|
|
|
pd->timing_8996[3]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL14,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_7,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_7,
|
|
|
|
pd->timing_8996[11],
|
|
|
|
pd->timing_8996[19]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL15,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_7,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_7,
|
|
|
|
pd->timing_8996[27],
|
|
|
|
pd->timing_8996[35]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL16,
|
|
|
|
DSIPHY_DLN0_TIMING_CTRL_8,
|
|
|
|
DSIPHY_DLN1_TIMING_CTRL_8,
|
|
|
|
pd->timing_8996[4],
|
|
|
|
pd->timing_8996[12]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL17,
|
|
|
|
DSIPHY_DLN2_TIMING_CTRL_8,
|
|
|
|
DSIPHY_DLN3_TIMING_CTRL_8,
|
|
|
|
pd->timing_8996[20],
|
|
|
|
pd->timing_8996[28]);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL18,
|
|
|
|
DSIPHY_CKLN_TIMING_CTRL_8,
|
|
|
|
DSIPHY_CMN_CTRL_1,
|
|
|
|
pd->timing_8996[36], 0);
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL30,
|
|
|
|
DSIPHY_CMN_GLBL_TEST_CTRL,
|
|
|
|
DSIPHY_CMN_GLBL_TEST_CTRL,
|
|
|
|
((glbl_tst_cntrl) & (~BIT(2))),
|
|
|
|
((glbl_tst_cntrl) & (~BIT(2))));
|
|
|
|
MDSS_DYN_REF_REG_W(ctrl->ctrl_base,
|
|
|
|
DSI_DYNAMIC_REFRESH_PLL_CTRL31,
|
|
|
|
DSIPHY_CMN_GLBL_TEST_CTRL,
|
|
|
|
DSIPHY_CMN_GLBL_TEST_CTRL,
|
|
|
|
((glbl_tst_cntrl) & (~BIT(2))),
|
|
|
|
((glbl_tst_cntrl) & (~BIT(2))));
|
|
|
|
}
|
|
|
|
|
|
|
|
wmb(); /* make sure phy timings are updated*/
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_ctrl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
/* start phy sw reset */
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x12c, 0x0001);
|
|
|
|
udelay(1000);
|
|
|
|
wmb(); /* make sure reset */
|
|
|
|
/* end phy sw reset */
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x12c, 0x0000);
|
|
|
|
udelay(100);
|
|
|
|
wmb(); /* maek sure reset cleared */
|
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_ctrl_pdata *sctrl = NULL;
|
|
|
|
struct dsi_shared_data *sdata;
|
|
|
|
struct mdss_dsi_ctrl_pdata *octrl;
|
|
|
|
u32 reg_val = 0;
|
|
|
|
|
|
|
|
if (ctrl == NULL) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdata = ctrl->shared_data;
|
|
|
|
octrl = mdss_dsi_get_other_ctrl(ctrl);
|
|
|
|
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
|
|
|
|
if (mdss_dsi_is_ctrl_clk_master(ctrl))
|
|
|
|
sctrl = mdss_dsi_get_ctrl_clk_slave();
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For dual dsi case if we do DSI PHY sw reset,
|
|
|
|
* this will reset DSI PHY regulators also.
|
|
|
|
* Since DSI PHY regulator is shared among both
|
|
|
|
* the DSI controllers, we should not do DSI PHY
|
|
|
|
* sw reset when the other DSI controller is still
|
|
|
|
* active.
|
|
|
|
*/
|
|
|
|
mutex_lock(&sdata->phy_reg_lock);
|
|
|
|
if ((mdss_dsi_is_hw_config_dual(sdata) &&
|
|
|
|
(octrl && octrl->is_phyreg_enabled))) {
|
|
|
|
/* start phy lane and HW reset */
|
|
|
|
reg_val = MIPI_INP(ctrl->ctrl_base + 0x12c);
|
|
|
|
reg_val |= (BIT(16) | BIT(8));
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x12c, reg_val);
|
|
|
|
/* wait for 1ms as per HW design */
|
|
|
|
usleep_range(1000, 2000);
|
|
|
|
/* ensure phy lane and HW reset starts */
|
|
|
|
wmb();
|
|
|
|
/* end phy lane and HW reset */
|
|
|
|
reg_val = MIPI_INP(ctrl->ctrl_base + 0x12c);
|
|
|
|
reg_val &= ~(BIT(16) | BIT(8));
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x12c, reg_val);
|
|
|
|
/* wait for 100us as per HW design */
|
|
|
|
usleep_range(100, 200);
|
|
|
|
/* ensure phy lane and HW reset ends */
|
|
|
|
wmb();
|
|
|
|
} else {
|
|
|
|
/* start phy sw reset */
|
|
|
|
mdss_dsi_ctrl_phy_reset(ctrl);
|
|
|
|
if (sctrl)
|
|
|
|
mdss_dsi_ctrl_phy_reset(sctrl);
|
|
|
|
|
|
|
|
}
|
|
|
|
mutex_unlock(&sdata->phy_reg_lock);
|
|
|
|
|
|
|
|
if ((sdata->hw_rev == MDSS_DSI_HW_REV_103) &&
|
|
|
|
!mdss_dsi_is_hw_config_dual(sdata) &&
|
|
|
|
mdss_dsi_is_right_ctrl(ctrl)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* phy sw reset will wipe out the pll settings for PLL.
|
|
|
|
* Need to explicitly turn off PLL1 if unused to avoid
|
|
|
|
* current leakage issues.
|
|
|
|
*/
|
|
|
|
if ((mdss_dsi_is_hw_config_split(sdata) ||
|
|
|
|
mdss_dsi_is_pll_src_pll0(sdata)) &&
|
|
|
|
ctrl->vco_dummy_clk) {
|
|
|
|
pr_debug("Turn off unused PLL1 registers\n");
|
|
|
|
clk_set_rate(ctrl->vco_dummy_clk, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20)
|
|
|
|
return;
|
|
|
|
|
|
|
|
MIPI_OUTP(ctrl->phy_regulator_io.base + 0x018, 0x000);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_phy_shutdown(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
|
|
|
|
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_PLL_CLKBUFLR_EN, 0);
|
|
|
|
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_GLBL_TEST_CTRL, 0);
|
|
|
|
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, 0);
|
|
|
|
} else {
|
|
|
|
MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mdss_dsi_lp_cd_rx() -- enable LP and CD at receiving
|
|
|
|
* @ctrl: pointer to DSI controller structure
|
|
|
|
*
|
|
|
|
* LP: low power
|
|
|
|
* CD: contention detection
|
|
|
|
*/
|
|
|
|
void mdss_dsi_lp_cd_rx(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
/* Strength ctrl 1, LP Rx + CD Rxcontention detection */
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + 0x0188, pd->strength[1]);
|
|
|
|
wmb();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_28nm_phy_regulator_enable(
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
if (pd->reg_ldo_mode) {
|
|
|
|
/* Regulator ctrl 0 */
|
|
|
|
MIPI_OUTP(ctrl_pdata->phy_regulator_io.base, 0x0);
|
|
|
|
/* Regulator ctrl - CAL_PWR_CFG */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x18, pd->regulator[6]);
|
|
|
|
/* Add H/w recommended delay */
|
|
|
|
udelay(1000);
|
|
|
|
/* Regulator ctrl - TEST */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x14, pd->regulator[5]);
|
|
|
|
/* Regulator ctrl 3 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0xc, pd->regulator[3]);
|
|
|
|
/* Regulator ctrl 2 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x8, pd->regulator[2]);
|
|
|
|
/* Regulator ctrl 1 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x4, pd->regulator[1]);
|
|
|
|
/* Regulator ctrl 4 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x10, pd->regulator[4]);
|
|
|
|
/* LDO ctrl */
|
|
|
|
if ((ctrl_pdata->shared_data->hw_rev ==
|
|
|
|
MDSS_DSI_HW_REV_103_1)
|
|
|
|
|| (ctrl_pdata->shared_data->hw_rev ==
|
|
|
|
MDSS_DSI_HW_REV_104_2))
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x05);
|
|
|
|
else
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x0d);
|
|
|
|
} else {
|
|
|
|
/* Regulator ctrl 0 */
|
|
|
|
MIPI_OUTP(ctrl_pdata->phy_regulator_io.base,
|
|
|
|
0x0);
|
|
|
|
/* Regulator ctrl - CAL_PWR_CFG */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x18, pd->regulator[6]);
|
|
|
|
/* Add H/w recommended delay */
|
|
|
|
udelay(1000);
|
|
|
|
/* Regulator ctrl 1 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x4, pd->regulator[1]);
|
|
|
|
/* Regulator ctrl 2 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x8, pd->regulator[2]);
|
|
|
|
/* Regulator ctrl 3 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0xc, pd->regulator[3]);
|
|
|
|
/* Regulator ctrl 4 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_regulator_io.base)
|
|
|
|
+ 0x10, pd->regulator[4]);
|
|
|
|
/* LDO ctrl */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00);
|
|
|
|
/* Regulator ctrl 0 */
|
|
|
|
MIPI_OUTP(ctrl_pdata->phy_regulator_io.base,
|
|
|
|
pd->regulator[0]);
|
|
|
|
}
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
static void mdss_dsi_28nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
int i, off, ln, offset;
|
|
|
|
|
|
|
|
if (!ctrl_pdata) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
/* Strength ctrl 0 for 28nm PHY*/
|
|
|
|
if ((ctrl_pdata->shared_data->hw_rev <= MDSS_DSI_HW_REV_104_2) &&
|
|
|
|
(ctrl_pdata->shared_data->hw_rev != MDSS_DSI_HW_REV_103)) {
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5b);
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0184, pd->strength[0]);
|
|
|
|
/* make sure PHY strength ctrl is set */
|
|
|
|
wmb();
|
|
|
|
}
|
|
|
|
|
|
|
|
off = 0x0140; /* phy timing ctrl 0 - 11 */
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->timing[i]);
|
|
|
|
wmb();
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 4 lanes + clk lane configuration */
|
|
|
|
/* lane config n * (0 - 4) & DataPath setup */
|
|
|
|
for (ln = 0; ln < 5; ln++) {
|
|
|
|
off = (ln * 0x40);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
offset = i + (ln * 9);
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + off,
|
|
|
|
pd->lanecfg[offset]);
|
|
|
|
wmb();
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_4 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0180, 0x0a);
|
|
|
|
wmb();
|
|
|
|
|
|
|
|
/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
|
|
|
|
if (!mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) {
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01);
|
|
|
|
} else {
|
|
|
|
if (((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) ||
|
|
|
|
(ctrl_pdata->shared_data->hw_rev == MDSS_DSI_HW_REV_103_1))
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01);
|
|
|
|
else
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x00);
|
|
|
|
}
|
|
|
|
/* ensure DSIPHY_GLBL_TEST_CTRL is set */
|
|
|
|
wmb();
|
|
|
|
|
|
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
|
|
|
|
/* make sure PHY lanes are powered on */
|
|
|
|
wmb();
|
|
|
|
|
|
|
|
off = 0x01b4; /* phy BIST ctrl 0 - 5 */
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->bistctrl[i]);
|
|
|
|
wmb();
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_20nm_phy_regulator_enable(struct mdss_dsi_ctrl_pdata
|
|
|
|
*ctrl_pdata)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
void __iomem *phy_io_base;
|
|
|
|
|
|
|
|
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
phy_io_base = ctrl_pdata->phy_regulator_io.base;
|
|
|
|
|
|
|
|
if (pd->regulator_len != 7) {
|
|
|
|
pr_err("%s: wrong regulator settings\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pd->reg_ldo_mode) {
|
|
|
|
MIPI_OUTP(ctrl_pdata->phy_io.base + MDSS_DSI_DSIPHY_LDO_CNTRL,
|
|
|
|
0x1d);
|
|
|
|
} else {
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CTRL_1,
|
|
|
|
pd->regulator[1]);
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CTRL_2,
|
|
|
|
pd->regulator[2]);
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CTRL_3,
|
|
|
|
pd->regulator[3]);
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CTRL_4,
|
|
|
|
pd->regulator[4]);
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CAL_PWR_CFG,
|
|
|
|
pd->regulator[6]);
|
|
|
|
MIPI_OUTP(ctrl_pdata->phy_io.base + MDSS_DSI_DSIPHY_LDO_CNTRL,
|
|
|
|
0x00);
|
|
|
|
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_REGULATOR_CTRL_0,
|
|
|
|
pd->regulator[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_20nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
int i, off, ln, offset;
|
|
|
|
|
|
|
|
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
if (pd->strength_len != 2) {
|
|
|
|
pr_err("%s: wrong strength ctrl\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_STRENGTH_CTRL_0,
|
|
|
|
pd->strength[0]);
|
|
|
|
|
|
|
|
|
|
|
|
if (!mdss_dsi_is_hw_config_dual(ctrl_pdata->shared_data)) {
|
|
|
|
if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) ||
|
|
|
|
mdss_dsi_is_left_ctrl(ctrl_pdata) ||
|
|
|
|
(mdss_dsi_is_right_ctrl(ctrl_pdata) &&
|
|
|
|
mdss_dsi_is_pll_src_pll0(ctrl_pdata->shared_data)))
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) +
|
|
|
|
MDSS_DSI_DSIPHY_GLBL_TEST_CTRL, 0x00);
|
|
|
|
else
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) +
|
|
|
|
MDSS_DSI_DSIPHY_GLBL_TEST_CTRL, 0x01);
|
|
|
|
} else {
|
|
|
|
if (mdss_dsi_is_left_ctrl(ctrl_pdata))
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) +
|
|
|
|
MDSS_DSI_DSIPHY_GLBL_TEST_CTRL, 0x00);
|
|
|
|
else
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) +
|
|
|
|
MDSS_DSI_DSIPHY_GLBL_TEST_CTRL, 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pd->lanecfg_len != 45) {
|
|
|
|
pr_err("%s: wrong lane cfg\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 4 lanes + clk lane configuration */
|
|
|
|
/* lane config n * (0 - 4) & DataPath setup */
|
|
|
|
for (ln = 0; ln < 5; ln++) {
|
|
|
|
off = (ln * 0x40);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
offset = i + (ln * 9);
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + off,
|
|
|
|
pd->lanecfg[offset]);
|
|
|
|
wmb();
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
off = 0; /* phy timing ctrl 0 - 11 */
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) +
|
|
|
|
MDSS_DSI_DSIPHY_TIMING_CTRL_0 + off, pd->timing[i]);
|
|
|
|
wmb();
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_CTRL_1, 0);
|
|
|
|
/* make sure everything is written before enable */
|
|
|
|
wmb();
|
|
|
|
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_CTRL_0, 0x7f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_8996_pll_source_standalone(
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pll right output enabled
|
|
|
|
* bit clk select from left
|
|
|
|
*/
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x01);
|
|
|
|
data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
|
|
|
|
data &= ~BIT(2);
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_8996_pll_source_from_right(
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pll left + right output disabled
|
|
|
|
* bit clk select from right
|
|
|
|
*/
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x00);
|
|
|
|
data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
|
|
|
|
data |= BIT(2);
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
|
|
|
|
|
|
|
|
/* enable bias current for pll1 during split display case */
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_PLL_BANDGAP, 0x3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_8996_pll_source_from_left(
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pll left + right output enabled
|
|
|
|
* bit clk select from left
|
|
|
|
*/
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x03);
|
|
|
|
data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
|
|
|
|
data &= ~BIT(2);
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_8996_phy_regulator_enable(
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
int j, off, ln, cnt, ln_off;
|
|
|
|
char *ip;
|
|
|
|
void __iomem *base;
|
|
|
|
|
|
|
|
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
/* 4 lanes + clk lane configuration */
|
|
|
|
for (ln = 0; ln < 5; ln++) {
|
|
|
|
/*
|
|
|
|
* data lane offset frome base: 0x100
|
|
|
|
* data lane size: 0x80
|
|
|
|
*/
|
|
|
|
base = ctrl->phy_io.base +
|
|
|
|
DATALANE_OFFSET_FROM_BASE_8996;
|
|
|
|
base += (ln * DATALANE_SIZE_8996); /* lane base */
|
|
|
|
|
|
|
|
/* vreg ctrl, 1 * 5 */
|
|
|
|
cnt = 1;
|
|
|
|
ln_off = cnt * ln;
|
|
|
|
ip = &pd->regulator[ln_off];
|
|
|
|
off = 0x64;
|
|
|
|
for (j = 0; j < cnt; j++, off += 4)
|
|
|
|
MIPI_OUTP(base + off, *ip++);
|
|
|
|
}
|
|
|
|
|
|
|
|
wmb(); /* make sure registers committed */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
|
|
int j, off, ln, cnt, ln_off;
|
|
|
|
char *ip;
|
|
|
|
void __iomem *base;
|
|
|
|
|
|
|
|
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
|
|
|
|
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
|
|
|
|
|
|
|
|
/* clk_en */
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, 0x1);
|
|
|
|
|
|
|
|
if (pd->lanecfg_len != 20) {
|
|
|
|
pr_err("%s: wrong lane cfg\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pd->strength_len != 10) {
|
|
|
|
pr_err("%s: wrong strength ctrl\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pd->regulator_len != 5) {
|
|
|
|
pr_err("%s: wrong regulator setting\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 4 lanes + clk lane configuration */
|
|
|
|
for (ln = 0; ln < 5; ln++) {
|
|
|
|
/*
|
|
|
|
* data lane offset frome base: 0x100
|
|
|
|
* data lane size: 0x80
|
|
|
|
*/
|
|
|
|
base = ctrl->phy_io.base +
|
|
|
|
DATALANE_OFFSET_FROM_BASE_8996;
|
|
|
|
base += (ln * DATALANE_SIZE_8996); /* lane base */
|
|
|
|
|
|
|
|
/* lane cfg, 4 * 5 */
|
|
|
|
cnt = 4;
|
|
|
|
ln_off = cnt * ln;
|
|
|
|
ip = &pd->lanecfg[ln_off];
|
|
|
|
off = 0x0;
|
|
|
|
for (j = 0; j < cnt; j++) {
|
|
|
|
MIPI_OUTP(base + off, *ip++);
|
|
|
|
off += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test str */
|
|
|
|
MIPI_OUTP(base + 0x14, 0x0088); /* fixed */
|
|
|
|
|
|
|
|
/* phy timing, 8 * 5 */
|
|
|
|
cnt = 8;
|
|
|
|
ln_off = cnt * ln;
|
|
|
|
ip = &pd->timing_8996[ln_off];
|
|
|
|
off = 0x18;
|
|
|
|
for (j = 0; j < cnt; j++, off += 4)
|
|
|
|
MIPI_OUTP(base + off, *ip++);
|
|
|
|
|
|
|
|
/* strength, 2 * 5 */
|
|
|
|
cnt = 2;
|
|
|
|
ln_off = cnt * ln;
|
|
|
|
ip = &pd->strength[ln_off];
|
|
|
|
off = 0x38;
|
|
|
|
for (j = 0; j < cnt; j++, off += 4)
|
|
|
|
MIPI_OUTP(base + off, *ip++);
|
|
|
|
}
|
|
|
|
|
|
|
|
wmb(); /* make sure registers committed */
|
|
|
|
|
|
|
|
/* reset digital block */
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_CTRL_1, 0x80);
|
|
|
|
udelay(100);
|
|
|
|
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_CTRL_1, 0x00);
|
|
|
|
|
|
|
|
if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) {
|
|
|
|
if (mdss_dsi_is_left_ctrl(ctrl))
|
|
|
|
mdss_dsi_8996_pll_source_from_left(ctrl);
|
|
|
|
else
|
|
|
|
mdss_dsi_8996_pll_source_from_right(ctrl);
|
|
|
|
} else {
|
|
|
|
if (mdss_dsi_is_right_ctrl(ctrl) &&
|
|
|
|
mdss_dsi_is_pll_src_pll0(ctrl->shared_data))
|
|
|
|
mdss_dsi_8996_pll_source_from_left(ctrl);
|
|
|
|
else
|
|
|
|
mdss_dsi_8996_pll_source_standalone(ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
wmb(); /* make sure registers committed */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_phy_regulator_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
|
|
|
|
bool enable)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_ctrl_pdata *other_ctrl;
|
|
|
|
struct dsi_shared_data *sdata;
|
|
|
|
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdata = ctrl->shared_data;
|
|
|
|
other_ctrl = mdss_dsi_get_other_ctrl(ctrl);
|
|
|
|
|
|
|
|
mutex_lock(&sdata->phy_reg_lock);
|
|
|
|
if (enable) {
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
|
|
|
|
mdss_dsi_8996_phy_regulator_enable(ctrl);
|
|
|
|
} else {
|
|
|
|
switch (ctrl->shared_data->hw_rev) {
|
|
|
|
case MDSS_DSI_HW_REV_103:
|
|
|
|
mdss_dsi_20nm_phy_regulator_enable(ctrl);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* For dual dsi case, do not reconfigure dsi phy
|
|
|
|
* regulator if the other dsi controller is still
|
|
|
|
* active.
|
|
|
|
*/
|
|
|
|
if (!mdss_dsi_is_hw_config_dual(sdata) ||
|
|
|
|
(other_ctrl && (!other_ctrl->is_phyreg_enabled
|
|
|
|
|| other_ctrl->mmss_clamp)))
|
|
|
|
mdss_dsi_28nm_phy_regulator_enable(ctrl);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctrl->is_phyreg_enabled = 1;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* In split-dsi/dual-dsi configuration, the dsi phy regulator
|
|
|
|
* should be turned off only when both the DSI devices are
|
|
|
|
* going to be turned off since it is shared.
|
|
|
|
*/
|
|
|
|
if (mdss_dsi_is_hw_config_split(ctrl->shared_data) ||
|
|
|
|
mdss_dsi_is_hw_config_dual(ctrl->shared_data)) {
|
|
|
|
if (other_ctrl && !other_ctrl->is_phyreg_enabled)
|
|
|
|
mdss_dsi_phy_regulator_disable(ctrl);
|
|
|
|
} else {
|
|
|
|
mdss_dsi_phy_regulator_disable(ctrl);
|
|
|
|
}
|
|
|
|
ctrl->is_phyreg_enabled = 0;
|
|
|
|
}
|
|
|
|
mutex_unlock(&sdata->phy_reg_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_dsi_phy_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_ctrl_pdata *other_ctrl;
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enable) {
|
|
|
|
|
|
|
|
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
|
|
|
|
mdss_dsi_8996_phy_config(ctrl);
|
|
|
|
} else {
|
|
|
|
switch (ctrl->shared_data->hw_rev) {
|
|
|
|
case MDSS_DSI_HW_REV_103:
|
|
|
|
mdss_dsi_20nm_phy_config(ctrl);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mdss_dsi_28nm_phy_config(ctrl);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* In split-dsi configuration, the phy should be disabled for
|
|
|
|
* the first controller only when the second controller is
|
|
|
|
* disabled. This is true regardless of whether broadcast
|
|
|
|
* mode is enabled.
|
|
|
|
*/
|
|
|
|
if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) {
|
|
|
|
other_ctrl = mdss_dsi_get_other_ctrl(ctrl);
|
|
|
|
if (mdss_dsi_is_right_ctrl(ctrl) && other_ctrl) {
|
|
|
|
mdss_dsi_phy_shutdown(other_ctrl);
|
|
|
|
mdss_dsi_phy_shutdown(ctrl);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mdss_dsi_phy_shutdown(ctrl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
if (ctrl == NULL) {
|
|
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mdss_dsi_phy_ctrl(ctrl, false);
|
|
|
|
mdss_dsi_phy_regulator_ctrl(ctrl, false);
|
|
|
|
/*
|
|
|
|
* Wait for the registers writes to complete in order to
|
|
|
|
* ensure that the phy is completely disabled
|
|
|
|
*/
|
|
|
|
wmb();
|
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
mdss_dsi_phy_regulator_ctrl(ctrl, true);
|
|
|
|
mdss_dsi_phy_ctrl(ctrl, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_dsi_core_clk_deinit(struct device *dev, struct dsi_shared_data *sdata)
|
|
|
|
{
|
|
|
|
if (sdata->mmss_misc_ahb_clk)
|
|
|
|
devm_clk_put(dev, sdata->mmss_misc_ahb_clk);
|
|
|
|
if (sdata->ext_pixel1_clk)
|
|
|
|
devm_clk_put(dev, sdata->ext_pixel1_clk);
|
|
|
|
if (sdata->ext_byte1_clk)
|
|
|
|
devm_clk_put(dev, sdata->ext_byte1_clk);
|
|
|
|
if (sdata->ext_pixel0_clk)
|
|
|
|
devm_clk_put(dev, sdata->ext_pixel0_clk);
|
|
|
|
if (sdata->ext_byte0_clk)
|
|
|
|
devm_clk_put(dev, sdata->ext_byte0_clk);
|
|
|
|
if (sdata->axi_clk)
|
|
|
|
devm_clk_put(dev, sdata->axi_clk);
|
|
|
|
if (sdata->ahb_clk)
|
|
|
|
devm_clk_put(dev, sdata->ahb_clk);
|
|
|
|
if (sdata->mdp_core_clk)
|
|
|
|
devm_clk_put(dev, sdata->mdp_core_clk);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata)
|
|
|
|
{
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
|
|
|
struct mdss_panel_info *pinfo = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!pdata) {
|
|
|
|
pr_err("%s: invalid panel data\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
|
|
panel_data);
|
|
|
|
pinfo = &pdata->panel_info;
|
|
|
|
|
|
|
|
if (!ctrl_pdata || !pinfo) {
|
|
|
|
pr_err("%s: invalid ctrl data\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Re-calculate frame rate before clk config */
|
|
|
|
pinfo->mipi.frame_rate = mdss_panel_calc_frame_rate(pinfo);
|
|
|
|
pr_debug("%s: new frame rate %d\n", __func__, pinfo->mipi.frame_rate);
|
|
|
|
|
|
|
|
rc = mdss_dsi_clk_div_config(&pdata->panel_info,
|
|
|
|
pdata->panel_info.mipi.frame_rate);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: unable to initialize the clk dividers\n",
|
|
|
|
__func__);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
ctrl_pdata->refresh_clk_rate = false;
|
|
|
|
ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate;
|
|
|
|
ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8;
|
|
|
|
pr_debug("%s ctrl_pdata->byte_clk_rate=%d ctrl_pdata->pclk_rate=%d\n",
|
|
|
|
__func__, ctrl_pdata->byte_clk_rate, ctrl_pdata->pclk_rate);
|
|
|
|
|
|
|
|
rc = mdss_dsi_clk_set_link_rate(ctrl_pdata->dsi_clk_handle,
|
|
|
|
MDSS_DSI_LINK_BYTE_CLK, ctrl_pdata->byte_clk_rate,
|
|
|
|
MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = mdss_dsi_clk_set_link_rate(ctrl_pdata->dsi_clk_handle,
|
|
|
|
MDSS_DSI_LINK_PIX_CLK, ctrl_pdata->pclk_rate,
|
|
|
|
MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* phy panel timing calaculation */
|
|
|
|
rc = mdss_dsi_phy_calc_timing_param(pinfo,
|
|
|
|
ctrl_pdata->shared_data->phy_rev, pinfo->mipi.frame_rate);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: unable to calculate phy timings\n", __func__);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_dsi_core_clk_init(struct platform_device *pdev,
|
|
|
|
struct dsi_shared_data *sdata)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
|
|
|
struct device *dev = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!pdev) {
|
|
|
|
pr_err("%s: Invalid pdev\n", __func__);
|
2024-09-09 08:57:42 +00:00
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dev = &pdev->dev;
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
/* Mandatory Clocks */
|
|
|
|
sdata->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
|
|
|
|
if (IS_ERR(sdata->mdp_core_clk)) {
|
|
|
|
rc = PTR_ERR(sdata->mdp_core_clk);
|
|
|
|
pr_err("%s: Unable to get mdp core clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdata->ahb_clk = devm_clk_get(dev, "iface_clk");
|
|
|
|
if (IS_ERR(sdata->ahb_clk)) {
|
|
|
|
rc = PTR_ERR(sdata->ahb_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
pr_err("%s: Unable to get mdss ahb clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
2024-09-09 08:57:42 +00:00
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->axi_clk = devm_clk_get(dev, "bus_clk");
|
|
|
|
if (IS_ERR(sdata->axi_clk)) {
|
|
|
|
rc = PTR_ERR(sdata->axi_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
pr_err("%s: Unable to get axi bus clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
2024-09-09 08:57:42 +00:00
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* Optional Clocks */
|
|
|
|
sdata->ext_byte0_clk = devm_clk_get(dev, "ext_byte0_clk");
|
|
|
|
if (IS_ERR(sdata->ext_byte0_clk)) {
|
|
|
|
pr_debug("%s: unable to get byte0 clk rcg. rc=%d\n",
|
2024-09-09 08:52:07 +00:00
|
|
|
__func__, rc);
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->ext_byte0_clk = NULL;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->ext_pixel0_clk = devm_clk_get(dev, "ext_pixel0_clk");
|
|
|
|
if (IS_ERR(sdata->ext_pixel0_clk)) {
|
|
|
|
pr_debug("%s: unable to get pixel0 clk rcg. rc=%d\n",
|
2024-09-09 08:52:07 +00:00
|
|
|
__func__, rc);
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->ext_pixel0_clk = NULL;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->ext_byte1_clk = devm_clk_get(dev, "ext_byte1_clk");
|
|
|
|
if (IS_ERR(sdata->ext_byte1_clk)) {
|
|
|
|
pr_debug("%s: unable to get byte1 clk rcg. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
sdata->ext_byte1_clk = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdata->ext_pixel1_clk = devm_clk_get(dev, "ext_pixel1_clk");
|
|
|
|
if (IS_ERR(sdata->ext_pixel1_clk)) {
|
|
|
|
pr_debug("%s: unable to get pixel1 clk rcg. rc=%d\n",
|
2024-09-09 08:52:07 +00:00
|
|
|
__func__, rc);
|
2024-09-09 08:57:42 +00:00
|
|
|
sdata->ext_pixel1_clk = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdata->mmss_misc_ahb_clk = devm_clk_get(dev, "core_mmss_clk");
|
|
|
|
if (IS_ERR(sdata->mmss_misc_ahb_clk)) {
|
|
|
|
sdata->mmss_misc_ahb_clk = NULL;
|
|
|
|
pr_debug("%s: Unable to get mmss misc ahb clk\n",
|
|
|
|
__func__);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
error:
|
2024-09-09 08:52:07 +00:00
|
|
|
if (rc)
|
2024-09-09 08:57:42 +00:00
|
|
|
mdss_dsi_core_clk_deinit(dev, sdata);
|
2024-09-09 08:52:07 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
void mdss_dsi_link_clk_deinit(struct device *dev,
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
if (ctrl->vco_dummy_clk)
|
|
|
|
devm_clk_put(dev, ctrl->vco_dummy_clk);
|
|
|
|
if (ctrl->pixel_clk_rcg)
|
|
|
|
devm_clk_put(dev, ctrl->pixel_clk_rcg);
|
|
|
|
if (ctrl->byte_clk_rcg)
|
|
|
|
devm_clk_put(dev, ctrl->byte_clk_rcg);
|
|
|
|
if (ctrl->byte_clk)
|
|
|
|
devm_clk_put(dev, ctrl->byte_clk);
|
|
|
|
if (ctrl->esc_clk)
|
|
|
|
devm_clk_put(dev, ctrl->esc_clk);
|
|
|
|
if (ctrl->pixel_clk)
|
|
|
|
devm_clk_put(dev, ctrl->pixel_clk);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_dsi_link_clk_init(struct platform_device *pdev,
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct device *dev = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!pdev) {
|
|
|
|
pr_err("%s: Invalid pdev\n", __func__);
|
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
dev = &pdev->dev;
|
|
|
|
|
|
|
|
/* Mandatory Clocks */
|
|
|
|
ctrl->byte_clk = devm_clk_get(dev, "byte_clk");
|
|
|
|
if (IS_ERR(ctrl->byte_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->byte_clk);
|
|
|
|
pr_err("%s: can't find dsi_byte_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->byte_clk = NULL;
|
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->pixel_clk = devm_clk_get(dev, "pixel_clk");
|
|
|
|
if (IS_ERR(ctrl->pixel_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->pixel_clk);
|
|
|
|
pr_err("%s: can't find dsi_pixel_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->pixel_clk = NULL;
|
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
ctrl->esc_clk = devm_clk_get(dev, "core_clk");
|
|
|
|
if (IS_ERR(ctrl->esc_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->esc_clk);
|
|
|
|
pr_err("%s: can't find dsi_esc_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->esc_clk = NULL;
|
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* Optional Clocks */
|
|
|
|
ctrl->byte_clk_rcg = devm_clk_get(dev, "byte_clk_rcg");
|
|
|
|
if (IS_ERR(ctrl->byte_clk_rcg)) {
|
|
|
|
pr_debug("%s: can't find byte clk rcg. rc=%d\n", __func__, rc);
|
|
|
|
ctrl->byte_clk_rcg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg");
|
|
|
|
if (IS_ERR(ctrl->pixel_clk_rcg)) {
|
|
|
|
pr_debug("%s: can't find pixel clk rcg. rc=%d\n", __func__, rc);
|
|
|
|
ctrl->pixel_clk_rcg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->vco_dummy_clk = devm_clk_get(dev, "pll_vco_dummy_clk");
|
|
|
|
if (IS_ERR(ctrl->vco_dummy_clk)) {
|
|
|
|
pr_debug("%s: can't find vco dummy clk. rc=%d\n", __func__, rc);
|
|
|
|
ctrl->vco_dummy_clk = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (rc)
|
|
|
|
mdss_dsi_link_clk_deinit(dev, ctrl);
|
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
void mdss_dsi_shadow_clk_deinit(struct device *dev,
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
if (ctrl->mux_byte_clk)
|
|
|
|
devm_clk_put(dev, ctrl->mux_byte_clk);
|
|
|
|
if (ctrl->mux_pixel_clk)
|
|
|
|
devm_clk_put(dev, ctrl->mux_pixel_clk);
|
|
|
|
if (ctrl->pll_byte_clk)
|
|
|
|
devm_clk_put(dev, ctrl->pll_byte_clk);
|
|
|
|
if (ctrl->pll_pixel_clk)
|
|
|
|
devm_clk_put(dev, ctrl->pll_pixel_clk);
|
|
|
|
if (ctrl->shadow_byte_clk)
|
|
|
|
devm_clk_put(dev, ctrl->shadow_byte_clk);
|
|
|
|
if (ctrl->shadow_pixel_clk)
|
|
|
|
devm_clk_put(dev, ctrl->shadow_pixel_clk);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_dsi_shadow_clk_init(struct platform_device *pdev,
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl)
|
|
|
|
{
|
|
|
|
struct device *dev = NULL;
|
2024-09-09 08:52:07 +00:00
|
|
|
int rc = 0;
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!pdev) {
|
|
|
|
pr_err("%s: Invalid pdev\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = &pdev->dev;
|
|
|
|
ctrl->mux_byte_clk = devm_clk_get(dev, "pll_byte_clk_mux");
|
|
|
|
if (IS_ERR(ctrl->mux_byte_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->mux_byte_clk);
|
|
|
|
pr_err("%s: can't find mux_byte_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->mux_byte_clk = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->mux_pixel_clk = devm_clk_get(dev, "pll_pixel_clk_mux");
|
|
|
|
if (IS_ERR(ctrl->mux_pixel_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->mux_pixel_clk);
|
|
|
|
pr_err("%s: can't find mdss_mux_pixel_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->mux_pixel_clk = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->pll_byte_clk = devm_clk_get(dev, "pll_byte_clk_src");
|
|
|
|
if (IS_ERR(ctrl->pll_byte_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->pll_byte_clk);
|
|
|
|
pr_err("%s: can't find pll_byte_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->pll_byte_clk = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->pll_pixel_clk = devm_clk_get(dev, "pll_pixel_clk_src");
|
|
|
|
if (IS_ERR(ctrl->pll_pixel_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->pll_pixel_clk);
|
|
|
|
pr_err("%s: can't find pll_pixel_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->pll_pixel_clk = NULL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl->shadow_byte_clk = devm_clk_get(dev, "pll_shadow_byte_clk_src");
|
|
|
|
if (IS_ERR(ctrl->shadow_byte_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->shadow_byte_clk);
|
|
|
|
pr_err("%s: can't find shadow_byte_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->shadow_byte_clk = NULL;
|
2024-09-09 08:52:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->shadow_pixel_clk = devm_clk_get(dev, "pll_shadow_pixel_clk_src");
|
|
|
|
if (IS_ERR(ctrl->shadow_pixel_clk)) {
|
|
|
|
rc = PTR_ERR(ctrl->shadow_pixel_clk);
|
|
|
|
pr_err("%s: can't find shadow_pixel_clk. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
ctrl->shadow_pixel_clk = NULL;
|
2024-09-09 08:52:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
2024-09-09 08:57:42 +00:00
|
|
|
if (rc)
|
|
|
|
mdss_dsi_shadow_clk_deinit(dev, ctrl);
|
2024-09-09 08:52:07 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
bool is_diff_frame_rate(struct mdss_panel_info *panel_info,
|
|
|
|
u32 frame_rate)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
if (panel_info->dynamic_fps && panel_info->current_fps)
|
|
|
|
return (frame_rate != panel_info->current_fps);
|
|
|
|
else
|
|
|
|
return (frame_rate != panel_info->mipi.frame_rate);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
|
|
|
|
int frame_rate)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
struct mdss_panel_data *pdata = container_of(panel_info,
|
|
|
|
struct mdss_panel_data, panel_info);
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata,
|
|
|
|
struct mdss_dsi_ctrl_pdata, panel_data);
|
|
|
|
u64 h_period, v_period, clk_rate;
|
|
|
|
u32 dsi_pclk_rate;
|
|
|
|
u8 lanes = 0, bpp;
|
|
|
|
|
|
|
|
if (panel_info->mipi.data_lane3)
|
|
|
|
lanes += 1;
|
|
|
|
if (panel_info->mipi.data_lane2)
|
|
|
|
lanes += 1;
|
|
|
|
if (panel_info->mipi.data_lane1)
|
|
|
|
lanes += 1;
|
|
|
|
if (panel_info->mipi.data_lane0)
|
|
|
|
lanes += 1;
|
|
|
|
|
|
|
|
switch (panel_info->mipi.dst_format) {
|
|
|
|
case DSI_CMD_DST_FORMAT_RGB888:
|
|
|
|
case DSI_VIDEO_DST_FORMAT_RGB888:
|
|
|
|
case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE:
|
|
|
|
bpp = 3;
|
|
|
|
break;
|
|
|
|
case DSI_CMD_DST_FORMAT_RGB565:
|
|
|
|
case DSI_VIDEO_DST_FORMAT_RGB565:
|
|
|
|
bpp = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bpp = 3; /* Default format set to RGB888 */
|
|
|
|
break;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
h_period = mdss_panel_get_htotal(panel_info, true);
|
|
|
|
v_period = mdss_panel_get_vtotal(panel_info);
|
|
|
|
|
|
|
|
if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info,
|
|
|
|
frame_rate) || (!panel_info->clk_rate)) {
|
|
|
|
if (lanes > 0) {
|
|
|
|
panel_info->clk_rate = h_period * v_period * frame_rate
|
|
|
|
* bpp * 8;
|
|
|
|
do_div(panel_info->clk_rate, lanes);
|
|
|
|
} else {
|
|
|
|
pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
|
|
|
|
panel_info->clk_rate =
|
|
|
|
h_period * v_period * frame_rate * bpp * 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (panel_info->clk_rate == 0)
|
|
|
|
panel_info->clk_rate = 454000000;
|
|
|
|
|
|
|
|
clk_rate = panel_info->clk_rate;
|
|
|
|
do_div(clk_rate, 8 * bpp);
|
|
|
|
dsi_pclk_rate = (u32) clk_rate * lanes;
|
|
|
|
|
|
|
|
if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
|
|
|
|
dsi_pclk_rate = 35000000;
|
|
|
|
panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate;
|
|
|
|
|
|
|
|
return 0;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/**
|
|
|
|
* mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode
|
|
|
|
* @ctrl: pointer to DSI controller structure
|
|
|
|
* @enable: 1 to enter ULPS, 0 to exit ULPS
|
|
|
|
*
|
|
|
|
* This function executes the necessary programming sequence to enter/exit
|
|
|
|
* DSI Ultra-Low Power State (ULPS). This function assumes that the link and
|
|
|
|
* core clocks are already on.
|
|
|
|
*/
|
|
|
|
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
|
|
|
|
int enable)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int ret = 0;
|
|
|
|
struct mdss_panel_data *pdata = NULL;
|
|
|
|
struct mdss_panel_info *pinfo;
|
|
|
|
struct mipi_panel_info *mipi;
|
|
|
|
u32 lane_status = 0;
|
|
|
|
u32 active_lanes = 0;
|
|
|
|
|
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: invalid input\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
pdata = &ctrl->panel_data;
|
|
|
|
if (!pdata) {
|
|
|
|
pr_err("%s: Invalid panel data\n", __func__);
|
|
|
|
return -EINVAL;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
pinfo = &pdata->panel_info;
|
|
|
|
mipi = &pinfo->mipi;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!mdss_dsi_ulps_feature_enabled(pdata) &&
|
|
|
|
!pinfo->ulps_suspend_enabled) {
|
|
|
|
pr_debug("%s: ULPS feature is not enabled\n", __func__);
|
|
|
|
return 0;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/*
|
|
|
|
* No need to enter ULPS when transitioning from splash screen to
|
|
|
|
* boot animation since it is expected that the clocks would be turned
|
|
|
|
* right back on.
|
|
|
|
*/
|
|
|
|
if (pinfo->cont_splash_enabled) {
|
|
|
|
pr_debug("%s: skip ULPS config with splash screen enabled\n",
|
|
|
|
__func__);
|
|
|
|
return 0;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* clock lane will always be programmed for ulps */
|
|
|
|
active_lanes = BIT(4);
|
|
|
|
/*
|
|
|
|
* make a note of all active data lanes for which ulps entry/exit
|
|
|
|
* is needed
|
|
|
|
*/
|
|
|
|
if (mipi->data_lane0)
|
|
|
|
active_lanes |= BIT(0);
|
|
|
|
if (mipi->data_lane1)
|
|
|
|
active_lanes |= BIT(1);
|
|
|
|
if (mipi->data_lane2)
|
|
|
|
active_lanes |= BIT(2);
|
|
|
|
if (mipi->data_lane3)
|
|
|
|
active_lanes |= BIT(3);
|
|
|
|
|
|
|
|
pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n",
|
|
|
|
__func__, (enable ? "on" : "off"), ctrl->ndx,
|
|
|
|
active_lanes);
|
|
|
|
|
|
|
|
if (enable && !ctrl->ulps) {
|
|
|
|
/*
|
|
|
|
* ULPS Entry Request.
|
|
|
|
* Wait for a short duration to ensure that the lanes
|
|
|
|
* enter ULP state.
|
|
|
|
*/
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes);
|
|
|
|
usleep_range(100, 100);
|
|
|
|
|
|
|
|
/* Check to make sure that all active data lanes are in ULPS */
|
|
|
|
lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8);
|
|
|
|
if (lane_status & (active_lanes << 8)) {
|
|
|
|
pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n",
|
|
|
|
__func__, ctrl->ndx, lane_status);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->ulps = true;
|
|
|
|
} else if (!enable && ctrl->ulps) {
|
|
|
|
/*
|
|
|
|
* Clear out any phy errors prior to exiting ULPS
|
|
|
|
* This fixes certain instances where phy does not exit
|
|
|
|
* ULPS cleanly. Also, do not print error during such cases.
|
|
|
|
*/
|
|
|
|
mdss_dsi_dln0_phy_err(ctrl, false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ULPS Exit Request
|
|
|
|
* Hardware requirement is to wait for at least 1ms
|
|
|
|
*/
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 8);
|
|
|
|
usleep_range(1000, 1000);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sometimes when exiting ULPS, it is possible that some DSI
|
|
|
|
* lanes are not in the stop state which could lead to DSI
|
|
|
|
* commands not going through. To avoid this, force the lanes
|
|
|
|
* to be in stop state.
|
|
|
|
*/
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 16);
|
|
|
|
|
|
|
|
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for a short duration before enabling
|
|
|
|
* data transmission
|
|
|
|
*/
|
|
|
|
usleep_range(100, 100);
|
|
|
|
|
|
|
|
lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8);
|
|
|
|
ctrl->ulps = false;
|
|
|
|
} else {
|
|
|
|
pr_debug("%s: No change requested: %s -> %s\n", __func__,
|
|
|
|
ctrl->ulps ? "enabled" : "disabled",
|
|
|
|
enable ? "enabled" : "disabled");
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
|
|
|
|
lane_status, enable ? "enabled" : "disabled");
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
error:
|
|
|
|
return ret;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/**
|
|
|
|
* mdss_dsi_clamp_ctrl() - Program DSI clamps for supporting power collapse
|
|
|
|
* @ctrl: pointer to DSI controller structure
|
|
|
|
* @enable: 1 to enable clamps, 0 to disable clamps
|
|
|
|
*
|
|
|
|
* For idle-screen usecases with command mode panels, MDSS can be power
|
|
|
|
* collapsed. However, DSI phy needs to remain on. To avoid any mismatch
|
|
|
|
* between the DSI controller state, DSI phy needs to be clamped before
|
|
|
|
* power collapsing. This function executes the required programming
|
|
|
|
* sequence to configure these DSI clamps. This function should only be called
|
|
|
|
* when the DSI link clocks are disabled.
|
|
|
|
*/
|
|
|
|
static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
struct mipi_panel_info *mipi = NULL;
|
|
|
|
u32 clamp_reg, regval = 0;
|
|
|
|
u32 clamp_reg_off, phyrst_reg_off;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: invalid input\n", __func__);
|
|
|
|
return -EINVAL;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!ctrl->mmss_misc_io.base) {
|
|
|
|
pr_err("%s: mmss_misc_io not mapped\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
clamp_reg_off = ctrl->shared_data->ulps_clamp_ctrl_off;
|
|
|
|
phyrst_reg_off = ctrl->shared_data->ulps_phyrst_ctrl_off;
|
|
|
|
mipi = &ctrl->panel_data.panel_info.mipi;
|
|
|
|
|
|
|
|
/* clock lane will always be clamped */
|
|
|
|
clamp_reg = BIT(9);
|
|
|
|
if (ctrl->ulps)
|
|
|
|
clamp_reg |= BIT(8);
|
|
|
|
/* make a note of all active data lanes which need to be clamped */
|
|
|
|
if (mipi->data_lane0) {
|
|
|
|
clamp_reg |= BIT(7);
|
|
|
|
if (ctrl->ulps)
|
|
|
|
clamp_reg |= BIT(6);
|
|
|
|
}
|
|
|
|
if (mipi->data_lane1) {
|
|
|
|
clamp_reg |= BIT(5);
|
|
|
|
if (ctrl->ulps)
|
|
|
|
clamp_reg |= BIT(4);
|
|
|
|
}
|
|
|
|
if (mipi->data_lane2) {
|
|
|
|
clamp_reg |= BIT(3);
|
|
|
|
if (ctrl->ulps)
|
|
|
|
clamp_reg |= BIT(2);
|
|
|
|
}
|
|
|
|
if (mipi->data_lane3) {
|
|
|
|
clamp_reg |= BIT(1);
|
|
|
|
if (ctrl->ulps)
|
|
|
|
clamp_reg |= BIT(0);
|
|
|
|
}
|
|
|
|
pr_debug("%s: called for ctrl%d, enable=%d, clamp_reg=0x%08x\n",
|
|
|
|
__func__, ctrl->ndx, enable, clamp_reg);
|
|
|
|
if (enable && !ctrl->mmss_clamp) {
|
|
|
|
regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off);
|
|
|
|
/* Enable MMSS DSI Clamps */
|
|
|
|
if (ctrl->ndx == DSI_CTRL_0) {
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval | clamp_reg);
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval | (clamp_reg | BIT(15)));
|
|
|
|
} else if (ctrl->ndx == DSI_CTRL_1) {
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval | (clamp_reg << 16));
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval | ((clamp_reg << 16) | BIT(31)));
|
|
|
|
}
|
|
|
|
/* update clamp ctrl before setting phy reset disable */
|
2024-09-09 08:52:07 +00:00
|
|
|
wmb();
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This register write ensures that DSI PHY will not be
|
|
|
|
* reset when mdss ahb clock reset is asserted while coming
|
|
|
|
* out of power collapse
|
|
|
|
*/
|
|
|
|
if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev,
|
|
|
|
MDSS_DSI_HW_REV_104) &&
|
|
|
|
(MDSS_GET_STEP(ctrl->shared_data->hw_rev) !=
|
|
|
|
MDSS_DSI_HW_REV_STEP_2)) {
|
|
|
|
|
|
|
|
regval = MIPI_INP(ctrl->mmss_misc_io.base +
|
|
|
|
clamp_reg_off);
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval | BIT(30));
|
|
|
|
} else {
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off,
|
|
|
|
0x1);
|
|
|
|
}
|
|
|
|
/* make sure that clamp ctrl is updated before disable call */
|
2024-09-09 08:52:07 +00:00
|
|
|
wmb();
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->mmss_clamp = true;
|
|
|
|
} else if (!enable && ctrl->mmss_clamp) {
|
|
|
|
if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev,
|
|
|
|
MDSS_DSI_HW_REV_104) &&
|
|
|
|
(MDSS_GET_STEP(ctrl->shared_data->hw_rev) !=
|
|
|
|
MDSS_DSI_HW_REV_STEP_2)) {
|
|
|
|
|
|
|
|
regval = MIPI_INP(ctrl->mmss_misc_io.base +
|
|
|
|
clamp_reg_off);
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval & ~BIT(30));
|
|
|
|
} else {
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off,
|
|
|
|
0x0);
|
|
|
|
}
|
|
|
|
/* update clamp ctrl before unsetting phy reset disable */
|
2024-09-09 08:52:07 +00:00
|
|
|
wmb();
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off);
|
|
|
|
/* Disable MMSS DSI Clamps */
|
|
|
|
if (ctrl->ndx == DSI_CTRL_0)
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval & ~(clamp_reg | BIT(15)));
|
|
|
|
else if (ctrl->ndx == DSI_CTRL_1)
|
|
|
|
MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
|
|
|
|
regval & ~((clamp_reg << 16) | BIT(31)));
|
|
|
|
/* make sure that clamp ctrl is updated before enable call */
|
2024-09-09 08:52:07 +00:00
|
|
|
wmb();
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->mmss_clamp = false;
|
|
|
|
} else {
|
|
|
|
pr_debug("%s: No change requested: %s -> %s\n", __func__,
|
|
|
|
ctrl->mmss_clamp ? "enabled" : "disabled",
|
|
|
|
enable ? "enabled" : "disabled");
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
return 0;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
DEFINE_MUTEX(dsi_clk_mutex);
|
|
|
|
|
|
|
|
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
|
|
|
|
enum mdss_dsi_clk_type clk_type, enum mdss_dsi_clk_state clk_state)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
|
|
|
|
int i;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid arg\n", __func__);
|
|
|
|
return -EINVAL;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
mutex_lock(&dsi_clk_mutex);
|
|
|
|
/*
|
|
|
|
* In sync_wait_broadcast mode, we need to enable clocks
|
|
|
|
* for the other controller as well when enabling clocks
|
|
|
|
* for the trigger controller.
|
|
|
|
*
|
|
|
|
* If sync wait_broadcase mode is not enabled, but if split display
|
|
|
|
* mode is enabled where both DSI controller's branch clocks are
|
|
|
|
* sourced out of a single PLL, then we need to ensure that the
|
|
|
|
* controller associated with that PLL also has it's clocks turned
|
|
|
|
* on. This is required to make sure that if that controller's PLL/PHY
|
|
|
|
* are clamped then they can be removed.
|
|
|
|
*/
|
|
|
|
if (mdss_dsi_sync_wait_trigger(ctrl)) {
|
|
|
|
mctrl = mdss_dsi_get_other_ctrl(ctrl);
|
|
|
|
if (!mctrl)
|
|
|
|
pr_warn("%s: Unable to get other control\n", __func__);
|
|
|
|
} else if (mdss_dsi_is_ctrl_clk_slave(ctrl)) {
|
|
|
|
mctrl = mdss_dsi_get_ctrl_clk_master();
|
|
|
|
if (!mctrl)
|
|
|
|
pr_warn("%s: Unable to get clk master control\n",
|
|
|
|
__func__);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/*
|
|
|
|
* When DSI is used in split mode, the link clock for master controller
|
|
|
|
* has to be turned on first before the link clock for slave can be
|
|
|
|
* turned on. In case the current controller is a slave, an ON vote is
|
|
|
|
* cast for master before changing the state of the slave clock. After
|
|
|
|
* the state change for slave, the ON votes will be removed depending on
|
|
|
|
* the new state.
|
|
|
|
*/
|
|
|
|
pr_debug("%s: DSI_%d: clk = %d, state = %d, caller = %pS, mctrl=%d\n",
|
|
|
|
__func__, ctrl->ndx, clk_type, clk_state,
|
|
|
|
__builtin_return_address(0), mctrl ? 1 : 0);
|
|
|
|
if (mctrl && (clk_type & MDSS_DSI_LINK_CLK)) {
|
|
|
|
rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle,
|
|
|
|
MDSS_DSI_ALL_CLKS,
|
|
|
|
MDSS_DSI_CLK_ON);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed to turn on mctrl clocks, rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
ctrl->m_vote_cnt++;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (mctrl && (clk_type & MDSS_DSI_LINK_CLK) &&
|
|
|
|
clk_state != MDSS_DSI_CLK_ON) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In case of split dsi, an ON vote is cast for all state change
|
|
|
|
* requests. If the current state is ON, then the vote would not
|
|
|
|
* be released.
|
|
|
|
*
|
|
|
|
* If the current state is ECG, there is one possible way to
|
|
|
|
* transition in to this state, which is ON -> ECG. In this case
|
|
|
|
* two votes will be removed because one was cast at ON and
|
|
|
|
* other when entering ECG.
|
|
|
|
*
|
|
|
|
* If the current state is OFF, it could have been due to two
|
|
|
|
* possible transitions in to OFF state.
|
|
|
|
* 1. ON -> OFF: In this case two votes were cast by the
|
|
|
|
* slave controller, one during ON (which is not
|
|
|
|
* removed) and one during OFF. So we need to remove two
|
|
|
|
* votes.
|
|
|
|
* 2. ECG -> OFF: In this case there is only one vote
|
|
|
|
* for ON, since the previous ECG state must have
|
|
|
|
* removed two votes to let clocks turn off.
|
|
|
|
*
|
|
|
|
* To satisfy the above requirement, m_vote_cnt keeps track of
|
|
|
|
* the number of ON votes for master requested by slave. For
|
|
|
|
* every OFF/ECG state request, Either 2 or m_vote_cnt number of
|
|
|
|
* votes are removed depending on which is lower.
|
|
|
|
*/
|
|
|
|
for (i = 0; (i < ctrl->m_vote_cnt && i < 2); i++) {
|
|
|
|
rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle,
|
|
|
|
MDSS_DSI_ALL_CLKS,
|
|
|
|
MDSS_DSI_CLK_OFF);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed to set mctrl clk state, rc = %d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctrl->m_vote_cnt -= i;
|
|
|
|
pr_debug("%s: ctrl=%d, m_vote_cnt=%d\n", __func__, ctrl->ndx,
|
|
|
|
ctrl->m_vote_cnt);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
error:
|
|
|
|
mutex_unlock(&dsi_clk_mutex);
|
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_dsi_pre_clkoff_cb(void *priv,
|
|
|
|
enum mdss_dsi_clk_type clk,
|
|
|
|
enum mdss_dsi_clk_state new_state)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl = priv;
|
|
|
|
struct mdss_panel_data *pdata = NULL;
|
|
|
|
|
|
|
|
pdata = &ctrl->panel_data;
|
|
|
|
|
|
|
|
if ((clk & MDSS_DSI_LINK_CLK) && (new_state == MDSS_DSI_CLK_OFF)) {
|
|
|
|
/*
|
|
|
|
* If ULPS feature is enabled, enter ULPS first.
|
|
|
|
* However, when blanking the panel, we should enter ULPS
|
|
|
|
* only if ULPS during suspend feature is enabled.
|
|
|
|
*/
|
|
|
|
if (!(ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE)) {
|
|
|
|
if (pdata->panel_info.ulps_suspend_enabled)
|
|
|
|
mdss_dsi_ulps_config(ctrl, 1);
|
|
|
|
} else if (mdss_dsi_ulps_feature_enabled(pdata)) {
|
|
|
|
rc = mdss_dsi_ulps_config(ctrl, 1);
|
|
|
|
}
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed enable ulps, rc = %d\n",
|
|
|
|
__func__, rc);
|
|
|
|
}
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if ((clk & MDSS_DSI_CORE_CLK) && (new_state == MDSS_DSI_CLK_OFF)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enable DSI clamps only if entering idle power collapse or
|
|
|
|
* when ULPS during suspend is enabled.
|
|
|
|
*/
|
|
|
|
if ((ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE) ||
|
|
|
|
pdata->panel_info.ulps_suspend_enabled) {
|
|
|
|
rc = mdss_dsi_clamp_ctrl(ctrl, 1);
|
|
|
|
if (rc)
|
|
|
|
pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_dsi_post_clkon_cb(void *priv,
|
|
|
|
enum mdss_dsi_clk_type clk,
|
|
|
|
enum mdss_dsi_clk_state curr_state)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct mdss_panel_data *pdata = NULL;
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl = priv;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
pdata = &ctrl->panel_data;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (clk & MDSS_DSI_CORE_CLK) {
|
|
|
|
if (!pdata->panel_info.cont_splash_enabled) {
|
|
|
|
mdss_dsi_read_hw_revision(ctrl);
|
|
|
|
mdss_dsi_read_phy_revision(ctrl);
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/*
|
|
|
|
* Phy and controller setup is needed if coming out of idle
|
|
|
|
* power collapse with clamps enabled.
|
|
|
|
*/
|
|
|
|
if (ctrl->mmss_clamp) {
|
|
|
|
mdss_dsi_phy_init(ctrl);
|
|
|
|
mdss_dsi_ctrl_setup(ctrl);
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (ctrl->ulps) {
|
|
|
|
/*
|
|
|
|
* ULPS Entry Request. This is needed if the lanes were
|
|
|
|
* in ULPS prior to power collapse, since after
|
|
|
|
* power collapse and reset, the DSI controller resets
|
|
|
|
* back to idle state and not ULPS. This ulps entry
|
|
|
|
* request will transition the state of the DSI
|
|
|
|
* controller to ULPS which will match the state of the
|
|
|
|
* DSI phy. This needs to be done prior to disabling
|
|
|
|
* the DSI clamps.
|
|
|
|
*
|
|
|
|
* Also, reset the ulps flag so that ulps_config
|
|
|
|
* function would reconfigure the controller state to
|
|
|
|
* ULPS.
|
|
|
|
*/
|
|
|
|
ctrl->ulps = false;
|
|
|
|
rc = mdss_dsi_ulps_config(ctrl, 1);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: Failed to enter ULPS. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
rc = mdss_dsi_clamp_ctrl(ctrl, 0);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (clk & MDSS_DSI_LINK_CLK) {
|
|
|
|
if (ctrl->ulps) {
|
|
|
|
rc = mdss_dsi_ulps_config(ctrl, 0);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed to disable ulps, rc= %d\n",
|
|
|
|
__func__, rc);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error:
|
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_dsi_post_clkoff_cb(void *priv,
|
|
|
|
enum mdss_dsi_clk_type clk_type,
|
|
|
|
enum mdss_dsi_clk_state curr_state)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl = priv;
|
|
|
|
struct mdss_panel_data *pdata = NULL;
|
|
|
|
struct dsi_shared_data *sdata;
|
|
|
|
int i;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: Invalid arg\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if ((clk_type & MDSS_DSI_CORE_CLK) &&
|
|
|
|
(curr_state == MDSS_DSI_CLK_OFF)) {
|
|
|
|
sdata = ctrl->shared_data;
|
|
|
|
pdata = &ctrl->panel_data;
|
|
|
|
|
|
|
|
for (i = DSI_MAX_PM - 1; i >= DSI_CORE_PM; i--) {
|
|
|
|
if ((i != DSI_CORE_PM) &&
|
|
|
|
(ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE))
|
|
|
|
continue;
|
|
|
|
rc = msm_dss_enable_vreg(
|
|
|
|
sdata->power_data[i].vreg_config,
|
|
|
|
sdata->power_data[i].num_vreg, 0);
|
|
|
|
if (rc) {
|
|
|
|
pr_warn("%s: failed to disable vregs for %s\n",
|
|
|
|
__func__,
|
|
|
|
__mdss_dsi_pm_name(i));
|
|
|
|
rc = 0;
|
|
|
|
} else {
|
|
|
|
ctrl->core_power = false;
|
|
|
|
}
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_dsi_pre_clkon_cb(void *priv,
|
|
|
|
enum mdss_dsi_clk_type clk_type,
|
|
|
|
enum mdss_dsi_clk_state new_state)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct mdss_dsi_ctrl_pdata *ctrl = priv;
|
|
|
|
struct mdss_panel_data *pdata = NULL;
|
|
|
|
struct dsi_shared_data *sdata;
|
|
|
|
int i;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (!ctrl) {
|
|
|
|
pr_err("%s: invalid input\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if ((clk_type & MDSS_DSI_CORE_CLK) && (new_state == MDSS_DSI_CLK_ON) &&
|
|
|
|
(ctrl->core_power == false)) {
|
|
|
|
sdata = ctrl->shared_data;
|
|
|
|
pdata = &ctrl->panel_data;
|
|
|
|
/*
|
|
|
|
* Enable DSI core power
|
|
|
|
* 1.> PANEL_PM are controlled as part of
|
|
|
|
* panel_power_ctrl. Needed not be handled here.
|
|
|
|
* 2.> CORE_PM are controlled by dsi clk manager.
|
|
|
|
* 2.> PHY_PM and CTRL_PM need to be enabled/disabled
|
|
|
|
* only during unblank/blank. Their state should
|
|
|
|
* not be changed during static screen.
|
|
|
|
*/
|
|
|
|
pr_debug("%s: Enable DSI core power\n", __func__);
|
|
|
|
for (i = DSI_CORE_PM; i < DSI_MAX_PM; i++) {
|
|
|
|
if ((i != DSI_CORE_PM) &&
|
|
|
|
(ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE) &&
|
|
|
|
!pdata->panel_info.cont_splash_enabled)
|
|
|
|
continue;
|
|
|
|
rc = msm_dss_enable_vreg(
|
|
|
|
sdata->power_data[i].vreg_config,
|
|
|
|
sdata->power_data[i].num_vreg, 1);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("%s: failed to enable vregs for %s\n",
|
|
|
|
__func__,
|
|
|
|
__mdss_dsi_pm_name(i));
|
|
|
|
} else {
|
|
|
|
ctrl->core_power = true;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
return rc;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_edp_clk_deinit(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
if (edp_drv->aux_clk)
|
|
|
|
clk_put(edp_drv->aux_clk);
|
|
|
|
if (edp_drv->pixel_clk)
|
|
|
|
clk_put(edp_drv->pixel_clk);
|
|
|
|
if (edp_drv->ahb_clk)
|
|
|
|
clk_put(edp_drv->ahb_clk);
|
|
|
|
if (edp_drv->link_clk)
|
|
|
|
clk_put(edp_drv->link_clk);
|
2024-09-09 08:57:42 +00:00
|
|
|
if (edp_drv->mdp_core_clk)
|
|
|
|
clk_put(edp_drv->mdp_core_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_edp_clk_init(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
struct device *dev = &(edp_drv->pdev->dev);
|
|
|
|
|
|
|
|
edp_drv->aux_clk = clk_get(dev, "core_clk");
|
|
|
|
if (IS_ERR(edp_drv->aux_clk)) {
|
|
|
|
pr_err("%s: Can't find aux_clk", __func__);
|
|
|
|
edp_drv->aux_clk = NULL;
|
|
|
|
goto mdss_edp_clk_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
edp_drv->pixel_clk = clk_get(dev, "pixel_clk");
|
|
|
|
if (IS_ERR(edp_drv->pixel_clk)) {
|
|
|
|
pr_err("%s: Can't find pixel_clk", __func__);
|
|
|
|
edp_drv->pixel_clk = NULL;
|
|
|
|
goto mdss_edp_clk_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
edp_drv->ahb_clk = clk_get(dev, "iface_clk");
|
|
|
|
if (IS_ERR(edp_drv->ahb_clk)) {
|
|
|
|
pr_err("%s: Can't find ahb_clk", __func__);
|
|
|
|
edp_drv->ahb_clk = NULL;
|
|
|
|
goto mdss_edp_clk_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
edp_drv->link_clk = clk_get(dev, "link_clk");
|
|
|
|
if (IS_ERR(edp_drv->link_clk)) {
|
|
|
|
pr_err("%s: Can't find link_clk", __func__);
|
|
|
|
edp_drv->link_clk = NULL;
|
|
|
|
goto mdss_edp_clk_err;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* need mdss clock to receive irq */
|
|
|
|
edp_drv->mdp_core_clk = clk_get(dev, "mdp_core_clk");
|
|
|
|
if (IS_ERR(edp_drv->mdp_core_clk)) {
|
|
|
|
pr_err("%s: Can't find mdp_core_clk", __func__);
|
|
|
|
edp_drv->mdp_core_clk = NULL;
|
|
|
|
goto mdss_edp_clk_err;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
mdss_edp_clk_err:
|
|
|
|
mdss_edp_clk_deinit(edp_drv);
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_edp_aux_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int ret;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
|
|
|
|
pr_err("%s: aux_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
ret = clk_enable(edp_drv->aux_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable aux clk\n", __func__);
|
|
|
|
goto c2;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = clk_enable(edp_drv->ahb_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable ahb clk\n", __func__);
|
|
|
|
goto c1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* need mdss clock to receive irq */
|
|
|
|
ret = clk_enable(edp_drv->mdp_core_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable mdp_core_clk\n", __func__);
|
|
|
|
goto c0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
c0:
|
|
|
|
clk_disable(edp_drv->ahb_clk);
|
|
|
|
c1:
|
|
|
|
clk_disable(edp_drv->aux_clk);
|
|
|
|
c2:
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_edp_aux_clk_disable(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
clk_disable(edp_drv->aux_clk);
|
|
|
|
clk_disable(edp_drv->ahb_clk);
|
|
|
|
clk_disable(edp_drv->mdp_core_clk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mdss_edp_clk_set_rate(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
if (clk_set_rate(edp_drv->link_clk, edp_drv->link_rate * 27000000) < 0)
|
|
|
|
pr_err("%s: link_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
if (clk_set_rate(edp_drv->pixel_clk, edp_drv->pixel_rate) < 0)
|
2024-09-09 08:52:07 +00:00
|
|
|
pr_err("%s: pixel_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
2024-09-09 08:57:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (edp_drv->clk_on) {
|
|
|
|
pr_info("%s: edp clks are already ON\n", __func__);
|
|
|
|
return 0;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (clk_set_rate(edp_drv->link_clk, edp_drv->link_rate * 27000000) < 0)
|
2024-09-09 08:52:07 +00:00
|
|
|
pr_err("%s: link_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if (clk_set_rate(edp_drv->aux_clk, edp_drv->aux_rate) < 0)
|
|
|
|
pr_err("%s: aux_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
if (clk_set_rate(edp_drv->pixel_clk, edp_drv->pixel_rate) < 0)
|
|
|
|
pr_err("%s: pixel_clk - clk_set_rate failed\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
ret = clk_enable(edp_drv->aux_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable aux clk\n", __func__);
|
|
|
|
goto c4;
|
|
|
|
}
|
|
|
|
ret = clk_enable(edp_drv->pixel_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable pixel clk\n", __func__);
|
|
|
|
goto c3;
|
|
|
|
}
|
|
|
|
ret = clk_enable(edp_drv->ahb_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable ahb clk\n", __func__);
|
|
|
|
goto c2;
|
|
|
|
}
|
|
|
|
ret = clk_enable(edp_drv->link_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable link clk\n", __func__);
|
|
|
|
goto c1;
|
|
|
|
}
|
|
|
|
ret = clk_enable(edp_drv->mdp_core_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to enable mdp_core_clk\n", __func__);
|
|
|
|
goto c0;
|
|
|
|
}
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
edp_drv->clk_on = 1;
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
c0:
|
|
|
|
clk_disable(edp_drv->link_clk);
|
|
|
|
c1:
|
|
|
|
clk_disable(edp_drv->ahb_clk);
|
|
|
|
c2:
|
|
|
|
clk_disable(edp_drv->pixel_clk);
|
|
|
|
c3:
|
|
|
|
clk_disable(edp_drv->aux_clk);
|
|
|
|
c4:
|
|
|
|
return ret;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mdss_edp_clk_disable(struct mdss_edp_drv_pdata *edp_drv)
|
|
|
|
{
|
|
|
|
if (edp_drv->clk_on == 0) {
|
|
|
|
pr_info("%s: edp clks are already OFF\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clk_disable(edp_drv->aux_clk);
|
|
|
|
clk_disable(edp_drv->pixel_clk);
|
|
|
|
clk_disable(edp_drv->ahb_clk);
|
|
|
|
clk_disable(edp_drv->link_clk);
|
2024-09-09 08:57:42 +00:00
|
|
|
clk_disable(edp_drv->mdp_core_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
edp_drv->clk_on = 0;
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_edp_prepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* ahb clock should be prepared first */
|
|
|
|
ret = clk_prepare(edp_drv->ahb_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare ahb clk\n", __func__);
|
|
|
|
goto c3;
|
|
|
|
}
|
|
|
|
ret = clk_prepare(edp_drv->aux_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare aux clk\n", __func__);
|
|
|
|
goto c2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* need mdss clock to receive irq */
|
|
|
|
ret = clk_prepare(edp_drv->mdp_core_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare mdp_core clk\n", __func__);
|
|
|
|
goto c1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
c1:
|
|
|
|
clk_unprepare(edp_drv->aux_clk);
|
|
|
|
c2:
|
|
|
|
clk_unprepare(edp_drv->ahb_clk);
|
|
|
|
c3:
|
|
|
|
return ret;
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
void mdss_edp_unprepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
clk_unprepare(edp_drv->mdp_core_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
clk_unprepare(edp_drv->aux_clk);
|
|
|
|
clk_unprepare(edp_drv->ahb_clk);
|
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
int mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
int ret;
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
mdss_edp_clk_set_rate(edp_drv);
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
/* ahb clock should be prepared first */
|
|
|
|
ret = clk_prepare(edp_drv->ahb_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare ahb clk\n", __func__);
|
|
|
|
goto c4;
|
|
|
|
}
|
|
|
|
ret = clk_prepare(edp_drv->aux_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare aux clk\n", __func__);
|
|
|
|
goto c3;
|
|
|
|
}
|
|
|
|
ret = clk_prepare(edp_drv->pixel_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare pixel clk\n", __func__);
|
|
|
|
goto c2;
|
|
|
|
}
|
|
|
|
ret = clk_prepare(edp_drv->link_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare link clk\n", __func__);
|
|
|
|
goto c1;
|
|
|
|
}
|
|
|
|
ret = clk_prepare(edp_drv->mdp_core_clk);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: Failed to prepare mdp_core clk\n", __func__);
|
|
|
|
goto c0;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
return 0;
|
|
|
|
c0:
|
|
|
|
clk_unprepare(edp_drv->link_clk);
|
|
|
|
c1:
|
|
|
|
clk_unprepare(edp_drv->pixel_clk);
|
|
|
|
c2:
|
|
|
|
clk_unprepare(edp_drv->aux_clk);
|
|
|
|
c3:
|
|
|
|
clk_unprepare(edp_drv->ahb_clk);
|
|
|
|
c4:
|
|
|
|
return ret;
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
clk_unprepare(edp_drv->mdp_core_clk);
|
|
|
|
clk_unprepare(edp_drv->aux_clk);
|
|
|
|
clk_unprepare(edp_drv->pixel_clk);
|
|
|
|
clk_unprepare(edp_drv->link_clk);
|
|
|
|
/* ahb clock should be last one to disable */
|
|
|
|
clk_unprepare(edp_drv->ahb_clk);
|
2024-09-09 08:52:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
void mdss_edp_clk_debug(unsigned char *edp_base, unsigned char *mmss_cc_base)
|
2024-09-09 08:52:07 +00:00
|
|
|
{
|
2024-09-09 08:57:42 +00:00
|
|
|
u32 da4, da0, d32c;
|
|
|
|
u32 dc4, dc0, d330;
|
|
|
|
|
|
|
|
/* pixel clk */
|
|
|
|
da0 = edp_read(mmss_cc_base + 0x0a0);
|
|
|
|
da4 = edp_read(mmss_cc_base + 0x0a4);
|
|
|
|
d32c = edp_read(mmss_cc_base + 0x32c);
|
|
|
|
|
|
|
|
/* main link clk */
|
|
|
|
dc0 = edp_read(mmss_cc_base + 0x0c0);
|
|
|
|
dc4 = edp_read(mmss_cc_base + 0x0c4);
|
|
|
|
d330 = edp_read(mmss_cc_base + 0x330);
|
|
|
|
|
|
|
|
pr_err("%s: da0=%x da4=%x d32c=%x dc0=%x dc4=%x d330=%x\n", __func__,
|
|
|
|
(int)da0, (int)da4, (int)d32c, (int)dc0, (int)dc4, (int)d330);
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
}
|