758 lines
20 KiB
C
758 lines
20 KiB
C
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
|
*
|
|
* 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>
|
|
|
|
#include <mach/clk.h>
|
|
#include <mach/msm_iomap.h>
|
|
|
|
#include "mdss_dsi.h"
|
|
#include "mdss_edp.h"
|
|
|
|
#define SW_RESET BIT(2)
|
|
#define SW_RESET_PLL BIT(0)
|
|
#define PWRDN_B BIT(7)
|
|
|
|
static struct dsi_clk_desc dsi_pclk;
|
|
|
|
int mdss_dsi_clk_init(struct platform_device *pdev,
|
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
struct device *dev = NULL;
|
|
int rc = 0;
|
|
|
|
if (!pdev) {
|
|
pr_err("%s: Invalid pdev\n", __func__);
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
dev = &pdev->dev;
|
|
ctrl_pdata->ahb_clk = clk_get(dev, "iface_clk");
|
|
if (IS_ERR(ctrl_pdata->ahb_clk)) {
|
|
rc = PTR_ERR(ctrl_pdata->ahb_clk);
|
|
pr_err("%s: Unable to get mdss ahb clk. rc=%d\n",
|
|
__func__, rc);
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
ctrl_pdata->axi_clk = clk_get(dev, "bus_clk");
|
|
if (IS_ERR(ctrl_pdata->axi_clk)) {
|
|
rc = PTR_ERR(ctrl_pdata->axi_clk);
|
|
pr_err("%s: Unable to get axi bus clk. rc=%d\n",
|
|
__func__, rc);
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
|
|
if (IS_ERR(ctrl_pdata->byte_clk)) {
|
|
rc = PTR_ERR(ctrl_pdata->byte_clk);
|
|
pr_err("%s: can't find dsi_byte_clk. rc=%d\n",
|
|
__func__, rc);
|
|
ctrl_pdata->byte_clk = NULL;
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
ctrl_pdata->pixel_clk = clk_get(dev, "pixel_clk");
|
|
if (IS_ERR(ctrl_pdata->pixel_clk)) {
|
|
rc = PTR_ERR(ctrl_pdata->pixel_clk);
|
|
pr_err("%s: can't find dsi_pixel_clk. rc=%d\n",
|
|
__func__, rc);
|
|
ctrl_pdata->pixel_clk = NULL;
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
ctrl_pdata->esc_clk = clk_get(dev, "core_clk");
|
|
if (IS_ERR(ctrl_pdata->esc_clk)) {
|
|
rc = PTR_ERR(ctrl_pdata->esc_clk);
|
|
pr_err("%s: can't find dsi_esc_clk. rc=%d\n",
|
|
__func__, rc);
|
|
ctrl_pdata->esc_clk = NULL;
|
|
goto mdss_dsi_clk_err;
|
|
}
|
|
|
|
mdss_dsi_clk_err:
|
|
if (rc)
|
|
mdss_dsi_clk_deinit(ctrl_pdata);
|
|
return rc;
|
|
}
|
|
|
|
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
if (ctrl_pdata->byte_clk)
|
|
clk_put(ctrl_pdata->byte_clk);
|
|
if (ctrl_pdata->esc_clk)
|
|
clk_put(ctrl_pdata->esc_clk);
|
|
if (ctrl_pdata->pixel_clk)
|
|
clk_put(ctrl_pdata->pixel_clk);
|
|
if (ctrl_pdata->axi_clk)
|
|
clk_put(ctrl_pdata->axi_clk);
|
|
if (ctrl_pdata->ahb_clk)
|
|
clk_put(ctrl_pdata->ahb_clk);
|
|
}
|
|
|
|
#define PREF_DIV_RATIO 27
|
|
struct dsiphy_pll_divider_config pll_divider_config;
|
|
|
|
int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
|
|
u32 *expected_dsi_pclk)
|
|
{
|
|
u32 fb_divider, rate, vco;
|
|
u32 div_ratio = 0;
|
|
u32 pll_analog_posDiv = 1;
|
|
struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
|
|
if (pll_divider_config.clk_rate == 0)
|
|
pll_divider_config.clk_rate = 454000000;
|
|
|
|
rate = (pll_divider_config.clk_rate / 2)
|
|
/ 1000000; /* Half Bit Clock In Mhz */
|
|
|
|
if (rate < 43) {
|
|
vco = rate * 16;
|
|
div_ratio = 16;
|
|
pll_analog_posDiv = 8;
|
|
} else if (rate < 85) {
|
|
vco = rate * 8;
|
|
div_ratio = 8;
|
|
pll_analog_posDiv = 4;
|
|
} else if (rate < 170) {
|
|
vco = rate * 4;
|
|
div_ratio = 4;
|
|
pll_analog_posDiv = 2;
|
|
} else if (rate < 340) {
|
|
vco = rate * 2;
|
|
div_ratio = 2;
|
|
pll_analog_posDiv = 1;
|
|
} else {
|
|
/* DSI PLL Direct path configuration */
|
|
vco = rate * 1;
|
|
div_ratio = 1;
|
|
pll_analog_posDiv = 1;
|
|
}
|
|
|
|
/* find the mnd settings from mnd_table entry */
|
|
for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
|
|
if (((mnd_entry->lanes) == lanes) &&
|
|
((mnd_entry->bpp) == bpp))
|
|
break;
|
|
}
|
|
|
|
if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) {
|
|
pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n",
|
|
__func__, lanes, bpp);
|
|
return -EINVAL;
|
|
}
|
|
fb_divider = ((vco * PREF_DIV_RATIO) / 27);
|
|
pll_divider_config.fb_divider = fb_divider;
|
|
pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO;
|
|
pll_divider_config.bit_clk_divider = div_ratio;
|
|
pll_divider_config.byte_clk_divider =
|
|
pll_divider_config.bit_clk_divider * 8;
|
|
pll_divider_config.analog_posDiv = pll_analog_posDiv;
|
|
pll_divider_config.digital_posDiv =
|
|
(mnd_entry->pll_digital_posDiv) * div_ratio;
|
|
|
|
if ((mnd_entry->pclk_d == 0)
|
|
|| (mnd_entry->pclk_m == 1)) {
|
|
dsi_pclk.mnd_mode = 0;
|
|
dsi_pclk.src = 0x3;
|
|
dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1);
|
|
} else {
|
|
dsi_pclk.mnd_mode = 2;
|
|
dsi_pclk.src = 0x3;
|
|
dsi_pclk.m = mnd_entry->pclk_m;
|
|
dsi_pclk.n = mnd_entry->pclk_n;
|
|
dsi_pclk.d = mnd_entry->pclk_d;
|
|
}
|
|
*expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
|
|
/ (8 * bpp));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
int rc = 0;
|
|
|
|
rc = clk_prepare_enable(ctrl_pdata->ahb_clk);
|
|
if (rc) {
|
|
pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
|
|
goto error;
|
|
}
|
|
|
|
rc = clk_prepare_enable(ctrl_pdata->axi_clk);
|
|
if (rc) {
|
|
pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
|
|
clk_disable_unprepare(ctrl_pdata->ahb_clk);
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
|
|
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
clk_disable_unprepare(ctrl_pdata->axi_clk);
|
|
clk_disable_unprepare(ctrl_pdata->ahb_clk);
|
|
}
|
|
|
|
void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
clk_prepare(ctrl_pdata->byte_clk);
|
|
clk_prepare(ctrl_pdata->esc_clk);
|
|
clk_prepare(ctrl_pdata->pixel_clk);
|
|
}
|
|
|
|
void mdss_dsi_unprepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
clk_unprepare(ctrl_pdata->esc_clk);
|
|
clk_unprepare(ctrl_pdata->pixel_clk);
|
|
clk_unprepare(ctrl_pdata->byte_clk);
|
|
}
|
|
|
|
void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
u32 esc_clk_rate = 19200000;
|
|
|
|
if (!ctrl_pdata) {
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (ctrl_pdata->mdss_dsi_clk_on) {
|
|
pr_info("%s: mdss_dsi_clks already ON\n", __func__);
|
|
return;
|
|
}
|
|
|
|
pr_debug("%s: Setting clock rates: pclk=%d, byteclk=%d escclk=%d\n",
|
|
__func__, ctrl_pdata->pclk_rate,
|
|
ctrl_pdata->byte_clk_rate, esc_clk_rate);
|
|
if (clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate) < 0)
|
|
pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", __func__);
|
|
|
|
if (clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate) < 0)
|
|
pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", __func__);
|
|
|
|
if (clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate) < 0)
|
|
pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", __func__);
|
|
|
|
clk_enable(ctrl_pdata->esc_clk);
|
|
clk_enable(ctrl_pdata->byte_clk);
|
|
clk_enable(ctrl_pdata->pixel_clk);
|
|
|
|
ctrl_pdata->mdss_dsi_clk_on = 1;
|
|
}
|
|
|
|
void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
|
{
|
|
if (!ctrl_pdata) {
|
|
pr_err("%s: Invalid input data\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (ctrl_pdata->mdss_dsi_clk_on == 0) {
|
|
pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
|
|
return;
|
|
}
|
|
|
|
clk_disable(ctrl_pdata->pixel_clk);
|
|
clk_disable(ctrl_pdata->byte_clk);
|
|
clk_disable(ctrl_pdata->esc_clk);
|
|
|
|
ctrl_pdata->mdss_dsi_clk_on = 0;
|
|
}
|
|
|
|
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)
|
|
{
|
|
/* start phy sw reset */
|
|
MIPI_OUTP(ctrl_base + 0x12c, 0x0001);
|
|
udelay(1000);
|
|
wmb();
|
|
/* end phy sw reset */
|
|
MIPI_OUTP(ctrl_base + 0x12c, 0x0000);
|
|
udelay(100);
|
|
wmb();
|
|
}
|
|
|
|
void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
|
|
{
|
|
if (on) {
|
|
MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
|
|
wmb();
|
|
usleep(100);
|
|
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
|
|
wmb();
|
|
usleep(100);
|
|
MIPI_OUTP(ctrl_base + 0x0268, 0x001);
|
|
wmb();
|
|
usleep(100);
|
|
MIPI_OUTP(ctrl_base + 0x0268, 0x000);
|
|
wmb();
|
|
usleep(100);
|
|
MIPI_OUTP(ctrl_base + 0x0220, 0x007);
|
|
wmb();
|
|
MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
|
|
wmb();
|
|
usleep(100);
|
|
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x06e);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x06c);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x064);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x065);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x075);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x077);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x07f);
|
|
wmb();
|
|
|
|
} else {
|
|
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
|
|
MIPI_OUTP(ctrl_base + 0x0470, 0x000);
|
|
MIPI_OUTP(ctrl_base + 0x0598, 0x000);
|
|
wmb();
|
|
}
|
|
}
|
|
|
|
void mdss_dsi_phy_init(struct mdss_panel_data *pdata)
|
|
{
|
|
struct mdss_dsi_phy_ctrl *pd;
|
|
int i, off, ln, offset;
|
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
|
|
|
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
panel_data);
|
|
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 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
|
|
|
|
/* phy regulator ctrl settings. Both the DSI controller
|
|
have one regulator */
|
|
if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
|
|
off = 0x0580;
|
|
else
|
|
off = 0x0580 - 0x600;
|
|
|
|
/* Regulator ctrl 0 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), 0x0);
|
|
/* Regulator ctrl - CAL_PWR_CFG */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
|
|
|
|
/* Regulator ctrl - TEST */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
|
|
/* Regulator ctrl 3 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
|
|
/* Regulator ctrl 2 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
|
|
/* Regulator ctrl 1 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
|
|
/* Regulator ctrl 0 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
|
|
/* Regulator ctrl 4 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
|
|
|
|
/* LDO ctrl 0 */
|
|
if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
|
|
else
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
|
|
|
|
off = 0x0440; /* phy timing ctrl 0 - 11 */
|
|
for (i = 0; i < 12; i++) {
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
|
|
wmb();
|
|
off += 4;
|
|
}
|
|
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
|
|
wmb();
|
|
|
|
/* Strength ctrl 1 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
|
|
wmb();
|
|
|
|
/* 4 lanes + clk lane configuration */
|
|
/* lane config n * (0 - 4) & DataPath setup */
|
|
for (ln = 0; ln < 5; ln++) {
|
|
off = 0x0300 + (ln * 0x40);
|
|
for (i = 0; i < 9; i++) {
|
|
offset = i + (ln * 9);
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
|
|
pd->laneCfg[offset]);
|
|
wmb();
|
|
off += 4;
|
|
}
|
|
}
|
|
|
|
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
|
|
wmb();
|
|
|
|
/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
|
|
if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
|
|
else
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x00);
|
|
wmb();
|
|
|
|
off = 0x04b4; /* phy BIST ctrl 0 - 5 */
|
|
for (i = 0; i < 6; i++) {
|
|
MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
|
|
wmb();
|
|
off += 4;
|
|
}
|
|
|
|
}
|
|
|
|
/* EDP phy configuration settings */
|
|
void mdss_edp_phy_sw_reset(unsigned char *edp_base)
|
|
{
|
|
/* phy sw reset */
|
|
edp_write(edp_base + 0x74, 0x100); /* EDP_PHY_CTRL */
|
|
wmb();
|
|
usleep(1);
|
|
edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
|
|
wmb();
|
|
usleep(1);
|
|
|
|
/* phy PLL sw reset */
|
|
edp_write(edp_base + 0x74, 0x001); /* EDP_PHY_CTRL */
|
|
wmb();
|
|
usleep(1);
|
|
edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
|
|
wmb();
|
|
usleep(1);
|
|
}
|
|
|
|
void mdss_edp_hw_powerup(unsigned char *edp_base, int enable)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (enable) {
|
|
/* EDP_PHY_EDPPHY_GLB_PD_CTL */
|
|
edp_write(edp_base + 0x52c, 0x3f);
|
|
/* EDP_PHY_EDPPHY_GLB_CFG */
|
|
edp_write(edp_base + 0x528, 0x1);
|
|
/* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
|
|
edp_write(edp_base + 0x620, 0xf);
|
|
/* EDP_AUX_CTRL */
|
|
ret = edp_read(edp_base + 0x300);
|
|
edp_write(edp_base + 0x300, ret | 0x1);
|
|
} else {
|
|
/* EDP_PHY_EDPPHY_GLB_PD_CTL */
|
|
edp_write(edp_base + 0x52c, 0xc0);
|
|
}
|
|
}
|
|
|
|
void mdss_edp_pll_configure(unsigned char *edp_base, int rate)
|
|
{
|
|
if (rate == 810000000) {
|
|
edp_write(edp_base + 0x60c, 0x18);
|
|
edp_write(edp_base + 0x664, 0x5);
|
|
edp_write(edp_base + 0x600, 0x0);
|
|
edp_write(edp_base + 0x638, 0x36);
|
|
edp_write(edp_base + 0x63c, 0x69);
|
|
edp_write(edp_base + 0x640, 0xff);
|
|
edp_write(edp_base + 0x644, 0x2f);
|
|
edp_write(edp_base + 0x648, 0x0);
|
|
edp_write(edp_base + 0x66c, 0x0a);
|
|
edp_write(edp_base + 0x674, 0x01);
|
|
edp_write(edp_base + 0x684, 0x5a);
|
|
edp_write(edp_base + 0x688, 0x0);
|
|
edp_write(edp_base + 0x68c, 0x60);
|
|
edp_write(edp_base + 0x690, 0x0);
|
|
edp_write(edp_base + 0x694, 0x2a);
|
|
edp_write(edp_base + 0x698, 0x3);
|
|
edp_write(edp_base + 0x65c, 0x10);
|
|
edp_write(edp_base + 0x660, 0x1a);
|
|
edp_write(edp_base + 0x604, 0x0);
|
|
edp_write(edp_base + 0x624, 0x0);
|
|
edp_write(edp_base + 0x628, 0x0);
|
|
|
|
edp_write(edp_base + 0x620, 0x1);
|
|
edp_write(edp_base + 0x620, 0x5);
|
|
edp_write(edp_base + 0x620, 0x7);
|
|
edp_write(edp_base + 0x620, 0xf);
|
|
|
|
} else if (rate == 138500000) {
|
|
edp_write(edp_base + 0x664, 0x5); /* UNIPHY_PLL_LKDET_CFG2 */
|
|
edp_write(edp_base + 0x600, 0x1); /* UNIPHY_PLL_REFCLK_CFG */
|
|
edp_write(edp_base + 0x638, 0x36); /* UNIPHY_PLL_SDM_CFG0 */
|
|
edp_write(edp_base + 0x63c, 0x62); /* UNIPHY_PLL_SDM_CFG1 */
|
|
edp_write(edp_base + 0x640, 0x0); /* UNIPHY_PLL_SDM_CFG2 */
|
|
edp_write(edp_base + 0x644, 0x28); /* UNIPHY_PLL_SDM_CFG3 */
|
|
edp_write(edp_base + 0x648, 0x0); /* UNIPHY_PLL_SDM_CFG4 */
|
|
edp_write(edp_base + 0x64c, 0x80); /* UNIPHY_PLL_SSC_CFG0 */
|
|
edp_write(edp_base + 0x650, 0x0); /* UNIPHY_PLL_SSC_CFG1 */
|
|
edp_write(edp_base + 0x654, 0x0); /* UNIPHY_PLL_SSC_CFG2 */
|
|
edp_write(edp_base + 0x658, 0x0); /* UNIPHY_PLL_SSC_CFG3 */
|
|
edp_write(edp_base + 0x66c, 0xa); /* UNIPHY_PLL_CAL_CFG0 */
|
|
edp_write(edp_base + 0x674, 0x1); /* UNIPHY_PLL_CAL_CFG2 */
|
|
edp_write(edp_base + 0x684, 0x5a); /* UNIPHY_PLL_CAL_CFG6 */
|
|
edp_write(edp_base + 0x688, 0x0); /* UNIPHY_PLL_CAL_CFG7 */
|
|
edp_write(edp_base + 0x68c, 0x60); /* UNIPHY_PLL_CAL_CFG8 */
|
|
edp_write(edp_base + 0x690, 0x0); /* UNIPHY_PLL_CAL_CFG9 */
|
|
edp_write(edp_base + 0x694, 0x46); /* UNIPHY_PLL_CAL_CFG10 */
|
|
edp_write(edp_base + 0x698, 0x5); /* UNIPHY_PLL_CAL_CFG11 */
|
|
edp_write(edp_base + 0x65c, 0x10); /* UNIPHY_PLL_LKDET_CFG0 */
|
|
edp_write(edp_base + 0x660, 0x1a); /* UNIPHY_PLL_LKDET_CFG1 */
|
|
edp_write(edp_base + 0x604, 0x0); /* UNIPHY_PLL_POSTDIV1_CFG */
|
|
edp_write(edp_base + 0x624, 0x0); /* UNIPHY_PLL_POSTDIV2_CFG */
|
|
edp_write(edp_base + 0x628, 0x0); /* UNIPHY_PLL_POSTDIV3_CFG */
|
|
|
|
edp_write(edp_base + 0x620, 0x1); /* UNIPHY_PLL_GLB_CFG */
|
|
edp_write(edp_base + 0x620, 0x5); /* UNIPHY_PLL_GLB_CFG */
|
|
edp_write(edp_base + 0x620, 0x7); /* UNIPHY_PLL_GLB_CFG */
|
|
edp_write(edp_base + 0x620, 0xf); /* UNIPHY_PLL_GLB_CFG */
|
|
} else {
|
|
pr_err("%s: Unknown configuration rate\n", __func__);
|
|
}
|
|
}
|
|
|
|
void mdss_edp_enable_aux(unsigned char *edp_base, int enable)
|
|
{
|
|
if (!enable) {
|
|
edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
|
|
return;
|
|
}
|
|
|
|
/*reset AUX */
|
|
edp_write(edp_base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
|
|
edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
|
|
|
|
/* Enable AUX */
|
|
edp_write(edp_base + 0x300, BIT(0)); /* EDP_AUX_CTRL */
|
|
|
|
edp_write(edp_base + 0x550, 0x2c); /* AUX_CFG0 */
|
|
edp_write(edp_base + 0x308, 0xffffffff); /* INTR_STATUS */
|
|
edp_write(edp_base + 0x568, 0xff); /* INTR_MASK */
|
|
}
|
|
|
|
void mdss_edp_enable_mainlink(unsigned char *edp_base, int enable)
|
|
{
|
|
u32 data;
|
|
|
|
data = edp_read(edp_base + 0x004);
|
|
data &= ~BIT(0);
|
|
|
|
if (enable) {
|
|
data |= 0x1;
|
|
edp_write(edp_base + 0x004, data);
|
|
edp_write(edp_base + 0x004, 0x1);
|
|
} else {
|
|
data |= 0x0;
|
|
edp_write(edp_base + 0x004, data);
|
|
}
|
|
}
|
|
|
|
void mdss_edp_enable_lane_bist(unsigned char *edp_base, int lane, int enable)
|
|
{
|
|
unsigned char *addr_ln_bist_cfg, *addr_ln_pd_ctrl;
|
|
|
|
/* EDP_PHY_EDPPHY_LNn_PD_CTL */
|
|
addr_ln_pd_ctrl = edp_base + 0x404 + (0x40 * lane);
|
|
/* EDP_PHY_EDPPHY_LNn_BIST_CFG0 */
|
|
addr_ln_bist_cfg = edp_base + 0x408 + (0x40 * lane);
|
|
|
|
if (enable) {
|
|
edp_write(addr_ln_pd_ctrl, 0x0);
|
|
edp_write(addr_ln_bist_cfg, 0x10);
|
|
|
|
} else {
|
|
edp_write(addr_ln_pd_ctrl, 0xf);
|
|
edp_write(addr_ln_bist_cfg, 0x10);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
return 0;
|
|
|
|
mdss_edp_clk_err:
|
|
mdss_edp_clk_deinit(edp_drv);
|
|
return -EPERM;
|
|
}
|
|
|
|
|
|
void mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
|
|
{
|
|
if (edp_drv->clk_on) {
|
|
pr_info("%s: edp clks are already ON\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
|
|
pr_err("%s: aux_clk - clk_set_rate failed\n",
|
|
__func__);
|
|
|
|
if (clk_set_rate(edp_drv->pixel_clk, 138500000) < 0)
|
|
pr_err("%s: pixel_clk - clk_set_rate failed\n",
|
|
__func__);
|
|
|
|
if (clk_set_rate(edp_drv->link_clk, 270000000) < 0)
|
|
pr_err("%s: link_clk - clk_set_rate failed\n",
|
|
__func__);
|
|
|
|
clk_enable(edp_drv->aux_clk);
|
|
clk_enable(edp_drv->pixel_clk);
|
|
clk_enable(edp_drv->ahb_clk);
|
|
clk_enable(edp_drv->link_clk);
|
|
|
|
edp_drv->clk_on = 1;
|
|
}
|
|
|
|
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);
|
|
|
|
edp_drv->clk_on = 0;
|
|
}
|
|
|
|
void mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
|
{
|
|
clk_prepare(edp_drv->aux_clk);
|
|
clk_prepare(edp_drv->pixel_clk);
|
|
clk_prepare(edp_drv->ahb_clk);
|
|
clk_prepare(edp_drv->link_clk);
|
|
}
|
|
|
|
void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
|
|
{
|
|
clk_unprepare(edp_drv->aux_clk);
|
|
clk_unprepare(edp_drv->pixel_clk);
|
|
clk_unprepare(edp_drv->ahb_clk);
|
|
clk_unprepare(edp_drv->link_clk);
|
|
}
|
|
|
|
void mdss_edp_enable_pixel_clk(unsigned char *edp_base,
|
|
unsigned char *mmss_cc_base, int enable)
|
|
{
|
|
if (!enable) {
|
|
edp_write(mmss_cc_base + 0x032c, 0); /* CBCR */
|
|
return;
|
|
}
|
|
|
|
edp_write(edp_base + 0x624, 0x1); /* PostDiv2 */
|
|
|
|
/* Configuring MND for Pixel */
|
|
edp_write(mmss_cc_base + 0x00a8, 0x3f); /* M value */
|
|
edp_write(mmss_cc_base + 0x00ac, 0xb); /* N value */
|
|
edp_write(mmss_cc_base + 0x00b0, 0x0); /* D value */
|
|
|
|
/* CFG RCGR */
|
|
edp_write(mmss_cc_base + 0x00a4, (5 << 8) | (2 << 12));
|
|
edp_write(mmss_cc_base + 0x00a0, 3); /* CMD RCGR */
|
|
|
|
edp_write(mmss_cc_base + 0x032c, 1); /* CBCR */
|
|
}
|
|
|
|
void mdss_edp_enable_link_clk(unsigned char *mmss_cc_base, int enable)
|
|
{
|
|
if (!enable) {
|
|
edp_write(mmss_cc_base + 0x0330, 0); /* CBCR */
|
|
return;
|
|
}
|
|
|
|
edp_write(mmss_cc_base + 0x00c4, (4 << 8)); /* CFG RCGR */
|
|
edp_write(mmss_cc_base + 0x00c0, 3); /* CMD RCGR */
|
|
|
|
edp_write(mmss_cc_base + 0x0330, 1); /* CBCR */
|
|
}
|
|
|
|
void mdss_edp_config_clk(unsigned char *edp_base, unsigned char *mmss_cc_base)
|
|
{
|
|
mdss_edp_enable_link_clk(mmss_cc_base, 1);
|
|
mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 1);
|
|
}
|
|
|
|
void mdss_edp_unconfig_clk(unsigned char *edp_base,
|
|
unsigned char *mmss_cc_base)
|
|
{
|
|
mdss_edp_enable_link_clk(mmss_cc_base, 0);
|
|
mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 0);
|
|
}
|
|
|
|
void mdss_edp_phy_misc_cfg(unsigned char *edp_base)
|
|
{
|
|
/* EDP_PHY_EDPPHY_GLB_VM_CFG0 */
|
|
edp_write(edp_base + 0x510, 0x3);
|
|
/* EDP_PHY_EDPPHY_GLB_VM_CFG1 */
|
|
edp_write(edp_base + 0x514, 0x64);
|
|
/* EDP_PHY_EDPPHY_GLB_MISC9 */
|
|
edp_write(edp_base + 0x518, 0x6c);
|
|
/* EDP_MISC1_MISC0 */
|
|
edp_write(edp_base + 0x2c, 0x1);
|
|
}
|