aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinliang Liu <xinliang.liu@linaro.org>2015-12-21 16:31:50 +0800
committerJohn Stultz <john.stultz@linaro.org>2016-02-02 19:32:28 -0800
commite718041d13e35f8d0ee162f959a899aa1f6de72c (patch)
treefdda34290603d7a150a9d051ebac2f48b36e38e5
parentfdf903e81ea0564f7843c7249f7a7243693fe06d (diff)
downloadhikey-linaro-e718041d13e35f8d0ee162f959a899aa1f6de72c.tar.gz
drm/hisilicon: dsi: Reset dsi when detect dsi transfer error
This is a workaround for bootup blanking issue. HDMI can detect dsi transfer error, when this error happened reseting dsi can bring display to normal. Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
-rw-r--r--drivers/gpu/drm/hisilicon/hisi_drm_drv.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hisi_drm_dsi.c71
-rw-r--r--drivers/gpu/drm/hisilicon/hisi_drm_dsi.h72
-rw-r--r--drivers/gpu/drm/hisilicon/hisi_mipi_reg.h13
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c39
5 files changed, 119 insertions, 78 deletions
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index c699529ca235..766168fc3545 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -17,7 +17,6 @@
#include <drm/drm_gem_cma_helper.h>
#include "hisi_drm_ade.h"
-#include "hisi_drm_dsi.h"
#include "hisi_drm_fb.h"
#ifdef CONFIG_DRM_HISI_FBDEV
#include "hisi_drm_fbdev.h"
@@ -66,7 +65,6 @@ static int hisi_drm_sub_drivers_init(struct drm_device *drm_dev)
#ifdef CONFIG_DRM_HISI_FBDEV
/* err_fbdev_init:*/
- hisi_drm_dsi_exit();
#endif
return ret;
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index df776a1b8586..1a589937af18 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -33,8 +33,6 @@
#define connector_to_dsi(connector) \
container_of(connector, struct hisi_dsi, connector)
-#define encoder_to_dsi(encoder) \
- container_of(encoder, struct hisi_dsi, base.base)
#define DEFAULT_MIPI_CLK_RATE 19200000
#define MAX_TX_ESC_CLK (10)
@@ -45,64 +43,6 @@
u8 *reg_base_mipi_dsi;
-struct mipi_dsi_phy_register {
- u32 clk_t_lpx;
- u32 clk_t_hs_prepare;
- u32 clk_t_hs_zero;
- u32 clk_t_hs_trial;
- u32 clk_t_wakeup;
- u32 data_t_lpx;
- u32 data_t_hs_prepare;
- u32 data_t_hs_zero;
- u32 data_t_hs_trial;
- u32 data_t_ta_go;
- u32 data_t_ta_get;
- u32 data_t_wakeup;
- u32 rg_hstx_ckg_sel;
- u32 rg_pll_fbd_div5f;
- u32 rg_pll_fbd_div1f;
- u32 rg_pll_fbd_2p;
- u32 rg_pll_enbwt;
- u32 rg_pll_fbd_p;
- u32 rg_pll_fbd_s;
- u32 rg_pll_pre_div1p;
- u32 rg_pll_pre_p;
- u32 rg_pll_vco_750M;
- u32 rg_pll_lpf_rs;
- u32 rg_pll_lpf_cs;
- u32 phy_clklp2hs_time;
- u32 phy_clkhs2lp_time;
- u32 phy_lp2hs_time;
- u32 phy_hs2lp_time;
- u32 clk_to_data_delay;
- u32 data_to_clk_delay;
- u32 lane_byte_clk_kHz;
- u32 clk_division;
- u32 burst_mode;
-};
-
-struct hisi_dsi {
- struct drm_encoder_slave base;
- struct drm_connector connector;
- struct i2c_client *client;
- struct drm_i2c_encoder_driver *drm_i2c_driver;
- struct clk *dsi_cfg_clk;
- struct videomode vm;
- int nominal_pixel_clock_kHz;
-
- u8 __iomem *reg_base;
- u8 color_mode;
-
- u32 lanes;
- u32 format;
- struct mipi_dsi_phy_register phyreg;
- u32 date_enable_pol;
- u32 vc;
- u32 mode_flags;
-
- bool enable;
-};
-
enum {
DSI_16BITS_1 = 0,
DSI_16BITS_2,
@@ -917,6 +857,16 @@ static void hisi_drm_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("exit success.\n");
}
+static int hisi_dsi_reset(struct drm_encoder *encoder)
+{
+ struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+
+ if (dsi->enable)
+ return mipi_init(dsi);
+
+ return 0;
+}
+
static struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
.dpms = hisi_drm_encoder_dpms,
.mode_fixup = hisi_drm_encoder_mode_fixup,
@@ -1144,6 +1094,7 @@ static int hisi_dsi_probe(struct platform_device *pdev)
dsi->lanes = 3;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ dsi->reset = hisi_dsi_reset;
ret = hisi_drm_encoder_create(dev, dsi);
if (ret) {
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.h b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.h
index e22a64df0a34..6177e789d035 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.h
@@ -12,17 +12,67 @@
#ifndef __HISI_DRM_DSI_H__
#define __HISI_DRM_DSI_H__
-#define outp32(addr, val) writel(val, addr)
-#define outp16(addr, val) writew(val, addr)
-#define outp8(addr, val) writeb(val, addr)
-#define outp(addr, val) outp32(addr, val)
+#define encoder_to_dsi(encoder) \
+ container_of(encoder, struct hisi_dsi, base.base)
-#define inp32(addr) readl(addr)
-#define inp16(addr) readw(addr)
-#define inp8(addr) readb(addr)
-#define inp(addr) inp32(addr)
+struct mipi_dsi_phy_register {
+ u32 clk_t_lpx;
+ u32 clk_t_hs_prepare;
+ u32 clk_t_hs_zero;
+ u32 clk_t_hs_trial;
+ u32 clk_t_wakeup;
+ u32 data_t_lpx;
+ u32 data_t_hs_prepare;
+ u32 data_t_hs_zero;
+ u32 data_t_hs_trial;
+ u32 data_t_ta_go;
+ u32 data_t_ta_get;
+ u32 data_t_wakeup;
+ u32 rg_hstx_ckg_sel;
+ u32 rg_pll_fbd_div5f;
+ u32 rg_pll_fbd_div1f;
+ u32 rg_pll_fbd_2p;
+ u32 rg_pll_enbwt;
+ u32 rg_pll_fbd_p;
+ u32 rg_pll_fbd_s;
+ u32 rg_pll_pre_div1p;
+ u32 rg_pll_pre_p;
+ u32 rg_pll_vco_750M;
+ u32 rg_pll_lpf_rs;
+ u32 rg_pll_lpf_cs;
+ u32 phy_clklp2hs_time;
+ u32 phy_clkhs2lp_time;
+ u32 phy_lp2hs_time;
+ u32 phy_hs2lp_time;
+ u32 clk_to_data_delay;
+ u32 data_to_clk_delay;
+ u32 lane_byte_clk_kHz;
+ u32 clk_division;
+ u32 burst_mode;
+};
+
+struct hisi_dsi {
+ struct drm_encoder_slave base;
+ struct drm_connector connector;
+ struct i2c_client *client;
+ struct drm_i2c_encoder_driver *drm_i2c_driver;
+ struct clk *dsi_cfg_clk;
+ struct videomode vm;
+ int nominal_pixel_clock_kHz;
+
+ u8 __iomem *reg_base;
+ u8 color_mode;
+
+ u32 lanes;
+ u32 format;
+ struct mipi_dsi_phy_register phyreg;
+ u32 date_enable_pol;
+ u32 vc;
+ u32 mode_flags;
+ bool enable;
+
+ /* when detect dsi transfer error call this callback to reset dsi */
+ int (*reset)(struct drm_encoder *encoder);
+};
-extern u8 *reg_base_mipi_dsi;
-extern int hisi_drm_dsi_init(void);
-extern void hisi_drm_dsi_exit(void);
#endif /* __HISI_DRM_DSI_H__ */
diff --git a/drivers/gpu/drm/hisilicon/hisi_mipi_reg.h b/drivers/gpu/drm/hisilicon/hisi_mipi_reg.h
index c8a7365da948..f64892f95fd9 100644
--- a/drivers/gpu/drm/hisilicon/hisi_mipi_reg.h
+++ b/drivers/gpu/drm/hisilicon/hisi_mipi_reg.h
@@ -13,9 +13,18 @@
#ifndef __HISI_MIPI_REG_H__
#define __HISI_MIPI_REG_H__
-#include "hisi_drm_dsi.h"
-
+extern u8 *reg_base_mipi_dsi;
#define get_dsi_virtual_addr() (reg_base_mipi_dsi)
+#define outp32(addr, val) writel(val, addr)
+#define outp16(addr, val) writew(val, addr)
+#define outp8(addr, val) writeb(val, addr)
+#define outp(addr, val) outp32(addr, val)
+
+#define inp32(addr) readl(addr)
+#define inp16(addr) readw(addr)
+#define inp8(addr) readb(addr)
+#define inp(addr) inp32(addr)
+
/* MIPIDSI_OFFSET_2 based on EDC: to be fixed */
#define MIPIDSI_VERSION_ADDR (0x0) /* Version of the DSI host controller */
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 1f8389bd0803..bec2b178919b 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <video/videomode.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
@@ -23,6 +24,7 @@
#include <linux/of_irq.h>
#include "adv7511.h"
+#include "../hisilicon/hisi_drm_dsi.h"
/* uncomment to enable Internal Timing Generator + DE */
//#define ITG
@@ -471,6 +473,8 @@ static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
/* disable internal timing generator */
regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
#endif
+ /* enable DSI RX interrupts */
+ regmap_update_bits(adv7511->regmap_cec, 0x38, BIT(4), BIT(4));
/* enable hdmi */
regmap_write(adv7511->regmap_cec, 0x03, 0x89);
@@ -479,6 +483,7 @@ static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
regmap_write(adv7511->regmap_cec, 0x55, 0x00);
/* deassert DSI reset */
regmap_update_bits(adv7511->regmap, 0x26, BIT(5), 0);
+ regmap_update_bits(adv7511->regmap, 0x26, BIT(5), BIT(5));
/* Black OFF */
regmap_write(adv7511->regmap, 0xd5, 0);
} else {
@@ -516,6 +521,8 @@ static void adv7511_power_on(struct adv7511 *adv7511)
adv7511->powered = true;
+ /* mask non-dsi interrupts */
+ regmap_write(adv7511->regmap, 0x94, 0);
adv7511_dsi_receiver_dpms(adv7511);
}
@@ -557,7 +564,10 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
static int adv7511_irq_process(struct adv7511 *adv7511)
{
- unsigned int irq0, irq1;
+ unsigned int irq0, irq1, state;
+ struct drm_encoder *encoder = adv7511->encoder;
+ struct hisi_dsi *dsi;
+ bool powered = adv7511->powered;
int ret;
ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
@@ -571,8 +581,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
- if (adv7511->encoder && (irq0 & ADV7511_INT0_HDP))
- drm_helper_hpd_irq_event(adv7511->encoder->dev);
+ if (encoder && (irq0 & ADV7511_INT0_HDP))
+ drm_helper_hpd_irq_event(encoder->dev);
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
adv7511->edid_read = true;
@@ -581,6 +591,29 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
wake_up_all(&adv7511->wq);
}
+ /*
+ * reset dsi TX/RX when transfer error
+ */
+ ret = regmap_read(adv7511->regmap_cec, 0x48, &state);
+ if (ret < 0)
+ return ret;
+ if (powered && (!irq1 || state & BIT(2))) {
+ /* only reset onece */
+ regmap_update_bits(adv7511->regmap_cec, 0x38, BIT(4), 0);
+ dsi = encoder_to_dsi(encoder);
+ ret = dsi->reset(encoder);
+ if (ret)
+ DRM_INFO("reset dsi error\n");
+
+ /* toggle to clear other RX interrupt sources */
+ regmap_update_bits(adv7511->regmap_cec, 0x38, BIT(1), BIT(1));
+ regmap_update_bits(adv7511->regmap_cec, 0x38, BIT(1), 0);
+
+ /* deassert DSI reset */
+ regmap_update_bits(adv7511->regmap, 0x26, BIT(5), 0);
+ regmap_update_bits(adv7511->regmap, 0x26, BIT(5), BIT(5));
+ }
+
return 0;
}