diff options
author | Xinliang Liu <xinliang.liu@linaro.org> | 2015-12-21 16:31:50 +0800 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2016-02-02 19:32:28 -0800 |
commit | e718041d13e35f8d0ee162f959a899aa1f6de72c (patch) | |
tree | fdda34290603d7a150a9d051ebac2f48b36e38e5 | |
parent | fdf903e81ea0564f7843c7249f7a7243693fe06d (diff) | |
download | hikey-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.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 71 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hisi_drm_dsi.h | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hisi_mipi_reg.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i2c/adv7511.c | 39 |
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; } |