* [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/Kconfig | 11 ++++++++++ drivers/video/fbdev/Makefile | 1 + drivers/video/fbdev/hisi/Kconfig | 6 +++++ drivers/video/fbdev/hisi/dss/Makefile | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) mode change 100644 => 100755 drivers/video/fbdev/Kconfig mode change 100644 => 100755 drivers/video/fbdev/Makefile create mode 100755 drivers/video/fbdev/hisi/Kconfig create mode 100755 drivers/video/fbdev/hisi/dss/Makefile diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig old mode 100644 new mode 100755 index 5d3b0db5ce0a..85c46cc75908 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2429,6 +2429,16 @@ config FB_HYPERV help This framebuffer driver supports Microsoft Hyper-V Synthetic Video. +config FB_HISI + tristate "Hisilicon Framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select REGMAP + help + This framebuffer driver supports Hisilicon FB. + config FB_SIMPLE bool "Simple framebuffer support" depends on (FB = y) @@ -2448,6 +2458,7 @@ config FB_SIMPLE source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" +source "drivers/video/fbdev/hisi/Kconfig" config FB_SH_MOBILE_MERAM tristate "SuperH Mobile MERAM read ahead support" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile old mode 100644 new mode 100755 index ee8c81405a7f..a10d3d2793e3 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_FB_I740) += i740fb.o obj-$(CONFIG_FB_MATROX) += matrox/ obj-$(CONFIG_FB_RIVA) += riva/ obj-$(CONFIG_FB_NVIDIA) += nvidia/ +obj-$(CONFIG_FB_HISI) += hisi/dss/ obj-$(CONFIG_FB_ATY) += aty/ macmodes.o obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o obj-$(CONFIG_FB_RADEON) += aty/ diff --git a/drivers/video/fbdev/hisi/Kconfig b/drivers/video/fbdev/hisi/Kconfig new file mode 100755 index 000000000000..c30747d52a38 --- /dev/null +++ b/drivers/video/fbdev/hisi/Kconfig @@ -0,0 +1,6 @@ +config HISI_FB_KIRIN960 + tristate "HISI FB KIRIN960 Framebuffer support" + depends on FB_HISI + + help + This framebuffer driver supports KIRIN960 FB. diff --git a/drivers/video/fbdev/hisi/dss/Makefile b/drivers/video/fbdev/hisi/dss/Makefile new file mode 100755 index 000000000000..60004880dd80 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/Makefile @@ -0,0 +1,41 @@ +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) +obj-$(CONFIG_HISI_FB_KIRIN960) := hisifb.o +endif + +hisifb-objs := \ + hisi_mipi_dsi_host.o \ + hisi_mipi_dsi.o \ + hisi_dpe.o \ + hisi_fb_panel.o \ + hisi_fb_isr.o \ + hisi_fb_vsync.o \ + hisi_fb_buf_sync.o \ + hisi_fb_bl.o \ + hisi_fb_utils.o \ + hisi_fb.o \ + hisi_overlay_utils.o \ + hisi_block_algorithm.o \ + hisi_overlay_online.o \ + hisi_overlay_cmdlist_utils.o + +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) +hisifb-objs += \ + hisi_dpe_utils_hi3660.o \ + hisi_overlay_utils_hi3660.o \ + panel/mipi_hikey_nte300nts.o \ + hdmi/adv75xx.o \ + hdmi/mipi_adi_hdmi.o +endif + +EXTRA_CFLAGS += -Idrivers/video/hisi/dss \ + -Idrivers/video/hisi/panel \ + -Idrivers/video/hisi \ + -Iinclude \ + -Idrivers/staging/android + +ifeq ($(CONFIG_HISI_PERIDVFS),y) +EXTRA_CFLAGS += -Idrivers/clk/hisi/peri_dvfs +endif + +clean: + rm *.o .*cmd -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/Kconfig | 11 ++++++++++ drivers/video/fbdev/Makefile | 1 + drivers/video/fbdev/hisi/Kconfig | 6 +++++ drivers/video/fbdev/hisi/dss/Makefile | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) mode change 100644 => 100755 drivers/video/fbdev/Kconfig mode change 100644 => 100755 drivers/video/fbdev/Makefile create mode 100755 drivers/video/fbdev/hisi/Kconfig create mode 100755 drivers/video/fbdev/hisi/dss/Makefile diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig old mode 100644 new mode 100755 index 5d3b0db5ce0a..85c46cc75908 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2429,6 +2429,16 @@ config FB_HYPERV help This framebuffer driver supports Microsoft Hyper-V Synthetic Video. +config FB_HISI + tristate "Hisilicon Framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select REGMAP + help + This framebuffer driver supports Hisilicon FB. + config FB_SIMPLE bool "Simple framebuffer support" depends on (FB = y) @@ -2448,6 +2458,7 @@ config FB_SIMPLE source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" +source "drivers/video/fbdev/hisi/Kconfig" config FB_SH_MOBILE_MERAM tristate "SuperH Mobile MERAM read ahead support" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile old mode 100644 new mode 100755 index ee8c81405a7f..a10d3d2793e3 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_FB_I740) += i740fb.o obj-$(CONFIG_FB_MATROX) += matrox/ obj-$(CONFIG_FB_RIVA) += riva/ obj-$(CONFIG_FB_NVIDIA) += nvidia/ +obj-$(CONFIG_FB_HISI) += hisi/dss/ obj-$(CONFIG_FB_ATY) += aty/ macmodes.o obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o obj-$(CONFIG_FB_RADEON) += aty/ diff --git a/drivers/video/fbdev/hisi/Kconfig b/drivers/video/fbdev/hisi/Kconfig new file mode 100755 index 000000000000..c30747d52a38 --- /dev/null +++ b/drivers/video/fbdev/hisi/Kconfig @@ -0,0 +1,6 @@ +config HISI_FB_KIRIN960 + tristate "HISI FB KIRIN960 Framebuffer support" + depends on FB_HISI + + help + This framebuffer driver supports KIRIN960 FB. diff --git a/drivers/video/fbdev/hisi/dss/Makefile b/drivers/video/fbdev/hisi/dss/Makefile new file mode 100755 index 000000000000..60004880dd80 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/Makefile @@ -0,0 +1,41 @@ +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) +obj-$(CONFIG_HISI_FB_KIRIN960) := hisifb.o +endif + +hisifb-objs := \ + hisi_mipi_dsi_host.o \ + hisi_mipi_dsi.o \ + hisi_dpe.o \ + hisi_fb_panel.o \ + hisi_fb_isr.o \ + hisi_fb_vsync.o \ + hisi_fb_buf_sync.o \ + hisi_fb_bl.o \ + hisi_fb_utils.o \ + hisi_fb.o \ + hisi_overlay_utils.o \ + hisi_block_algorithm.o \ + hisi_overlay_online.o \ + hisi_overlay_cmdlist_utils.o + +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) +hisifb-objs += \ + hisi_dpe_utils_hi3660.o \ + hisi_overlay_utils_hi3660.o \ + panel/mipi_hikey_nte300nts.o \ + hdmi/adv75xx.o \ + hdmi/mipi_adi_hdmi.o +endif + +EXTRA_CFLAGS += -Idrivers/video/hisi/dss \ + -Idrivers/video/hisi/panel \ + -Idrivers/video/hisi \ + -Iinclude \ + -Idrivers/staging/android + +ifeq ($(CONFIG_HISI_PERIDVFS),y) +EXTRA_CFLAGS += -Idrivers/clk/hisi/peri_dvfs +endif + +clean: + rm *.o .*cmd -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c | 1522 ++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h | 496 +++++++ drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c | 310 ++++ drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c | 314 ++++ .../fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c | 525 +++++++ 5 files changed, 3167 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c create mode 100755 drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c new file mode 100755 index 000000000000..328cd6869149 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c @@ -0,0 +1,1522 @@ +/** + * + * + **/ + +#include "adv75xx.h" +#define HPD_ENABLE 0 +/* #define TEST_COLORBAR_DISPLAY */ + +static void adv75xx_power_on(struct adi_hdmi *adv75xx); +static void adv75xx_power_off(struct adi_hdmi *adv75xx); + +/* ADI recommended values for proper operation. */ +static const struct reg_sequence adv7511_fixed_registers[] = { + {0x98, 0x03}, + {0x9a, 0xe0}, + {0x9c, 0x30}, + {0x9d, 0x61}, + {0xa2, 0xa4}, + {0xa3, 0xa4}, + {0xe0, 0xd0}, + {0xf9, 0x00}, + {0x55, 0x02}, +}; + +/* ADI recommended values for proper operation. */ +static const struct reg_sequence adv7533_fixed_registers[] = { + {0x16, 0x20}, + {0x9a, 0xe0}, + {0xba, 0x70}, + {0xde, 0x82}, + {0xe4, 0x40}, + {0xe5, 0x80}, +}; + +static const struct reg_sequence adv7533_cec_fixed_registers[] = { + {0x15, 0xd0}, + {0x17, 0xd0}, + {0x24, 0x20}, + {0x57, 0x11}, + {0x05, 0xc8}, +}; + +/* ----------------------------------------------------------------------------- + * Register access + */ + +static const uint8_t adv75xx_register_defaults[] = { + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ + 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, + 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ + 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, + 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ + 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ + 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ + 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ + 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, + 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, + 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static bool adv7511_register_volatile(struct device *dev, unsigned int reg) +{ + int ret = 0; + + switch (reg) { + case ADV7533_REG_CHIP_REVISION: + case ADV7533_REG_SPDIF_FREQ: + case ADV7533_REG_CTS_AUTOMATIC1: + case ADV7533_REG_CTS_AUTOMATIC2: + case ADV7533_REG_VIC_DETECTED: + case ADV7533_REG_VIC_SEND: + case ADV7533_REG_AUX_VIC_DETECTED: + case ADV7533_REG_STATUS: + case ADV7533_REG_GC(1): + case ADV7533_REG_INT(0): + case ADV7533_REG_INT(1): + case ADV7533_REG_PLL_STATUS: + case ADV7533_REG_AN(0): + case ADV7533_REG_AN(1): + case ADV7533_REG_AN(2): + case ADV7533_REG_AN(3): + case ADV7533_REG_AN(4): + case ADV7533_REG_AN(5): + case ADV7533_REG_AN(6): + case ADV7533_REG_AN(7): + case ADV7533_REG_HDCP_STATUS: + case ADV7533_REG_BCAPS: + case ADV7533_REG_BKSV(0): + case ADV7533_REG_BKSV(1): + case ADV7533_REG_BKSV(2): + case ADV7533_REG_BKSV(3): + case ADV7533_REG_BKSV(4): + case ADV7533_REG_DDC_STATUS: + case ADV7533_REG_BSTATUS(0): + case ADV7533_REG_BSTATUS(1): + case ADV7533_REG_CHIP_ID_HIGH: + case ADV7533_REG_CHIP_ID_LOW: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret ? true : false; +} + +static const struct regmap_config adv75xx_regmap_config = { + .name = "adv75xx", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .reg_defaults_raw = adv75xx_register_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(adv75xx_register_defaults), + .volatile_reg = adv7511_register_volatile, +}; + +static const struct regmap_config adv7533_cec_regmap_config = { + .name = "adv7533_cec", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_config adv7533_packet_regmap_config = { + .name = "adv7533_packet", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +}; + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ +static void adv75xx_set_colormap(struct adi_hdmi *adv75xx, bool enable, + const u16 *coeff, unsigned int scaling_factor) +{ + unsigned int i; + + HISI_FB_INFO("+.\n"); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, ADV7533_CSC_UPDATE_MODE); + + if (enable) { + for (i = 0; i < 12; ++i) { + regmap_update_bits(adv75xx->regmap, + ADV7533_REG_CSC_UPPER(i), + 0x1f, coeff[i] >> 8); + regmap_write(adv75xx->regmap, + ADV7533_REG_CSC_LOWER(i), coeff[i] & 0xff); + } + } + + if (enable) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(0), + 0xe0, 0x80 | (scaling_factor << 5)); + else + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(0), + 0x80, 0x00); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, 0); + + HISI_FB_INFO("-.\n"); +} + +int adv75xx_packet_enable(struct adi_hdmi *adv75xx, unsigned int packet) +{ + HISI_FB_INFO("+.\n"); + + if (packet & 0xff) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE0, + packet, 0xff); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE1, + packet, 0xff); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +int adv75xx_packet_disable(struct adi_hdmi *adv75xx, unsigned int packet) +{ + HISI_FB_INFO("+.\n"); + + if (packet & 0xff) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE0, + packet, 0x00); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE1, + packet, 0x00); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +/* Coefficients for adv75xx color space conversion */ +static const uint16_t adv75xx_csc_ycbcr_to_rgb[] = { + 0x0734, 0x04ad, 0x0000, 0x1c1b, + 0x1ddc, 0x04ad, 0x1f24, 0x0135, + 0x0000, 0x04ad, 0x087c, 0x1b77, +}; + +static void adv75xx_set_config_csc(struct adi_hdmi *adv75xx, bool rgb) +{ + struct adv75xx_video_config config; + bool output_format_422, output_format_ycbcr; + unsigned int mode; + uint8_t infoframe[17]; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->edid) + config.hdmi_mode = true; + else + config.hdmi_mode = false; + + config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; + + HISI_FB_INFO("adv75xx->rgb is %d\n", adv75xx->rgb); + + if (rgb) { + config.csc_enable = false; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } else { + config.csc_scaling_factor = ADV75xx_CSC_SCALING_4; + config.csc_coefficents = adv75xx_csc_ycbcr_to_rgb; + } + + HISI_FB_INFO("config.avi_infoframe.colorspace = %d\n", + config.avi_infoframe.colorspace); + + if (config.hdmi_mode) { + mode = ADV7533_HDMI_CFG_MODE_HDMI; + + switch (config.avi_infoframe.colorspace) { + case HDMI_COLORSPACE_YUV444: + output_format_422 = false; + output_format_ycbcr = true; + break; + case HDMI_COLORSPACE_YUV422: + output_format_422 = true; + output_format_ycbcr = true; + break; + default: + output_format_422 = false; + output_format_ycbcr = false; + break; + } + } else { + mode = ADV7533_HDMI_CFG_MODE_DVI; + output_format_422 = false; + output_format_ycbcr = false; + } + + adv75xx_packet_disable(adv75xx, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); + + adv75xx_set_colormap(adv75xx, config.csc_enable, + config.csc_coefficents, config.csc_scaling_factor); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_VIDEO_INPUT_CFG1, 0x81, + (output_format_422 << 7) | output_format_ycbcr); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_HDCP_HDMI_CFG, + ADV7533_HDMI_CFG_MODE_MASK, mode); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv75xx->regmap, ADV7533_REG_AVI_INFOFRAME_VERSION, + infoframe + 1, sizeof(infoframe) - 1); + + adv75xx_packet_enable(adv75xx, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_dsi_config_tgen(struct adi_hdmi *adv75xx) +{ + u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + HISI_FB_INFO("+.\n"); + + hsw = adv75xx->mode->hsync_pulse_width; + hfp = adv75xx->mode->hsync_offset; + hbp = adv75xx->mode->htotal - adv75xx->mode->hsync_end; + vsw = adv75xx->mode->vsync_pulse_width; + vfp = adv75xx->mode->vsync_offset; + vbp = adv75xx->mode->vtotal - adv75xx->mode->vsync_end; + + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + +#ifdef TEST_COLORBAR_DISPLAY + /* set pixel clock auto mode */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_CEC_PIXEL_CLOCK_DIV, 0x00); +#else + /* set pixel clock divider mode */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_CEC_PIXEL_CLOCK_DIV, + clock_div_by_lanes[adv75xx->num_dsi_lanes - 2] << 3); +#endif + + HISI_FB_INFO("dsi->lanes = %d, htotal = %d, vtotal = %d\n", + adv75xx->num_dsi_lanes, adv75xx->mode->htotal, + adv75xx->mode->vtotal); + + /* horizontal porch params */ + regmap_write(adv75xx->regmap_cec, 0x28, adv75xx->mode->htotal >> 4); + regmap_write(adv75xx->regmap_cec, 0x29, + (adv75xx->mode->htotal << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2a, hsw >> 4); + regmap_write(adv75xx->regmap_cec, 0x2b, (hsw << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2c, hfp >> 4); + regmap_write(adv75xx->regmap_cec, 0x2d, (hfp << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2e, hbp >> 4); + regmap_write(adv75xx->regmap_cec, 0x2f, (hbp << 4) & 0xff); + + /* vertical porch params */ + regmap_write(adv75xx->regmap_cec, 0x30, adv75xx->mode->vtotal >> 4); + regmap_write(adv75xx->regmap_cec, 0x31, + (adv75xx->mode->vtotal << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x32, vsw >> 4); + regmap_write(adv75xx->regmap_cec, 0x33, (vsw << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x34, vfp >> 4); + regmap_write(adv75xx->regmap_cec, 0x35, (vfp << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x36, vbp >> 4); + regmap_write(adv75xx->regmap_cec, 0x37, (vbp << 4) & 0xff); + + /* 30Hz Low Refresh Rate (VIC Detection) */ + + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_dsi_receiver_dpms(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + if (adv75xx->type != ADV7533) + return; + + if (adv75xx->powered) { + adv75xx_dsi_config_tgen(adv75xx); + + /* set number of dsi lanes */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_DSI_DATA_LANES, + adv75xx->num_dsi_lanes << 4); + +#ifdef TEST_COLORBAR_DISPLAY + /* reset internal timing generator */ + regmap_write(adv75xx->regmap_cec, 0x27, 0xcb); + regmap_write(adv75xx->regmap_cec, 0x27, 0x8b); + regmap_write(adv75xx->regmap_cec, 0x27, 0xcb); +#else + /* disable internal timing generator */ + regmap_write(adv75xx->regmap_cec, 0x27, 0x0b); +#endif + + /* 09-03 AVI Infoframe - RGB - 16-9 Aspect Ratio */ + regmap_write(adv75xx->regmap, 0x55, 0x10); + regmap_write(adv75xx->regmap, 0x56, 0x28); + + /* 04-04 GC Packet Enable */ + regmap_write(adv75xx->regmap, 0x40, 0x80); + + /* 04-06 GC Colour Depth - 24 Bit */ + regmap_write(adv75xx->regmap, 0x4c, 0x04); + + /* 04-09 Down Dither Output Colour Depth - 8 Bit (default) */ + regmap_write(adv75xx->regmap, 0x49, 0x00); + + /* 07-01 CEC Power Mode - Always Active */ + regmap_write(adv75xx->regmap_cec, 0xbe, 0x3d); + + /* enable hdmi */ + regmap_write(adv75xx->regmap_cec, 0x03, 0x89); + +#ifdef TEST_COLORBAR_DISPLAY + /*enable test mode */ + regmap_write(adv75xx->regmap_cec, 0x55, 0x80); +#else + /* disable test mode */ + regmap_write(adv75xx->regmap_cec, 0x55, 0x00); +#endif + /* SPD */ + { + static const unsigned char spd_if[] = { + 0x83, 0x01, 25, 0x00, + 'L', 'i', 'n', 'a', 'r', 'o', 0, 0, + '9', '6', 'b', 'o', 'a', 'r', 'd', 's', + ':', 'H', 'i', 'k', 'e', 'y', 0, 0, + }; + int n; + + for (n = 0; n < sizeof(spd_if); n++) + regmap_write(adv75xx->regmap_packet, n, + spd_if[n]); + + /* enable send SPD */ + regmap_update_bits(adv75xx->regmap, 0x40, BIT(6), BIT(6)); + } + + /* force audio */ + /* hide Audio infoframe updates */ + regmap_update_bits(adv75xx->regmap, 0x4a, BIT(5), BIT(5)); + + /* i2s, internal mclk, mclk-256 */ + regmap_update_bits(adv75xx->regmap, 0x0a, 0x1f, 1); + regmap_update_bits(adv75xx->regmap, 0x0b, 0xe0, 0); + /* enable i2s, use i2s format, sample rate from i2s */ + regmap_update_bits(adv75xx->regmap, 0x0c, 0xc7, BIT(2)); + /* 16 bit audio */ + regmap_update_bits(adv75xx->regmap, 0x0d, 0xff, 16); + /* 16-bit audio */ + regmap_update_bits(adv75xx->regmap, 0x14, 0x0f, 2 << 4); + /* 48kHz */ + regmap_update_bits(adv75xx->regmap, 0x15, 0xf0, 2 << 4); + /* enable N/CTS, enable Audio sample packets */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(5), BIT(5)); + /* N = 6144 */ + regmap_write(adv75xx->regmap, 1, (6144 >> 16) & 0xf); + regmap_write(adv75xx->regmap, 2, (6144 >> 8) & 0xff); + regmap_write(adv75xx->regmap, 3, (6144) & 0xff); + /* automatic cts */ + regmap_update_bits(adv75xx->regmap, 0x0a, BIT(7), 0); + /* enable N/CTS */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(6), BIT(6)); + /* not copyrighted */ + regmap_update_bits(adv75xx->regmap, 0x12, BIT(5), BIT(5)); + + /* left source */ + regmap_update_bits(adv75xx->regmap, 0x0e, 7 << 3, 0); + /* right source */ + regmap_update_bits(adv75xx->regmap, 0x0e, 7 << 0, 1); + /* number of channels: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x73, 7, 1); + /* number of channels: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x73, 0xf0, 1 << 4); + /* sample rate: 48kHz */ + regmap_update_bits(adv75xx->regmap, 0x74, 7 << 2, 3 << 2); + /* channel allocation reg: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x76, 0xff, 0); + /* enable audio infoframes */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(3), BIT(3)); + + /* AV mute disable */ + regmap_update_bits(adv75xx->regmap, 0x4b, BIT(7) | BIT(6), BIT(7)); + + /* use Audio infoframe updated info */ + regmap_update_bits(adv75xx->regmap, 0x4a, BIT(5), 0); + } else { + regmap_write(adv75xx->regmap_cec, 0x03, 0x0b); + regmap_write(adv75xx->regmap_cec, 0x27, 0x0b); + } + + HISI_FB_INFO("-.\n"); +} + +/* ----------------------------------------------------------------------------- + * Interrupt and hotplug detection + */ + +#if HPD_ENABLE +static bool adv75xx_hpd(struct adi_hdmi *adv75xx) +{ + unsigned int irq0; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return false; + + HISI_FB_INFO("irq0 = 0x%x\n", irq0); + + if (irq0 & ADV7533_INT0_HDP) { + HISI_FB_INFO("HPD interrupt detected!\n"); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_HDP); + return true; + } + + HISI_FB_INFO("-.\n"); + + return false; +} +#endif + +static int adv75xx_irq_process(struct adi_hdmi *adv75xx, bool process_hpd) +{ + unsigned int irq0, irq1; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return ret; + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(1), &irq1); + if (ret < 0) + return ret; + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), irq0); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), irq1); + + HISI_FB_INFO("adv7511_irq_process --> irq0 = 0x%x \n", irq0); + HISI_FB_INFO("adv7511_irq_process --> irq1 = 0x%x \n", irq1); + + if (irq0 & ADV7533_INT0_EDID_READY || irq1 & ADV7533_INT1_DDC_ERROR) { + adv75xx->edid_read = true; + if (adv75xx->i2c_main->irq) + HISI_FB_INFO("adv7511_irq_process -->get i2c_main irq \n"); + + wake_up_all(&adv75xx->wq); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static irqreturn_t adv75xx_irq_handler(int irq, void *devid) +{ + struct adi_hdmi *adv75xx = devid; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = adv75xx_irq_process(adv75xx, true); + + HISI_FB_INFO("-.\n"); + + return ret < 0 ? IRQ_NONE : IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * EDID retrieval + */ + +static int adv75xx_wait_for_edid(struct adi_hdmi *adv75xx, int timeout) +{ + int ret; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->i2c_main->irq) { + ret = wait_event_interruptible_timeout(adv75xx->wq, + adv75xx->edid_read, + msecs_to_jiffies(timeout)); + } else { + for (; timeout > 0; timeout -= 25) { + ret = adv75xx_irq_process(adv75xx, false); + if (ret < 0) + break; + + if (adv75xx->edid_read) + break; + + msleep(25); + } + } + + HISI_FB_INFO("-.\n"); + + return adv75xx->edid_read ? 0 : -EIO; +} + +static void print_edid_info(u8 *block) +{ + int step, count; + + count = 0x0; + while (count < EDID_LENGTH) { + step = 0; + do { + if (step == 0) { + HISI_FB_INFO("------ edid[%d]: 0x%2x \t", count, + block[count]); + } else { + HISI_FB_INFO(" 0x%2x \t", block[count]); + } + step++; + count++; + } while (step < 8); + + HISI_FB_INFO("\n"); + } +} + +struct hisi_display_mode *hisi_set_mode_info(void) +{ + struct hisi_display_mode *mode; + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + mode = kzalloc(sizeof(struct hisi_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + mode->width_mm = 160 * 100; + mode->height_mm = 90 * 100; + mode->clock = 148500; + mode->hdisplay = 1920; + mode->vdisplay = 1080; + mode->hsync_offset = 88; + mode->hsync_pulse_width = 44; + mode->hsync_start = 2008; + mode->hsync_end = 2052; + mode->htotal = 2200; + + mode->vsync_offset = 4; + mode->vsync_pulse_width = 5; + mode->vsync_start = 1084; + mode->vsync_end = 1089; + mode->vtotal = 1125; + + hsw = mode->hsync_pulse_width; + hfp = mode->hsync_offset; + hbp = mode->htotal - mode->hsync_end; + vsw = mode->vsync_pulse_width; + vfp = mode->vsync_offset; + vbp = mode->vtotal - mode->vsync_end; + + HISI_FB_INFO("The pixel clock is %d!!\n", mode->clock); + HISI_FB_INFO("The resolution is %d x %d !!\n", mode->hdisplay, + mode->vdisplay); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + + + return mode; +} + +struct hisi_display_mode *hisi_parse_edid_base_info(u8 *block) +{ + struct hisi_display_mode *mode; + char edid_vendor[3]; + unsigned hblank; + unsigned vblank; + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + mode = kzalloc(sizeof(struct hisi_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + edid_vendor[0] = ((block[8] & 0x7c) >> 2) + '@'; + edid_vendor[1] = (((block[8] & 0x3) << 3) | + ((block[1] & 0xe0) >> 5)) + '@'; + edid_vendor[2] = (block[9] & 0x1f) + '@'; + + mode->width_mm = block[21] * 100; + mode->height_mm = block[22] * 100; + HISI_FB_INFO("The product vender is %c%c%c !!!\n", edid_vendor[0], + edid_vendor[1], edid_vendor[2]); + HISI_FB_INFO + ("The screen supported max width is %d cm, max height is %d cm !!\n", + block[21], block[22]); + HISI_FB_INFO("The display gamma is %d !!\n", block[23]); + HISI_FB_INFO("The display is RGB or YCbCr is 0x%x !!\n", + (block[24] & 0x18) >> 3); + /******** Detailed Timing Descriptor **********/ + mode->clock = (block[55] << 8 | block[54]) * 10; + mode->hdisplay = ((block[58] & 0xf0) << 4) | block[56]; + hblank = ((block[58] & 0x0f) << 8) | block[57]; + mode->vdisplay = ((block[61] & 0xf0) << 4) | block[59]; + vblank = ((block[61] & 0x0f) << 8) | block[60]; + mode->hsync_offset = block[62]; + mode->hsync_pulse_width = block[63]; + mode->vsync_offset = (block[64] & 0xf0) >> 4; + mode->vsync_pulse_width = block[64] & 0x0f; + + mode->hsync_start = mode->hdisplay + mode->hsync_offset; + mode->hsync_end = mode->hsync_start + mode->hsync_pulse_width; + mode->htotal = mode->hdisplay + hblank; + mode->vsync_start = mode->vdisplay + mode->vsync_offset; + mode->vsync_end = mode->vsync_start + mode->vsync_pulse_width; + mode->vtotal = mode->vdisplay + vblank; + + hsw = mode->hsync_pulse_width; + hfp = mode->hsync_offset; + hbp = mode->htotal - mode->hsync_end; + vsw = mode->vsync_pulse_width; + vfp = mode->vsync_offset; + vbp = mode->vtotal - mode->vsync_end; + + HISI_FB_INFO("The pixel clock is %d!!\n", mode->clock); + HISI_FB_INFO("The resolution is %d x %d !!\n", mode->hdisplay, + mode->vdisplay); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + + + return mode; +} + +static int adv75xx_get_edid_block(void *data, u8 *buf, unsigned int block, + size_t len) +{ + struct adi_hdmi *adv75xx = data; + struct i2c_msg xfer[2]; + uint8_t offset, edid_buf[256]; + unsigned int i; + int ret; + + if (len > EDID_LENGTH) + return -EINVAL; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->current_edid_segment != block) { + unsigned int status; + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_DDC_STATUS, + &status); + if (ret < 0) + return ret; + + if (status != IDLE) { + adv75xx->edid_read = false; + regmap_write(adv75xx->regmap, ADV7533_REG_EDID_SEGMENT, + block); + ret = adv75xx_wait_for_edid(adv75xx, 200); + if (ret < 0) + return ret; + } + + /* Break this apart, hopefully more I2C controllers will + * support 64 byte transfers than 256 byte transfers + */ + + xfer[0].addr = adv75xx->i2c_edid->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = &offset; + xfer[1].addr = adv75xx->i2c_edid->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 64; + xfer[1].buf = edid_buf; + + offset = 0; + + for (i = 0; i < 4; ++i) { + ret = i2c_transfer(adv75xx->i2c_edid->adapter, xfer, + ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + xfer[1].buf += 64; + offset += 64; + } + + adv75xx->current_edid_segment = block; + } + + if (block % 2 == 0) + memcpy(buf, edid_buf, len); + else + memcpy(buf, edid_buf + EDID_LENGTH, len); + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static bool edid_is_zero(const u8 *in_edid, int length) +{ + if (memchr_inv(in_edid, 0, length)) + return false; + + return true; +} + +/** + * hisi_do_get_edid - get EDID data using a custom EDID block read function + * @get_edid_block: EDID block read function + * @data: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *hisi_do_get_edid(int (*get_edid_block) (void *data, u8 *buf, + unsigned int block, + size_t len), void *data) +{ + u8 *block; + bool print_bad_edid = true; + + HISI_FB_INFO("+.\n"); + + if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) + return NULL; + + HISI_FB_INFO("EDID_LENGTH = %d \n", EDID_LENGTH); + /* base block fetch */ + if (get_edid_block(data, block, 0, EDID_LENGTH)) + goto out; + + if (edid_is_zero(block, EDID_LENGTH)) + goto carp; + + HISI_FB_INFO("edid_block read success!!!\n"); + + print_edid_info(block); + + return (struct edid *)block; + + carp: + if (print_bad_edid) + HISI_FB_ERR("EDID block invalid.\n"); + out: + kfree(block); + return NULL; +} + +struct hisi_display_mode *adv75xx_get_modes(struct adi_hdmi *adv75xx) +{ + struct edid *edid; + struct hisi_display_mode *mode; + + HISI_FB_INFO("+.\n"); + + /* Reading the EDID only works if the device is powered */ + if (!adv75xx->powered) { + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_NONE); /* 0xc0 */ + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), + ADV7533_INT1_DDC_ERROR); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); /* 0x41 0x10 */ + + adv75xx->current_edid_segment = -1; + /* wait some time for edid is ready */ + msleep(200); + } + + edid = hisi_do_get_edid(adv75xx_get_edid_block, adv75xx); + + if (!adv75xx->powered) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + + kfree(adv75xx->edid); + adv75xx->edid = edid; + if (!edid) { + HISI_FB_ERR("Fail to get really edid info !!!\n"); + mode = hisi_set_mode_info(); + return mode; + } + + mode = hisi_parse_edid_base_info((u8 *) adv75xx->edid); + + adv75xx_set_config_csc(adv75xx, adv75xx->rgb); + + HISI_FB_INFO("-.\n"); + + return mode; +} + +/*==========================================================*/ +static enum connector_status adv75xx_detect(struct adi_hdmi *adv75xx) +{ + enum connector_status status; + unsigned int val; +#if HPD_ENABLE + bool hpd; +#endif + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_STATUS, &val); + if (ret < 0) { + HISI_FB_INFO("HDMI connector status is disconnected !!!\n"); + return connector_status_disconnected; + } + + if (val & ADV7533_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + +#if HPD_ENABLE + hpd = adv75xx_hpd(adv75xx); + + /* The chip resets itself when the cable is disconnected, so in case + * there is a pending HPD interrupt and the cable is connected there was + * at least one transition from disconnected to connected and the chip + * has to be reinitialized. */ + if (status == connector_status_connected && hpd && adv75xx->powered) { + regcache_mark_dirty(adv75xx->regmap); + adv75xx_power_on(adv75xx); + adv75xx_get_modes(adv75xx); + if (adv75xx->status == connector_status_connected) + status = connector_status_disconnected; + } else { + /* Renable HDP sensing */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_BOTH); + } +#endif + + adv75xx->status = status; + + HISI_FB_INFO("adv7511->status = %d <1-connected,2-disconnected>\n", + status); + HISI_FB_INFO("-.\n"); + + return status; +} + +/** + * mode_vrefresh - get the vrefresh of a mode + * @mode: mode + * + * Returns: + * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the + * value first if it is not yet set. + */ +static int mode_vrefresh(const struct hisi_display_mode *mode) +{ + int refresh = 0; + unsigned int calc_val; + + if (mode->vrefresh > 0) + refresh = mode->vrefresh; + else if (mode->htotal > 0 && mode->vtotal > 0) { + int vtotal; + vtotal = mode->vtotal; + /* work out vrefresh the value will be x1000 */ + calc_val = (mode->clock * 1000); + calc_val /= mode->htotal; + refresh = (calc_val + vtotal / 2) / vtotal; + } + return refresh; +} + +static int adv75xx_mode_valid(struct hisi_display_mode *mode) +{ + if (NULL == mode) { + HISI_FB_ERR("mode is null\n"); + return MODE_NOMODE; + } + + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + /* + * some work well modes which want to put in the front of the mode list. + */ + HISI_FB_INFO("Checking mode %ix%i@%i clock: %i...", + mode->hdisplay, mode->vdisplay, mode_vrefresh(mode), + mode->clock); + if ((mode->hdisplay == 1920 && mode->vdisplay == 1080 + && mode->clock == 148500) + || (mode->hdisplay == 1280 && mode->vdisplay == 800 + && mode->clock == 83496) + || (mode->hdisplay == 1280 && mode->vdisplay == 720 + && mode->clock == 74440) + || (mode->hdisplay == 1280 && mode->vdisplay == 720 + && mode->clock == 74250) + || (mode->hdisplay == 1024 && mode->vdisplay == 768 + && mode->clock == 75000) + || (mode->hdisplay == 1024 && mode->vdisplay == 768 + && mode->clock == 81833) + || (mode->hdisplay == 800 && mode->vdisplay == 600 + && mode->clock == 40000)) { + HISI_FB_INFO("OK\n"); + return MODE_OK; + } + HISI_FB_INFO("BAD\n"); + + return MODE_BAD; +} + +static void adv75xx_mode_set(struct adi_hdmi *adv75xx, + struct hisi_display_mode *mode) +{ + unsigned int low_refresh_rate; + unsigned int hsync_polarity = 0; + unsigned int vsync_polarity = 0; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->embedded_sync) { + unsigned int hsync_offset, hsync_len; + unsigned int vsync_offset, vsync_len; + + hsync_offset = mode->hsync_offset; + vsync_offset = mode->vsync_offset; + hsync_len = mode->hsync_end - mode->hsync_start; + vsync_len = mode->vsync_end - mode->vsync_start; + + /* The hardware vsync generator has a off-by-one bug */ + vsync_offset += 1; + + regmap_write(adv75xx->regmap, ADV7533_REG_HSYNC_PLACEMENT_MSB, + ((hsync_offset >> 10) & 0x7) << 5); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(0), + (hsync_offset >> 2) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(1), + ((hsync_offset & 0x3) << 6) | + ((hsync_len >> 4) & 0x3f)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(2), + ((hsync_len & 0xf) << 4) | + ((vsync_offset >> 6) & 0xf)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(3), + ((vsync_offset & 0x3f) << 2) | + ((vsync_len >> 8) & 0x3)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(4), + vsync_len & 0xff); + + hsync_polarity = !(mode->flags & MODE_FLAG_PHSYNC); + vsync_polarity = !(mode->flags & MODE_FLAG_PVSYNC); + } else { + /** + * If the input signal is always low or always high we want to + * invert or let it passthrough depending on the polarity of the + * current mode. + **/ + adv75xx->hsync_polarity = ADV7533_SYNC_POLARITY_PASSTHROUGH; + adv75xx->vsync_polarity = ADV7533_SYNC_POLARITY_PASSTHROUGH; + + hsync_polarity = adv75xx->hsync_polarity; + vsync_polarity = adv75xx->vsync_polarity; + } + mode->vrefresh = mode_vrefresh(mode); + HISI_FB_INFO("hsync_polarity = %d; vsync_polarity = %d\n", + hsync_polarity, vsync_polarity); + HISI_FB_INFO("mode->vrefresh = %d \n", mode->vrefresh); + + if (mode->vrefresh <= 24000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_24HZ; + else if (mode->vrefresh <= 25000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_25HZ; + else if (mode->vrefresh <= 30000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_30HZ; + else + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_NONE; + + HISI_FB_INFO("low_refresh_rate = %d \n", low_refresh_rate); + + regmap_update_bits(adv75xx->regmap, 0xfb, 0x6, low_refresh_rate << 1); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_SYNC_POLARITY, + 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); + + /* + * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is + * supposed to give better results. + */ + + adv75xx->f_tmds = mode->clock; + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_power_on(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + adv75xx->current_edid_segment = -1; + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), + ADV7533_INT1_DDC_ERROR); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); + + /* + * Per spec it is allowed to pulse the HDP signal to indicate that the + * EDID information has changed. Some monitors do this when they wakeup + * from standby or are enabled. When the HDP goes low the adv7511 is + * reset and the outputs are disabled which might cause the monitor to + * go to standby again. To avoid this we ignore the HDP pin for the + * first few seconds after enabling the output. + */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_NONE); + + /* + * Most of the registers are reset during power down or when HPD is low. + */ + regcache_sync(adv75xx->regmap); + + regmap_register_patch(adv75xx->regmap_cec, + adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + adv75xx->powered = true; + + adv75xx_dsi_receiver_dpms(adv75xx); + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_power_off(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + /* TODO: setup additional power down modes */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + regcache_mark_dirty(adv75xx->regmap); + + adv75xx->powered = false; + + adv75xx_dsi_receiver_dpms(adv75xx); + + HISI_FB_INFO("-.\n"); +} + +/* =========================================================*/ +static int adv7533_init_regulators(struct adi_hdmi *adv75xx) +{ + int ret; + struct device *dev = &adv75xx->i2c_main->dev; + + adv75xx->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(adv75xx->vdd)) { + ret = PTR_ERR(adv75xx->vdd); + dev_err(dev, "failed to get vdd regulator %d\n", ret); + return ret; + } + + adv75xx->v1p2 = devm_regulator_get(dev, "v1p2"); + if (IS_ERR(adv75xx->v1p2)) { + ret = PTR_ERR(adv75xx->v1p2); + dev_err(dev, "failed to get v1p2 regulator %d\n", ret); + return ret; + } + + ret = regulator_set_voltage(adv75xx->vdd, 1800000, 1800000); + if (ret) { + dev_err(dev, "failed to set avdd voltage %d\n", ret); + return ret; + } + + ret = regulator_set_voltage(adv75xx->v1p2, 1200000, 1200000); + if (ret) { + dev_err(dev, "failed to set v1p2 voltage %d\n", ret); + return ret; + } + + /* keep the regulators always on */ + ret = regulator_enable(adv75xx->vdd); + if (ret) { + dev_err(dev, "failed to enable vdd %d\n", ret); + return ret; + } + + ret = regulator_enable(adv75xx->v1p2); + if (ret) { + dev_err(dev, "failed to enable v1p2 %d\n", ret); + return ret; + } + + return 0; +} + +static int adv7533_parse_dt(struct device_node *np, struct adi_hdmi *adv75xx) +{ + int ret; + u32 num_lanes; + + ret = of_property_read_u32(np, "adi,dsi-lanes", &num_lanes); + if (ret) { + HISI_FB_WARNING("get 'adi,dsi-lanes' resource failed!\n"); + return ret; + } + + if (num_lanes < 1 || num_lanes > 4) + return -EINVAL; + + adv75xx->num_dsi_lanes = num_lanes; + + /* TODO: Check if these need to be parsed by DT or not */ + adv75xx->rgb = true; + adv75xx->embedded_sync = false; + + return 0; +} + +static const int edid_i2c_addr = 0x7e; +static const int packet_i2c_addr = 0x70; +static const int cec_i2c_addr = 0x78; + +static const struct of_device_id adv75xx_of_ids[] = { + {.compatible = "adi,adv7511", .data = (void *)ADV7511}, + {.compatible = "adi,adv7511w", .data = (void *)ADV7511}, + {.compatible = "adi,adv7513", .data = (void *)ADV7511}, + {.compatible = "adi,adv7533", .data = (void *)ADV7533}, + {}, +}; + +MODULE_DEVICE_TABLE(of, adv75xx_of_ids); + +static const struct i2c_device_id adv75xx_i2c_ids[] = { + {"adv7511", ADV7511}, + {"adv7511w", ADV7511}, + {"adv7513", ADV7511}, + {"adv7533", ADV7533}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, adv75xx_i2c_ids); + +static struct adi_operation_funcs opt_funcs = { + .power_on = adv75xx_power_on, + .power_off = adv75xx_power_off, + .mode_set = adv75xx_mode_set, +}; + +static int adv75xx_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct adi_hdmi *adv75xx; + struct device *dev = &i2c->dev; + enum connector_status status; + struct hisi_display_mode *mode; + struct platform_device *hdmi_pdev = NULL; + unsigned int val; + int ret; + + if (!dev) { + HISI_FB_ERR("dev is NULL!\n"); + return -ENOMEM; + } + + adv75xx = devm_kzalloc(dev, sizeof(struct adi_hdmi), GFP_KERNEL); + if (!adv75xx) { + HISI_FB_ERR("adv75xx alloc failed!\n"); + return -ENOMEM; + } + adv75xx->powered = false; + adv75xx->status = connector_status_disconnected; + + if (dev->of_node) { + const struct of_device_id *of_id; + + of_id = of_match_node(adv75xx_of_ids, dev->of_node); + adv75xx->type = (enum adv75xx_type)of_id->data; + } else { + adv75xx->type = ADV7533; + } + + ret = adv7533_parse_dt(dev->of_node, adv75xx); + if (ret) { + HISI_FB_ERR("parse dts error!\n"); + goto err_return; + } + + adv75xx->i2c_main = i2c; + + if (adv75xx->type == ADV7533) { + ret = adv7533_init_regulators(adv75xx); /* adv7533 vdd--1.8v v1p2--1.2v */ + if (ret) + return ret; + } + + /* + * The power down GPIO is optional. If present, toggle it from active(1) to + * inactive(0) to wake up the encoder. + */ + adv75xx->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(adv75xx->gpio_pd)) { + HISI_FB_ERR("get gpio pd error!\n"); + return PTR_ERR(adv75xx->gpio_pd); + } + HISI_FB_INFO("adv75xx->gpio_pd = %s!\n", adv75xx->gpio_pd->label); + + if (adv75xx->gpio_pd) { + mdelay(5); + gpiod_set_value_cansleep(adv75xx->gpio_pd, 0); + } + + adv75xx->regmap = devm_regmap_init_i2c(i2c, &adv75xx_regmap_config); + if (IS_ERR(adv75xx->regmap)) { + HISI_FB_ERR("regmap init i2c failed!\n"); + return PTR_ERR(adv75xx->regmap); + } + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_CHIP_REVISION, &val); + if (ret) { + HISI_FB_ERR("regmap read failed, ret = %d!\n", ret); + goto err_return; + } + /* the corect val is 20. */ + HISI_FB_INFO("%s of the Chip reversion is %d\n", dev_name(dev), val); + dev_err(dev, "Rev. %d\n", val); + + ret = regmap_register_patch(adv75xx->regmap, + adv7533_fixed_registers, + ARRAY_SIZE(adv7533_fixed_registers)); + if (ret) { + HISI_FB_ERR("regmap register failed!\n"); + goto err_return; + } + + regmap_write(adv75xx->regmap, ADV7533_REG_EDID_I2C_ADDR, edid_i2c_addr); + regmap_write(adv75xx->regmap, ADV7533_REG_PACKET_I2C_ADDR, + packet_i2c_addr); + regmap_write(adv75xx->regmap, ADV7533_REG_CEC_I2C_ADDR, cec_i2c_addr); + adv75xx_packet_disable(adv75xx, 0xffff); + + adv75xx->i2c_packet = i2c_new_dummy(i2c->adapter, packet_i2c_addr >> 1); + if (!adv75xx->i2c_packet) { + HISI_FB_ERR("i2c_new_dummy i2c_packet failed!\n"); + return -ENOMEM; + } + + adv75xx->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); + if (!adv75xx->i2c_edid) { + HISI_FB_ERR("i2c_new_dummy i2c_edid failed!\n"); + goto err_i2c_unregister_packet; + } + + adv75xx->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1); + if (!adv75xx->i2c_cec) { + ret = -ENOMEM; + HISI_FB_ERR("i2c_new_dummy i2c_cec failed!\n"); + goto err_i2c_unregister_edid; + } + + adv75xx->regmap_cec = devm_regmap_init_i2c(adv75xx->i2c_cec, + &adv7533_cec_regmap_config); + if (IS_ERR(adv75xx->regmap_cec)) { + ret = PTR_ERR(adv75xx->regmap_cec); + HISI_FB_ERR("devm_regmap_init_i2c regmap_cec failed!\n"); + goto err_i2c_unregister_cec; + } + + adv75xx->regmap_packet = devm_regmap_init_i2c(adv75xx->i2c_packet, + &adv7533_packet_regmap_config); + if (IS_ERR(adv75xx->regmap_packet)) { + ret = PTR_ERR(adv75xx->regmap_packet); + HISI_FB_ERR("devm_regmap_init_i2c regmap_packet failed!\n"); + goto err_i2c_unregister_cec; + } + + if (adv75xx->type == ADV7533) { + ret = regmap_register_patch(adv75xx->regmap_cec, + adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + if (ret) { + HISI_FB_ERR + ("regmap_register_patch cec_fixed_registers failed!\n"); + goto err_return; + } + } + + HISI_FB_INFO("i2c->irq = %d!\n", i2c->irq); + if (i2c->irq) { + init_waitqueue_head(&adv75xx->wq); + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, + adv75xx_irq_handler, + IRQF_ONESHOT, dev_name(dev), adv75xx); + if (ret) { + HISI_FB_ERR("adv7511_irq_handler registers failed!\n"); + goto err_i2c_unregister_cec; + } + } + + /* CEC is unused for now */ + regmap_write(adv75xx->regmap, ADV7533_REG_CEC_CTRL, + ADV7533_CEC_CTRL_POWER_DOWN); + + adv75xx_power_off(adv75xx); + + i2c_set_clientdata(i2c, adv75xx); + + /* adv7511_audio_init(dev); */ + status = adv75xx_detect(adv75xx); + if (status != connector_status_connected) { + HISI_FB_ERR("adv75xx connector not connected !\n"); + } + + mode = adv75xx_get_modes(adv75xx); + + ret = adv75xx_mode_valid(mode); + if (ret) { + HISI_FB_ERR("adv75xx not supported this mode !!\n"); + kfree(mode); + mode = hisi_set_mode_info(); + } + adv75xx->mode = mode; + adv75xx->opt_funcs = &opt_funcs; + + hdmi_pdev = + platform_device_alloc("adi_hdmi", + (((uint32_t) PANEL_MIPI_VIDEO << 16) | + (uint32_t) 1)); + if (hdmi_pdev) { + if (platform_device_add_data + (hdmi_pdev, adv75xx, sizeof(struct adi_hdmi))) { + HISI_FB_ERR("failed to platform_device_add_data!\n"); + platform_device_put(hdmi_pdev); + } + } + HISI_FB_INFO("platform_device_add_data ok !\n"); + + /* set driver data */ + platform_set_drvdata(hdmi_pdev, adv75xx); + if (platform_device_add(hdmi_pdev)) { + HISI_FB_ERR("platform_device_add failed!\n"); + goto err_device_put; + } + + return 0; + + err_i2c_unregister_cec: + i2c_unregister_device(adv75xx->i2c_cec); + err_i2c_unregister_edid: + i2c_unregister_device(adv75xx->i2c_edid); + err_i2c_unregister_packet: + i2c_unregister_device(adv75xx->i2c_packet); + err_device_put: + platform_device_put(hdmi_pdev); + err_return: + kfree(adv75xx); + return ret; +} + +static int adv75xx_remove(struct i2c_client *i2c) +{ + struct adi_hdmi *adv75xx = i2c_get_clientdata(i2c); + + i2c_unregister_device(adv75xx->i2c_cec); + i2c_unregister_device(adv75xx->i2c_edid); + + kfree(adv75xx->edid); + kfree(adv75xx->mode); + kfree(adv75xx); + + return 0; +} + +static struct i2c_driver adv75xx_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv75xx", + .of_match_table = adv75xx_of_ids, + }, + .id_table = adv75xx_i2c_ids, + .probe = adv75xx_probe, + .remove = adv75xx_remove, +}; + +static int __init adv75xx_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&adv75xx_driver); + if (ret) { + HISI_FB_ERR("i2c_add_driver error!\n"); + } + return ret; +} + +module_init(adv75xx_init); + +static void __exit adv75xx_exit(void) +{ + i2c_del_driver(&adv75xx_driver); +} + +module_exit(adv75xx_exit); + +MODULE_AUTHOR("Hisilicon Inc"); +MODULE_DESCRIPTION("ADV75XX HDMI transmitter driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h new file mode 100755 index 000000000000..d2f84d846271 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h @@ -0,0 +1,496 @@ +/** + * + * + **/ + +#ifndef __ADV75XX_H__ +#define __ADV75XX_H__ +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/hdmi.h> + +#include "../hisi_fb.h" + +#define DISPLAY_MODE_LEN 32 + +#define ADV7533_REG_CHIP_REVISION 0x00 +#define ADV7533_REG_N0 0x01 +#define ADV7533_REG_N1 0x02 +#define ADV7533_REG_N2 0x03 +#define ADV7533_REG_SPDIF_FREQ 0x04 +#define ADV7533_REG_CTS_AUTOMATIC1 0x05 +#define ADV7533_REG_CTS_AUTOMATIC2 0x06 +#define ADV7533_REG_CTS_MANUAL0 0x07 +#define ADV7533_REG_CTS_MANUAL1 0x08 +#define ADV7533_REG_CTS_MANUAL2 0x09 +#define ADV7533_REG_AUDIO_SOURCE 0x0a +#define ADV7533_REG_AUDIO_CONFIG 0x0b +#define ADV7533_REG_I2S_CONFIG 0x0c +#define ADV7533_REG_I2S_WIDTH 0x0d +#define ADV7533_REG_AUDIO_SUB_SRC0 0x0e +#define ADV7533_REG_AUDIO_SUB_SRC1 0x0f +#define ADV7533_REG_AUDIO_SUB_SRC2 0x10 +#define ADV7533_REG_AUDIO_SUB_SRC3 0x11 +#define ADV7533_REG_AUDIO_CFG1 0x12 +#define ADV7533_REG_AUDIO_CFG2 0x13 +#define ADV7533_REG_AUDIO_CFG3 0x14 +#define ADV7533_REG_I2C_FREQ_ID_CFG 0x15 +#define ADV7533_REG_VIDEO_INPUT_CFG1 0x16 +#define ADV7533_REG_CEC_PIXEL_CLOCK_DIV 0x16 +#define ADV7533_REG_SYNC_POLARITY 0x17 +#define ADV7533_REG_DSI_DATA_LANES 0x1c +#define ADV7533_REG_CSC_UPPER(x) (0x18 + (x) * 2) +#define ADV7533_REG_CSC_LOWER(x) (0x19 + (x) * 2) +#define ADV7533_REG_SYNC_DECODER(x) (0x30 + (x)) +#define ADV7533_REG_DE_GENERATOR (0x35 + (x)) +#define ADV7533_REG_PIXEL_REPETITION 0x3b +#define ADV7533_REG_VIC_MANUAL 0x3c +#define ADV7533_REG_VIC_SEND 0x3d +#define ADV7533_REG_VIC_DETECTED 0x3e +#define ADV7533_REG_AUX_VIC_DETECTED 0x3f +#define ADV7533_REG_PACKET_ENABLE0 0x40 +#define ADV7533_REG_POWER 0x41 +#define ADV7533_REG_STATUS 0x42 +#define ADV7533_REG_EDID_I2C_ADDR 0x43 +#define ADV7533_REG_PACKET_ENABLE1 0x44 +#define ADV7533_REG_PACKET_I2C_ADDR 0x45 +#define ADV7533_REG_DSD_ENABLE 0x46 +#define ADV7533_REG_VIDEO_INPUT_CFG2 0x48 +#define ADV7533_REG_INFOFRAME_UPDATE 0x4a +#define ADV7533_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ +#define ADV7533_REG_AVI_INFOFRAME_VERSION 0x52 +#define ADV7533_REG_AVI_INFOFRAME_LENGTH 0x53 +#define ADV7533_REG_AVI_INFOFRAME_CHECKSUM 0x54 +#define ADV7533_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ +#define ADV7533_REG_AUDIO_INFOFRAME_VERSION 0x70 +#define ADV7533_REG_AUDIO_INFOFRAME_LENGTH 0x71 +#define ADV7533_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 +#define ADV7533_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ +#define ADV7533_REG_INT_ENABLE(x) (0x94 + (x)) +#define ADV7533_REG_INT(x) (0x96 + (x)) +#define ADV7533_REG_INPUT_CLK_DIV 0x9d +#define ADV7533_REG_PLL_STATUS 0x9e +#define ADV7533_REG_HDMI_POWER 0xa1 +#define ADV7533_REG_HDCP_HDMI_CFG 0xaf +#define ADV7533_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ +#define ADV7533_REG_HDCP_STATUS 0xb8 +#define ADV7533_REG_BCAPS 0xbe +#define ADV7533_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ +#define ADV7533_REG_EDID_SEGMENT 0xc4 +#define ADV7533_REG_DDC_STATUS 0xc8 +#define ADV7533_REG_EDID_READ_CTRL 0xc9 +#define ADV7533_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ +#define ADV7533_REG_TIMING_GEN_SEQ 0xd0 +#define ADV7533_REG_POWER2 0xd6 +#define ADV7533_REG_HSYNC_PLACEMENT_MSB 0xfa + +#define ADV7533_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ +#define ADV7533_REG_TMDS_CLOCK_INV 0xde +#define ADV7533_REG_ARC_CTRL 0xdf +#define ADV7533_REG_CEC_I2C_ADDR 0xe1 +#define ADV7533_REG_CEC_CTRL 0xe2 +#define ADV7533_REG_CHIP_ID_HIGH 0xf5 +#define ADV7533_REG_CHIP_ID_LOW 0xf6 + +#define ADV7533_CSC_ENABLE BIT(7) +#define ADV7533_CSC_UPDATE_MODE BIT(5) + +#define ADV7533_INT0_HDP BIT(7) +#define ADV7533_INT0_VSYNC BIT(5) +#define ADV7533_INT0_AUDIO_FIFO_FULL BIT(4) +#define ADV7533_INT0_EDID_READY BIT(2) +#define ADV7533_INT0_HDCP_AUTHENTICATED BIT(1) + +#define ADV7533_INT1_DDC_ERROR BIT(7) +#define ADV7533_INT1_BKSV BIT(6) +#define ADV7533_INT1_CEC_TX_READY BIT(5) +#define ADV7533_INT1_CEC_TX_ARBIT_LOST BIT(4) +#define ADV7533_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) +#define ADV7533_INT1_CEC_RX_READY3 BIT(2) +#define ADV7533_INT1_CEC_RX_READY2 BIT(1) +#define ADV7533_INT1_CEC_RX_READY1 BIT(0) + +#define ADV7533_ARC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_CEC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_POWER_POWER_DOWN BIT(6) + +#define ADV7533_HDMI_CFG_MODE_MASK 0x2 +#define ADV7533_HDMI_CFG_MODE_DVI 0x0 +#define ADV7533_HDMI_CFG_MODE_HDMI 0x2 + +#define ADV7533_AUDIO_SELECT_I2C 0x0 +#define ADV7533_AUDIO_SELECT_SPDIF 0x1 +#define ADV7533_AUDIO_SELECT_DSD 0x2 +#define ADV7533_AUDIO_SELECT_HBR 0x3 +#define ADV7533_AUDIO_SELECT_DST 0x4 + +#define ADV7533_I2S_SAMPLE_LEN_16 0x2 +#define ADV7533_I2S_SAMPLE_LEN_20 0x3 +#define ADV7533_I2S_SAMPLE_LEN_18 0x4 +#define ADV7533_I2S_SAMPLE_LEN_22 0x5 +#define ADV7533_I2S_SAMPLE_LEN_19 0x8 +#define ADV7533_I2S_SAMPLE_LEN_23 0x9 +#define ADV7533_I2S_SAMPLE_LEN_24 0xb +#define ADV7533_I2S_SAMPLE_LEN_17 0xc +#define ADV7533_I2S_SAMPLE_LEN_21 0xd + +#define ADV7533_SAMPLE_FREQ_44100 0x0 +#define ADV7533_SAMPLE_FREQ_48000 0x2 +#define ADV7533_SAMPLE_FREQ_32000 0x3 +#define ADV7533_SAMPLE_FREQ_88200 0x8 +#define ADV7533_SAMPLE_FREQ_96000 0xa +#define ADV7533_SAMPLE_FREQ_176400 0xc +#define ADV7533_SAMPLE_FREQ_192000 0xe + +#define ADV7533_STATUS_POWER_DOWN_POLARITY BIT(7) +#define ADV7533_STATUS_HPD BIT(6) +#define ADV7533_STATUS_MONITOR_SENSE BIT(5) +#define ADV7533_STATUS_I2S_32BIT_MODE BIT(3) + +#define ADV7533_PACKET_ENABLE_N_CTS BIT(8+6) +#define ADV7533_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) +#define ADV7533_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) +#define ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) +#define ADV7533_PACKET_ENABLE_GC BIT(7) +#define ADV7533_PACKET_ENABLE_SPD BIT(6) +#define ADV7533_PACKET_ENABLE_MPEG BIT(5) +#define ADV7533_PACKET_ENABLE_ACP BIT(4) +#define ADV7533_PACKET_ENABLE_ISRC BIT(3) +#define ADV7533_PACKET_ENABLE_GM BIT(2) +#define ADV7533_PACKET_ENABLE_SPARE2 BIT(1) +#define ADV7533_PACKET_ENABLE_SPARE1 BIT(0) + +#define ADV7533_REG_POWER2_HDP_SRC_MASK 0xc0 +#define ADV7533_REG_POWER2_HDP_SRC_BOTH 0x00 +#define ADV7533_REG_POWER2_HDP_SRC_HDP 0x40 +#define ADV7533_REG_POWER2_HDP_SRC_CEC 0x80 +#define ADV7533_REG_POWER2_HDP_SRC_NONE 0xc0 +#define ADV7533_REG_POWER2_TDMS_ENABLE BIT(4) +#define ADV7533_REG_POWER2_GATE_INPUT_CLK BIT(0) + +#define ADV7533_LOW_REFRESH_RATE_NONE 0x0 +#define ADV7533_LOW_REFRESH_RATE_24HZ 0x1 +#define ADV7533_LOW_REFRESH_RATE_25HZ 0x2 +#define ADV7533_LOW_REFRESH_RATE_30HZ 0x3 + +#define ADV7533_AUDIO_CFG3_LEN_MASK 0x0f +#define ADV7533_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 + +#define ADV7533_AUDIO_SOURCE_I2S 0 +#define ADV7533_AUDIO_SOURCE_SPDIF 1 + +#define ADV7533_I2S_FORMAT_I2S 0 +#define ADV7533_I2S_FORMAT_RIGHT_J 1 +#define ADV7533_I2S_FORMAT_LEFT_J 2 + +#define ADV7533_PACKET(p, x) ((p) * 0x20 + (x)) +#define ADV7533_PACKET_SDP(x) ADV7533_PACKET(0, x) +#define ADV7533_PACKET_MPEG(x) ADV7533_PACKET(1, x) +#define ADV7533_PACKET_ACP(x) ADV7533_PACKET(2, x) +#define ADV7533_PACKET_ISRC1(x) ADV7533_PACKET(3, x) +#define ADV7533_PACKET_ISRC2(x) ADV7533_PACKET(4, x) +#define ADV7533_PACKET_GM(x) ADV7533_PACKET(5, x) +#define ADV7533_PACKET_SPARE(x) ADV7533_PACKET(6, x) + +#define EDID_LENGTH 0x80 +#define EDID_EXTENSION_NUM 0x7e + +/* Video mode flags */ +/* bit compatible with the xorg definitions. */ +#define MODE_FLAG_PHSYNC (1<<0) +#define MODE_FLAG_NHSYNC (1<<1) +#define MODE_FLAG_PVSYNC (1<<2) +#define MODE_FLAG_NVSYNC (1<<3) +#define MODE_FLAG_INTERLACE (1<<4) +#define MODE_FLAG_DBLSCAN (1<<5) +#define MODE_FLAG_CSYNC (1<<6) +#define MODE_FLAG_PCSYNC (1<<7) +#define MODE_FLAG_NCSYNC (1<<8) +#define MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define MODE_FLAG_BCAST (1<<10) +#define MODE_FLAG_PIXMUX (1<<11) +#define MODE_FLAG_DBLCLK (1<<12) +#define MODE_FLAG_CLKDIV2 (1<<13) + +/* + * Note on terminology: here, for brevity and convenience, we refer to connector + * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, + * DVI, etc. And 'screen' refers to the whole of the visible display, which + * may span multiple monitors (and therefore multiple CRTC and connector + * structures). + */ + +enum mode_status { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a matching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_NO_STEREO, /* stereo modes not supported */ + MODE_UNVERIFIED = -3, /* mode needs to reverified */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +}; + +enum DDC_controller_status { + IN_RESET = 0, /* In Reset (No Hot Plug Detected) */ + READING_EDID, /* Reading EDID */ + IDLE, /* IDLE (Waiting for HDCP Requested) */ + INIT_HDCP, /* Initializing HDCP */ + HDCP_ENABLE, /* HDCP Enabled */ + INIT_HDCP_REPEAT /* Initializing HDCP Repeater */ +}; + +/* If detailed data is pixel timing */ +struct detailed_pixel_timing { + u8 hactive_lo; + u8 hblank_lo; + u8 hactive_hblank_hi; + u8 vactive_lo; + u8 vblank_lo; + u8 vactive_vblank_hi; + u8 hsync_offset_lo; + u8 hsync_pulse_width_lo; + u8 vsync_offset_pulse_width_lo; + u8 hsync_vsync_offset_pulse_width_hi; + u8 width_mm_lo; + u8 height_mm_lo; + u8 width_height_mm_hi; + u8 hborder; + u8 vborder; + u8 misc; +} __attribute__ ((packed)); + +struct est_timings { + u8 t1; + u8 t2; + u8 mfg_rsvd; +} __attribute__ ((packed)); + +struct std_timing { + u8 hsize; /* need to multiply by 8 then add 248 */ + u8 vfreq_aspect; +} __attribute__ ((packed)); + +struct detailed_timing { + __le16 pixel_clock; /* need to multiply by 10 KHz */ + union { + struct detailed_pixel_timing pixel_data; + /* struct detailed_non_pixel other_data;*/ + } data; +} __attribute__ ((packed)); + +struct edid { + u8 header[8]; + /* Vendor & product info */ + u8 mfg_id[2]; + u8 prod_code[2]; + u32 serial; /* FIXME: byte order */ + u8 mfg_week; + u8 mfg_year; + /* EDID version */ + u8 version; + u8 revision; + /* Display info: */ + u8 input; + u8 width_cm; + u8 height_cm; + u8 gamma; + u8 features; + /* Color characteristics */ + u8 red_green_lo; + u8 black_white_lo; + u8 red_x; + u8 red_y; + u8 green_x; + u8 green_y; + u8 blue_x; + u8 blue_y; + u8 white_x; + u8 white_y; + /* Est. timings and mfg rsvd timings */ + struct est_timings established_timings; + /* Standard timings 1-8 */ + struct std_timing standard_timings[8]; + /* Detailing timings 1-4 */ + struct detailed_timing detailed_timings[4]; + /* Number of 128 byte ext. blocks */ + u8 extensions; + /* Checksum */ + u8 checksum; +} __attribute__ ((packed)); + +/** + * enum adv75xx_csc_scaling - Scaling factor for the ADV75xx CSC + * @ADV75xx_CSC_SCALING_1: CSC results are not scaled + * @ADV75xx_CSC_SCALING_2: CSC results are scaled by a factor of two + * @ADV75xx_CSC_SCALING_4: CSC results are scalled by a factor of four + */ +enum adv75xx_csc_scaling { + ADV75xx_CSC_SCALING_1 = 0, + ADV75xx_CSC_SCALING_2 = 1, + ADV75xx_CSC_SCALING_4 = 2, +}; + +/** + * struct adv75xx_video_config - Describes adv75xx hardware configuration + * @csc_enable: Whether to enable color space conversion + * @csc_scaling_factor: Color space conversion scaling factor + * @csc_coefficents: Color space conversion coefficents + * @hdmi_mode: Whether to use HDMI or DVI output mode + * @avi_infoframe: HDMI infoframe + */ +struct adv75xx_video_config { + bool csc_enable; + enum adv75xx_csc_scaling csc_scaling_factor; + const uint16_t *csc_coefficents; + + bool hdmi_mode; + struct hdmi_avi_infoframe avi_infoframe; +}; + +struct hisi_display_mode { + + unsigned int type; + + /* Proposed mode values */ + int clock; /* in kHz */ + int hdisplay; + int hsync_start; + int hsync_end; + int hsync_pulse_width; + int hsync_offset; + int htotal; + + int vdisplay; + int vsync_start; + int vsync_end; + int vsync_pulse_width; + int vsync_offset; + int vtotal; + int vscan; + unsigned int flags; + + /* Addressable image size (may be 0 for projectors, etc.) */ + int width_mm; + int height_mm; + + int vrefresh; /* in Hz */ + int hsync; /* in kHz */ + enum hdmi_picture_aspect picture_aspect_ratio; +}; + +/** + * enum adv7511_sync_polarity - Polarity for the input sync signals + * @ADV7533_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of + * the currently configured mode. + * @ADV7533_SYNC_POLARITY_LOW: Sync polarity is low + * @ADV7533_SYNC_POLARITY_HIGH: Sync polarity is high + * + * If the polarity is set to either LOW or HIGH the driver will configure the + * ADV7533 to internally invert the sync signal if required to match the sync + * polarity setting for the currently selected output mode. + * + * If the polarity is set to PASSTHROUGH, the ADV7533 will route the signal + * unchanged. This is used when the upstream graphics core already generates + * the sync signals with the correct polarity. + */ +enum adi_sync_polarity { + ADV7533_SYNC_POLARITY_PASSTHROUGH, + ADV7533_SYNC_POLARITY_LOW, + ADV7533_SYNC_POLARITY_HIGH, +}; + +enum adv75xx_type { + ADV7511, + ADV7533, + ADV7535, +}; + +enum connector_status { + connector_status_connected = 1, + connector_status_disconnected = 2, + connector_status_unknown = 3, +}; + +struct adi_hdmi { + enum adv75xx_type type; + bool powered; + + struct regulator *vdd; + struct regulator *v1p2; + + struct i2c_client *i2c_main; + struct i2c_client *i2c_edid; + struct i2c_client *i2c_cec; + struct i2c_client *i2c_packet; + + struct regmap *regmap; + struct regmap *regmap_cec; + struct regmap *regmap_packet; + enum connector_status status; + + unsigned int f_tmds; + unsigned int f_audio; + unsigned int audio_source; + + bool edid_read; + unsigned int current_edid_segment; + + wait_queue_head_t wq; + + bool rgb; + bool embedded_sync; + enum adi_sync_polarity vsync_polarity; + enum adi_sync_polarity hsync_polarity; + uint8_t num_dsi_lanes; + + struct edid *edid; + struct gpio_desc *gpio_pd; + + struct hisi_display_mode *mode; + struct adi_operation_funcs *opt_funcs; +}; + +struct adi_operation_funcs { + void (*power_on)(struct adi_hdmi *adv75xx); + void (*power_off)(struct adi_hdmi *adv75xx); + void (*mode_set)(struct adi_hdmi *adv75xx, + struct hisi_display_mode *mode); +}; + +#endif /* __ADV75XX_H__ */ diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c new file mode 100755 index 000000000000..8242579107b2 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c @@ -0,0 +1,310 @@ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "adv75xx.h" + +static const struct snd_soc_dapm_widget adv75xx_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("TMDS"), + SND_SOC_DAPM_AIF_IN("AIFIN", "Playback", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route adv75xx_routes[] = { + {"TMDS", NULL, "AIFIN"}, +}; + +static void adv75xx_calc_cts_n(unsigned int f_tmds, unsigned int fs, + unsigned int *cts, unsigned int *n) +{ + switch (fs) { + case 32000: + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + *n = 6144; + break; + } + + *cts = ((f_tmds * *n) / (128 * fs)) * 1000; +} + +static int adv75xx_update_cts_n(struct adi_hdmi *adv75xx) +{ + unsigned int cts = 0; + unsigned int n = 0; + + adv75xx_calc_cts_n(adv75xx->f_tmds, adv75xx->f_audio, &cts, &n); + + regmap_write(adv75xx->regmap, ADV7533_REG_N0, (n >> 16) & 0xf); + regmap_write(adv75xx->regmap, ADV7533_REG_N1, (n >> 8) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_N2, n & 0xff); + + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL0, + (cts >> 16) & 0xf); + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL1, + (cts >> 8) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL2, cts & 0xff); + + return 0; +} + +static int adv75xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + unsigned int len; + switch (params_rate(params)) { + case 32000: + rate = ADV7533_SAMPLE_FREQ_32000; + break; + case 44100: + rate = ADV7533_SAMPLE_FREQ_44100; + break; + case 48000: + rate = ADV7533_SAMPLE_FREQ_48000; + break; + case 88200: + rate = ADV7533_SAMPLE_FREQ_88200; + break; + case 96000: + rate = ADV7533_SAMPLE_FREQ_96000; + break; + case 176400: + rate = ADV7533_SAMPLE_FREQ_176400; + break; + case 192000: + rate = ADV7533_SAMPLE_FREQ_192000; + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + len = ADV7533_I2S_SAMPLE_LEN_16; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + len = ADV7533_I2S_SAMPLE_LEN_18; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + len = ADV7533_I2S_SAMPLE_LEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + len = ADV7533_I2S_SAMPLE_LEN_24; + break; + default: + return -EINVAL; + } + + adv75xx->f_audio = params_rate(params); + + adv75xx_update_cts_n(adv75xx); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CFG3, + ADV7533_AUDIO_CFG3_LEN_MASK, len); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_I2C_FREQ_ID_CFG, + ADV7533_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4); + regmap_write(adv75xx->regmap, 0x73, 0x1); + + return 0; +} + +static int adv75xx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + unsigned int audio_source, i2s_format = 0; + unsigned int invert_clock; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_LEFT_J; + break; + /* + case SND_SOC_DAIFMT_SPDIF: + audio_source = ADV7533_AUDIO_SOURCE_SPDIF; + break; + */ + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_clock = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + invert_clock = 1; + break; + default: + return -EINVAL; + } + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_SOURCE, 0x70, + audio_source << 4); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CONFIG, BIT(6), + invert_clock << 6); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_I2S_CONFIG, 0x03, + i2s_format); + + adv75xx->audio_source = audio_source; + + return 0; +} + +static int adv75xx_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + + switch (level) { + case SND_SOC_BIAS_ON: + switch (adv75xx->audio_source) { + case ADV7533_AUDIO_SOURCE_I2S: + break; + case ADV7533_AUDIO_SOURCE_SPDIF: + regmap_update_bits(adv75xx->regmap, + ADV7533_REG_AUDIO_CONFIG, BIT(7), + BIT(7)); + break; + } + break; + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_SAMPLE); + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME); + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_N_CTS); + } else { + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_SAMPLE); + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME); + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_N_CTS); + } + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CONFIG, + BIT(7), 0); + break; + case SND_SOC_BIAS_OFF: + break; + } + dapm->bias_level = level; + return 0; +} + +#define ADV7533_RATES (SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define ADV7533_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops adv75xx_dai_ops = { + .hw_params = adv75xx_hw_params, + /*.set_sysclk = adv75xx_set_dai_sysclk, */ + .set_fmt = adv75xx_set_dai_fmt, +}; + +static struct snd_soc_dai_driver adv75xx_dai = { + .name = "adv75xx", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ADV7533_RATES, + .formats = ADV7533_FORMATS, + }, + .ops = &adv75xx_dai_ops, +}; + +static int adv75xx_suspend(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_OFF); +} + +static int adv75xx_resume(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv75xx_probe(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv75xx_remove(struct snd_soc_codec *codec) +{ + adv75xx_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static struct snd_soc_codec_driver adv75xx_codec_driver = { + .probe = adv75xx_probe, + .remove = adv75xx_remove, + .suspend = adv75xx_suspend, + .resume = adv75xx_resume, + .set_bias_level = adv75xx_set_bias_level, + + .dapm_widgets = adv75xx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adv75xx_dapm_widgets), + .dapm_routes = adv75xx_routes, + .num_dapm_routes = ARRAY_SIZE(adv75xx_routes), +}; + +int adv75xx_audio_init(struct device *dev) +{ + return snd_soc_register_codec(dev, &adv75xx_codec_driver, + &adv75xx_dai, 1); +} + +void adv75xx_audio_exit(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} diff --git a/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c b/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c new file mode 100755 index 000000000000..65313f54878d --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c @@ -0,0 +1,314 @@ +/* Copyright (c) 2008-2011, Hisilicon Tech. Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "../hisi_fb.h" +#include "adv75xx.h" + +/******************************************************************************* + ** + */ +static int mipi_adi_hdmi_on(struct platform_device *pdev) +{ + struct adi_hdmi *adv75xx = NULL; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + + HISI_FB_INFO("+.\n"); + + if (pdev == NULL) { + HISI_FB_ERR("pdev is NULL!\n"); + return -1; + } + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d\n", pdev->name, pdev->id); + + hisifd = platform_get_drvdata(pdev); + if (hisifd == NULL) { + HISI_FB_ERR("platform get drivre data failed!!\n"); + return -1; + } + + HISI_FB_INFO("fb%d, +!\n", hisifd->index); + + pinfo = &(hisifd->panel_info); + + pdata = dev_get_platdata(&pdev->dev); + if (pdata == NULL) { + HISI_FB_ERR("devices get platform data failed!!\n"); + return -1; + } + + if (pdata->next) { + adv75xx = platform_get_drvdata(pdata->next); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + return -1; + } + } else { + HISI_FB_ERR("pdata->next is NULL!!\n"); + return -1; + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + if (pinfo->lcd_init_step == LCD_INIT_POWER_ON) { + pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step == LCD_INIT_MIPI_LP_SEND_SEQUENCE) { + pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step == LCD_INIT_MIPI_HS_SEND_SEQUENCE) { + adv75xx->opt_funcs->mode_set(adv75xx, adv75xx->mode); + adv75xx->opt_funcs->power_on(adv75xx); + } else { + HISI_FB_ERR("failed to init hdmi!\n"); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static int mipi_adi_hdmi_off(struct platform_device *pdev) +{ + struct adi_hdmi *adv75xx = NULL; + struct hisi_fb_panel_data *pdata = NULL; + + HISI_FB_INFO("+.\n"); + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d +.\n", pdev->name, + pdev->id); + + if (pdata->next) { + adv75xx = platform_get_drvdata(pdata->next); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + return -1; + } + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + adv75xx->opt_funcs->power_off(adv75xx); + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static int mipi_adi_hdmi_remove(struct platform_device *pdev) +{ + + return 0; +} + +/******************************************************************************* + ** + */ +static struct hisi_panel_info g_adi_hdmi_info = { 0 }; + +static struct hisi_fb_panel_data g_adi_hdmi_data = { + .panel_info = &g_adi_hdmi_info, + .on = mipi_adi_hdmi_on, + .off = mipi_adi_hdmi_off, +}; + +/******************************************************************************* + ** + */ +static int mipi_adi_hdmi_probe(struct platform_device *pdev) +{ + int ret = 0; + struct adi_hdmi *adv75xx = NULL; + struct hisi_panel_info *pinfo = NULL; + struct hisi_display_mode *mode = NULL; + + if (pdev == NULL) + HISI_FB_ERR("platform device is NULL!\n"); + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d +.\n", pdev->name, + pdev->id); + + adv75xx = platform_get_drvdata(pdev); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + goto err_probe_defer; + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + if (adv75xx->mode) { + mode = adv75xx->mode; + /* init hdmi display info */ + pinfo = g_adi_hdmi_data.panel_info; + pinfo->xres = mode->hdisplay; + pinfo->yres = mode->vdisplay; + pinfo->width = mode->width_mm; + pinfo->height = mode->height_mm; + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = BL_SET_BY_MIPI; + + pinfo->type = PANEL_MIPI_VIDEO; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + + pinfo->pxl_clk_rate = mode->clock * 1000UL; + pinfo->ldi.h_back_porch = mode->htotal - mode->hsync_end; + pinfo->ldi.h_front_porch = mode->hsync_offset; + pinfo->ldi.h_pulse_width = mode->hsync_pulse_width; + pinfo->ldi.v_back_porch = mode->vtotal - mode->vsync_end; + pinfo->ldi.v_front_porch = mode->vsync_offset; + pinfo->ldi.v_pulse_width = mode->vsync_pulse_width; + } else { + /* init hdmi display info */ + pinfo = g_adi_hdmi_data.panel_info; + pinfo->xres = 1920; + pinfo->yres = 1080; + pinfo->width = 16000; + pinfo->height = 9000; + + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = BL_SET_BY_MIPI; + + pinfo->type = PANEL_MIPI_VIDEO; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + + pinfo->ldi.h_back_porch = 148; + pinfo->ldi.h_front_porch = 88; + pinfo->ldi.h_pulse_width = 44; + pinfo->ldi.v_back_porch = 36; + pinfo->ldi.v_front_porch = 4; + pinfo->ldi.v_pulse_width = 5; + } + + + pinfo->mipi.dsi_bit_clk = 480; + + + pinfo->dsi_bit_clk_upt_support = 0; + pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk; + + pinfo->mipi.non_continue_en = 0; + + pinfo->pxl_clk_rate = 160 * 1000000UL; + + + pinfo->mipi.lane_nums = DSI_4_LANES; + pinfo->mipi.color_mode = DSI_24BITS_1; + pinfo->mipi.vc = 0; + pinfo->mipi.max_tx_esc_clk = 10 * 1000000; + pinfo->mipi.burst_mode = DSI_NON_BURST_SYNC_PULSES; + + pinfo->mipi.clk_post_adjust = 120; + pinfo->mipi.clk_pre_adjust = 0; + pinfo->mipi.clk_t_hs_prepare_adjust = 0; + pinfo->mipi.clk_t_lpx_adjust = 0; + pinfo->mipi.clk_t_hs_trial_adjust = 0; + pinfo->mipi.clk_t_hs_exit_adjust = 0; + pinfo->mipi.clk_t_hs_zero_adjust = 0; + + pinfo->pxl_clk_rate_div = 1; + + g_adi_hdmi_data.next = pdev; + HISI_FB_INFO("The pixel clock is %llu !\n", pinfo->pxl_clk_rate); + HISI_FB_INFO("The resolution is %d x %d !\n", pinfo->xres, pinfo->yres); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + pinfo->ldi.h_pulse_width, pinfo->ldi.h_front_porch, + pinfo->ldi.h_back_porch, pinfo->ldi.v_pulse_width, + pinfo->ldi.v_front_porch, pinfo->ldi.v_back_porch); + + + ret = platform_device_add_data(pdev, &g_adi_hdmi_data, + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("platform_device_add_data failed!\n"); + goto err_device_put; + } + + hisi_fb_add_device(pdev); + + HISI_FB_INFO("-.\n"); + + return 0; + + err_device_put: + platform_device_put(pdev); + err_probe_defer: + return -EPROBE_DEFER; +} + +static struct platform_driver this_driver = { + .probe = mipi_adi_hdmi_probe, + .remove = mipi_adi_hdmi_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "adi_hdmi", + } +}; + +static int __init mipi_adi_hdmi_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(mipi_adi_hdmi_init); diff --git a/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c b/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c new file mode 100755 index 000000000000..7e1fbd0ee5c6 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c @@ -0,0 +1,525 @@ +/* Copyright (c) 2008-2014, Hisilicon Tech. Co., Ltd. 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 "../hisi_fb.h" + +#define DTS_COMP_MIPI_HIKEY "hisilicon,mipi_hikey" + +/********************************Hikey start*********************** + **Power ON Sequence(sleep mode to Normal mode) + */ +static char hikey_power_on_param1[] = { + 0x01, +}; + +static char hikey_power_on_param2[] = { + 0xB0, + 0x00, +}; + +static char hikey_power_on_param3[] = { + 0xD6, + 0x01, +}; + +static char hikey_power_on_param4[] = { + 0xB3, + 0x14, 0x08, 0x00, 0x22, 0x00, +}; + +static char hikey_power_on_param5[] = { + 0xB4, + 0x0C, +}; + +static char hikey_power_on_param6[] = { + 0xB6, + 0x3A, 0xC3, +}; + +static char hikey_power_on_param7[] = { + 0x2A, + 0x00, 0x00, 0X04, 0XAF, +}; + +static char hikey_power_on_param8[] = { + 0x2B, + 0x00, 0x00, 0X07, 0X7F, +}; + +static char hikey_power_on_param9[] = { + 0x51, + 0xA6, +}; + +static char hikey_power_on_param10[] = { + 0x53, + 0x2C, +}; + +static char hikey_power_on_param11[] = { + 0x3A, + 0x66, +}; + +static char hikey_power_on_param12[] = { + 0x29, +}; + +static char hikey_power_on_param13[] = { + 0x11, +}; + +static char hikey_display_off[] = { + 0x28, +}; + +static char hikey_enter_sleep[] = { + 0x10, +}; + +static struct dsi_cmd_desc hikey_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 0, 20, WAIT_TYPE_MS, + sizeof(hikey_display_off), hikey_display_off} + , + {DTYPE_DCS_WRITE, 0, 80, WAIT_TYPE_MS, + sizeof(hikey_enter_sleep), hikey_enter_sleep} + , +}; + +/*short or long packet*/ +static struct dsi_cmd_desc hikey_display_on_cmds[] = { + {DTYPE_DCS_WRITE, 0, 5, WAIT_TYPE_MS, + sizeof(hikey_power_on_param1), hikey_power_on_param1} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param2), hikey_power_on_param2} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param3), hikey_power_on_param3} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param4), hikey_power_on_param4} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param5), hikey_power_on_param5} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param6), hikey_power_on_param6} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param7), hikey_power_on_param7} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param8), hikey_power_on_param8} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param9), hikey_power_on_param9} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param10), hikey_power_on_param10} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param11), hikey_power_on_param11} + , + {DTYPE_DCS_WRITE, 0, 20, WAIT_TYPE_MS, + sizeof(hikey_power_on_param12), hikey_power_on_param12} + , + {DTYPE_DCS_WRITE, 0, 150, WAIT_TYPE_MS, + sizeof(hikey_power_on_param13), hikey_power_on_param13} + , +}; + +/********************************hikey end*************************/ + +/******************************************************************************* + ** LCD GPIO + */ +#define GPIO_LCD_PWR_ENABLE_NAME "gpio_lcd_pwr_enable" +#define GPIO_LCD_BL_ENABLE_NAME "gpio_lcd_bl_enable" +#define GPIO_LCD_PWM_NAME "gpio_lcd_pwm" +#define GPIO_SWITCH_DSI_HDMI "gpio_switch_dsi_hdmi" + +static uint32_t gpio_lcd_pwr_enable; +static uint32_t gpio_lcd_bl_enable; +static uint32_t gpio_lcd_pwm; +static uint32_t gpio_switch_dsi_hdmi; + +static struct gpio_desc hikey_lcd_gpio_request_cmds[] = { + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_gpio_free_cmds[] = { + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_gpio_normal_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 1}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 1}, +}; + +static struct gpio_desc hikey_lcd_gpio_off_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_backlight_enable_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 1}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 1}, +}; + +static struct gpio_desc hikey_lcd_backlight_disable_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, +}; + +static struct hisi_fb_panel_data g_panel_data; + +static void hikey_set_backlight_on(void) +{ + msleep(200); + gpio_cmds_tx(hikey_lcd_backlight_enable_cmds, + ARRAY_SIZE(hikey_lcd_backlight_enable_cmds)); + return; +} + +static void hikey_set_backlight_off(void) +{ + gpio_cmds_tx(hikey_lcd_backlight_disable_cmds, + ARRAY_SIZE(hikey_lcd_backlight_disable_cmds)); + return; +} + +static int hikey_panel_on(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + char __iomem *mipi_dsi0_base = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + BUG_ON(pinfo == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + mipi_dsi0_base = hisifd->mipi_dsi0_base; + + if (pinfo->lcd_init_step == LCD_INIT_POWER_ON) { + pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step == LCD_INIT_MIPI_LP_SEND_SEQUENCE) { + /*lcd gpio request */ + gpio_cmds_tx(hikey_lcd_gpio_request_cmds, + ARRAY_SIZE(hikey_lcd_gpio_request_cmds)); + /*lcd gpio normal */ + gpio_cmds_tx(hikey_lcd_gpio_normal_cmds, + ARRAY_SIZE(hikey_lcd_gpio_normal_cmds)); + /*lcd display on sequence */ + msleep(250); + mipi_dsi_cmds_tx(hikey_display_on_cmds, + ARRAY_SIZE(hikey_display_on_cmds), + mipi_dsi0_base); + + pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step == LCD_INIT_MIPI_HS_SEND_SEQUENCE) { + ; + } else { + HISI_FB_ERR("failed to init lcd!\n"); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_off(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + char __iomem *mipi_dsi0_base = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + BUG_ON(pinfo == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + mipi_dsi0_base = hisifd->mipi_dsi0_base; + /*lcd enter sleep */ + mipi_dsi_cmds_tx(hikey_display_off_cmds, + ARRAY_SIZE(hikey_display_off_cmds), mipi_dsi0_base); + gpio_cmds_tx(hikey_lcd_gpio_off_cmds, + ARRAY_SIZE(hikey_lcd_gpio_off_cmds)); + gpio_cmds_tx(hikey_lcd_gpio_free_cmds, + ARRAY_SIZE(hikey_lcd_gpio_free_cmds)); + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_remove(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_set_backlight(struct platform_device *pdev, + uint32_t bl_level) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (bl_level == 0) { + hikey_set_backlight_off(); + } else { + hikey_set_backlight_on(); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static struct hisi_panel_info g_panel_info = { 0 }; + +static struct hisi_fb_panel_data g_panel_data = { + .panel_info = &g_panel_info, + .on = hikey_panel_on, + .off = hikey_panel_off, + .remove = hikey_panel_remove, + .set_backlight = hikey_panel_set_backlight, +}; + +static int hikey_probe(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_panel_info *pinfo = NULL; + struct device_node *np = NULL; + uint32_t bl_type = 0; + + uint32_t lcd_display_type = 0; + uint32_t lcd_ifbc_type = 0; + + HISI_FB_DEBUG("+.\n"); + + np = of_find_compatible_node(NULL, NULL, DTS_COMP_MIPI_HIKEY); + if (!np) { + HISI_FB_ERR("NOT FOUND device node %s!\n", DTS_COMP_MIPI_HIKEY); + goto err_return; + } + + ret = of_property_read_u32(np, LCD_BL_TYPE_NAME, &bl_type); + if (ret) { + HISI_FB_ERR("get lcd_bl_type failed!\n"); + bl_type = BL_SET_BY_BLPWM; + } + + ret = + of_property_read_u32(np, LCD_DISPLAY_TYPE_NAME, &lcd_display_type); + if (ret) { + HISI_FB_ERR("get lcd_display_type failed!\n"); + lcd_display_type = PANEL_MIPI_VIDEO; + } + + ret = of_property_read_u32(np, LCD_IFBC_TYPE_NAME, &lcd_ifbc_type); + if (ret) { + HISI_FB_ERR("get ifbc_type failed!\n"); + lcd_ifbc_type = IFBC_TYPE_NONE; + } + + /*GPIO_26_8 GPIO_216 */ + gpio_lcd_pwr_enable = of_get_named_gpio(np, "gpios", 0); + /*GPIO_27_2 GPIO_218 */ + gpio_lcd_bl_enable = of_get_named_gpio(np, "gpios", 1); + /*GPIO_22_6 GPIO_182 */ + gpio_lcd_pwm = of_get_named_gpio(np, "gpios", 2); + /*GPIO_2_4 GPIO_020 */ + gpio_switch_dsi_hdmi = of_get_named_gpio(np, "gpios", 3); + + if (hisi_fb_device_probe_defer(lcd_display_type, bl_type)) { + goto err_probe_defer; + } + + pdev->id = 1; + /*init lcd panel info */ + pinfo = g_panel_data.panel_info; + memset(pinfo, 0, sizeof(struct hisi_panel_info)); + pinfo->xres = 1200; + pinfo->yres = 1920; + pinfo->width = 94; + pinfo->height = 151; + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = bl_type; + + pinfo->type = PANEL_MIPI_VIDEO; + pinfo->ifbc_type = 0; + + if (pinfo->bl_set_type == BL_SET_BY_BLPWM) + pinfo->blpwm_input_ena = 0; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + pinfo->esd_enable = 0; + + /*ldi */ + pinfo->ldi.h_back_porch = 60; + pinfo->ldi.h_front_porch = 200; + pinfo->ldi.h_pulse_width = 12; + pinfo->ldi.v_back_porch = 8; + pinfo->ldi.v_front_porch = 8; + pinfo->ldi.v_pulse_width = 2; + + /* + pinfo->ldi.hsync_plr = 0; + pinfo->ldi.vsync_plr = 0; + pinfo->ldi.pixelclk_plr = 1; + pinfo->ldi.data_en_plr = 0; + */ + + /*mipi */ + pinfo->mipi.lane_nums = DSI_4_LANES; + pinfo->mipi.color_mode = DSI_24BITS_1; + pinfo->mipi.vc = 0; + pinfo->mipi.max_tx_esc_clk = 10 * 1000000; + pinfo->mipi.burst_mode = DSI_BURST_SYNC_PULSES_1; + + pinfo->mipi.dsi_bit_clk = 480; + pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk; + + pinfo->pxl_clk_rate = 146 * 1000000UL; + pinfo->pxl_clk_rate_div = 1; + pinfo->fps = 50; + + pinfo->vsync_ctrl_type = 0; + pinfo->dirty_region_updt_support = 0; + pinfo->dsi_bit_clk_upt_support = 0; + + /*alloc panel device data */ + ret = platform_device_add_data(pdev, &g_panel_data, + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("platform_device_add_data failed!\n"); + goto err_device_put; + } + + hisi_fb_add_device(pdev); + + /* + vdd = devm_regulator_get(&(pdev->dev), "vdd"); + if (IS_ERR(vdd)) { + ret = PTR_ERR(vdd); + HISI_FB_ERR("vdd regulator get fail\n"); + return ret; + } + + ret = regulator_set_voltage(vdd, 1800000, 1800000); + if (ret) { + HISI_FB_ERR("vdd regulator set voltage fail\n"); + return ret; + } + + ret = regulator_enable(vdd); + if (ret) { + HISI_FB_ERR("vdd regulator enable fail\n"); + return ret; + } + */ + + HISI_FB_DEBUG("-.\n"); + return 0; + + err_device_put: + platform_device_put(pdev); + err_return: + return ret; + err_probe_defer: + return -EPROBE_DEFER; +} + +static const struct of_device_id hisi_panel_match_table[] = { + { + .compatible = DTS_COMP_MIPI_HIKEY, + .data = NULL, + }, + {}, +}; + +static struct platform_driver this_driver = { + .probe = hikey_probe, + .remove = NULL, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "mipi_hikey", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(hisi_panel_match_table), + }, +}; + +static int __init hikey_panel_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(hikey_panel_init); -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c | 1522 ++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h | 496 +++++++ drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c | 310 ++++ drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c | 314 ++++ .../fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c | 525 +++++++ 5 files changed, 3167 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c create mode 100755 drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c create mode 100755 drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c new file mode 100755 index 000000000000..328cd6869149 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.c @@ -0,0 +1,1522 @@ +/** + * + * + **/ + +#include "adv75xx.h" +#define HPD_ENABLE 0 +/* #define TEST_COLORBAR_DISPLAY */ + +static void adv75xx_power_on(struct adi_hdmi *adv75xx); +static void adv75xx_power_off(struct adi_hdmi *adv75xx); + +/* ADI recommended values for proper operation. */ +static const struct reg_sequence adv7511_fixed_registers[] = { + {0x98, 0x03}, + {0x9a, 0xe0}, + {0x9c, 0x30}, + {0x9d, 0x61}, + {0xa2, 0xa4}, + {0xa3, 0xa4}, + {0xe0, 0xd0}, + {0xf9, 0x00}, + {0x55, 0x02}, +}; + +/* ADI recommended values for proper operation. */ +static const struct reg_sequence adv7533_fixed_registers[] = { + {0x16, 0x20}, + {0x9a, 0xe0}, + {0xba, 0x70}, + {0xde, 0x82}, + {0xe4, 0x40}, + {0xe5, 0x80}, +}; + +static const struct reg_sequence adv7533_cec_fixed_registers[] = { + {0x15, 0xd0}, + {0x17, 0xd0}, + {0x24, 0x20}, + {0x57, 0x11}, + {0x05, 0xc8}, +}; + +/* ----------------------------------------------------------------------------- + * Register access + */ + +static const uint8_t adv75xx_register_defaults[] = { + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ + 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, + 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ + 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, + 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ + 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ + 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ + 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ + 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, + 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, + 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static bool adv7511_register_volatile(struct device *dev, unsigned int reg) +{ + int ret = 0; + + switch (reg) { + case ADV7533_REG_CHIP_REVISION: + case ADV7533_REG_SPDIF_FREQ: + case ADV7533_REG_CTS_AUTOMATIC1: + case ADV7533_REG_CTS_AUTOMATIC2: + case ADV7533_REG_VIC_DETECTED: + case ADV7533_REG_VIC_SEND: + case ADV7533_REG_AUX_VIC_DETECTED: + case ADV7533_REG_STATUS: + case ADV7533_REG_GC(1): + case ADV7533_REG_INT(0): + case ADV7533_REG_INT(1): + case ADV7533_REG_PLL_STATUS: + case ADV7533_REG_AN(0): + case ADV7533_REG_AN(1): + case ADV7533_REG_AN(2): + case ADV7533_REG_AN(3): + case ADV7533_REG_AN(4): + case ADV7533_REG_AN(5): + case ADV7533_REG_AN(6): + case ADV7533_REG_AN(7): + case ADV7533_REG_HDCP_STATUS: + case ADV7533_REG_BCAPS: + case ADV7533_REG_BKSV(0): + case ADV7533_REG_BKSV(1): + case ADV7533_REG_BKSV(2): + case ADV7533_REG_BKSV(3): + case ADV7533_REG_BKSV(4): + case ADV7533_REG_DDC_STATUS: + case ADV7533_REG_BSTATUS(0): + case ADV7533_REG_BSTATUS(1): + case ADV7533_REG_CHIP_ID_HIGH: + case ADV7533_REG_CHIP_ID_LOW: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret ? true : false; +} + +static const struct regmap_config adv75xx_regmap_config = { + .name = "adv75xx", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .reg_defaults_raw = adv75xx_register_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(adv75xx_register_defaults), + .volatile_reg = adv7511_register_volatile, +}; + +static const struct regmap_config adv7533_cec_regmap_config = { + .name = "adv7533_cec", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_config adv7533_packet_regmap_config = { + .name = "adv7533_packet", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +}; + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ +static void adv75xx_set_colormap(struct adi_hdmi *adv75xx, bool enable, + const u16 *coeff, unsigned int scaling_factor) +{ + unsigned int i; + + HISI_FB_INFO("+.\n"); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, ADV7533_CSC_UPDATE_MODE); + + if (enable) { + for (i = 0; i < 12; ++i) { + regmap_update_bits(adv75xx->regmap, + ADV7533_REG_CSC_UPPER(i), + 0x1f, coeff[i] >> 8); + regmap_write(adv75xx->regmap, + ADV7533_REG_CSC_LOWER(i), coeff[i] & 0xff); + } + } + + if (enable) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(0), + 0xe0, 0x80 | (scaling_factor << 5)); + else + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(0), + 0x80, 0x00); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, 0); + + HISI_FB_INFO("-.\n"); +} + +int adv75xx_packet_enable(struct adi_hdmi *adv75xx, unsigned int packet) +{ + HISI_FB_INFO("+.\n"); + + if (packet & 0xff) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE0, + packet, 0xff); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE1, + packet, 0xff); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +int adv75xx_packet_disable(struct adi_hdmi *adv75xx, unsigned int packet) +{ + HISI_FB_INFO("+.\n"); + + if (packet & 0xff) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE0, + packet, 0x00); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv75xx->regmap, ADV7533_REG_PACKET_ENABLE1, + packet, 0x00); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +/* Coefficients for adv75xx color space conversion */ +static const uint16_t adv75xx_csc_ycbcr_to_rgb[] = { + 0x0734, 0x04ad, 0x0000, 0x1c1b, + 0x1ddc, 0x04ad, 0x1f24, 0x0135, + 0x0000, 0x04ad, 0x087c, 0x1b77, +}; + +static void adv75xx_set_config_csc(struct adi_hdmi *adv75xx, bool rgb) +{ + struct adv75xx_video_config config; + bool output_format_422, output_format_ycbcr; + unsigned int mode; + uint8_t infoframe[17]; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->edid) + config.hdmi_mode = true; + else + config.hdmi_mode = false; + + config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; + + HISI_FB_INFO("adv75xx->rgb is %d\n", adv75xx->rgb); + + if (rgb) { + config.csc_enable = false; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } else { + config.csc_scaling_factor = ADV75xx_CSC_SCALING_4; + config.csc_coefficents = adv75xx_csc_ycbcr_to_rgb; + } + + HISI_FB_INFO("config.avi_infoframe.colorspace = %d\n", + config.avi_infoframe.colorspace); + + if (config.hdmi_mode) { + mode = ADV7533_HDMI_CFG_MODE_HDMI; + + switch (config.avi_infoframe.colorspace) { + case HDMI_COLORSPACE_YUV444: + output_format_422 = false; + output_format_ycbcr = true; + break; + case HDMI_COLORSPACE_YUV422: + output_format_422 = true; + output_format_ycbcr = true; + break; + default: + output_format_422 = false; + output_format_ycbcr = false; + break; + } + } else { + mode = ADV7533_HDMI_CFG_MODE_DVI; + output_format_422 = false; + output_format_ycbcr = false; + } + + adv75xx_packet_disable(adv75xx, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); + + adv75xx_set_colormap(adv75xx, config.csc_enable, + config.csc_coefficents, config.csc_scaling_factor); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_VIDEO_INPUT_CFG1, 0x81, + (output_format_422 << 7) | output_format_ycbcr); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_HDCP_HDMI_CFG, + ADV7533_HDMI_CFG_MODE_MASK, mode); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv75xx->regmap, ADV7533_REG_AVI_INFOFRAME_VERSION, + infoframe + 1, sizeof(infoframe) - 1); + + adv75xx_packet_enable(adv75xx, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_dsi_config_tgen(struct adi_hdmi *adv75xx) +{ + u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + HISI_FB_INFO("+.\n"); + + hsw = adv75xx->mode->hsync_pulse_width; + hfp = adv75xx->mode->hsync_offset; + hbp = adv75xx->mode->htotal - adv75xx->mode->hsync_end; + vsw = adv75xx->mode->vsync_pulse_width; + vfp = adv75xx->mode->vsync_offset; + vbp = adv75xx->mode->vtotal - adv75xx->mode->vsync_end; + + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + +#ifdef TEST_COLORBAR_DISPLAY + /* set pixel clock auto mode */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_CEC_PIXEL_CLOCK_DIV, 0x00); +#else + /* set pixel clock divider mode */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_CEC_PIXEL_CLOCK_DIV, + clock_div_by_lanes[adv75xx->num_dsi_lanes - 2] << 3); +#endif + + HISI_FB_INFO("dsi->lanes = %d, htotal = %d, vtotal = %d\n", + adv75xx->num_dsi_lanes, adv75xx->mode->htotal, + adv75xx->mode->vtotal); + + /* horizontal porch params */ + regmap_write(adv75xx->regmap_cec, 0x28, adv75xx->mode->htotal >> 4); + regmap_write(adv75xx->regmap_cec, 0x29, + (adv75xx->mode->htotal << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2a, hsw >> 4); + regmap_write(adv75xx->regmap_cec, 0x2b, (hsw << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2c, hfp >> 4); + regmap_write(adv75xx->regmap_cec, 0x2d, (hfp << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x2e, hbp >> 4); + regmap_write(adv75xx->regmap_cec, 0x2f, (hbp << 4) & 0xff); + + /* vertical porch params */ + regmap_write(adv75xx->regmap_cec, 0x30, adv75xx->mode->vtotal >> 4); + regmap_write(adv75xx->regmap_cec, 0x31, + (adv75xx->mode->vtotal << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x32, vsw >> 4); + regmap_write(adv75xx->regmap_cec, 0x33, (vsw << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x34, vfp >> 4); + regmap_write(adv75xx->regmap_cec, 0x35, (vfp << 4) & 0xff); + regmap_write(adv75xx->regmap_cec, 0x36, vbp >> 4); + regmap_write(adv75xx->regmap_cec, 0x37, (vbp << 4) & 0xff); + + /* 30Hz Low Refresh Rate (VIC Detection) */ + + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_dsi_receiver_dpms(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + if (adv75xx->type != ADV7533) + return; + + if (adv75xx->powered) { + adv75xx_dsi_config_tgen(adv75xx); + + /* set number of dsi lanes */ + regmap_write(adv75xx->regmap_cec, ADV7533_REG_DSI_DATA_LANES, + adv75xx->num_dsi_lanes << 4); + +#ifdef TEST_COLORBAR_DISPLAY + /* reset internal timing generator */ + regmap_write(adv75xx->regmap_cec, 0x27, 0xcb); + regmap_write(adv75xx->regmap_cec, 0x27, 0x8b); + regmap_write(adv75xx->regmap_cec, 0x27, 0xcb); +#else + /* disable internal timing generator */ + regmap_write(adv75xx->regmap_cec, 0x27, 0x0b); +#endif + + /* 09-03 AVI Infoframe - RGB - 16-9 Aspect Ratio */ + regmap_write(adv75xx->regmap, 0x55, 0x10); + regmap_write(adv75xx->regmap, 0x56, 0x28); + + /* 04-04 GC Packet Enable */ + regmap_write(adv75xx->regmap, 0x40, 0x80); + + /* 04-06 GC Colour Depth - 24 Bit */ + regmap_write(adv75xx->regmap, 0x4c, 0x04); + + /* 04-09 Down Dither Output Colour Depth - 8 Bit (default) */ + regmap_write(adv75xx->regmap, 0x49, 0x00); + + /* 07-01 CEC Power Mode - Always Active */ + regmap_write(adv75xx->regmap_cec, 0xbe, 0x3d); + + /* enable hdmi */ + regmap_write(adv75xx->regmap_cec, 0x03, 0x89); + +#ifdef TEST_COLORBAR_DISPLAY + /*enable test mode */ + regmap_write(adv75xx->regmap_cec, 0x55, 0x80); +#else + /* disable test mode */ + regmap_write(adv75xx->regmap_cec, 0x55, 0x00); +#endif + /* SPD */ + { + static const unsigned char spd_if[] = { + 0x83, 0x01, 25, 0x00, + 'L', 'i', 'n', 'a', 'r', 'o', 0, 0, + '9', '6', 'b', 'o', 'a', 'r', 'd', 's', + ':', 'H', 'i', 'k', 'e', 'y', 0, 0, + }; + int n; + + for (n = 0; n < sizeof(spd_if); n++) + regmap_write(adv75xx->regmap_packet, n, + spd_if[n]); + + /* enable send SPD */ + regmap_update_bits(adv75xx->regmap, 0x40, BIT(6), BIT(6)); + } + + /* force audio */ + /* hide Audio infoframe updates */ + regmap_update_bits(adv75xx->regmap, 0x4a, BIT(5), BIT(5)); + + /* i2s, internal mclk, mclk-256 */ + regmap_update_bits(adv75xx->regmap, 0x0a, 0x1f, 1); + regmap_update_bits(adv75xx->regmap, 0x0b, 0xe0, 0); + /* enable i2s, use i2s format, sample rate from i2s */ + regmap_update_bits(adv75xx->regmap, 0x0c, 0xc7, BIT(2)); + /* 16 bit audio */ + regmap_update_bits(adv75xx->regmap, 0x0d, 0xff, 16); + /* 16-bit audio */ + regmap_update_bits(adv75xx->regmap, 0x14, 0x0f, 2 << 4); + /* 48kHz */ + regmap_update_bits(adv75xx->regmap, 0x15, 0xf0, 2 << 4); + /* enable N/CTS, enable Audio sample packets */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(5), BIT(5)); + /* N = 6144 */ + regmap_write(adv75xx->regmap, 1, (6144 >> 16) & 0xf); + regmap_write(adv75xx->regmap, 2, (6144 >> 8) & 0xff); + regmap_write(adv75xx->regmap, 3, (6144) & 0xff); + /* automatic cts */ + regmap_update_bits(adv75xx->regmap, 0x0a, BIT(7), 0); + /* enable N/CTS */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(6), BIT(6)); + /* not copyrighted */ + regmap_update_bits(adv75xx->regmap, 0x12, BIT(5), BIT(5)); + + /* left source */ + regmap_update_bits(adv75xx->regmap, 0x0e, 7 << 3, 0); + /* right source */ + regmap_update_bits(adv75xx->regmap, 0x0e, 7 << 0, 1); + /* number of channels: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x73, 7, 1); + /* number of channels: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x73, 0xf0, 1 << 4); + /* sample rate: 48kHz */ + regmap_update_bits(adv75xx->regmap, 0x74, 7 << 2, 3 << 2); + /* channel allocation reg: sect 4.5.4: set to 0 */ + regmap_update_bits(adv75xx->regmap, 0x76, 0xff, 0); + /* enable audio infoframes */ + regmap_update_bits(adv75xx->regmap, 0x44, BIT(3), BIT(3)); + + /* AV mute disable */ + regmap_update_bits(adv75xx->regmap, 0x4b, BIT(7) | BIT(6), BIT(7)); + + /* use Audio infoframe updated info */ + regmap_update_bits(adv75xx->regmap, 0x4a, BIT(5), 0); + } else { + regmap_write(adv75xx->regmap_cec, 0x03, 0x0b); + regmap_write(adv75xx->regmap_cec, 0x27, 0x0b); + } + + HISI_FB_INFO("-.\n"); +} + +/* ----------------------------------------------------------------------------- + * Interrupt and hotplug detection + */ + +#if HPD_ENABLE +static bool adv75xx_hpd(struct adi_hdmi *adv75xx) +{ + unsigned int irq0; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return false; + + HISI_FB_INFO("irq0 = 0x%x\n", irq0); + + if (irq0 & ADV7533_INT0_HDP) { + HISI_FB_INFO("HPD interrupt detected!\n"); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_HDP); + return true; + } + + HISI_FB_INFO("-.\n"); + + return false; +} +#endif + +static int adv75xx_irq_process(struct adi_hdmi *adv75xx, bool process_hpd) +{ + unsigned int irq0, irq1; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return ret; + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_INT(1), &irq1); + if (ret < 0) + return ret; + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), irq0); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), irq1); + + HISI_FB_INFO("adv7511_irq_process --> irq0 = 0x%x \n", irq0); + HISI_FB_INFO("adv7511_irq_process --> irq1 = 0x%x \n", irq1); + + if (irq0 & ADV7533_INT0_EDID_READY || irq1 & ADV7533_INT1_DDC_ERROR) { + adv75xx->edid_read = true; + if (adv75xx->i2c_main->irq) + HISI_FB_INFO("adv7511_irq_process -->get i2c_main irq \n"); + + wake_up_all(&adv75xx->wq); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static irqreturn_t adv75xx_irq_handler(int irq, void *devid) +{ + struct adi_hdmi *adv75xx = devid; + int ret; + + HISI_FB_INFO("+.\n"); + + ret = adv75xx_irq_process(adv75xx, true); + + HISI_FB_INFO("-.\n"); + + return ret < 0 ? IRQ_NONE : IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * EDID retrieval + */ + +static int adv75xx_wait_for_edid(struct adi_hdmi *adv75xx, int timeout) +{ + int ret; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->i2c_main->irq) { + ret = wait_event_interruptible_timeout(adv75xx->wq, + adv75xx->edid_read, + msecs_to_jiffies(timeout)); + } else { + for (; timeout > 0; timeout -= 25) { + ret = adv75xx_irq_process(adv75xx, false); + if (ret < 0) + break; + + if (adv75xx->edid_read) + break; + + msleep(25); + } + } + + HISI_FB_INFO("-.\n"); + + return adv75xx->edid_read ? 0 : -EIO; +} + +static void print_edid_info(u8 *block) +{ + int step, count; + + count = 0x0; + while (count < EDID_LENGTH) { + step = 0; + do { + if (step = 0) { + HISI_FB_INFO("------ edid[%d]: 0x%2x \t", count, + block[count]); + } else { + HISI_FB_INFO(" 0x%2x \t", block[count]); + } + step++; + count++; + } while (step < 8); + + HISI_FB_INFO("\n"); + } +} + +struct hisi_display_mode *hisi_set_mode_info(void) +{ + struct hisi_display_mode *mode; + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + mode = kzalloc(sizeof(struct hisi_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + mode->width_mm = 160 * 100; + mode->height_mm = 90 * 100; + mode->clock = 148500; + mode->hdisplay = 1920; + mode->vdisplay = 1080; + mode->hsync_offset = 88; + mode->hsync_pulse_width = 44; + mode->hsync_start = 2008; + mode->hsync_end = 2052; + mode->htotal = 2200; + + mode->vsync_offset = 4; + mode->vsync_pulse_width = 5; + mode->vsync_start = 1084; + mode->vsync_end = 1089; + mode->vtotal = 1125; + + hsw = mode->hsync_pulse_width; + hfp = mode->hsync_offset; + hbp = mode->htotal - mode->hsync_end; + vsw = mode->vsync_pulse_width; + vfp = mode->vsync_offset; + vbp = mode->vtotal - mode->vsync_end; + + HISI_FB_INFO("The pixel clock is %d!!\n", mode->clock); + HISI_FB_INFO("The resolution is %d x %d !!\n", mode->hdisplay, + mode->vdisplay); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + + + return mode; +} + +struct hisi_display_mode *hisi_parse_edid_base_info(u8 *block) +{ + struct hisi_display_mode *mode; + char edid_vendor[3]; + unsigned hblank; + unsigned vblank; + unsigned int hsw, hfp, hbp, vsw, vfp, vbp; + + mode = kzalloc(sizeof(struct hisi_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + edid_vendor[0] = ((block[8] & 0x7c) >> 2) + '@'; + edid_vendor[1] = (((block[8] & 0x3) << 3) | + ((block[1] & 0xe0) >> 5)) + '@'; + edid_vendor[2] = (block[9] & 0x1f) + '@'; + + mode->width_mm = block[21] * 100; + mode->height_mm = block[22] * 100; + HISI_FB_INFO("The product vender is %c%c%c !!!\n", edid_vendor[0], + edid_vendor[1], edid_vendor[2]); + HISI_FB_INFO + ("The screen supported max width is %d cm, max height is %d cm !!\n", + block[21], block[22]); + HISI_FB_INFO("The display gamma is %d !!\n", block[23]); + HISI_FB_INFO("The display is RGB or YCbCr is 0x%x !!\n", + (block[24] & 0x18) >> 3); + /******** Detailed Timing Descriptor **********/ + mode->clock = (block[55] << 8 | block[54]) * 10; + mode->hdisplay = ((block[58] & 0xf0) << 4) | block[56]; + hblank = ((block[58] & 0x0f) << 8) | block[57]; + mode->vdisplay = ((block[61] & 0xf0) << 4) | block[59]; + vblank = ((block[61] & 0x0f) << 8) | block[60]; + mode->hsync_offset = block[62]; + mode->hsync_pulse_width = block[63]; + mode->vsync_offset = (block[64] & 0xf0) >> 4; + mode->vsync_pulse_width = block[64] & 0x0f; + + mode->hsync_start = mode->hdisplay + mode->hsync_offset; + mode->hsync_end = mode->hsync_start + mode->hsync_pulse_width; + mode->htotal = mode->hdisplay + hblank; + mode->vsync_start = mode->vdisplay + mode->vsync_offset; + mode->vsync_end = mode->vsync_start + mode->vsync_pulse_width; + mode->vtotal = mode->vdisplay + vblank; + + hsw = mode->hsync_pulse_width; + hfp = mode->hsync_offset; + hbp = mode->htotal - mode->hsync_end; + vsw = mode->vsync_pulse_width; + vfp = mode->vsync_offset; + vbp = mode->vtotal - mode->vsync_end; + + HISI_FB_INFO("The pixel clock is %d!!\n", mode->clock); + HISI_FB_INFO("The resolution is %d x %d !!\n", mode->hdisplay, + mode->vdisplay); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + hsw, hfp, hbp, vsw, vfp, vbp); + + + return mode; +} + +static int adv75xx_get_edid_block(void *data, u8 *buf, unsigned int block, + size_t len) +{ + struct adi_hdmi *adv75xx = data; + struct i2c_msg xfer[2]; + uint8_t offset, edid_buf[256]; + unsigned int i; + int ret; + + if (len > EDID_LENGTH) + return -EINVAL; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->current_edid_segment != block) { + unsigned int status; + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_DDC_STATUS, + &status); + if (ret < 0) + return ret; + + if (status != IDLE) { + adv75xx->edid_read = false; + regmap_write(adv75xx->regmap, ADV7533_REG_EDID_SEGMENT, + block); + ret = adv75xx_wait_for_edid(adv75xx, 200); + if (ret < 0) + return ret; + } + + /* Break this apart, hopefully more I2C controllers will + * support 64 byte transfers than 256 byte transfers + */ + + xfer[0].addr = adv75xx->i2c_edid->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = &offset; + xfer[1].addr = adv75xx->i2c_edid->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 64; + xfer[1].buf = edid_buf; + + offset = 0; + + for (i = 0; i < 4; ++i) { + ret = i2c_transfer(adv75xx->i2c_edid->adapter, xfer, + ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + xfer[1].buf += 64; + offset += 64; + } + + adv75xx->current_edid_segment = block; + } + + if (block % 2 = 0) + memcpy(buf, edid_buf, len); + else + memcpy(buf, edid_buf + EDID_LENGTH, len); + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static bool edid_is_zero(const u8 *in_edid, int length) +{ + if (memchr_inv(in_edid, 0, length)) + return false; + + return true; +} + +/** + * hisi_do_get_edid - get EDID data using a custom EDID block read function + * @get_edid_block: EDID block read function + * @data: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *hisi_do_get_edid(int (*get_edid_block) (void *data, u8 *buf, + unsigned int block, + size_t len), void *data) +{ + u8 *block; + bool print_bad_edid = true; + + HISI_FB_INFO("+.\n"); + + if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) = NULL) + return NULL; + + HISI_FB_INFO("EDID_LENGTH = %d \n", EDID_LENGTH); + /* base block fetch */ + if (get_edid_block(data, block, 0, EDID_LENGTH)) + goto out; + + if (edid_is_zero(block, EDID_LENGTH)) + goto carp; + + HISI_FB_INFO("edid_block read success!!!\n"); + + print_edid_info(block); + + return (struct edid *)block; + + carp: + if (print_bad_edid) + HISI_FB_ERR("EDID block invalid.\n"); + out: + kfree(block); + return NULL; +} + +struct hisi_display_mode *adv75xx_get_modes(struct adi_hdmi *adv75xx) +{ + struct edid *edid; + struct hisi_display_mode *mode; + + HISI_FB_INFO("+.\n"); + + /* Reading the EDID only works if the device is powered */ + if (!adv75xx->powered) { + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_NONE); /* 0xc0 */ + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), + ADV7533_INT1_DDC_ERROR); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); /* 0x41 0x10 */ + + adv75xx->current_edid_segment = -1; + /* wait some time for edid is ready */ + msleep(200); + } + + edid = hisi_do_get_edid(adv75xx_get_edid_block, adv75xx); + + if (!adv75xx->powered) + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + + kfree(adv75xx->edid); + adv75xx->edid = edid; + if (!edid) { + HISI_FB_ERR("Fail to get really edid info !!!\n"); + mode = hisi_set_mode_info(); + return mode; + } + + mode = hisi_parse_edid_base_info((u8 *) adv75xx->edid); + + adv75xx_set_config_csc(adv75xx, adv75xx->rgb); + + HISI_FB_INFO("-.\n"); + + return mode; +} + +/*=============================*/ +static enum connector_status adv75xx_detect(struct adi_hdmi *adv75xx) +{ + enum connector_status status; + unsigned int val; +#if HPD_ENABLE + bool hpd; +#endif + int ret; + + HISI_FB_INFO("+.\n"); + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_STATUS, &val); + if (ret < 0) { + HISI_FB_INFO("HDMI connector status is disconnected !!!\n"); + return connector_status_disconnected; + } + + if (val & ADV7533_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + +#if HPD_ENABLE + hpd = adv75xx_hpd(adv75xx); + + /* The chip resets itself when the cable is disconnected, so in case + * there is a pending HPD interrupt and the cable is connected there was + * at least one transition from disconnected to connected and the chip + * has to be reinitialized. */ + if (status = connector_status_connected && hpd && adv75xx->powered) { + regcache_mark_dirty(adv75xx->regmap); + adv75xx_power_on(adv75xx); + adv75xx_get_modes(adv75xx); + if (adv75xx->status = connector_status_connected) + status = connector_status_disconnected; + } else { + /* Renable HDP sensing */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_BOTH); + } +#endif + + adv75xx->status = status; + + HISI_FB_INFO("adv7511->status = %d <1-connected,2-disconnected>\n", + status); + HISI_FB_INFO("-.\n"); + + return status; +} + +/** + * mode_vrefresh - get the vrefresh of a mode + * @mode: mode + * + * Returns: + * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the + * value first if it is not yet set. + */ +static int mode_vrefresh(const struct hisi_display_mode *mode) +{ + int refresh = 0; + unsigned int calc_val; + + if (mode->vrefresh > 0) + refresh = mode->vrefresh; + else if (mode->htotal > 0 && mode->vtotal > 0) { + int vtotal; + vtotal = mode->vtotal; + /* work out vrefresh the value will be x1000 */ + calc_val = (mode->clock * 1000); + calc_val /= mode->htotal; + refresh = (calc_val + vtotal / 2) / vtotal; + } + return refresh; +} + +static int adv75xx_mode_valid(struct hisi_display_mode *mode) +{ + if (NULL = mode) { + HISI_FB_ERR("mode is null\n"); + return MODE_NOMODE; + } + + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + /* + * some work well modes which want to put in the front of the mode list. + */ + HISI_FB_INFO("Checking mode %ix%i@%i clock: %i...", + mode->hdisplay, mode->vdisplay, mode_vrefresh(mode), + mode->clock); + if ((mode->hdisplay = 1920 && mode->vdisplay = 1080 + && mode->clock = 148500) + || (mode->hdisplay = 1280 && mode->vdisplay = 800 + && mode->clock = 83496) + || (mode->hdisplay = 1280 && mode->vdisplay = 720 + && mode->clock = 74440) + || (mode->hdisplay = 1280 && mode->vdisplay = 720 + && mode->clock = 74250) + || (mode->hdisplay = 1024 && mode->vdisplay = 768 + && mode->clock = 75000) + || (mode->hdisplay = 1024 && mode->vdisplay = 768 + && mode->clock = 81833) + || (mode->hdisplay = 800 && mode->vdisplay = 600 + && mode->clock = 40000)) { + HISI_FB_INFO("OK\n"); + return MODE_OK; + } + HISI_FB_INFO("BAD\n"); + + return MODE_BAD; +} + +static void adv75xx_mode_set(struct adi_hdmi *adv75xx, + struct hisi_display_mode *mode) +{ + unsigned int low_refresh_rate; + unsigned int hsync_polarity = 0; + unsigned int vsync_polarity = 0; + + HISI_FB_INFO("+.\n"); + + if (adv75xx->embedded_sync) { + unsigned int hsync_offset, hsync_len; + unsigned int vsync_offset, vsync_len; + + hsync_offset = mode->hsync_offset; + vsync_offset = mode->vsync_offset; + hsync_len = mode->hsync_end - mode->hsync_start; + vsync_len = mode->vsync_end - mode->vsync_start; + + /* The hardware vsync generator has a off-by-one bug */ + vsync_offset += 1; + + regmap_write(adv75xx->regmap, ADV7533_REG_HSYNC_PLACEMENT_MSB, + ((hsync_offset >> 10) & 0x7) << 5); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(0), + (hsync_offset >> 2) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(1), + ((hsync_offset & 0x3) << 6) | + ((hsync_len >> 4) & 0x3f)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(2), + ((hsync_len & 0xf) << 4) | + ((vsync_offset >> 6) & 0xf)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(3), + ((vsync_offset & 0x3f) << 2) | + ((vsync_len >> 8) & 0x3)); + regmap_write(adv75xx->regmap, ADV7533_REG_SYNC_DECODER(4), + vsync_len & 0xff); + + hsync_polarity = !(mode->flags & MODE_FLAG_PHSYNC); + vsync_polarity = !(mode->flags & MODE_FLAG_PVSYNC); + } else { + /** + * If the input signal is always low or always high we want to + * invert or let it passthrough depending on the polarity of the + * current mode. + **/ + adv75xx->hsync_polarity = ADV7533_SYNC_POLARITY_PASSTHROUGH; + adv75xx->vsync_polarity = ADV7533_SYNC_POLARITY_PASSTHROUGH; + + hsync_polarity = adv75xx->hsync_polarity; + vsync_polarity = adv75xx->vsync_polarity; + } + mode->vrefresh = mode_vrefresh(mode); + HISI_FB_INFO("hsync_polarity = %d; vsync_polarity = %d\n", + hsync_polarity, vsync_polarity); + HISI_FB_INFO("mode->vrefresh = %d \n", mode->vrefresh); + + if (mode->vrefresh <= 24000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_24HZ; + else if (mode->vrefresh <= 25000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_25HZ; + else if (mode->vrefresh <= 30000) + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_30HZ; + else + low_refresh_rate = ADV7533_LOW_REFRESH_RATE_NONE; + + HISI_FB_INFO("low_refresh_rate = %d \n", low_refresh_rate); + + regmap_update_bits(adv75xx->regmap, 0xfb, 0x6, low_refresh_rate << 1); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_SYNC_POLARITY, + 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); + + /* + * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is + * supposed to give better results. + */ + + adv75xx->f_tmds = mode->clock; + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_power_on(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + adv75xx->current_edid_segment = -1; + + regmap_write(adv75xx->regmap, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY); + regmap_write(adv75xx->regmap, ADV7533_REG_INT(1), + ADV7533_INT1_DDC_ERROR); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); + + /* + * Per spec it is allowed to pulse the HDP signal to indicate that the + * EDID information has changed. Some monitors do this when they wakeup + * from standby or are enabled. When the HDP goes low the adv7511 is + * reset and the outputs are disabled which might cause the monitor to + * go to standby again. To avoid this we ignore the HDP pin for the + * first few seconds after enabling the output. + */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER2, + ADV7533_REG_POWER2_HDP_SRC_MASK, + ADV7533_REG_POWER2_HDP_SRC_NONE); + + /* + * Most of the registers are reset during power down or when HPD is low. + */ + regcache_sync(adv75xx->regmap); + + regmap_register_patch(adv75xx->regmap_cec, + adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + adv75xx->powered = true; + + adv75xx_dsi_receiver_dpms(adv75xx); + + HISI_FB_INFO("-.\n"); +} + +static void adv75xx_power_off(struct adi_hdmi *adv75xx) +{ + HISI_FB_INFO("+.\n"); + + /* TODO: setup additional power down modes */ + regmap_update_bits(adv75xx->regmap, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + regcache_mark_dirty(adv75xx->regmap); + + adv75xx->powered = false; + + adv75xx_dsi_receiver_dpms(adv75xx); + + HISI_FB_INFO("-.\n"); +} + +/* =============================*/ +static int adv7533_init_regulators(struct adi_hdmi *adv75xx) +{ + int ret; + struct device *dev = &adv75xx->i2c_main->dev; + + adv75xx->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(adv75xx->vdd)) { + ret = PTR_ERR(adv75xx->vdd); + dev_err(dev, "failed to get vdd regulator %d\n", ret); + return ret; + } + + adv75xx->v1p2 = devm_regulator_get(dev, "v1p2"); + if (IS_ERR(adv75xx->v1p2)) { + ret = PTR_ERR(adv75xx->v1p2); + dev_err(dev, "failed to get v1p2 regulator %d\n", ret); + return ret; + } + + ret = regulator_set_voltage(adv75xx->vdd, 1800000, 1800000); + if (ret) { + dev_err(dev, "failed to set avdd voltage %d\n", ret); + return ret; + } + + ret = regulator_set_voltage(adv75xx->v1p2, 1200000, 1200000); + if (ret) { + dev_err(dev, "failed to set v1p2 voltage %d\n", ret); + return ret; + } + + /* keep the regulators always on */ + ret = regulator_enable(adv75xx->vdd); + if (ret) { + dev_err(dev, "failed to enable vdd %d\n", ret); + return ret; + } + + ret = regulator_enable(adv75xx->v1p2); + if (ret) { + dev_err(dev, "failed to enable v1p2 %d\n", ret); + return ret; + } + + return 0; +} + +static int adv7533_parse_dt(struct device_node *np, struct adi_hdmi *adv75xx) +{ + int ret; + u32 num_lanes; + + ret = of_property_read_u32(np, "adi,dsi-lanes", &num_lanes); + if (ret) { + HISI_FB_WARNING("get 'adi,dsi-lanes' resource failed!\n"); + return ret; + } + + if (num_lanes < 1 || num_lanes > 4) + return -EINVAL; + + adv75xx->num_dsi_lanes = num_lanes; + + /* TODO: Check if these need to be parsed by DT or not */ + adv75xx->rgb = true; + adv75xx->embedded_sync = false; + + return 0; +} + +static const int edid_i2c_addr = 0x7e; +static const int packet_i2c_addr = 0x70; +static const int cec_i2c_addr = 0x78; + +static const struct of_device_id adv75xx_of_ids[] = { + {.compatible = "adi,adv7511", .data = (void *)ADV7511}, + {.compatible = "adi,adv7511w", .data = (void *)ADV7511}, + {.compatible = "adi,adv7513", .data = (void *)ADV7511}, + {.compatible = "adi,adv7533", .data = (void *)ADV7533}, + {}, +}; + +MODULE_DEVICE_TABLE(of, adv75xx_of_ids); + +static const struct i2c_device_id adv75xx_i2c_ids[] = { + {"adv7511", ADV7511}, + {"adv7511w", ADV7511}, + {"adv7513", ADV7511}, + {"adv7533", ADV7533}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, adv75xx_i2c_ids); + +static struct adi_operation_funcs opt_funcs = { + .power_on = adv75xx_power_on, + .power_off = adv75xx_power_off, + .mode_set = adv75xx_mode_set, +}; + +static int adv75xx_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct adi_hdmi *adv75xx; + struct device *dev = &i2c->dev; + enum connector_status status; + struct hisi_display_mode *mode; + struct platform_device *hdmi_pdev = NULL; + unsigned int val; + int ret; + + if (!dev) { + HISI_FB_ERR("dev is NULL!\n"); + return -ENOMEM; + } + + adv75xx = devm_kzalloc(dev, sizeof(struct adi_hdmi), GFP_KERNEL); + if (!adv75xx) { + HISI_FB_ERR("adv75xx alloc failed!\n"); + return -ENOMEM; + } + adv75xx->powered = false; + adv75xx->status = connector_status_disconnected; + + if (dev->of_node) { + const struct of_device_id *of_id; + + of_id = of_match_node(adv75xx_of_ids, dev->of_node); + adv75xx->type = (enum adv75xx_type)of_id->data; + } else { + adv75xx->type = ADV7533; + } + + ret = adv7533_parse_dt(dev->of_node, adv75xx); + if (ret) { + HISI_FB_ERR("parse dts error!\n"); + goto err_return; + } + + adv75xx->i2c_main = i2c; + + if (adv75xx->type = ADV7533) { + ret = adv7533_init_regulators(adv75xx); /* adv7533 vdd--1.8v v1p2--1.2v */ + if (ret) + return ret; + } + + /* + * The power down GPIO is optional. If present, toggle it from active(1) to + * inactive(0) to wake up the encoder. + */ + adv75xx->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(adv75xx->gpio_pd)) { + HISI_FB_ERR("get gpio pd error!\n"); + return PTR_ERR(adv75xx->gpio_pd); + } + HISI_FB_INFO("adv75xx->gpio_pd = %s!\n", adv75xx->gpio_pd->label); + + if (adv75xx->gpio_pd) { + mdelay(5); + gpiod_set_value_cansleep(adv75xx->gpio_pd, 0); + } + + adv75xx->regmap = devm_regmap_init_i2c(i2c, &adv75xx_regmap_config); + if (IS_ERR(adv75xx->regmap)) { + HISI_FB_ERR("regmap init i2c failed!\n"); + return PTR_ERR(adv75xx->regmap); + } + + ret = regmap_read(adv75xx->regmap, ADV7533_REG_CHIP_REVISION, &val); + if (ret) { + HISI_FB_ERR("regmap read failed, ret = %d!\n", ret); + goto err_return; + } + /* the corect val is 20. */ + HISI_FB_INFO("%s of the Chip reversion is %d\n", dev_name(dev), val); + dev_err(dev, "Rev. %d\n", val); + + ret = regmap_register_patch(adv75xx->regmap, + adv7533_fixed_registers, + ARRAY_SIZE(adv7533_fixed_registers)); + if (ret) { + HISI_FB_ERR("regmap register failed!\n"); + goto err_return; + } + + regmap_write(adv75xx->regmap, ADV7533_REG_EDID_I2C_ADDR, edid_i2c_addr); + regmap_write(adv75xx->regmap, ADV7533_REG_PACKET_I2C_ADDR, + packet_i2c_addr); + regmap_write(adv75xx->regmap, ADV7533_REG_CEC_I2C_ADDR, cec_i2c_addr); + adv75xx_packet_disable(adv75xx, 0xffff); + + adv75xx->i2c_packet = i2c_new_dummy(i2c->adapter, packet_i2c_addr >> 1); + if (!adv75xx->i2c_packet) { + HISI_FB_ERR("i2c_new_dummy i2c_packet failed!\n"); + return -ENOMEM; + } + + adv75xx->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); + if (!adv75xx->i2c_edid) { + HISI_FB_ERR("i2c_new_dummy i2c_edid failed!\n"); + goto err_i2c_unregister_packet; + } + + adv75xx->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1); + if (!adv75xx->i2c_cec) { + ret = -ENOMEM; + HISI_FB_ERR("i2c_new_dummy i2c_cec failed!\n"); + goto err_i2c_unregister_edid; + } + + adv75xx->regmap_cec = devm_regmap_init_i2c(adv75xx->i2c_cec, + &adv7533_cec_regmap_config); + if (IS_ERR(adv75xx->regmap_cec)) { + ret = PTR_ERR(adv75xx->regmap_cec); + HISI_FB_ERR("devm_regmap_init_i2c regmap_cec failed!\n"); + goto err_i2c_unregister_cec; + } + + adv75xx->regmap_packet = devm_regmap_init_i2c(adv75xx->i2c_packet, + &adv7533_packet_regmap_config); + if (IS_ERR(adv75xx->regmap_packet)) { + ret = PTR_ERR(adv75xx->regmap_packet); + HISI_FB_ERR("devm_regmap_init_i2c regmap_packet failed!\n"); + goto err_i2c_unregister_cec; + } + + if (adv75xx->type = ADV7533) { + ret = regmap_register_patch(adv75xx->regmap_cec, + adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + if (ret) { + HISI_FB_ERR + ("regmap_register_patch cec_fixed_registers failed!\n"); + goto err_return; + } + } + + HISI_FB_INFO("i2c->irq = %d!\n", i2c->irq); + if (i2c->irq) { + init_waitqueue_head(&adv75xx->wq); + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, + adv75xx_irq_handler, + IRQF_ONESHOT, dev_name(dev), adv75xx); + if (ret) { + HISI_FB_ERR("adv7511_irq_handler registers failed!\n"); + goto err_i2c_unregister_cec; + } + } + + /* CEC is unused for now */ + regmap_write(adv75xx->regmap, ADV7533_REG_CEC_CTRL, + ADV7533_CEC_CTRL_POWER_DOWN); + + adv75xx_power_off(adv75xx); + + i2c_set_clientdata(i2c, adv75xx); + + /* adv7511_audio_init(dev); */ + status = adv75xx_detect(adv75xx); + if (status != connector_status_connected) { + HISI_FB_ERR("adv75xx connector not connected !\n"); + } + + mode = adv75xx_get_modes(adv75xx); + + ret = adv75xx_mode_valid(mode); + if (ret) { + HISI_FB_ERR("adv75xx not supported this mode !!\n"); + kfree(mode); + mode = hisi_set_mode_info(); + } + adv75xx->mode = mode; + adv75xx->opt_funcs = &opt_funcs; + + hdmi_pdev + platform_device_alloc("adi_hdmi", + (((uint32_t) PANEL_MIPI_VIDEO << 16) | + (uint32_t) 1)); + if (hdmi_pdev) { + if (platform_device_add_data + (hdmi_pdev, adv75xx, sizeof(struct adi_hdmi))) { + HISI_FB_ERR("failed to platform_device_add_data!\n"); + platform_device_put(hdmi_pdev); + } + } + HISI_FB_INFO("platform_device_add_data ok !\n"); + + /* set driver data */ + platform_set_drvdata(hdmi_pdev, adv75xx); + if (platform_device_add(hdmi_pdev)) { + HISI_FB_ERR("platform_device_add failed!\n"); + goto err_device_put; + } + + return 0; + + err_i2c_unregister_cec: + i2c_unregister_device(adv75xx->i2c_cec); + err_i2c_unregister_edid: + i2c_unregister_device(adv75xx->i2c_edid); + err_i2c_unregister_packet: + i2c_unregister_device(adv75xx->i2c_packet); + err_device_put: + platform_device_put(hdmi_pdev); + err_return: + kfree(adv75xx); + return ret; +} + +static int adv75xx_remove(struct i2c_client *i2c) +{ + struct adi_hdmi *adv75xx = i2c_get_clientdata(i2c); + + i2c_unregister_device(adv75xx->i2c_cec); + i2c_unregister_device(adv75xx->i2c_edid); + + kfree(adv75xx->edid); + kfree(adv75xx->mode); + kfree(adv75xx); + + return 0; +} + +static struct i2c_driver adv75xx_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv75xx", + .of_match_table = adv75xx_of_ids, + }, + .id_table = adv75xx_i2c_ids, + .probe = adv75xx_probe, + .remove = adv75xx_remove, +}; + +static int __init adv75xx_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&adv75xx_driver); + if (ret) { + HISI_FB_ERR("i2c_add_driver error!\n"); + } + return ret; +} + +module_init(adv75xx_init); + +static void __exit adv75xx_exit(void) +{ + i2c_del_driver(&adv75xx_driver); +} + +module_exit(adv75xx_exit); + +MODULE_AUTHOR("Hisilicon Inc"); +MODULE_DESCRIPTION("ADV75XX HDMI transmitter driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h new file mode 100755 index 000000000000..d2f84d846271 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx.h @@ -0,0 +1,496 @@ +/** + * + * + **/ + +#ifndef __ADV75XX_H__ +#define __ADV75XX_H__ +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/hdmi.h> + +#include "../hisi_fb.h" + +#define DISPLAY_MODE_LEN 32 + +#define ADV7533_REG_CHIP_REVISION 0x00 +#define ADV7533_REG_N0 0x01 +#define ADV7533_REG_N1 0x02 +#define ADV7533_REG_N2 0x03 +#define ADV7533_REG_SPDIF_FREQ 0x04 +#define ADV7533_REG_CTS_AUTOMATIC1 0x05 +#define ADV7533_REG_CTS_AUTOMATIC2 0x06 +#define ADV7533_REG_CTS_MANUAL0 0x07 +#define ADV7533_REG_CTS_MANUAL1 0x08 +#define ADV7533_REG_CTS_MANUAL2 0x09 +#define ADV7533_REG_AUDIO_SOURCE 0x0a +#define ADV7533_REG_AUDIO_CONFIG 0x0b +#define ADV7533_REG_I2S_CONFIG 0x0c +#define ADV7533_REG_I2S_WIDTH 0x0d +#define ADV7533_REG_AUDIO_SUB_SRC0 0x0e +#define ADV7533_REG_AUDIO_SUB_SRC1 0x0f +#define ADV7533_REG_AUDIO_SUB_SRC2 0x10 +#define ADV7533_REG_AUDIO_SUB_SRC3 0x11 +#define ADV7533_REG_AUDIO_CFG1 0x12 +#define ADV7533_REG_AUDIO_CFG2 0x13 +#define ADV7533_REG_AUDIO_CFG3 0x14 +#define ADV7533_REG_I2C_FREQ_ID_CFG 0x15 +#define ADV7533_REG_VIDEO_INPUT_CFG1 0x16 +#define ADV7533_REG_CEC_PIXEL_CLOCK_DIV 0x16 +#define ADV7533_REG_SYNC_POLARITY 0x17 +#define ADV7533_REG_DSI_DATA_LANES 0x1c +#define ADV7533_REG_CSC_UPPER(x) (0x18 + (x) * 2) +#define ADV7533_REG_CSC_LOWER(x) (0x19 + (x) * 2) +#define ADV7533_REG_SYNC_DECODER(x) (0x30 + (x)) +#define ADV7533_REG_DE_GENERATOR (0x35 + (x)) +#define ADV7533_REG_PIXEL_REPETITION 0x3b +#define ADV7533_REG_VIC_MANUAL 0x3c +#define ADV7533_REG_VIC_SEND 0x3d +#define ADV7533_REG_VIC_DETECTED 0x3e +#define ADV7533_REG_AUX_VIC_DETECTED 0x3f +#define ADV7533_REG_PACKET_ENABLE0 0x40 +#define ADV7533_REG_POWER 0x41 +#define ADV7533_REG_STATUS 0x42 +#define ADV7533_REG_EDID_I2C_ADDR 0x43 +#define ADV7533_REG_PACKET_ENABLE1 0x44 +#define ADV7533_REG_PACKET_I2C_ADDR 0x45 +#define ADV7533_REG_DSD_ENABLE 0x46 +#define ADV7533_REG_VIDEO_INPUT_CFG2 0x48 +#define ADV7533_REG_INFOFRAME_UPDATE 0x4a +#define ADV7533_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ +#define ADV7533_REG_AVI_INFOFRAME_VERSION 0x52 +#define ADV7533_REG_AVI_INFOFRAME_LENGTH 0x53 +#define ADV7533_REG_AVI_INFOFRAME_CHECKSUM 0x54 +#define ADV7533_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ +#define ADV7533_REG_AUDIO_INFOFRAME_VERSION 0x70 +#define ADV7533_REG_AUDIO_INFOFRAME_LENGTH 0x71 +#define ADV7533_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 +#define ADV7533_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ +#define ADV7533_REG_INT_ENABLE(x) (0x94 + (x)) +#define ADV7533_REG_INT(x) (0x96 + (x)) +#define ADV7533_REG_INPUT_CLK_DIV 0x9d +#define ADV7533_REG_PLL_STATUS 0x9e +#define ADV7533_REG_HDMI_POWER 0xa1 +#define ADV7533_REG_HDCP_HDMI_CFG 0xaf +#define ADV7533_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ +#define ADV7533_REG_HDCP_STATUS 0xb8 +#define ADV7533_REG_BCAPS 0xbe +#define ADV7533_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ +#define ADV7533_REG_EDID_SEGMENT 0xc4 +#define ADV7533_REG_DDC_STATUS 0xc8 +#define ADV7533_REG_EDID_READ_CTRL 0xc9 +#define ADV7533_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ +#define ADV7533_REG_TIMING_GEN_SEQ 0xd0 +#define ADV7533_REG_POWER2 0xd6 +#define ADV7533_REG_HSYNC_PLACEMENT_MSB 0xfa + +#define ADV7533_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ +#define ADV7533_REG_TMDS_CLOCK_INV 0xde +#define ADV7533_REG_ARC_CTRL 0xdf +#define ADV7533_REG_CEC_I2C_ADDR 0xe1 +#define ADV7533_REG_CEC_CTRL 0xe2 +#define ADV7533_REG_CHIP_ID_HIGH 0xf5 +#define ADV7533_REG_CHIP_ID_LOW 0xf6 + +#define ADV7533_CSC_ENABLE BIT(7) +#define ADV7533_CSC_UPDATE_MODE BIT(5) + +#define ADV7533_INT0_HDP BIT(7) +#define ADV7533_INT0_VSYNC BIT(5) +#define ADV7533_INT0_AUDIO_FIFO_FULL BIT(4) +#define ADV7533_INT0_EDID_READY BIT(2) +#define ADV7533_INT0_HDCP_AUTHENTICATED BIT(1) + +#define ADV7533_INT1_DDC_ERROR BIT(7) +#define ADV7533_INT1_BKSV BIT(6) +#define ADV7533_INT1_CEC_TX_READY BIT(5) +#define ADV7533_INT1_CEC_TX_ARBIT_LOST BIT(4) +#define ADV7533_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) +#define ADV7533_INT1_CEC_RX_READY3 BIT(2) +#define ADV7533_INT1_CEC_RX_READY2 BIT(1) +#define ADV7533_INT1_CEC_RX_READY1 BIT(0) + +#define ADV7533_ARC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_CEC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_POWER_POWER_DOWN BIT(6) + +#define ADV7533_HDMI_CFG_MODE_MASK 0x2 +#define ADV7533_HDMI_CFG_MODE_DVI 0x0 +#define ADV7533_HDMI_CFG_MODE_HDMI 0x2 + +#define ADV7533_AUDIO_SELECT_I2C 0x0 +#define ADV7533_AUDIO_SELECT_SPDIF 0x1 +#define ADV7533_AUDIO_SELECT_DSD 0x2 +#define ADV7533_AUDIO_SELECT_HBR 0x3 +#define ADV7533_AUDIO_SELECT_DST 0x4 + +#define ADV7533_I2S_SAMPLE_LEN_16 0x2 +#define ADV7533_I2S_SAMPLE_LEN_20 0x3 +#define ADV7533_I2S_SAMPLE_LEN_18 0x4 +#define ADV7533_I2S_SAMPLE_LEN_22 0x5 +#define ADV7533_I2S_SAMPLE_LEN_19 0x8 +#define ADV7533_I2S_SAMPLE_LEN_23 0x9 +#define ADV7533_I2S_SAMPLE_LEN_24 0xb +#define ADV7533_I2S_SAMPLE_LEN_17 0xc +#define ADV7533_I2S_SAMPLE_LEN_21 0xd + +#define ADV7533_SAMPLE_FREQ_44100 0x0 +#define ADV7533_SAMPLE_FREQ_48000 0x2 +#define ADV7533_SAMPLE_FREQ_32000 0x3 +#define ADV7533_SAMPLE_FREQ_88200 0x8 +#define ADV7533_SAMPLE_FREQ_96000 0xa +#define ADV7533_SAMPLE_FREQ_176400 0xc +#define ADV7533_SAMPLE_FREQ_192000 0xe + +#define ADV7533_STATUS_POWER_DOWN_POLARITY BIT(7) +#define ADV7533_STATUS_HPD BIT(6) +#define ADV7533_STATUS_MONITOR_SENSE BIT(5) +#define ADV7533_STATUS_I2S_32BIT_MODE BIT(3) + +#define ADV7533_PACKET_ENABLE_N_CTS BIT(8+6) +#define ADV7533_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) +#define ADV7533_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) +#define ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) +#define ADV7533_PACKET_ENABLE_GC BIT(7) +#define ADV7533_PACKET_ENABLE_SPD BIT(6) +#define ADV7533_PACKET_ENABLE_MPEG BIT(5) +#define ADV7533_PACKET_ENABLE_ACP BIT(4) +#define ADV7533_PACKET_ENABLE_ISRC BIT(3) +#define ADV7533_PACKET_ENABLE_GM BIT(2) +#define ADV7533_PACKET_ENABLE_SPARE2 BIT(1) +#define ADV7533_PACKET_ENABLE_SPARE1 BIT(0) + +#define ADV7533_REG_POWER2_HDP_SRC_MASK 0xc0 +#define ADV7533_REG_POWER2_HDP_SRC_BOTH 0x00 +#define ADV7533_REG_POWER2_HDP_SRC_HDP 0x40 +#define ADV7533_REG_POWER2_HDP_SRC_CEC 0x80 +#define ADV7533_REG_POWER2_HDP_SRC_NONE 0xc0 +#define ADV7533_REG_POWER2_TDMS_ENABLE BIT(4) +#define ADV7533_REG_POWER2_GATE_INPUT_CLK BIT(0) + +#define ADV7533_LOW_REFRESH_RATE_NONE 0x0 +#define ADV7533_LOW_REFRESH_RATE_24HZ 0x1 +#define ADV7533_LOW_REFRESH_RATE_25HZ 0x2 +#define ADV7533_LOW_REFRESH_RATE_30HZ 0x3 + +#define ADV7533_AUDIO_CFG3_LEN_MASK 0x0f +#define ADV7533_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 + +#define ADV7533_AUDIO_SOURCE_I2S 0 +#define ADV7533_AUDIO_SOURCE_SPDIF 1 + +#define ADV7533_I2S_FORMAT_I2S 0 +#define ADV7533_I2S_FORMAT_RIGHT_J 1 +#define ADV7533_I2S_FORMAT_LEFT_J 2 + +#define ADV7533_PACKET(p, x) ((p) * 0x20 + (x)) +#define ADV7533_PACKET_SDP(x) ADV7533_PACKET(0, x) +#define ADV7533_PACKET_MPEG(x) ADV7533_PACKET(1, x) +#define ADV7533_PACKET_ACP(x) ADV7533_PACKET(2, x) +#define ADV7533_PACKET_ISRC1(x) ADV7533_PACKET(3, x) +#define ADV7533_PACKET_ISRC2(x) ADV7533_PACKET(4, x) +#define ADV7533_PACKET_GM(x) ADV7533_PACKET(5, x) +#define ADV7533_PACKET_SPARE(x) ADV7533_PACKET(6, x) + +#define EDID_LENGTH 0x80 +#define EDID_EXTENSION_NUM 0x7e + +/* Video mode flags */ +/* bit compatible with the xorg definitions. */ +#define MODE_FLAG_PHSYNC (1<<0) +#define MODE_FLAG_NHSYNC (1<<1) +#define MODE_FLAG_PVSYNC (1<<2) +#define MODE_FLAG_NVSYNC (1<<3) +#define MODE_FLAG_INTERLACE (1<<4) +#define MODE_FLAG_DBLSCAN (1<<5) +#define MODE_FLAG_CSYNC (1<<6) +#define MODE_FLAG_PCSYNC (1<<7) +#define MODE_FLAG_NCSYNC (1<<8) +#define MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define MODE_FLAG_BCAST (1<<10) +#define MODE_FLAG_PIXMUX (1<<11) +#define MODE_FLAG_DBLCLK (1<<12) +#define MODE_FLAG_CLKDIV2 (1<<13) + +/* + * Note on terminology: here, for brevity and convenience, we refer to connector + * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, + * DVI, etc. And 'screen' refers to the whole of the visible display, which + * may span multiple monitors (and therefore multiple CRTC and connector + * structures). + */ + +enum mode_status { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a matching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_NO_STEREO, /* stereo modes not supported */ + MODE_UNVERIFIED = -3, /* mode needs to reverified */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +}; + +enum DDC_controller_status { + IN_RESET = 0, /* In Reset (No Hot Plug Detected) */ + READING_EDID, /* Reading EDID */ + IDLE, /* IDLE (Waiting for HDCP Requested) */ + INIT_HDCP, /* Initializing HDCP */ + HDCP_ENABLE, /* HDCP Enabled */ + INIT_HDCP_REPEAT /* Initializing HDCP Repeater */ +}; + +/* If detailed data is pixel timing */ +struct detailed_pixel_timing { + u8 hactive_lo; + u8 hblank_lo; + u8 hactive_hblank_hi; + u8 vactive_lo; + u8 vblank_lo; + u8 vactive_vblank_hi; + u8 hsync_offset_lo; + u8 hsync_pulse_width_lo; + u8 vsync_offset_pulse_width_lo; + u8 hsync_vsync_offset_pulse_width_hi; + u8 width_mm_lo; + u8 height_mm_lo; + u8 width_height_mm_hi; + u8 hborder; + u8 vborder; + u8 misc; +} __attribute__ ((packed)); + +struct est_timings { + u8 t1; + u8 t2; + u8 mfg_rsvd; +} __attribute__ ((packed)); + +struct std_timing { + u8 hsize; /* need to multiply by 8 then add 248 */ + u8 vfreq_aspect; +} __attribute__ ((packed)); + +struct detailed_timing { + __le16 pixel_clock; /* need to multiply by 10 KHz */ + union { + struct detailed_pixel_timing pixel_data; + /* struct detailed_non_pixel other_data;*/ + } data; +} __attribute__ ((packed)); + +struct edid { + u8 header[8]; + /* Vendor & product info */ + u8 mfg_id[2]; + u8 prod_code[2]; + u32 serial; /* FIXME: byte order */ + u8 mfg_week; + u8 mfg_year; + /* EDID version */ + u8 version; + u8 revision; + /* Display info: */ + u8 input; + u8 width_cm; + u8 height_cm; + u8 gamma; + u8 features; + /* Color characteristics */ + u8 red_green_lo; + u8 black_white_lo; + u8 red_x; + u8 red_y; + u8 green_x; + u8 green_y; + u8 blue_x; + u8 blue_y; + u8 white_x; + u8 white_y; + /* Est. timings and mfg rsvd timings */ + struct est_timings established_timings; + /* Standard timings 1-8 */ + struct std_timing standard_timings[8]; + /* Detailing timings 1-4 */ + struct detailed_timing detailed_timings[4]; + /* Number of 128 byte ext. blocks */ + u8 extensions; + /* Checksum */ + u8 checksum; +} __attribute__ ((packed)); + +/** + * enum adv75xx_csc_scaling - Scaling factor for the ADV75xx CSC + * @ADV75xx_CSC_SCALING_1: CSC results are not scaled + * @ADV75xx_CSC_SCALING_2: CSC results are scaled by a factor of two + * @ADV75xx_CSC_SCALING_4: CSC results are scalled by a factor of four + */ +enum adv75xx_csc_scaling { + ADV75xx_CSC_SCALING_1 = 0, + ADV75xx_CSC_SCALING_2 = 1, + ADV75xx_CSC_SCALING_4 = 2, +}; + +/** + * struct adv75xx_video_config - Describes adv75xx hardware configuration + * @csc_enable: Whether to enable color space conversion + * @csc_scaling_factor: Color space conversion scaling factor + * @csc_coefficents: Color space conversion coefficents + * @hdmi_mode: Whether to use HDMI or DVI output mode + * @avi_infoframe: HDMI infoframe + */ +struct adv75xx_video_config { + bool csc_enable; + enum adv75xx_csc_scaling csc_scaling_factor; + const uint16_t *csc_coefficents; + + bool hdmi_mode; + struct hdmi_avi_infoframe avi_infoframe; +}; + +struct hisi_display_mode { + + unsigned int type; + + /* Proposed mode values */ + int clock; /* in kHz */ + int hdisplay; + int hsync_start; + int hsync_end; + int hsync_pulse_width; + int hsync_offset; + int htotal; + + int vdisplay; + int vsync_start; + int vsync_end; + int vsync_pulse_width; + int vsync_offset; + int vtotal; + int vscan; + unsigned int flags; + + /* Addressable image size (may be 0 for projectors, etc.) */ + int width_mm; + int height_mm; + + int vrefresh; /* in Hz */ + int hsync; /* in kHz */ + enum hdmi_picture_aspect picture_aspect_ratio; +}; + +/** + * enum adv7511_sync_polarity - Polarity for the input sync signals + * @ADV7533_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of + * the currently configured mode. + * @ADV7533_SYNC_POLARITY_LOW: Sync polarity is low + * @ADV7533_SYNC_POLARITY_HIGH: Sync polarity is high + * + * If the polarity is set to either LOW or HIGH the driver will configure the + * ADV7533 to internally invert the sync signal if required to match the sync + * polarity setting for the currently selected output mode. + * + * If the polarity is set to PASSTHROUGH, the ADV7533 will route the signal + * unchanged. This is used when the upstream graphics core already generates + * the sync signals with the correct polarity. + */ +enum adi_sync_polarity { + ADV7533_SYNC_POLARITY_PASSTHROUGH, + ADV7533_SYNC_POLARITY_LOW, + ADV7533_SYNC_POLARITY_HIGH, +}; + +enum adv75xx_type { + ADV7511, + ADV7533, + ADV7535, +}; + +enum connector_status { + connector_status_connected = 1, + connector_status_disconnected = 2, + connector_status_unknown = 3, +}; + +struct adi_hdmi { + enum adv75xx_type type; + bool powered; + + struct regulator *vdd; + struct regulator *v1p2; + + struct i2c_client *i2c_main; + struct i2c_client *i2c_edid; + struct i2c_client *i2c_cec; + struct i2c_client *i2c_packet; + + struct regmap *regmap; + struct regmap *regmap_cec; + struct regmap *regmap_packet; + enum connector_status status; + + unsigned int f_tmds; + unsigned int f_audio; + unsigned int audio_source; + + bool edid_read; + unsigned int current_edid_segment; + + wait_queue_head_t wq; + + bool rgb; + bool embedded_sync; + enum adi_sync_polarity vsync_polarity; + enum adi_sync_polarity hsync_polarity; + uint8_t num_dsi_lanes; + + struct edid *edid; + struct gpio_desc *gpio_pd; + + struct hisi_display_mode *mode; + struct adi_operation_funcs *opt_funcs; +}; + +struct adi_operation_funcs { + void (*power_on)(struct adi_hdmi *adv75xx); + void (*power_off)(struct adi_hdmi *adv75xx); + void (*mode_set)(struct adi_hdmi *adv75xx, + struct hisi_display_mode *mode); +}; + +#endif /* __ADV75XX_H__ */ diff --git a/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c new file mode 100755 index 000000000000..8242579107b2 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/adv75xx_audio.c @@ -0,0 +1,310 @@ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "adv75xx.h" + +static const struct snd_soc_dapm_widget adv75xx_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("TMDS"), + SND_SOC_DAPM_AIF_IN("AIFIN", "Playback", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route adv75xx_routes[] = { + {"TMDS", NULL, "AIFIN"}, +}; + +static void adv75xx_calc_cts_n(unsigned int f_tmds, unsigned int fs, + unsigned int *cts, unsigned int *n) +{ + switch (fs) { + case 32000: + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + *n = 6144; + break; + } + + *cts = ((f_tmds * *n) / (128 * fs)) * 1000; +} + +static int adv75xx_update_cts_n(struct adi_hdmi *adv75xx) +{ + unsigned int cts = 0; + unsigned int n = 0; + + adv75xx_calc_cts_n(adv75xx->f_tmds, adv75xx->f_audio, &cts, &n); + + regmap_write(adv75xx->regmap, ADV7533_REG_N0, (n >> 16) & 0xf); + regmap_write(adv75xx->regmap, ADV7533_REG_N1, (n >> 8) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_N2, n & 0xff); + + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL0, + (cts >> 16) & 0xf); + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL1, + (cts >> 8) & 0xff); + regmap_write(adv75xx->regmap, ADV7533_REG_CTS_MANUAL2, cts & 0xff); + + return 0; +} + +static int adv75xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + unsigned int len; + switch (params_rate(params)) { + case 32000: + rate = ADV7533_SAMPLE_FREQ_32000; + break; + case 44100: + rate = ADV7533_SAMPLE_FREQ_44100; + break; + case 48000: + rate = ADV7533_SAMPLE_FREQ_48000; + break; + case 88200: + rate = ADV7533_SAMPLE_FREQ_88200; + break; + case 96000: + rate = ADV7533_SAMPLE_FREQ_96000; + break; + case 176400: + rate = ADV7533_SAMPLE_FREQ_176400; + break; + case 192000: + rate = ADV7533_SAMPLE_FREQ_192000; + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + len = ADV7533_I2S_SAMPLE_LEN_16; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + len = ADV7533_I2S_SAMPLE_LEN_18; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + len = ADV7533_I2S_SAMPLE_LEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + len = ADV7533_I2S_SAMPLE_LEN_24; + break; + default: + return -EINVAL; + } + + adv75xx->f_audio = params_rate(params); + + adv75xx_update_cts_n(adv75xx); + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CFG3, + ADV7533_AUDIO_CFG3_LEN_MASK, len); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_I2C_FREQ_ID_CFG, + ADV7533_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4); + regmap_write(adv75xx->regmap, 0x73, 0x1); + + return 0; +} + +static int adv75xx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + unsigned int audio_source, i2s_format = 0; + unsigned int invert_clock; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + audio_source = ADV7533_AUDIO_SOURCE_I2S; + i2s_format = ADV7533_I2S_FORMAT_LEFT_J; + break; + /* + case SND_SOC_DAIFMT_SPDIF: + audio_source = ADV7533_AUDIO_SOURCE_SPDIF; + break; + */ + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_clock = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + invert_clock = 1; + break; + default: + return -EINVAL; + } + + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_SOURCE, 0x70, + audio_source << 4); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CONFIG, BIT(6), + invert_clock << 6); + regmap_update_bits(adv75xx->regmap, ADV7533_REG_I2S_CONFIG, 0x03, + i2s_format); + + adv75xx->audio_source = audio_source; + + return 0; +} + +static int adv75xx_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct adi_hdmi *adv75xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + + switch (level) { + case SND_SOC_BIAS_ON: + switch (adv75xx->audio_source) { + case ADV7533_AUDIO_SOURCE_I2S: + break; + case ADV7533_AUDIO_SOURCE_SPDIF: + regmap_update_bits(adv75xx->regmap, + ADV7533_REG_AUDIO_CONFIG, BIT(7), + BIT(7)); + break; + } + break; + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level = SND_SOC_BIAS_STANDBY) { + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_SAMPLE); + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME); + adv75xx_packet_enable(adv75xx, + ADV7533_PACKET_ENABLE_N_CTS); + } else { + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_SAMPLE); + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME); + adv75xx_packet_disable(adv75xx, + ADV7533_PACKET_ENABLE_N_CTS); + } + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(adv75xx->regmap, ADV7533_REG_AUDIO_CONFIG, + BIT(7), 0); + break; + case SND_SOC_BIAS_OFF: + break; + } + dapm->bias_level = level; + return 0; +} + +#define ADV7533_RATES (SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define ADV7533_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops adv75xx_dai_ops = { + .hw_params = adv75xx_hw_params, + /*.set_sysclk = adv75xx_set_dai_sysclk, */ + .set_fmt = adv75xx_set_dai_fmt, +}; + +static struct snd_soc_dai_driver adv75xx_dai = { + .name = "adv75xx", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ADV7533_RATES, + .formats = ADV7533_FORMATS, + }, + .ops = &adv75xx_dai_ops, +}; + +static int adv75xx_suspend(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_OFF); +} + +static int adv75xx_resume(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv75xx_probe(struct snd_soc_codec *codec) +{ + return adv75xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +} + +static int adv75xx_remove(struct snd_soc_codec *codec) +{ + adv75xx_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static struct snd_soc_codec_driver adv75xx_codec_driver = { + .probe = adv75xx_probe, + .remove = adv75xx_remove, + .suspend = adv75xx_suspend, + .resume = adv75xx_resume, + .set_bias_level = adv75xx_set_bias_level, + + .dapm_widgets = adv75xx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adv75xx_dapm_widgets), + .dapm_routes = adv75xx_routes, + .num_dapm_routes = ARRAY_SIZE(adv75xx_routes), +}; + +int adv75xx_audio_init(struct device *dev) +{ + return snd_soc_register_codec(dev, &adv75xx_codec_driver, + &adv75xx_dai, 1); +} + +void adv75xx_audio_exit(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} diff --git a/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c b/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c new file mode 100755 index 000000000000..65313f54878d --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hdmi/mipi_adi_hdmi.c @@ -0,0 +1,314 @@ +/* Copyright (c) 2008-2011, Hisilicon Tech. Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "../hisi_fb.h" +#include "adv75xx.h" + +/******************************************************************************* + ** + */ +static int mipi_adi_hdmi_on(struct platform_device *pdev) +{ + struct adi_hdmi *adv75xx = NULL; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + + HISI_FB_INFO("+.\n"); + + if (pdev = NULL) { + HISI_FB_ERR("pdev is NULL!\n"); + return -1; + } + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d\n", pdev->name, pdev->id); + + hisifd = platform_get_drvdata(pdev); + if (hisifd = NULL) { + HISI_FB_ERR("platform get drivre data failed!!\n"); + return -1; + } + + HISI_FB_INFO("fb%d, +!\n", hisifd->index); + + pinfo = &(hisifd->panel_info); + + pdata = dev_get_platdata(&pdev->dev); + if (pdata = NULL) { + HISI_FB_ERR("devices get platform data failed!!\n"); + return -1; + } + + if (pdata->next) { + adv75xx = platform_get_drvdata(pdata->next); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + return -1; + } + } else { + HISI_FB_ERR("pdata->next is NULL!!\n"); + return -1; + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + if (pinfo->lcd_init_step = LCD_INIT_POWER_ON) { + pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE) { + pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE) { + adv75xx->opt_funcs->mode_set(adv75xx, adv75xx->mode); + adv75xx->opt_funcs->power_on(adv75xx); + } else { + HISI_FB_ERR("failed to init hdmi!\n"); + } + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static int mipi_adi_hdmi_off(struct platform_device *pdev) +{ + struct adi_hdmi *adv75xx = NULL; + struct hisi_fb_panel_data *pdata = NULL; + + HISI_FB_INFO("+.\n"); + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d +.\n", pdev->name, + pdev->id); + + if (pdata->next) { + adv75xx = platform_get_drvdata(pdata->next); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + return -1; + } + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + adv75xx->opt_funcs->power_off(adv75xx); + + HISI_FB_INFO("-.\n"); + + return 0; +} + +static int mipi_adi_hdmi_remove(struct platform_device *pdev) +{ + + return 0; +} + +/******************************************************************************* + ** + */ +static struct hisi_panel_info g_adi_hdmi_info = { 0 }; + +static struct hisi_fb_panel_data g_adi_hdmi_data = { + .panel_info = &g_adi_hdmi_info, + .on = mipi_adi_hdmi_on, + .off = mipi_adi_hdmi_off, +}; + +/******************************************************************************* + ** + */ +static int mipi_adi_hdmi_probe(struct platform_device *pdev) +{ + int ret = 0; + struct adi_hdmi *adv75xx = NULL; + struct hisi_panel_info *pinfo = NULL; + struct hisi_display_mode *mode = NULL; + + if (pdev = NULL) + HISI_FB_ERR("platform device is NULL!\n"); + + HISI_FB_INFO("pdev->name = %s, pdev->id = %d +.\n", pdev->name, + pdev->id); + + adv75xx = platform_get_drvdata(pdev); + if (!adv75xx) { + HISI_FB_ERR("platform get drivre data failed!\n"); + goto err_probe_defer; + } + + HISI_FB_INFO("adv75xx->i2c_main->name is %s!\n", + adv75xx->i2c_main->name); + + HISI_FB_INFO("adv75xx->mode->vdisplay is %d!\n", + adv75xx->mode->vdisplay); + + if (adv75xx->mode) { + mode = adv75xx->mode; + /* init hdmi display info */ + pinfo = g_adi_hdmi_data.panel_info; + pinfo->xres = mode->hdisplay; + pinfo->yres = mode->vdisplay; + pinfo->width = mode->width_mm; + pinfo->height = mode->height_mm; + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = BL_SET_BY_MIPI; + + pinfo->type = PANEL_MIPI_VIDEO; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + + pinfo->pxl_clk_rate = mode->clock * 1000UL; + pinfo->ldi.h_back_porch = mode->htotal - mode->hsync_end; + pinfo->ldi.h_front_porch = mode->hsync_offset; + pinfo->ldi.h_pulse_width = mode->hsync_pulse_width; + pinfo->ldi.v_back_porch = mode->vtotal - mode->vsync_end; + pinfo->ldi.v_front_porch = mode->vsync_offset; + pinfo->ldi.v_pulse_width = mode->vsync_pulse_width; + } else { + /* init hdmi display info */ + pinfo = g_adi_hdmi_data.panel_info; + pinfo->xres = 1920; + pinfo->yres = 1080; + pinfo->width = 16000; + pinfo->height = 9000; + + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = BL_SET_BY_MIPI; + + pinfo->type = PANEL_MIPI_VIDEO; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + + pinfo->ldi.h_back_porch = 148; + pinfo->ldi.h_front_porch = 88; + pinfo->ldi.h_pulse_width = 44; + pinfo->ldi.v_back_porch = 36; + pinfo->ldi.v_front_porch = 4; + pinfo->ldi.v_pulse_width = 5; + } + + + pinfo->mipi.dsi_bit_clk = 480; + + + pinfo->dsi_bit_clk_upt_support = 0; + pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk; + + pinfo->mipi.non_continue_en = 0; + + pinfo->pxl_clk_rate = 160 * 1000000UL; + + + pinfo->mipi.lane_nums = DSI_4_LANES; + pinfo->mipi.color_mode = DSI_24BITS_1; + pinfo->mipi.vc = 0; + pinfo->mipi.max_tx_esc_clk = 10 * 1000000; + pinfo->mipi.burst_mode = DSI_NON_BURST_SYNC_PULSES; + + pinfo->mipi.clk_post_adjust = 120; + pinfo->mipi.clk_pre_adjust = 0; + pinfo->mipi.clk_t_hs_prepare_adjust = 0; + pinfo->mipi.clk_t_lpx_adjust = 0; + pinfo->mipi.clk_t_hs_trial_adjust = 0; + pinfo->mipi.clk_t_hs_exit_adjust = 0; + pinfo->mipi.clk_t_hs_zero_adjust = 0; + + pinfo->pxl_clk_rate_div = 1; + + g_adi_hdmi_data.next = pdev; + HISI_FB_INFO("The pixel clock is %llu !\n", pinfo->pxl_clk_rate); + HISI_FB_INFO("The resolution is %d x %d !\n", pinfo->xres, pinfo->yres); + HISI_FB_INFO + ("hsw = %d, hfp = %d, hbp = %d, vsw = %d, vfp= %d, vbp = %d\n", + pinfo->ldi.h_pulse_width, pinfo->ldi.h_front_porch, + pinfo->ldi.h_back_porch, pinfo->ldi.v_pulse_width, + pinfo->ldi.v_front_porch, pinfo->ldi.v_back_porch); + + + ret = platform_device_add_data(pdev, &g_adi_hdmi_data, + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("platform_device_add_data failed!\n"); + goto err_device_put; + } + + hisi_fb_add_device(pdev); + + HISI_FB_INFO("-.\n"); + + return 0; + + err_device_put: + platform_device_put(pdev); + err_probe_defer: + return -EPROBE_DEFER; +} + +static struct platform_driver this_driver = { + .probe = mipi_adi_hdmi_probe, + .remove = mipi_adi_hdmi_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "adi_hdmi", + } +}; + +static int __init mipi_adi_hdmi_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(mipi_adi_hdmi_init); diff --git a/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c b/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c new file mode 100755 index 000000000000..7e1fbd0ee5c6 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/panel/mipi_hikey_nte300nts.c @@ -0,0 +1,525 @@ +/* Copyright (c) 2008-2014, Hisilicon Tech. Co., Ltd. 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 "../hisi_fb.h" + +#define DTS_COMP_MIPI_HIKEY "hisilicon,mipi_hikey" + +/********************************Hikey start*********************** + **Power ON Sequence(sleep mode to Normal mode) + */ +static char hikey_power_on_param1[] = { + 0x01, +}; + +static char hikey_power_on_param2[] = { + 0xB0, + 0x00, +}; + +static char hikey_power_on_param3[] = { + 0xD6, + 0x01, +}; + +static char hikey_power_on_param4[] = { + 0xB3, + 0x14, 0x08, 0x00, 0x22, 0x00, +}; + +static char hikey_power_on_param5[] = { + 0xB4, + 0x0C, +}; + +static char hikey_power_on_param6[] = { + 0xB6, + 0x3A, 0xC3, +}; + +static char hikey_power_on_param7[] = { + 0x2A, + 0x00, 0x00, 0X04, 0XAF, +}; + +static char hikey_power_on_param8[] = { + 0x2B, + 0x00, 0x00, 0X07, 0X7F, +}; + +static char hikey_power_on_param9[] = { + 0x51, + 0xA6, +}; + +static char hikey_power_on_param10[] = { + 0x53, + 0x2C, +}; + +static char hikey_power_on_param11[] = { + 0x3A, + 0x66, +}; + +static char hikey_power_on_param12[] = { + 0x29, +}; + +static char hikey_power_on_param13[] = { + 0x11, +}; + +static char hikey_display_off[] = { + 0x28, +}; + +static char hikey_enter_sleep[] = { + 0x10, +}; + +static struct dsi_cmd_desc hikey_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 0, 20, WAIT_TYPE_MS, + sizeof(hikey_display_off), hikey_display_off} + , + {DTYPE_DCS_WRITE, 0, 80, WAIT_TYPE_MS, + sizeof(hikey_enter_sleep), hikey_enter_sleep} + , +}; + +/*short or long packet*/ +static struct dsi_cmd_desc hikey_display_on_cmds[] = { + {DTYPE_DCS_WRITE, 0, 5, WAIT_TYPE_MS, + sizeof(hikey_power_on_param1), hikey_power_on_param1} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param2), hikey_power_on_param2} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param3), hikey_power_on_param3} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param4), hikey_power_on_param4} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param5), hikey_power_on_param5} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param6), hikey_power_on_param6} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param7), hikey_power_on_param7} + , + {DTYPE_DCS_LWRITE, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param8), hikey_power_on_param8} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param9), hikey_power_on_param9} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param10), hikey_power_on_param10} + , + {DTYPE_DCS_WRITE1, 0, 2, WAIT_TYPE_MS, + sizeof(hikey_power_on_param11), hikey_power_on_param11} + , + {DTYPE_DCS_WRITE, 0, 20, WAIT_TYPE_MS, + sizeof(hikey_power_on_param12), hikey_power_on_param12} + , + {DTYPE_DCS_WRITE, 0, 150, WAIT_TYPE_MS, + sizeof(hikey_power_on_param13), hikey_power_on_param13} + , +}; + +/********************************hikey end*************************/ + +/******************************************************************************* + ** LCD GPIO + */ +#define GPIO_LCD_PWR_ENABLE_NAME "gpio_lcd_pwr_enable" +#define GPIO_LCD_BL_ENABLE_NAME "gpio_lcd_bl_enable" +#define GPIO_LCD_PWM_NAME "gpio_lcd_pwm" +#define GPIO_SWITCH_DSI_HDMI "gpio_switch_dsi_hdmi" + +static uint32_t gpio_lcd_pwr_enable; +static uint32_t gpio_lcd_bl_enable; +static uint32_t gpio_lcd_pwm; +static uint32_t gpio_switch_dsi_hdmi; + +static struct gpio_desc hikey_lcd_gpio_request_cmds[] = { + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, + {DTYPE_GPIO_REQUEST, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_gpio_free_cmds[] = { + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, + {DTYPE_GPIO_FREE, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_gpio_normal_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 1}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 1}, +}; + +static struct gpio_desc hikey_lcd_gpio_off_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWR_ENABLE_NAME, &gpio_lcd_pwr_enable, 0}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_SWITCH_DSI_HDMI, &gpio_switch_dsi_hdmi, 0}, +}; + +static struct gpio_desc hikey_lcd_backlight_enable_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 1}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 1}, +}; + +static struct gpio_desc hikey_lcd_backlight_disable_cmds[] = { + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_BL_ENABLE_NAME, &gpio_lcd_bl_enable, 0}, + {DTYPE_GPIO_OUTPUT, WAIT_TYPE_MS, 0, + GPIO_LCD_PWM_NAME, &gpio_lcd_pwm, 0}, +}; + +static struct hisi_fb_panel_data g_panel_data; + +static void hikey_set_backlight_on(void) +{ + msleep(200); + gpio_cmds_tx(hikey_lcd_backlight_enable_cmds, + ARRAY_SIZE(hikey_lcd_backlight_enable_cmds)); + return; +} + +static void hikey_set_backlight_off(void) +{ + gpio_cmds_tx(hikey_lcd_backlight_disable_cmds, + ARRAY_SIZE(hikey_lcd_backlight_disable_cmds)); + return; +} + +static int hikey_panel_on(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + char __iomem *mipi_dsi0_base = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + pinfo = &(hisifd->panel_info); + BUG_ON(pinfo = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + mipi_dsi0_base = hisifd->mipi_dsi0_base; + + if (pinfo->lcd_init_step = LCD_INIT_POWER_ON) { + pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step = LCD_INIT_MIPI_LP_SEND_SEQUENCE) { + /*lcd gpio request */ + gpio_cmds_tx(hikey_lcd_gpio_request_cmds, + ARRAY_SIZE(hikey_lcd_gpio_request_cmds)); + /*lcd gpio normal */ + gpio_cmds_tx(hikey_lcd_gpio_normal_cmds, + ARRAY_SIZE(hikey_lcd_gpio_normal_cmds)); + /*lcd display on sequence */ + msleep(250); + mipi_dsi_cmds_tx(hikey_display_on_cmds, + ARRAY_SIZE(hikey_display_on_cmds), + mipi_dsi0_base); + + pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE; + } else if (pinfo->lcd_init_step = LCD_INIT_MIPI_HS_SEND_SEQUENCE) { + ; + } else { + HISI_FB_ERR("failed to init lcd!\n"); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_off(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + char __iomem *mipi_dsi0_base = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + pinfo = &(hisifd->panel_info); + BUG_ON(pinfo = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + mipi_dsi0_base = hisifd->mipi_dsi0_base; + /*lcd enter sleep */ + mipi_dsi_cmds_tx(hikey_display_off_cmds, + ARRAY_SIZE(hikey_display_off_cmds), mipi_dsi0_base); + gpio_cmds_tx(hikey_lcd_gpio_off_cmds, + ARRAY_SIZE(hikey_lcd_gpio_off_cmds)); + gpio_cmds_tx(hikey_lcd_gpio_free_cmds, + ARRAY_SIZE(hikey_lcd_gpio_free_cmds)); + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_remove(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hikey_panel_set_backlight(struct platform_device *pdev, + uint32_t bl_level) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (bl_level = 0) { + hikey_set_backlight_off(); + } else { + hikey_set_backlight_on(); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static struct hisi_panel_info g_panel_info = { 0 }; + +static struct hisi_fb_panel_data g_panel_data = { + .panel_info = &g_panel_info, + .on = hikey_panel_on, + .off = hikey_panel_off, + .remove = hikey_panel_remove, + .set_backlight = hikey_panel_set_backlight, +}; + +static int hikey_probe(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_panel_info *pinfo = NULL; + struct device_node *np = NULL; + uint32_t bl_type = 0; + + uint32_t lcd_display_type = 0; + uint32_t lcd_ifbc_type = 0; + + HISI_FB_DEBUG("+.\n"); + + np = of_find_compatible_node(NULL, NULL, DTS_COMP_MIPI_HIKEY); + if (!np) { + HISI_FB_ERR("NOT FOUND device node %s!\n", DTS_COMP_MIPI_HIKEY); + goto err_return; + } + + ret = of_property_read_u32(np, LCD_BL_TYPE_NAME, &bl_type); + if (ret) { + HISI_FB_ERR("get lcd_bl_type failed!\n"); + bl_type = BL_SET_BY_BLPWM; + } + + ret + of_property_read_u32(np, LCD_DISPLAY_TYPE_NAME, &lcd_display_type); + if (ret) { + HISI_FB_ERR("get lcd_display_type failed!\n"); + lcd_display_type = PANEL_MIPI_VIDEO; + } + + ret = of_property_read_u32(np, LCD_IFBC_TYPE_NAME, &lcd_ifbc_type); + if (ret) { + HISI_FB_ERR("get ifbc_type failed!\n"); + lcd_ifbc_type = IFBC_TYPE_NONE; + } + + /*GPIO_26_8 GPIO_216 */ + gpio_lcd_pwr_enable = of_get_named_gpio(np, "gpios", 0); + /*GPIO_27_2 GPIO_218 */ + gpio_lcd_bl_enable = of_get_named_gpio(np, "gpios", 1); + /*GPIO_22_6 GPIO_182 */ + gpio_lcd_pwm = of_get_named_gpio(np, "gpios", 2); + /*GPIO_2_4 GPIO_020 */ + gpio_switch_dsi_hdmi = of_get_named_gpio(np, "gpios", 3); + + if (hisi_fb_device_probe_defer(lcd_display_type, bl_type)) { + goto err_probe_defer; + } + + pdev->id = 1; + /*init lcd panel info */ + pinfo = g_panel_data.panel_info; + memset(pinfo, 0, sizeof(struct hisi_panel_info)); + pinfo->xres = 1200; + pinfo->yres = 1920; + pinfo->width = 94; + pinfo->height = 151; + pinfo->orientation = LCD_PORTRAIT; + pinfo->bpp = LCD_RGB888; + pinfo->bgr_fmt = LCD_RGB; + pinfo->bl_set_type = bl_type; + + pinfo->type = PANEL_MIPI_VIDEO; + pinfo->ifbc_type = 0; + + if (pinfo->bl_set_type = BL_SET_BY_BLPWM) + pinfo->blpwm_input_ena = 0; + + pinfo->bl_min = 1; + pinfo->bl_max = 255; + pinfo->bl_default = 102; + pinfo->esd_enable = 0; + + /*ldi */ + pinfo->ldi.h_back_porch = 60; + pinfo->ldi.h_front_porch = 200; + pinfo->ldi.h_pulse_width = 12; + pinfo->ldi.v_back_porch = 8; + pinfo->ldi.v_front_porch = 8; + pinfo->ldi.v_pulse_width = 2; + + /* + pinfo->ldi.hsync_plr = 0; + pinfo->ldi.vsync_plr = 0; + pinfo->ldi.pixelclk_plr = 1; + pinfo->ldi.data_en_plr = 0; + */ + + /*mipi */ + pinfo->mipi.lane_nums = DSI_4_LANES; + pinfo->mipi.color_mode = DSI_24BITS_1; + pinfo->mipi.vc = 0; + pinfo->mipi.max_tx_esc_clk = 10 * 1000000; + pinfo->mipi.burst_mode = DSI_BURST_SYNC_PULSES_1; + + pinfo->mipi.dsi_bit_clk = 480; + pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk; + + pinfo->pxl_clk_rate = 146 * 1000000UL; + pinfo->pxl_clk_rate_div = 1; + pinfo->fps = 50; + + pinfo->vsync_ctrl_type = 0; + pinfo->dirty_region_updt_support = 0; + pinfo->dsi_bit_clk_upt_support = 0; + + /*alloc panel device data */ + ret = platform_device_add_data(pdev, &g_panel_data, + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("platform_device_add_data failed!\n"); + goto err_device_put; + } + + hisi_fb_add_device(pdev); + + /* + vdd = devm_regulator_get(&(pdev->dev), "vdd"); + if (IS_ERR(vdd)) { + ret = PTR_ERR(vdd); + HISI_FB_ERR("vdd regulator get fail\n"); + return ret; + } + + ret = regulator_set_voltage(vdd, 1800000, 1800000); + if (ret) { + HISI_FB_ERR("vdd regulator set voltage fail\n"); + return ret; + } + + ret = regulator_enable(vdd); + if (ret) { + HISI_FB_ERR("vdd regulator enable fail\n"); + return ret; + } + */ + + HISI_FB_DEBUG("-.\n"); + return 0; + + err_device_put: + platform_device_put(pdev); + err_return: + return ret; + err_probe_defer: + return -EPROBE_DEFER; +} + +static const struct of_device_id hisi_panel_match_table[] = { + { + .compatible = DTS_COMP_MIPI_HIKEY, + .data = NULL, + }, + {}, +}; + +static struct platform_driver this_driver = { + .probe = hikey_probe, + .remove = NULL, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "mipi_hikey", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(hisi_panel_match_table), + }, +}; + +static int __init hikey_panel_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(hikey_panel_init); -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei (?) (?) @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_dpe.c | 763 +++++++++ drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h | 64 + drivers/video/fbdev/hisi/dss/hisi_fb.c | 2232 +++++++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_fb.h | 559 +++++++ drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c | 1686 +++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h | 152 ++ 6 files changed, 5456 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dpe.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_dpe.c b/drivers/video/fbdev/hisi/dss/hisi_dpe.c new file mode 100755 index 000000000000..fef13287c933 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_dpe.c @@ -0,0 +1,763 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_dpe_utils.h" +#include "hisi_overlay_utils.h" +#ifdef CONFIG_HISI_OCBC +#include <linux/hisi/ocbc.h> +#endif + +static int dpe_init(struct hisi_fb_data_type *hisifd, bool fastboot_enable) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + init_post_scf(hisifd); + init_dbuf(hisifd); + init_dpp(hisifd); + /* init_sbl(hisifd); */ + init_acm(hisifd); + init_dpp_csc(hisifd); + init_igm_gmp_xcc_gm(hisifd); + + init_ifbc(hisifd); + init_ldi(hisifd, fastboot_enable); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + if (hisifd->dss_pxl1_clk) + clk_disable(hisifd->dss_pxl1_clk); + + set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_DSI1_CLK_SEL, + 0x1, 1, 0); + + if (hisifd->dss_pxl1_clk) + clk_enable(hisifd->dss_pxl1_clk); + + set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_DSI1_RST_SEL, + 0x1, 1, 0); + /* dual lcd: dsi_mux_sel=1, dual mipi: dsi_mux_sel=0 */ + set_reg(hisifd->dss_base + DSS_MCTRL_SYS_OFFSET + + MCTL_DSI_MUX_SEL, 0x1, 1, 0); + + init_dbuf(hisifd); + init_ldi(hisifd, fastboot_enable); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + ; + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + } + + return 0; +} + +static int dpe_deinit(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + deinit_ldi(hisifd); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + deinit_ldi(hisifd); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + ; + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + } + + return 0; +} + +static void dpe_check_itf_status(struct hisi_fb_data_type *hisifd) +{ + int tmp = 0; + int delay_count = 0; + bool is_timeout = true; + int itf_idx = 0; + char __iomem *mctl_sys_base = NULL; + + BUG_ON(hisifd == NULL); + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + itf_idx = hisifd->index; + mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET; + + while (1) { + tmp = + inp32(mctl_sys_base + MCTL_MOD17_STATUS + + itf_idx * 0x4); + if (((tmp & 0x10) == 0x10) || delay_count > 100) { + is_timeout = (delay_count > 100) ? true : false; + delay_count = 0; + break; + } else { + mdelay(1); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_DEBUG + ("mctl_itf%d not in idle status,ints=0x%x !\n", + hisifd->index, tmp); + } + } +} + +static int dpe_irq_enable(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->dpe_irq) + enable_irq(hisifd->dpe_irq); + + return 0; +} + +static int dpe_irq_disable(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->dpe_irq) + disable_irq(hisifd->dpe_irq); + + return 0; +} + +static int dpe_irq_disable_nosync(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->dpe_irq) + disable_irq_nosync(hisifd->dpe_irq); + + return 0; +} + +int dpe_common_clk_enable(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + +#ifdef CONFIG_DSS_MMBUF_CLK_USED + clk_tmp = hisifd->dss_mmbuf_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_mmbuf_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_mmbuf_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } +#endif + + clk_tmp = hisifd->dss_axi_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_axi_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_axi_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + clk_tmp = hisifd->dss_pclk_dss_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dss_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dss_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + return 0; +} + +int dpe_inner_clk_enable(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + + clk_tmp = hisifd->dss_pri_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pri_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pri_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + clk_tmp = hisifd->dss_pxl0_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pxl0_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pxl0_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + clk_tmp = hisifd->dss_pxl1_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pxl1_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pxl1_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + } else { + ; + } + + return 0; +} + +int dpe_common_clk_disable(struct hisi_fb_data_type *hisifd) +{ + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + + clk_tmp = hisifd->dss_pclk_dss_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + clk_tmp = hisifd->dss_axi_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } +#ifdef CONFIG_DSS_MMBUF_CLK_USED + clk_tmp = hisifd->dss_mmbuf_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } +#endif + + return 0; +} + +int dpe_inner_clk_disable(struct hisi_fb_data_type *hisifd) +{ + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + clk_tmp = hisifd->dss_pxl0_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + clk_tmp = hisifd->dss_pxl1_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + } else { + ; + } + + clk_tmp = hisifd->dss_pri_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + return 0; +} + +/******************************************************************************* + ** + */ +static int dpe_on(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + dpe_common_clk_enable(hisifd); + dpe_inner_clk_enable(hisifd); + /*DSS regulator are already enabled in fastboot, kernel don't care */ + /*dpe_regulator_enable(hisifd); */ + + dss_inner_clk_common_enable(hisifd, false); + if (hisifd->index == PRIMARY_PANEL_IDX) { + dss_inner_clk_pdp_enable(hisifd, false); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + dss_inner_clk_sdp_enable(hisifd); + } else { + ; + } + + dpe_init(hisifd, false); + if (dpe_recover_pxl_clock(hisifd)) { + HISI_FB_ERR + ("fb%d failed to recover pixel clock which is larger than 288M!\n", + hisifd->index); + return -EINVAL; + } + + if (is_ldi_panel(hisifd)) { + hisifd->panel_info.lcd_init_step = LCD_INIT_POWER_ON; + ret = panel_next_on(pdev); + if (ret) { + HISI_FB_ERR("fb%d failed ret %d\n", hisifd->index, ret); + return -EINVAL; + } + } + + ret = panel_next_on(pdev); + if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) { + dpe_interrupt_mask(hisifd); + dpe_interrupt_clear(hisifd); + dpe_irq_enable(hisifd); + dpe_interrupt_unmask(hisifd); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int dpe_off(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) { + dpe_interrupt_mask(hisifd); + dpe_irq_disable(hisifd); + } else { + if (hisifd->vsync_ctrl.vsync_ctrl_enabled == 1) { + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) { + dpe_interrupt_mask(hisifd); + dpe_irq_disable(hisifd); + HISI_FB_INFO + ("fb%d, need to disable dpe irq! vsync_ctrl_enabled=%d.\n", + hisifd->index, + hisifd->vsync_ctrl.vsync_ctrl_enabled); + } + } + } + + ret = panel_next_off(pdev); + + dpe_deinit(hisifd); + dpe_check_itf_status(hisifd); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + dss_inner_clk_pdp_disable(hisifd); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + dss_inner_clk_sdp_disable(hisifd); + } else { + ; + } + dss_inner_clk_common_disable(hisifd); + + /*dpe_regulator_disable(hisifd); */ + dpe_inner_clk_disable(hisifd); + dpe_common_clk_disable(hisifd); + + if (hisifd->vsync_ctrl_type != VSYNC_CTRL_NONE) { + if (!is_dss_idle_enable()) + hisifd->panel_info.vsync_ctrl_type = VSYNC_CTRL_NONE; + else + hisifd->panel_info.vsync_ctrl_type = + hisifd->vsync_ctrl_type; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int dpe_remove(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = panel_next_remove(pdev); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int dpe_set_backlight(struct platform_device *pdev, uint32_t bl_level) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + HISI_FB_DEBUG("fb%d, bl_level=%d.\n", hisifd->index, bl_level); + + if (pinfo->bl_max < 1) { + HISI_FB_ERR("bl_max(%d) is out of range!!", pinfo->bl_max); + return -EINVAL; + } + + if (bl_level > pinfo->bl_max) { + bl_level = pinfo->bl_max; + } + + if (bl_level < pinfo->bl_min && bl_level) { + bl_level = pinfo->bl_min; + } + + ret = panel_next_set_backlight(pdev, bl_level); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int dpe_vsync_ctrl(struct platform_device *pdev, int enable) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (enable) { + ret = panel_next_vsync_ctrl(pdev, enable); + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) { + dpe_interrupt_mask(hisifd); + dpe_interrupt_clear(hisifd); + dpe_irq_enable(hisifd); + dpe_interrupt_unmask(hisifd); + } + } else { + ret = panel_next_vsync_ctrl(pdev, enable); + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) { + dpe_interrupt_mask(hisifd); + dpe_interrupt_clear(hisifd); + dpe_irq_disable_nosync(hisifd); + } + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int dpe_regulator_clk_irq_setup(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_panel_info *pinfo = NULL; + struct dss_clk_rate *pdss_clk_rate = NULL; + const char *irq_name = NULL; + irqreturn_t(*isr_fnc)(int irq, void *ptr); + int ret = 0; + uint64_t pxl_clk_rate = 0; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + pinfo = &(hisifd->panel_info); + pdss_clk_rate = get_dss_clk_rate(hisifd); + BUG_ON(pdss_clk_rate == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + irq_name = IRQ_PDP_NAME; + isr_fnc = dss_pdp_isr; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + irq_name = IRQ_SDP_NAME; + isr_fnc = dss_sdp_isr; + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + irq_name = IRQ_ADP_NAME; + isr_fnc = dss_adp_isr; + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + return -EINVAL; + } + + HISI_FB_INFO("dss_pclk_dss_clk:[%llu]->[%llu].\n", + pdss_clk_rate->dss_pclk_dss_rate, + (uint64_t) clk_get_rate(hisifd->dss_pclk_dss_clk)); + + ret = + clk_set_rate(hisifd->dss_pri_clk, pdss_clk_rate->dss_pri_clk_rate); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_pri_clk clk_set_rate(%llu) failed, error=%d!\n", + hisifd->index, pdss_clk_rate->dss_pri_clk_rate, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_pri_clk:[%llu]->[%llu].\n", + pdss_clk_rate->dss_pri_clk_rate, + (uint64_t) clk_get_rate(hisifd->dss_pri_clk)); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + pxl_clk_rate = + (pinfo->pxl_clk_rate > + DSS_MAX_PXL0_CLK_288M) ? DSS_MAX_PXL0_CLK_288M : pinfo-> + pxl_clk_rate; + if (pinfo->pxl_clk_rate_adjust > 0) { + ret = + clk_set_rate(hisifd->dss_pxl0_clk, + pinfo->pxl_clk_rate_adjust); + } else { + ret = clk_set_rate(hisifd->dss_pxl0_clk, pxl_clk_rate); + } + + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_pxl0_clk clk_set_rate(%llu) failed, error=%d!\n", + hisifd->index, pinfo->pxl_clk_rate, ret); + } + HISI_FB_INFO("dss_pxl0_clk:[%llu]->[%llu].\n", + pinfo->pxl_clk_rate, + (uint64_t) clk_get_rate(hisifd->dss_pxl0_clk)); + } else if ((hisifd->index == EXTERNAL_PANEL_IDX) + && !hisifd->panel_info.fake_hdmi) { + ret = clk_set_rate(hisifd->dss_pxl1_clk, pinfo->pxl_clk_rate); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_pxl1_clk clk_set_rate(%llu) failed, error=%d!\n", + hisifd->index, pinfo->pxl_clk_rate, ret); + } + HISI_FB_INFO("dss_pxl1_clk:[%llu]->[%llu].\n", + pinfo->pxl_clk_rate, + (uint64_t) clk_get_rate(hisifd->dss_pxl1_clk)); + } else { + ; + } + + if (hisifd->dpe_irq) { + ret = + request_irq(hisifd->dpe_irq, isr_fnc, 0, irq_name, + (void *)hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d request_irq failed, irq_no=%d error=%d!\n", + hisifd->index, hisifd->dpe_irq, ret); + return ret; + } else { + disable_irq(hisifd->dpe_irq); + } + } + return 0; +} + +static int dpe_probe(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct platform_device *hisi_fb_dev = NULL; + struct hisi_fb_panel_data *pdata = NULL; + struct fb_info *fbi = NULL; + int ret = 0; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = dpe_regulator_clk_irq_setup(pdev); + if (ret) { + HISI_FB_ERR("fb%d dpe_irq_clk_setup failed, error=%d!\n", + hisifd->index, ret); + goto err; + } + + /* alloc device */ + hisi_fb_dev = platform_device_alloc(DEV_NAME_FB, pdev->id); + if (!hisi_fb_dev) { + HISI_FB_ERR("fb%d platform_device_alloc failed, error=%d!\n", + hisifd->index, ret); + ret = -ENOMEM; + goto err_device_alloc; + } + + /* link to the latest pdev */ + hisifd->pdev = hisi_fb_dev; + + /* alloc panel device data */ + ret = + platform_device_add_data(hisi_fb_dev, dev_get_platdata(&pdev->dev), + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("fb%d platform_device_add_data failed, error=%d!\n", + hisifd->index, ret); + goto err_device_put; + } + + /* data chain */ + pdata = dev_get_platdata(&hisi_fb_dev->dev); + pdata->on = dpe_on; + pdata->off = dpe_off; + pdata->remove = dpe_remove; + pdata->set_backlight = dpe_set_backlight; + pdata->vsync_ctrl = dpe_vsync_ctrl; + pdata->next = pdev; + + /* get/set panel info */ + memcpy(&hisifd->panel_info, pdata->panel_info, + sizeof(struct hisi_panel_info)); + + fbi = hisifd->fbi; + fbi->var.pixclock = hisifd->panel_info.pxl_clk_rate; + /*fbi->var.pixclock = clk_round_rate(hisifd->dpe_clk, + hisifd->panel_info.pxl_clk_rate); */ + fbi->var.left_margin = hisifd->panel_info.ldi.h_back_porch; + fbi->var.right_margin = hisifd->panel_info.ldi.h_front_porch; + fbi->var.upper_margin = hisifd->panel_info.ldi.v_back_porch; + fbi->var.lower_margin = hisifd->panel_info.ldi.v_front_porch; + fbi->var.hsync_len = hisifd->panel_info.ldi.h_pulse_width; + fbi->var.vsync_len = hisifd->panel_info.ldi.v_pulse_width; + + hisifd->vsync_ctrl_type = hisifd->panel_info.vsync_ctrl_type; + + /* set driver data */ + platform_set_drvdata(hisi_fb_dev, hisifd); + ret = platform_device_add(hisi_fb_dev); + if (ret) { + HISI_FB_ERR("fb%d platform_device_add failed, error=%d!\n", + hisifd->index, ret); + goto err_device_put; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; + + err_device_put: + platform_device_put(hisi_fb_dev); + err_device_alloc: + err: + return ret; +} + +static struct platform_driver this_driver = { + .probe = dpe_probe, + .remove = NULL, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = DEV_NAME_DSS_DPE, + }, +}; + +static int __init dpe_driver_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(dpe_driver_init); diff --git a/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h new file mode 100755 index 000000000000..5cacb874c39b --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ + +#ifndef HISI_DPE_UTILS_H +#define HISI_DPE_UTILS_H + +#include "hisi_fb.h" + +#define COMFORM_MAX 80 +#define CHANGE_MAX 100 +#define DISCOUNT_COEFFICIENT(value) (CHANGE_MAX - value) / CHANGE_MAX + +struct dss_clk_rate *get_dss_clk_rate(struct hisi_fb_data_type *hisifd); +int set_dss_clk_rate(struct hisi_fb_data_type *hisifd, + dss_clk_rate_t dss_clk_rate); + +void init_post_scf(struct hisi_fb_data_type *hisifd); +void init_dbuf(struct hisi_fb_data_type *hisifd); +void init_dpp(struct hisi_fb_data_type *hisifd); +void init_acm(struct hisi_fb_data_type *hisifd); +void init_igm_gmp_xcc_gm(struct hisi_fb_data_type *hisifd); +void init_ifbc(struct hisi_fb_data_type *hisifd); +void init_ldi(struct hisi_fb_data_type *hisifd, bool fastboot_enable); +void deinit_ldi(struct hisi_fb_data_type *hisifd); +void enable_ldi(struct hisi_fb_data_type *hisifd); +void disable_ldi(struct hisi_fb_data_type *hisifd); +void ldi_frame_update(struct hisi_fb_data_type *hisifd, bool update); +void single_frame_update(struct hisi_fb_data_type *hisifd); +void ldi_data_gate(struct hisi_fb_data_type *hisifd, bool enble); +int dpe_recover_pxl_clock(struct hisi_fb_data_type *hisifd); +void init_dpp_csc(struct hisi_fb_data_type *hisifd); + +/* isr */ +irqreturn_t dss_pdp_isr(int irq, void *ptr); +irqreturn_t dss_sdp_isr(int irq, void *ptr); +irqreturn_t dss_adp_isr(int irq, void *ptr); + +void dpe_interrupt_clear(struct hisi_fb_data_type *hisifd); +void dpe_interrupt_unmask(struct hisi_fb_data_type *hisifd); +void dpe_interrupt_mask(struct hisi_fb_data_type *hisifd); +int dpe_common_clk_enable(struct hisi_fb_data_type *hisifd); +int dpe_inner_clk_enable(struct hisi_fb_data_type *hisifd); +int dpe_common_clk_disable(struct hisi_fb_data_type *hisifd); +int dpe_inner_clk_disable(struct hisi_fb_data_type *hisifd); +void dss_inner_clk_common_enable(struct hisi_fb_data_type *hisifd, + bool fastboot_enable); +void dss_inner_clk_common_disable(struct hisi_fb_data_type *hisifd); +void dss_inner_clk_pdp_enable(struct hisi_fb_data_type *hisifd, + bool fastboot_enable); +void dss_inner_clk_pdp_disable(struct hisi_fb_data_type *hisifd); +void dss_inner_clk_sdp_enable(struct hisi_fb_data_type *hisifd); +void dss_inner_clk_sdp_disable(struct hisi_fb_data_type *hisifd); + +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb.c b/drivers/video/fbdev/hisi/dss/hisi_fb.c new file mode 100755 index 000000000000..e3ff413e5d42 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb.c @@ -0,0 +1,2232 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_overlay_utils.h" +#include <linux/init.h> + +static int hisi_fb_resource_initialized; +static struct platform_device *pdev_list[HISI_FB_MAX_DEV_LIST] = { 0 }; + +static int pdev_list_cnt; +struct fb_info *fbi_list[HISI_FB_MAX_FBI_LIST] = { 0 }; + +static int fbi_list_index; + +struct hisi_fb_data_type *hisifd_list[HISI_FB_MAX_FBI_LIST] = { 0 }; + +static int hisifd_list_index; + +#define HISI_FB_ION_CLIENT_NAME "hisi_fb_ion" + +uint32_t g_dts_resouce_ready = 0; +uint32_t g_dss_base_phy = 0; +uint32_t g_dss_module_resource_initialized = 0; + +struct iommu_domain *g_hisi_domain; + +static char __iomem *hisifd_dss_base; +static char __iomem *hisifd_peri_crg_base; +static char __iomem *hisifd_sctrl_base; +static char __iomem *hisifd_pctrl_base; +static char __iomem *hisifd_noc_dss_base; +static char __iomem *hisifd_mmbuf_crg_base; +static char __iomem *hisifd_mmbuf_asc0_base; +static char __iomem *hisifd_pmctrl_base; + +static uint32_t hisifd_irq_pdp; +static uint32_t hisifd_irq_sdp; +static uint32_t hisifd_irq_adp; +static uint32_t hisifd_irq_dsi0; +static uint32_t hisifd_irq_dsi1; + +/*DSS regulators are already enabled in fastboot, so kernel don't care*/ +/* +#define MAX_DPE_NUM (2) +static struct regulator_bulk_data g_dpe_regulator[MAX_DPE_NUM] = {{0}, {0}}; +*/ + +static struct clk *dss_aclk_dss; +static struct clk *dss_pclk_dss; +static struct clk *dss_clk_edc0; +static struct clk *dss_clk_ldi0; +static struct clk *dss_clk_ldi1; +static struct clk *dss_clk_dss_axi_mm; +static struct clk *dss_pclk_mmbuf; +static struct clk *dss_clk_txdphy0_ref; +static struct clk *dss_clk_txdphy1_ref; +static struct clk *dss_clk_txdphy0_cfg; +static struct clk *dss_clk_txdphy1_cfg; +static struct clk *dss_pclk_dsi0; +static struct clk *dss_pclk_dsi1; + +int g_debug_enable_lcd_sleep_in = 0; +int g_err_status = 0; + +/* + ** for debug, S_IRUGO + ** /sys/module/hisifb/parameters + */ +unsigned hisi_fb_msg_level = 7; +module_param_named(debug_msg_level, hisi_fb_msg_level, int, 0644); +MODULE_PARM_DESC(debug_msg_level, "hisi fb msg level"); + +int g_debug_mmu_error = 0; +module_param_named(debug_mmu_error, g_debug_mmu_error, int, 0644); +MODULE_PARM_DESC(debug_mmu_error, "hisi mmu error debug"); + +int g_debug_ldi_underflow = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ldi_underflow, g_debug_ldi_underflow, int, 0644); +MODULE_PARM_DESC(debug_ldi_underflow, "hisi ldi_underflow debug"); +#endif + +int g_debug_ldi_underflow_clear = 1; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ldi_underflow_clear, + g_debug_ldi_underflow_clear, int, 0644); +MODULE_PARM_DESC(debug_ldi_underflow_clear, "hisi ldi_underflow_clear debug"); +#endif + +int g_debug_set_reg_val = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_set_reg_val, g_debug_set_reg_val, int, 0644); +MODULE_PARM_DESC(debug_set_reg_val, "hisi set reg val debug"); +#endif + +int g_debug_online_vsync = 0; +module_param_named(debug_online_vsync, g_debug_online_vsync, int, 0644); +MODULE_PARM_DESC(debug_online_vsync, "hisi online vsync debug"); + +int g_debug_ovl_online_composer = 0; +module_param_named(debug_ovl_online_composer, + g_debug_ovl_online_composer, int, 0644); +MODULE_PARM_DESC(debug_ovl_online_composer, + "hisi overlay online composer debug"); + +int g_debug_ovl_online_composer_hold = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ovl_online_composer_hold, + g_debug_ovl_online_composer_hold, int, 0644); +MODULE_PARM_DESC(debug_ovl_online_composer_hold, + "hisi overlay online composer hold debug"); +#endif + +int g_debug_ovl_online_composer_return = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ovl_online_composer_return, + g_debug_ovl_online_composer_return, int, 0644); +MODULE_PARM_DESC(debug_ovl_online_composer_return, + "hisi overlay online composer return debug"); +#endif + +int g_debug_ovl_online_composer_timediff = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ovl_online_composer_timediff, + g_debug_ovl_online_composer_timediff, int, 0644); +MODULE_PARM_DESC(debug_ovl_online_composer_timediff, + "hisi overlay online composer timediff debug"); +#endif + +int g_debug_ovl_online_composer_time_threshold = 6000; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ovl_online_composer_time_threshold, + g_debug_ovl_online_composer_time_threshold, int, 0644); +MODULE_PARM_DESC(debug_ovl_online_composer_time_threshold, + "hisi overlay online composer time threshold debug"); +#endif + +int g_debug_ovl_block_composer = 0; +module_param_named(debug_ovl_block_composer, + g_debug_ovl_block_composer, int, 0644); +MODULE_PARM_DESC(debug_ovl_block_composer, + "hisi overlay block composer debug"); + +int g_debug_ovl_cmdlist = 0; +module_param_named(debug_ovl_cmdlist, g_debug_ovl_cmdlist, int, 0644); +MODULE_PARM_DESC(debug_ovl_cmdlist, "hisi overlay cmdlist debug"); + +int g_dump_cmdlist_content = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(dump_cmdlist_content, g_dump_cmdlist_content, int, 0644); +MODULE_PARM_DESC(dump_cmdlist_content, "hisi overlay dump cmdlist content"); +#endif + +int g_enable_ovl_cmdlist_online = 1; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_ovl_cmdlist_online, + g_enable_ovl_cmdlist_online, int, 0644); +MODULE_PARM_DESC(enable_ovl_cmdlist_online, + "hisi overlay cmdlist online enable"); +#endif + +int g_enable_ovl_cmdlist_offline = 1; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_ovl_cmdlist_offline, + g_enable_ovl_cmdlist_offline, int, 0644); +MODULE_PARM_DESC(enable_ovl_cmdlist_offline, + "hisi overlay cmdlist offline enable"); +#endif + +int g_rdma_stretch_threshold = RDMA_STRETCH_THRESHOLD; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(rdma_stretch_threshold, + g_rdma_stretch_threshold, int, 0644); +MODULE_PARM_DESC(rdma_stretch_threshold, "hisi rdma stretch threshold"); +#endif + +int g_enable_dirty_region_updt = 1; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_dirty_region_updt, + g_enable_dirty_region_updt, int, 0644); +MODULE_PARM_DESC(enable_dirty_region_updt, + "hisi dss dirty_region_updt enable"); +#endif + +int g_debug_dirty_region_updt = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_dirty_region_updt, + g_debug_dirty_region_updt, int, 0644); +MODULE_PARM_DESC(debug_dirty_region_updt, + "hisi dss dirty_region_updt debug"); +#endif + +int g_enable_crc_debug = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_crc_debug, g_enable_crc_debug, int, 0644); +MODULE_PARM_DESC(enable_crc_debug, "hisi dss crc debug enable"); +#endif + +int g_ldi_data_gate_en = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_ldi_data_gate, g_ldi_data_gate_en, int, 0644); +MODULE_PARM_DESC(enable_ldi_data_gate, "hisi dss ldi data gate enable"); +#endif + +int g_debug_need_save_file = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_need_save_file, g_debug_need_save_file, int, 0644); +MODULE_PARM_DESC(debug_need_save_file, "hisi dss debug need to save file"); +#endif + +int g_debug_ovl_credit_step = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_ovl_credit_step, g_debug_ovl_credit_step, int, 0644); +MODULE_PARM_DESC(debug_ovl_credit_step, "hisi overlay debug_ovl_credit_step"); +#endif + +int g_debug_layerbuf_sync = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(debug_layerbuf_sync, g_debug_layerbuf_sync, int, 0644); +MODULE_PARM_DESC(debug_layerbuf_sync, "hisi dss debug_layerbuf_sync"); +#endif + +int g_enable_dss_idle; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(enable_dss_idle, g_enable_dss_idle, int, 0644); +MODULE_PARM_DESC(enable_dss_idle, "hisi dss enable_dss_idle"); +#endif + +unsigned int g_dss_smmu_outstanding = DSS_SMMU_OUTSTANDING_VAL + 1; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(dss_smmu_outstanding, g_dss_smmu_outstanding, int, 0644); +MODULE_PARM_DESC(dss_smmu_outstanding, "hisi dss smmu outstanding"); +#endif + +int g_debug_dump_mmbuf = 0; +module_param_named(debug_dump_mmbuf, g_debug_dump_mmbuf, int, 0644); +MODULE_PARM_DESC(debug_dump_mmbuf, "hisi dump mmbuf debug"); + +uint32_t g_underflow_stop_perf_stat = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(underflow_stop_perf, g_underflow_stop_perf_stat, int, 0600); +MODULE_PARM_DESC(underflow_stop_perf, "hisi underflow stop perf stat"); +#endif + +uint32_t g_dss_min_bandwidth_inbusbusy = 200; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(dss_min_bandwidth_inbusbusy, + g_dss_min_bandwidth_inbusbusy, int, 0644); +MODULE_PARM_DESC(dss_min_bandwidth_inbusbusy, + "hisi overlay dss_min_bandwidth_inbusbusy"); +#endif + +uint32_t g_mmbuf_addr_test = 0; +#ifdef CONFIG_FB_DEBUG_USED +module_param_named(mmbuf_addr_test, g_mmbuf_addr_test, int, 0600); +MODULE_PARM_DESC(mmbuf_addr_test, "hisi mmbuf addr test"); +#endif + +/****************************************************************************** + ** FUNCTIONS PROTOTYPES + */ +static int hisi_fb_register(struct hisi_fb_data_type *hisifd); + +static int hisi_fb_open(struct fb_info *info, int user); +static int hisi_fb_release(struct fb_info *info, int user); +static int hisi_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int hisi_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int hisi_fb_set_par(struct fb_info *info); +static int hisi_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int hisi_fb_mmap(struct fb_info *info, struct vm_area_struct *vma); + +static int hisi_fb_suspend_sub(struct hisi_fb_data_type *hisifd); +static int hisi_fb_resume_sub(struct hisi_fb_data_type *hisifd); + +/******************************************************************************* + ** + */ +struct platform_device *hisi_fb_add_device(struct platform_device *pdev) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct platform_device *this_dev = NULL; + struct fb_info *fbi = NULL; + struct hisi_fb_data_type *hisifd = NULL; + uint32_t type = 0; + uint32_t id = 0; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + if (fbi_list_index >= HISI_FB_MAX_FBI_LIST) { + HISI_FB_ERR("no more framebuffer info list!\n"); + return NULL; + } + + id = pdev->id; + type = pdata->panel_info->type; + + /* alloc panel device data */ + this_dev = hisi_fb_device_alloc(pdata, type, id); + if (!this_dev) { + HISI_FB_ERR("failed to hisi_fb_device_alloc!\n"); + return NULL; + } + + /* alloc framebuffer info + par data */ + fbi = framebuffer_alloc(sizeof(struct hisi_fb_data_type), NULL); + if (fbi == NULL) { + HISI_FB_ERR("can't alloc framebuffer info data!\n"); + platform_device_put(this_dev); + return NULL; + } + + /* data chain */ + pdata = dev_get_platdata(&this_dev->dev); + pdata->next = pdev; + + hisifd = (struct hisi_fb_data_type *)fbi->par; + memset(hisifd, 0, sizeof(struct hisi_fb_data_type)); + hisifd->fbi = fbi; + + hisifd->fb_imgType = HISI_FB_PIXEL_FORMAT_BGRA_8888; + hisifd->index = fbi_list_index; + hisifd->dss_base = hisifd_dss_base; + hisifd->peri_crg_base = hisifd_peri_crg_base; + hisifd->sctrl_base = hisifd_sctrl_base; + hisifd->pctrl_base = hisifd_pctrl_base; + hisifd->noc_dss_base = hisifd_noc_dss_base; + hisifd->mmbuf_crg_base = hisifd_mmbuf_crg_base; + hisifd->mmbuf_asc0_base = hisifd_mmbuf_asc0_base; + hisifd->pmctrl_base = hisifd_pmctrl_base; + + hisifd->mipi_dsi0_base = hisifd->dss_base + DSS_MIPI_DSI0_OFFSET; + hisifd->mipi_dsi1_base = hisifd->dss_base + DSS_MIPI_DSI1_OFFSET; + hisifd->dss_base_phy = g_dss_base_phy; + + hisifd->dss_axi_clk = dss_aclk_dss; + hisifd->dss_pclk_dss_clk = dss_pclk_dss; + hisifd->dss_pri_clk = dss_clk_edc0; + hisifd->dss_pxl0_clk = dss_clk_ldi0; + hisifd->dss_pxl1_clk = dss_clk_ldi1; + hisifd->dss_mmbuf_clk = dss_clk_dss_axi_mm; + hisifd->dss_pclk_mmbuf_clk = dss_pclk_mmbuf; + hisifd->dss_dphy0_ref_clk = dss_clk_txdphy0_ref; + hisifd->dss_dphy1_ref_clk = dss_clk_txdphy1_ref; + hisifd->dss_dphy0_cfg_clk = dss_clk_txdphy0_cfg; + hisifd->dss_dphy1_cfg_clk = dss_clk_txdphy1_cfg; + hisifd->dss_pclk_dsi0_clk = dss_pclk_dsi0; + hisifd->dss_pclk_dsi1_clk = dss_pclk_dsi1; + + hisifd->dsi0_irq = hisifd_irq_dsi0; + hisifd->dsi1_irq = hisifd_irq_dsi1; + if (hisifd->index == PRIMARY_PANEL_IDX) { + hisifd->fb_num = HISI_FB0_NUM; + hisifd->dpe_irq = hisifd_irq_pdp; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + hisifd->fb_num = HISI_FB1_NUM; + hisifd->dpe_irq = hisifd_irq_sdp; + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifd->fb_num = HISI_FB2_NUM; + hisifd->dpe_irq = hisifd_irq_adp; + } else { + HISI_FB_ERR("fb%d not support now!\n", hisifd->index); + platform_device_put(this_dev); + framebuffer_release(fbi); + return NULL; + } + + /* link to the latest pdev */ + hisifd->pdev = this_dev; + + hisifd_list[hisifd_list_index++] = hisifd; + fbi_list[fbi_list_index++] = fbi; + + /* get/set panel info */ + memcpy(&hisifd->panel_info, pdata->panel_info, + sizeof(struct hisi_panel_info)); + + /* set driver data */ + platform_set_drvdata(this_dev, hisifd); + + if (platform_device_add(this_dev)) { + HISI_FB_ERR("failed to platform_device_add!\n"); + framebuffer_release(fbi); + platform_device_put(this_dev); + hisifd_list_index--; + fbi_list_index--; + return NULL; + } + + return this_dev; +} + +int hisi_fb_blank_sub(int blank_mode, struct fb_info *info) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + int curr_pwr_state = 0; + + hisifd = (struct hisi_fb_data_type *)info->par; + BUG_ON(hisifd == NULL); + + down(&hisifd->blank_sem); + down(&hisifd->blank_sem0); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (!hisifd->panel_power_on) { + ret = hisifd->on_fnc(hisifd); + if (ret == 0) { + hisifd->panel_power_on = true; + } + } + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + default: + if (hisifd->panel_power_on) { + curr_pwr_state = hisifd->panel_power_on; + hisifd->panel_power_on = false; + + if (hisifd->bl_cancel) { + hisifd->bl_cancel(hisifd); + } + + ret = hisifd->off_fnc(hisifd); + if (ret) + hisifd->panel_power_on = curr_pwr_state; + + if (hisifd->buf_sync_suspend) + hisifd->buf_sync_suspend(hisifd); + } + break; + } + up(&hisifd->blank_sem); + up(&hisifd->blank_sem0); + + return ret; +} + +static int hisi_fb_open_sub(struct fb_info *info) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + bool needed = false; + + BUG_ON(info == NULL); + hisifd = (struct hisi_fb_data_type *)info->par; + BUG_ON(hisifd == NULL); + + if (hisifd->set_fastboot_fnc) { + needed = hisifd->set_fastboot_fnc(info); + } + + if (!needed) { + ret = hisi_fb_blank_sub(FB_BLANK_UNBLANK, info); + if (ret != 0) { + HISI_FB_ERR("can't turn on display!\n"); + return ret; + } + } + + return 0; +} + +static int hisi_fb_release_sub(struct fb_info *info) +{ + int ret = 0; + + BUG_ON(info == NULL); + + ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, info); + if (ret != 0) { + HISI_FB_ERR("can't turn off display!\n"); + return ret; + } + + return 0; +} + +/******************************************************************************* + ** + */ +static int hisi_fb_blank(int blank_mode, struct fb_info *info) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + if (hisifd->panel_info.fake_hdmi + && (hisifd->index == EXTERNAL_PANEL_IDX)) { + HISI_FB_INFO("it is fake, blank it fail \n"); + return -EINVAL; + } +#if 0 + if (blank_mode == FB_BLANK_POWERDOWN) { + struct fb_event event; + event.info = info; + event.data = &blank_mode; + fb_notifier_call_chain(FB_EVENT_BLANK, &event); + } +#endif + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + HISI_FB_DEBUG("fb%d, blank_mode(%d) +.\n", hisifd->index, + blank_mode); + } else { + HISI_FB_INFO("fb%d, blank_mode(%d) +.\n", hisifd->index, + blank_mode); + } + + ret = hisi_fb_blank_sub(blank_mode, info); + if (ret != 0) { + HISI_FB_ERR("fb%d, blank_mode(%d) failed!\n", hisifd->index, + blank_mode); + return ret; + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + HISI_FB_DEBUG("fb%d, blank_mode(%d) -.\n", hisifd->index, + blank_mode); + } else { + HISI_FB_INFO("fb%d, blank_mode(%d) -.\n", hisifd->index, + blank_mode); + } + + return 0; +} + +static int hisi_fb_open(struct fb_info *info, int user) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + if (hisifd->panel_info.fake_hdmi + && (hisifd->index == EXTERNAL_PANEL_IDX)) { + HISI_FB_INFO("fb%d, is fake, open it fail \n", hisifd->index); + return -EINVAL; + } + + if (!hisifd->ref_cnt) { + HISI_FB_DEBUG("fb%d, +!\n", hisifd->index); + if (hisifd->open_sub_fnc) { + ret = hisifd->open_sub_fnc(info); + } + HISI_FB_DEBUG("fb%d, -!\n", hisifd->index); + } + + hisifd->ref_cnt++; + + return ret; +} + +static int hisi_fb_release(struct fb_info *info, int user) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + if (hisifd->panel_info.fake_hdmi + && (hisifd->index == EXTERNAL_PANEL_IDX)) { + HISI_FB_INFO("fb%d, is fake, release it fail \n", + hisifd->index); + return -EINVAL; + } + + if (!hisifd->ref_cnt) { + HISI_FB_INFO("try to close unopened fb%d!\n", hisifd->index); + return -EINVAL; + } + + hisifd->ref_cnt--; + + if (!hisifd->ref_cnt) { + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + if (hisifd->release_sub_fnc) { + ret = hisifd->release_sub_fnc(info); + } + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (hisifd->fb_mem_free_flag) + hisifb_free_fb_buffer(hisifd); + } + } + return ret; +} + +static int hisi_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + if (var->rotate != FB_ROTATE_UR) { + HISI_FB_ERR("error rotate %d!\n", var->rotate); + return -EINVAL; + } + + if (var->grayscale != info->var.grayscale) { + HISI_FB_DEBUG("error grayscale %d!\n", var->grayscale); + return -EINVAL; + } + + if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) { + HISI_FB_ERR("xres_virtual=%d yres_virtual=%d out of range!", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } +#if 0 + if (info->fix.smem_len < + (hisifb_line_length + (hisifd->index, var->xres_virtual, + (var->bits_per_pixel >> 3)) * var->yres_virtual)) { + HISI_FB_ERR("fb%d smem_len=%d is out of range!\n", + hisifd->index, info->fix.smem_len); + return -EINVAL; + } +#endif + + if ((var->xres == 0) || (var->yres == 0)) { + HISI_FB_ERR("xres=%d, yres=%d is invalid!\n", var->xres, + var->yres); + return -EINVAL; + } + + if (var->xoffset > (var->xres_virtual - var->xres)) { + HISI_FB_ERR + ("xoffset=%d(xres_virtual=%d, xres=%d) out of range!\n", + var->xoffset, var->xres_virtual, var->xres); + return -EINVAL; + } + + if (var->yoffset > (var->yres_virtual - var->yres)) { + HISI_FB_ERR + ("yoffset=%d(yres_virtual=%d, yres=%d) out of range!\n", + var->yoffset, var->yres_virtual, var->yres); + return -EINVAL; + } + + return 0; +} + +static int hisi_fb_set_par(struct fb_info *info) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct fb_var_screeninfo *var = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + + var = &info->var; + + hisifd->fbi->fix.line_length = + hisifb_line_length(hisifd->index, var->xres_virtual, + var->bits_per_pixel >> 3); + + return 0; +} + +static int hisi_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == var || NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + down(&hisifd->blank_sem); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel power off!\n", hisifd->index); + ret = -EPERM; + goto err_out; + } + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) { + ret = -EINVAL; + goto err_out; + } + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) { + ret = -EINVAL; + goto err_out; + } + + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; + + if (hisifd->pan_display_fnc) { + hisifd->pan_display_fnc(hisifd); + } else { + HISI_FB_ERR("fb%d pan_display_fnc not set!\n", hisifd->index); + } + + up(&hisifd->blank_sem); + + if (hisifd->bl_update) { + hisifd->bl_update(hisifd); + } + + return ret; + + err_out: + up(&hisifd->blank_sem); + return 0; +} + +static int hisifb_lcd_dirty_region_info_get(struct fb_info *info, + void __user *argp) +{ + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (copy_to_user(argp, &(hisifd->panel_info.dirty_region_info), + sizeof(struct lcd_dirty_region_info))) { + HISI_FB_ERR("copy to user fail"); + return -EFAULT; + } + + return 0; +} + +static int hisifb_dirty_region_updt_set(struct fb_info *info, + void __user *argp) +{ + int enable = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (g_enable_dirty_region_updt + && hisifd->panel_info.dirty_region_updt_support + && !hisifd->sbl_enable + && !hisifd->color_temperature_flag && !hisifd->esd_happened) { + enable = 1; + } + + if (copy_to_user(argp, &enable, sizeof(enable))) { + HISI_FB_ERR("copy to user fail"); + return -EFAULT; + } + + return 0; +} + +static int hisifb_dss_mmbuf_alloc(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + dss_mmbuf_t mmbuf_info; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + ret = copy_from_user(&mmbuf_info, argp, sizeof(dss_mmbuf_t)); + if (ret) { + HISI_FB_ERR("fb%d, copy for user failed!ret=%d.\n", + hisifd->index, ret); + ret = -EINVAL; + goto err_out; + } + + if ((mmbuf_info.size <= 0) || (mmbuf_info.size > MMBUF_SIZE_MAX) + || (mmbuf_info.size & (MMBUF_ADDR_ALIGN - 1))) { + HISI_FB_ERR("fb%d, mmbuf size is invalid, size=%d!\n", + hisifd->index, mmbuf_info.size); + ret = -EINVAL; + goto err_out; + } + + if (g_mmbuf_addr_test > 0) { + if (g_mmbuf_addr_test >= (MMBUF_SIZE_MAX + 0x40)) { + HISI_FB_ERR + ("g_mmbuf_addr_test(0x%x) is overflow max mmbuf size + 0x40(0x%x)\n", + g_mmbuf_addr_test, MMBUF_SIZE_MAX + 0x40); + + HISI_FB_ERR("remain buff size if %d \n", + (MMBUF_SIZE_MAX + 0x40) - + (g_mmbuf_addr_test - mmbuf_info.size)); + + g_mmbuf_addr_test = 0; + } else { + mmbuf_info.addr = g_mmbuf_addr_test; + g_mmbuf_addr_test += mmbuf_info.size; + } + + HISI_FB_INFO + ("addr = 0x%x, size =%d, g_mmbuf_addr_test = 0x%x, MAX_SIZE= 0x%x\n", + mmbuf_info.addr, mmbuf_info.size, g_mmbuf_addr_test, + MMBUF_SIZE_MAX + 0x40); + } + + if (0 == g_mmbuf_addr_test) { + mmbuf_info.addr = + hisi_dss_mmbuf_alloc(hisifd->mmbuf_gen_pool, + mmbuf_info.size); + if (mmbuf_info.addr < MMBUF_BASE) { + ret = -EINVAL; + goto err_out; + } + } + + ret = copy_to_user(argp, &mmbuf_info, sizeof(dss_mmbuf_t)); + if (ret) { + HISI_FB_ERR("fb%d, copy to user failed!ret=%d.", + hisifd->index, ret); + hisi_dss_mmbuf_free(hisifd->mmbuf_gen_pool, + mmbuf_info.addr, mmbuf_info.size); + ret = -EFAULT; + goto err_out; + } + + return 0; + + err_out: + return ret; +} + +static int hisifb_dss_mmbuf_free(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_fb_panel_data *pdata = NULL; + dss_mmbuf_t mmbuf_info; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + pdata = dev_get_platdata(&hisifd->pdev->dev); + if (NULL == pdata) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + ret = copy_from_user(&mmbuf_info, argp, sizeof(dss_mmbuf_t)); + if (ret) { + HISI_FB_ERR("fb%d, copy for user failed!ret=%d.", hisifd->index, + ret); + ret = -EINVAL; + goto err_out; + } + + if ((mmbuf_info.addr <= 0) || (mmbuf_info.size <= 0)) { + HISI_FB_ERR("fb%d, addr=0x%x, size=%d is invalid!\n", + hisifd->index, mmbuf_info.addr, mmbuf_info.size); + ret = -EINVAL; + goto err_out; + } + + hisi_dss_mmbuf_free(hisifd->mmbuf_gen_pool, mmbuf_info.addr, + mmbuf_info.size); + + return 0; + + err_out: + return ret; +} + +static int hisifb_dss_get_platform_type(struct fb_info *info, + void __user *argp) +{ + int type; + int ret = 0; + + type = HISIFB_DSS_PLATFORM_TYPE; + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + ret = copy_to_user(argp, &type, sizeof(type)); + if (ret) { + HISI_FB_ERR("copy to user failed! ret=%d.", ret); + ret = -EFAULT; + } + + return ret; +} + +static int hisi_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + int ret = -ENOSYS; + struct hisi_fb_data_type *hisifd = NULL; + void __user *argp = (void __user *)arg; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer"); + return -EINVAL; + } + + switch (cmd) { + case HISIFB_VSYNC_CTRL: + if (hisifd->vsync_ctrl_fnc) { + ret = hisifd->vsync_ctrl_fnc(info, argp); + } + break; + + case HISIFB_DSS_CLK_RATE_SET: + ret = hisifb_ctrl_dss_clk_rate_set(info, argp); + break; + + case HISIFB_LCD_DIRTY_REGION_INFO_GET: + ret = hisifb_lcd_dirty_region_info_get(info, argp); + break; + + case HISIFB_DIRTY_REGION_UPDT_SET: + ret = hisifb_dirty_region_updt_set(info, argp); + break; + + case HISIFB_DSS_MMBUF_ALLOC: + ret = hisifb_dss_mmbuf_alloc(info, argp); + break; + + case HISIFB_DSS_MMBUF_FREE: + ret = hisifb_dss_mmbuf_free(info, argp); + break; + + case HISIFB_PLATFORM_TYPE_GET: + ret = hisifb_dss_get_platform_type(info, argp); + break; + + default: + if (hisifd->ov_ioctl_handler) + ret = hisifd->ov_ioctl_handler(hisifd, cmd, argp); + break; + } + + if (ret == -ENOSYS) + HISI_FB_ERR("unsupported ioctl (%x)\n", cmd); + + return ret; +} + +static int hisi_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct sg_table *table = NULL; + struct scatterlist *sg = NULL; + struct page *page = NULL; + unsigned long remainder = 0; + unsigned long len = 0; + unsigned long addr = 0; + unsigned long offset = 0; + int i = 0; + int ret = 0; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer"); + return -EINVAL; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (hisifd->fb_mem_free_flag) { + if (!hisifb_alloc_fb_buffer(hisifd)) { + HISI_FB_ERR("fb%d, hisifb_alloc_buffer failed!\n", + hisifd->index); + return -ENOMEM; + } + } + } else { + HISI_FB_ERR("fb%d, no fb buffer!\n", hisifd->index); + return -EFAULT;; + } + + table = ion_sg_table(hisifd->ion_client, hisifd->ion_handle); + BUG_ON(table == NULL); + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + addr = vma->vm_start; + offset = vma->vm_pgoff * PAGE_SIZE; + + for_each_sg(table->sgl, sg, table->nents, i) { + page = sg_page(sg); + remainder = vma->vm_end - addr; + len = sg->length; + + if (offset >= sg->length) { + offset -= sg->length; + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len = sg->length - offset; + offset = 0; + } + len = min(len, remainder); + ret = remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + if (ret != 0) { + HISI_FB_ERR("fb%d, failed to remap_pfn_range! ret=%d\n", + hisifd->index, ret); + } + + addr += len; + if (addr >= vma->vm_end) + return 0; + } + + return 0; +} + +unsigned long hisifb_alloc_fb_buffer(struct hisi_fb_data_type *hisifd) +{ + struct fb_info *fbi = NULL; + struct ion_client *client = NULL; + struct ion_handle *handle = NULL; + size_t buf_len = 0; + unsigned long buf_addr = 0; + + BUG_ON(hisifd == NULL); + fbi = hisifd->fbi; + BUG_ON(fbi == NULL); + + if (hisifd->ion_handle != NULL) + return fbi->fix.smem_start; + + client = hisifd->ion_client; + if (IS_ERR_OR_NULL(client)) { + HISI_FB_ERR("failed to create ion client!\n"); + goto err_return; + } + + buf_len = fbi->fix.smem_len; + handle = + ion_alloc(client, buf_len, PAGE_SIZE, ION_HEAP(ION_SYSTEM_HEAP_ID), 0); + + if (IS_ERR_OR_NULL(handle)) { + HISI_FB_ERR("failed to ion_alloc!\n"); + goto err_return; + } + + fbi->screen_base = ion_map_kernel(client, handle); + if (!fbi->screen_base) { + HISI_FB_ERR("failed to ion_map_kernel!\n"); + goto err_ion_map; + } + + if (ion_map_iommu(client, handle, &(hisifd->iommu_format))) { + HISI_FB_ERR("failed to ion_map_iommu!\n"); + goto err_ion_get_addr; + } + + buf_addr = hisifd->iommu_format.iova_start; + + fbi->fix.smem_start = buf_addr; + fbi->screen_size = fbi->fix.smem_len; + + + hisifd->ion_handle = handle; + + return buf_addr; + + err_ion_get_addr: + ion_unmap_kernel(hisifd->ion_client, handle); + err_ion_map: + ion_free(hisifd->ion_client, handle); + err_return: + return 0; +} + +void hisifb_free_fb_buffer(struct hisi_fb_data_type *hisifd) +{ + struct fb_info *fbi = NULL; + + BUG_ON(hisifd == NULL); + fbi = hisifd->fbi; + BUG_ON(fbi == NULL); + + if (hisifd->ion_client != NULL && hisifd->ion_handle != NULL) { + ion_unmap_iommu(hisifd->ion_client, hisifd->ion_handle); + ion_unmap_kernel(hisifd->ion_client, hisifd->ion_handle); + ion_free(hisifd->ion_client, hisifd->ion_handle); + hisifd->ion_handle = NULL; + fbi->screen_base = 0; + fbi->fix.smem_start = 0; + } +} + +/******************************************************************************* + ** fb sys fs + */ +static void hisifb_sysfs_init(struct hisi_fb_data_type *hisifd) +{ + int i = 0; + + BUG_ON(hisifd == NULL); + + hisifd->sysfs_index = 0; + for (i = 0; i < HISI_FB_SYSFS_ATTRS_NUM; i++) { + hisifd->sysfs_attrs[i] = NULL; + } + hisifd->sysfs_attr_group.attrs = hisifd->sysfs_attrs; +} + +static void hisifb_sysfs_attrs_append(struct hisi_fb_data_type *hisifd, + struct attribute *attr) +{ + BUG_ON(hisifd == NULL); + BUG_ON(attr == NULL); + + if (hisifd->sysfs_index >= HISI_FB_SYSFS_ATTRS_NUM) { + HISI_FB_ERR("fb%d, sysfs_atts_num(%d) is out of range(%d)!\n", + hisifd->index, hisifd->sysfs_index, + HISI_FB_SYSFS_ATTRS_NUM); + BUG_ON(1); + return; + } + + hisifd->sysfs_attrs[hisifd->sysfs_index] = attr; + hisifd->sysfs_index++; +} + +static int hisifb_sysfs_create(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + ret = + sysfs_create_group(&hisifd->fbi->dev->kobj, + &(hisifd->sysfs_attr_group)); + if (ret) { + HISI_FB_ERR("fb%d sysfs group creation failed, error=%d!\n", + hisifd->index, ret); + } + + return ret; +} + +static void hisifb_sysfs_remove(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + sysfs_remove_group(&hisifd->fbi->dev->kobj, + &(hisifd->sysfs_attr_group)); + + hisifb_sysfs_init(hisifd); +} + +/******************************************************************************* + ** + */ +static struct fb_ops hisi_fb_ops = { + .owner = THIS_MODULE, + .fb_open = hisi_fb_open, + .fb_release = hisi_fb_release, + .fb_read = NULL, + .fb_write = NULL, + .fb_cursor = NULL, + .fb_check_var = hisi_fb_check_var, + .fb_set_par = hisi_fb_set_par, + .fb_setcolreg = NULL, + .fb_blank = hisi_fb_blank, + .fb_pan_display = hisi_fb_pan_display, + .fb_fillrect = NULL, + .fb_copyarea = NULL, + .fb_imageblit = NULL, + .fb_rotate = NULL, + .fb_sync = NULL, + .fb_ioctl = hisi_fb_ioctl, + .fb_compat_ioctl = hisi_fb_ioctl, + .fb_mmap = hisi_fb_mmap, +}; + +static int hisi_fb_register(struct hisi_fb_data_type *hisifd) +{ + int bpp = 0; + struct hisi_panel_info *panel_info = NULL; + struct fb_info *fbi = NULL; + struct fb_fix_screeninfo *fix = NULL; + struct fb_var_screeninfo *var = NULL; + + BUG_ON(hisifd == NULL); + panel_info = &hisifd->panel_info; + BUG_ON(panel_info == NULL); + + /* + * fb info initialization + */ + fbi = hisifd->fbi; + fix = &fbi->fix; + var = &fbi->var; + + fix->type_aux = 0; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->ywrapstep = 0; + fix->mmio_start = 0; + fix->mmio_len = 0; + fix->accel = FB_ACCEL_NONE; + + var->xoffset = 0; + var->yoffset = 0; + var->grayscale = 0; + var->nonstd = 0; + var->activate = FB_ACTIVATE_VBL; + var->height = panel_info->height; + var->width = panel_info->width; + var->accel_flags = 0; + var->sync = 0; + var->rotate = 0; + + switch (hisifd->fb_imgType) { + case HISI_FB_PIXEL_FORMAT_BGR_565: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->transp.offset = 0; + + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->transp.length = 0; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + bpp = 2; + break; + + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 4; + var->red.offset = 8; + var->transp.offset = 0; + + var->blue.length = 4; + var->green.length = 4; + var->red.length = 4; + var->transp.length = 0; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + bpp = 2; + break; + + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 4; + var->red.offset = 8; + var->transp.offset = 12; + + var->blue.length = 4; + var->green.length = 4; + var->red.length = 4; + var->transp.length = 4; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + bpp = 2; + break; + + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 10; + var->transp.offset = 0; + + var->blue.length = 5; + var->green.length = 5; + var->red.length = 5; + var->transp.length = 0; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + bpp = 2; + break; + + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 10; + var->transp.offset = 15; + + var->blue.length = 5; + var->green.length = 5; + var->red.length = 5; + var->transp.length = 1; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + bpp = 2; + break; + + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->transp.offset = 24; + + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->transp.length = 8; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + + bpp = 4; + break; + + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->xpanstep = 2; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* FIXME: R/G/B offset? */ + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->transp.offset = 0; + + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->transp.length = 0; + + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.msb_right = 0; + + bpp = 2; + break; + + default: + HISI_FB_ERR("fb%d, unkown image type!\n", hisifd->index); + return -EINVAL; + } + + + memset(&(hisifd->resolution_rect), 0, sizeof(dss_rect_t)); + memset(&(hisifd->res_updt_rect), 0, sizeof(dss_rect_t)); + + var->xres = panel_info->xres; + var->yres = panel_info->yres; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres * hisifd->fb_num; + var->bits_per_pixel = bpp * 8; + + snprintf(fix->id, sizeof(fix->id), "hisifb%d", hisifd->index); + fix->line_length = + hisifb_line_length(hisifd->index, var->xres_virtual, bpp); + fix->smem_len = + roundup(fix->line_length * var->yres_virtual, PAGE_SIZE); + fix->smem_start = 0; + + fbi->screen_base = 0; + fbi->fbops = &hisi_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = NULL; + + fix->reserved[0] = is_mipi_cmd_panel(hisifd) ? 1 : 0; + + hisifd->ion_client = hisi_ion_client_create(HISI_FB_ION_CLIENT_NAME); + if (IS_ERR_OR_NULL(hisifd->ion_client)) { + HISI_FB_ERR("failed to create ion client!\n"); + return -ENOMEM; + } + hisifd->ion_handle = NULL; + memset(&hisifd->iommu_format, 0, sizeof(struct iommu_map_format)); + + if (fix->smem_len > 0) { + if (!hisifb_alloc_fb_buffer(hisifd)) { + HISI_FB_ERR("hisifb_alloc_buffer failed!\n"); + return -ENOMEM; + } + } + + hisifd->ref_cnt = 0; + hisifd->panel_power_on = false; + hisifd->aod_function = 0; + sema_init(&hisifd->blank_sem, 1); + sema_init(&hisifd->blank_sem0, 1); + + hisifb_sysfs_init(hisifd); + + hisifd->on_fnc = hisifb_ctrl_on; + hisifd->off_fnc = hisifb_ctrl_off; + hisifd->hisi_domain = g_hisi_domain; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + hisifd->fb_mem_free_flag = false; + hisifd->open_sub_fnc = hisi_fb_open_sub; + hisifd->release_sub_fnc = hisi_fb_release_sub; + hisifd->sysfs_attrs_add_fnc = hisifb_sysfs_attrs_add; + hisifd->sysfs_attrs_append_fnc = hisifb_sysfs_attrs_append; + hisifd->sysfs_create_fnc = hisifb_sysfs_create; + hisifd->sysfs_remove_fnc = hisifb_sysfs_remove; + hisifd->bl_register = hisifb_backlight_register; + hisifd->bl_unregister = hisifb_backlight_unregister; + hisifd->bl_update = hisifb_backlight_update; + hisifd->bl_cancel = hisifb_backlight_cancel; + hisifd->vsync_register = hisifb_vsync_register; + hisifd->vsync_unregister = hisifb_vsync_unregister; + hisifd->vsync_ctrl_fnc = hisifb_vsync_ctrl; + hisifd->vsync_isr_handler = hisifb_vsync_isr_handler; + hisifd->buf_sync_register = hisifb_buf_sync_register; + hisifd->buf_sync_unregister = hisifb_buf_sync_unregister; + hisifd->buf_sync_signal = hisifb_buf_sync_signal; + hisifd->buf_sync_suspend = hisifb_buf_sync_suspend; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + hisifd->fb_mem_free_flag = true; + hisifd->release_sub_fnc = hisi_fb_release_sub; + hisifd->bl_register = hisifb_backlight_register; + hisifd->bl_unregister = hisifb_backlight_unregister; + hisifd->bl_update = hisifb_backlight_update; + hisifd->bl_cancel = hisifb_backlight_cancel; + hisifd->vsync_register = hisifb_vsync_register; + hisifd->vsync_unregister = hisifb_vsync_unregister; + hisifd->vsync_ctrl_fnc = hisifb_vsync_ctrl; + hisifd->vsync_isr_handler = hisifb_vsync_isr_handler; + hisifd->buf_sync_register = hisifb_buf_sync_register; + hisifd->buf_sync_unregister = hisifb_buf_sync_unregister; + hisifd->buf_sync_signal = hisifb_buf_sync_signal; + hisifd->buf_sync_suspend = hisifb_buf_sync_suspend; + + } else { + sema_init(&hisifd->offline_composer_sr_sem, 1); + hisifd->offline_composer_sr_refcount = 0; + hisifd->fb_mem_free_flag = true; + } + + if (hisi_overlay_init(hisifd)) { + HISI_FB_ERR("unable to init overlay!\n"); + return -EPERM; + } + + if (register_framebuffer(fbi) < 0) { + HISI_FB_ERR("fb%d failed to register_framebuffer!", + hisifd->index); + return -EPERM; + } + + if (hisifd->sysfs_attrs_add_fnc) { + hisifd->sysfs_attrs_add_fnc(hisifd); + } + + /* backlight register */ + if (hisifd->bl_register) + hisifd->bl_register(hisifd->pdev); + /* vsync register */ + if (hisifd->vsync_register) + hisifd->vsync_register(hisifd->pdev); + /* buf_sync register */ + if (hisifd->buf_sync_register) + hisifd->buf_sync_register(hisifd->pdev); + /* fb sysfs create */ + if (hisifd->sysfs_create_fnc) + hisifd->sysfs_create_fnc(hisifd->pdev); + + HISI_FB_INFO + ("FrameBuffer[%d] %dx%d size=%d bytes phy_addr=%lu virt_addr=%p " + "is registered successfully!\n", hisifd->index, var->xres, + var->yres, fbi->fix.smem_len, fix->smem_start, fbi->screen_base); + + return 0; +} + +/******************************************************************************* + ** + */ +static int hisi_fb_enable_iommu(struct platform_device *pdev) +{ + struct iommu_domain *hisi_domain = NULL; + struct device *dev = NULL; + + BUG_ON(pdev == NULL); + + dev = &pdev->dev; + + /* create iommu domain */ + hisi_domain = iommu_domain_alloc(dev->bus); + if (!hisi_domain) { + HISI_FB_ERR("iommu_domain_alloc failed!\n"); + return -EINVAL; + } + + iommu_attach_device(hisi_domain, dev); + + g_hisi_domain = hisi_domain; + + return 0; +} + +static int hisi_fb_probe(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + struct device_node *np = NULL; + + if (!hisi_fb_resource_initialized) { + HISI_FB_DEBUG("initialized=%d, +.\n", + hisi_fb_resource_initialized); + + pdev->id = 0; + np = of_find_compatible_node(NULL, NULL, DTS_COMP_FB_NAME); + if (!np) { + HISI_FB_ERR("NOT FOUND device node %s!\n", + DTS_COMP_FB_NAME); + return -ENXIO; + } + + dss_aclk_dss = devm_clk_get(&pdev->dev, "aclk_dss"); + if (IS_ERR(dss_aclk_dss)) { + ret = PTR_ERR(dss_aclk_dss); + HISI_FB_ERR("dss_aclk_dss error, ret = %d", ret); + return ret; + } + + dss_pclk_dss = devm_clk_get(&pdev->dev, "pclk_dss"); + if (IS_ERR(dss_pclk_dss)) { + ret = PTR_ERR(dss_pclk_dss); + HISI_FB_ERR("dss_pclk_dss error, ret = %d", ret); + return ret; + } + + dss_clk_edc0 = devm_clk_get(&pdev->dev, "clk_edc0"); + if (IS_ERR(dss_clk_edc0)) { + ret = PTR_ERR(dss_clk_edc0); + HISI_FB_ERR("dss_clk_edc0 error, ret = %d", ret); + return ret; + } + + dss_clk_ldi0 = devm_clk_get(&pdev->dev, "clk_ldi0"); + if (IS_ERR(dss_clk_ldi0)) { + ret = PTR_ERR(dss_clk_ldi0); + HISI_FB_ERR("dss_clk_ldi0 error, ret = %d", ret); + return ret; + } + + dss_clk_ldi1 = devm_clk_get(&pdev->dev, "clk_ldi1"); + if (IS_ERR(dss_clk_ldi1)) { + ret = PTR_ERR(dss_clk_ldi1); + HISI_FB_ERR("dss_clk_ldi1 error, ret = %d", ret); + return ret; + } + + dss_clk_dss_axi_mm = devm_clk_get(&pdev->dev, "clk_dss_axi_mm"); + if (IS_ERR(dss_clk_dss_axi_mm)) { + ret = PTR_ERR(dss_clk_dss_axi_mm); + HISI_FB_ERR("dss_clk_dss_axi_mm error, ret = %d", ret); + return ret; + } + + dss_pclk_mmbuf = devm_clk_get(&pdev->dev, "pclk_mmbuf"); + if (IS_ERR(dss_pclk_mmbuf)) { + ret = PTR_ERR(dss_pclk_mmbuf); + HISI_FB_ERR("dss_pclk_mmbuf error, ret = %d", ret); + return ret; + } + + dss_clk_txdphy0_ref = + devm_clk_get(&pdev->dev, "clk_txdphy0_ref"); + if (IS_ERR(dss_clk_txdphy0_ref)) { + ret = PTR_ERR(dss_clk_txdphy0_ref); + HISI_FB_ERR("dss_clk_txdphy0_ref error, ret = %d", ret); + return ret; + } + + dss_clk_txdphy1_ref = + devm_clk_get(&pdev->dev, "clk_txdphy1_ref"); + if (IS_ERR(dss_clk_txdphy1_ref)) { + ret = PTR_ERR(dss_clk_txdphy1_ref); + HISI_FB_ERR("dss_clk_txdphy1_ref error, ret = %d", ret); + return ret; + } + + dss_clk_txdphy0_cfg = + devm_clk_get(&pdev->dev, "clk_txdphy0_cfg"); + if (IS_ERR(dss_clk_txdphy0_cfg)) { + ret = PTR_ERR(dss_clk_txdphy0_cfg); + HISI_FB_ERR("dss_clk_txdphy0_cfg error, ret = %d", ret); + return ret; + } + + dss_clk_txdphy1_cfg = + devm_clk_get(&pdev->dev, "clk_txdphy1_cfg"); + if (IS_ERR(dss_clk_txdphy1_cfg)) { + ret = PTR_ERR(dss_clk_txdphy1_cfg); + HISI_FB_ERR("dss_clk_txdphy1_cfg error, ret = %d", ret); + return ret; + } + + dss_pclk_dsi0 = devm_clk_get(&pdev->dev, "pclk_dsi0"); + if (IS_ERR(dss_pclk_dsi0)) { + ret = PTR_ERR(dss_pclk_dsi0); + HISI_FB_ERR("dss_pclk_dsi0 error, ret = %d", ret); + return ret; + } + + dss_pclk_dsi1 = devm_clk_get(&pdev->dev, "pclk_dsi1"); + if (IS_ERR(dss_pclk_dsi1)) { + ret = PTR_ERR(dss_pclk_dsi1); + HISI_FB_ERR("dss_pclk_dsi1 error, ret = %d", ret); + return ret; + } + + ret = of_property_read_u32(np, "dss_base_phy", &g_dss_base_phy); + if (ret) { + HISI_FB_ERR("failed to get dss_base_phy.\n"); + return -ENXIO; + } + HISI_FB_INFO("g_dss_base_phy=0x%x.\n", g_dss_base_phy); + + /* get irq no */ + hisifd_irq_pdp = irq_of_parse_and_map(np, 0); + if (!hisifd_irq_pdp) { + HISI_FB_ERR("failed to get hisifd_irq_pdp resource.\n"); + return -ENXIO; + } + + hisifd_irq_sdp = irq_of_parse_and_map(np, 1); + if (!hisifd_irq_sdp) { + HISI_FB_ERR("failed to get hisifd_irq_sdp resource.\n"); + return -ENXIO; + } + + hisifd_irq_adp = irq_of_parse_and_map(np, 2); + if (!hisifd_irq_sdp) { + HISI_FB_ERR("failed to get hisifd_irq_sdp resource.\n"); + return -ENXIO; + } + + hisifd_irq_dsi0 = irq_of_parse_and_map(np, 3); + if (!hisifd_irq_dsi0) { + HISI_FB_ERR + ("failed to get hisifd_irq_dsi0 resource.\n"); + return -ENXIO; + } + + hisifd_irq_dsi1 = irq_of_parse_and_map(np, 4); + if (!hisifd_irq_dsi1) { + HISI_FB_ERR + ("failed to get hisifd_irq_dsi1 resource.\n"); + return -ENXIO; + } + + /* get dss reg base */ + hisifd_dss_base = of_iomap(np, 0); + if (!hisifd_dss_base) { + HISI_FB_ERR + ("failed to get hisifd_dss_base resource.\n"); + return -ENXIO; + } + + hisifd_peri_crg_base = of_iomap(np, 1); + if (!hisifd_peri_crg_base) { + HISI_FB_ERR + ("failed to get hisifd_peri_crg_base resource.\n"); + return -ENXIO; + } + + hisifd_sctrl_base = of_iomap(np, 2); + if (!hisifd_sctrl_base) { + HISI_FB_ERR + ("failed to get hisifd_sctrl_base resource.\n"); + return -ENXIO; + } + + hisifd_pctrl_base = of_iomap(np, 3); + if (!hisifd_pctrl_base) { + HISI_FB_ERR + ("failed to get hisifd_pctrl_base resource.\n"); + return -ENXIO; + } + + hisifd_noc_dss_base = of_iomap(np, 4); + if (!hisifd_noc_dss_base) { + HISI_FB_ERR + ("failed to get hisifd_noc_dss_base resource.\n"); + return -ENXIO; + } + + hisifd_mmbuf_crg_base = of_iomap(np, 5); + if (!hisifd_mmbuf_crg_base) { + HISI_FB_ERR + ("failed to get hisifd_mmbuf_crg_base resource.\n"); + return -ENXIO; + } + + hisifd_pmctrl_base = of_iomap(np, 6); + if (!hisifd_pmctrl_base) { + HISI_FB_ERR + ("failed to get hisifd_pmctrl_base resource.\n"); + return -ENXIO; + } + + /* get regulator resource, DSS regulator is already enabled in fastboot, so kernel dont care */ + /* + g_dpe_regulator[0].supply = REGULATOR_PDP_NAME; + g_dpe_regulator[1].supply = REGULATOR_MMBUF; + ret = devm_regulator_bulk_get(&(pdev->dev), + ARRAY_SIZE(g_dpe_regulator), g_dpe_regulator); + if (ret) { + HISI_FB_ERR("failed to get regulator resource! ret=%d.\n", ret); + return -ENXIO; + } + */ + + ret = hisi_fb_enable_iommu(pdev); + if (ret != 0) { + HISI_FB_ERR("failed to hisi_fb_enable_iommu! ret=%d.\n", + ret); + return -ENXIO; + } + + hisi_fb_resource_initialized = 1; + hisi_fb_device_set_status0(DTS_FB_RESOURCE_INIT_READY); + + HISI_FB_DEBUG("initialized = %d, -.\n", + hisi_fb_resource_initialized); + return 0; + } + + if (pdev->id < 0) { + HISI_FB_ERR("WARNING: id=%d, name=%s!\n", pdev->id, pdev->name); + return 0; + } + + if (!hisi_fb_resource_initialized) { + HISI_FB_ERR("fb resource not initialized!\n"); + return -EPERM; + } + + if (pdev_list_cnt >= HISI_FB_MAX_DEV_LIST) { + HISI_FB_ERR("too many fb devices, num=%d!\n", pdev_list_cnt); + return -ENOMEM; + } + + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = hisi_fb_register(hisifd); + if (ret) { + HISI_FB_ERR("fb%d hisi_fb_register failed, error=%d!\n", + hisifd->index, ret); + return ret; + } + + pdev_list[pdev_list_cnt++] = pdev; + + /* set device probe status */ + hisi_fb_device_set_status1(hisifd); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hisi_fb_remove(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + /* stop the device */ + if (hisi_fb_suspend_sub(hisifd) != 0) + HISI_FB_ERR("fb%d hisi_fb_suspend_sub failed!\n", + hisifd->index); + + /* overlay destroy */ + hisi_overlay_deinit(hisifd); + + /* free framebuffer */ + hisifb_free_fb_buffer(hisifd); + if (hisifd->ion_client) { + ion_client_destroy(hisifd->ion_client); + hisifd->ion_client = NULL; + } + + /* remove /dev/fb* */ + unregister_framebuffer(hisifd->fbi); + + /* unregister buf_sync */ + if (hisifd->buf_sync_unregister) + hisifd->buf_sync_unregister(pdev); + /* unregister vsync */ + if (hisifd->vsync_unregister) + hisifd->vsync_unregister(pdev); + /* unregister backlight */ + if (hisifd->bl_unregister) + hisifd->bl_unregister(pdev); + /* fb sysfs remove */ + if (hisifd->sysfs_remove_fnc) + hisifd->sysfs_remove_fnc(hisifd->pdev); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; +} + +static int hisi_fb_suspend_sub(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, hisifd->fbi); + if (ret) { + HISI_FB_ERR("fb%d can't turn off display, error=%d!\n", + hisifd->index, ret); + return ret; + } + + return 0; +} + +static int hisi_fb_resume_sub(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + ret = hisi_fb_blank_sub(FB_BLANK_UNBLANK, hisifd->fbi); + if (ret) { + HISI_FB_ERR("fb%d can't turn on display, error=%d!\n", + hisifd->index, ret); + } + + return ret; +} + +#ifdef CONFIG_PM +static int hisi_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + console_lock(); + fb_set_suspend(hisifd->fbi, FBINFO_STATE_SUSPENDED); + ret = hisi_fb_suspend_sub(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d hisi_fb_suspend_sub failed, error=%d!\n", + hisifd->index, ret); + fb_set_suspend(hisifd->fbi, FBINFO_STATE_RUNNING); + } else { + pdev->dev.power.power_state = state; + } + console_unlock(); + + HISI_FB_INFO("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int hisi_fb_resume(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + console_lock(); + ret = hisi_fb_resume_sub(hisifd); + pdev->dev.power.power_state = PMSG_ON; + fb_set_suspend(hisifd->fbi, FBINFO_STATE_RUNNING); + console_unlock(); + + HISI_FB_INFO("fb%d, -.\n", hisifd->index); + + return ret; +} +#else +#define hisi_fb_suspend NULL +#define hisi_fb_resume NULL +#endif + +#ifdef CONFIG_PM_SLEEP +static int hisi_fb_pm_suspend(struct device *dev) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + + if (NULL == dev) { + HISI_FB_ERR("NULL Poniter\n"); + return 0; + } + + hisifd = dev_get_drvdata(dev); + if (!hisifd) + return 0; + + if (hisifd->index != PRIMARY_PANEL_IDX) + return 0; + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + ret = hisi_fb_suspend_sub(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, failed to hisi_fb_suspend_sub! ret=%d\n", + hisifd->index, ret); + } + + HISI_FB_INFO("fb%d, -.\n", hisifd->index); + + return 0; +} + +#if 0 +static int hisi_fb_pm_resume(struct device *dev) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + + hisifd = dev_get_drvdata(dev); + if (!hisifd) + return 0; + + if (hisifd->index != PRIMARY_PANEL_IDX) + return 0; + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + ret = hisi_fb_resume_sub(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, failed to hisi_fb_resume_sub! ret=%d\n", + hisifd->index, ret); + } + + HISI_FB_INFO("fb%d, -.\n", hisifd->index); + + return 0; +} +#endif +#endif + +static void hisi_fb_shutdown(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == pdev) { + HISI_FB_ERR("pdev NULL Pointer\n"); + return; + } + + hisifd = platform_get_drvdata(pdev); + if (!hisifd) { + if (pdev->id) { + HISI_FB_ERR("hisifd NULL Pointer,pdev->id=%d\n", + pdev->id); + } + return; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_DEBUG("fb%d do not shutdown\n", hisifd->index); + return; + } + + HISI_FB_INFO("fb%d shutdown +\n", hisifd->index); + hisifd->fb_shutdown = true; + + ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, hisifd->fbi); + if (ret) { + HISI_FB_ERR("fb%d can't turn off display, error=%d!\n", + hisifd->index, ret); + } + + HISI_FB_INFO("fb%d shutdown -\n", hisifd->index); +} + +/******************************************************************************* + ** + */ +static struct dev_pm_ops hisi_fb_dev_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = hisi_fb_pm_suspend, + .resume = NULL, +#endif +}; + +static const struct of_device_id hisi_fb_match_table[] = { + { + .compatible = DTS_COMP_FB_NAME, + .data = NULL, + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, hisi_fb_match_table); + +static struct platform_driver hisi_fb_driver = { + .probe = hisi_fb_probe, + .remove = hisi_fb_remove, + .suspend = hisi_fb_suspend, + .resume = hisi_fb_resume, + .shutdown = hisi_fb_shutdown, + .driver = { + .name = DEV_NAME_FB, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(hisi_fb_match_table), + .pm = &hisi_fb_dev_pm_ops, + }, +}; + +static int __init hisi_fb_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&hisi_fb_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + + return ret; +} + +module_init(hisi_fb_init); + +MODULE_DESCRIPTION("Hisilicon Framebuffer Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb.h b/drivers/video/fbdev/hisi/dss/hisi_fb.h new file mode 100755 index 000000000000..d13ca97797d7 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb.h @@ -0,0 +1,559 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_FB_H +#define HISI_FB_H + +#include <linux/console.h> +#include <linux/uaccess.h> +#include <linux/leds.h> +#include <linux/interrupt.h> +#include <linux/wait.h> +#include <linux/fb.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/raid/pq.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/time.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/backlight.h> +#include <linux/pwm.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/memblock.h> + +#include <linux/spi/spi.h> + +#include <linux/ion.h> +#include <linux/hisi/hisi_ion.h> +#include <linux/gpio.h> + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> + +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/pinctrl/consumer.h> +#include <linux/file.h> +#include <linux/dma-buf.h> +#include <linux/genalloc.h> +#include <linux/hisi/hisi-iommu.h> + + + +#include "hisi_fb_def.h" +#include "hisi_fb_panel.h" +#include "hisi_dss.h" +#include "hisi_mipi_dsi.h" +#include "hisi_overlay_cmdlist_utils.h" + +#include "hisi_dss_regs_hi3660.h" +#include "hisi_overlay_utils_hi3660.h" +#include "hisi_dpe_utils.h" +#include "hisi_overlay_utils.h" + +#define CONFIG_HISI_FB_BACKLIGHT_DELAY +#define CONFIG_BUF_SYNC_USED +#define CONFIG_FB_DEBUG_USED +#define CONFIG_SMMU_RWERRADDR_USED +#define CONFIG_DSS_MMBUF_CLK_USED +#define CONFIG_BACKLIGHT_2048 + +#define HISI_DSS_COMPOSER_HOLD_TIME (1000 * 3600 * 24 * 7) + +#define HISI_FB0_NUM (3) +#define HISI_FB1_NUM (0) +#define HISI_FB2_NUM (0) + +#define HISI_FB_SYSFS_ATTRS_NUM (64) + +#define HISI_FB_MAX_DEV_LIST (32) +#define HISI_FB_MAX_FBI_LIST (32) + +#define HISI_DSS_OFFLINE_MAX_BLOCK (64) +#define HISI_DSS_OFFLINE_MAX_LIST (128) + +#define ESD_CHECK_TIME_PERIOD (5000) + +struct hisifb_vsync { + wait_queue_head_t vsync_wait; + ktime_t vsync_timestamp; + int vsync_created; + int vsync_enabled; + int vsync_infinite; + int vsync_infinite_count; + + int vsync_ctrl_expire_count; + int vsync_ctrl_enabled; + int vsync_ctrl_disabled_set; + int vsync_ctrl_isr_enabled; + int vsync_ctrl_offline_enabled; + struct work_struct vsync_ctrl_work; + spinlock_t spin_lock; + + struct mutex vsync_lock; +#ifdef CONFIG_HISI_FB_VSYNC_THREAD + struct task_struct *vsync_thread; +#endif + + atomic_t buffer_updated; + void (*vsync_report_fnc) (int buffer_updated); + + struct hisi_fb_data_type *hisifd; +}; + +enum bl_control_mode { + REG_ONLY_MODE = 1, + PWM_ONLY_MODE, + MUTI_THEN_RAMP_MODE, + RAMP_THEN_MUTI_MODE, +}; + +enum ESD_RECOVER_STATE { + ESD_RECOVER_STATE_NONE = 0, + ESD_RECOVER_STATE_START = 1, + ESD_RECOVER_STATE_COMPLETE = 2, +}; + +/* esd func define */ +struct hisifb_esd { + int esd_inited; + struct hrtimer esd_hrtimer; + struct workqueue_struct *esd_check_wq; + struct work_struct esd_check_work; + struct task_struct *esd_handle_thread; + wait_queue_head_t esd_handle_wait; + + struct hisi_fb_data_type *hisifd; +}; + +#ifdef CONFIG_BUF_SYNC_USED +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) +#include "sync.h" +#include "sw_sync.h" +#else +#include <linux/sync.h> +#include <linux/sw_sync.h> +#endif +#endif + +struct hisifb_buf_sync { +#ifdef CONFIG_BUF_SYNC_USED + struct sw_sync_timeline *timeline; + int timeline_max; + int refresh; + spinlock_t refresh_lock; +#endif + struct workqueue_struct *free_layerbuf_queue; + struct work_struct free_layerbuf_work; + struct list_head layerbuf_list; + bool layerbuf_flushed; + spinlock_t layerbuf_spinlock; +}; + +struct hisifb_layerbuf { + struct ion_handle *ion_handle; + struct list_head list_node; + int timeline; + bool has_map_iommu; + + int32_t shared_fd; + uint32_t frame_no; + dss_mmbuf_t mmbuf; + uint64_t vir_addr; + int32_t chn_idx; +}; + +struct hisifb_backlight { +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + struct delayed_work bl_worker; +#endif + struct semaphore bl_sem; + int bl_updated; + int bl_level_old; + int frame_updated; + + struct workqueue_struct *sbl_queue; + struct work_struct sbl_work; +}; + +struct hisi_fb_data_type { + uint32_t index; + uint32_t ref_cnt; + uint32_t fb_num; + uint32_t fb_imgType; + uint32_t bl_level; + + char __iomem *dss_base; + char __iomem *peri_crg_base; + char __iomem *sctrl_base; + char __iomem *pctrl_base; + char __iomem *noc_dss_base; + char __iomem *mmbuf_crg_base; + char __iomem *pmctrl_base; + char __iomem *mmbuf_asc0_base; + char __iomem *mipi_dsi0_base; + char __iomem *mipi_dsi1_base; + + uint32_t dss_base_phy; + + uint32_t dpe_irq; + uint32_t dsi0_irq; + uint32_t dsi1_irq; + uint32_t mmbuf_asc0_irq; + + struct regulator_bulk_data *dpe_regulator; + struct regulator_bulk_data *mmbuf_regulator; + + const char *dss_axi_clk_name; + const char *dss_pclk_dss_name; + const char *dss_pri_clk_name; + const char *dss_pxl0_clk_name; + const char *dss_pxl1_clk_name; + const char *dss_mmbuf_clk_name; + const char *dss_pclk_mmbuf_name; + const char *dss_dphy0_ref_clk_name; + const char *dss_dphy1_ref_clk_name; + const char *dss_dphy0_cfg_clk_name; + const char *dss_dphy1_cfg_clk_name; + const char *dss_pclk_dsi0_name; + const char *dss_pclk_dsi1_name; + const char *dss_pclk_pctrl_name; + + struct clk *dss_axi_clk; + struct clk *dss_pclk_dss_clk; + struct clk *dss_pri_clk; + struct clk *dss_pxl0_clk; + struct clk *dss_pxl1_clk; + struct clk *dss_mmbuf_clk; + struct clk *dss_pclk_mmbuf_clk; + struct clk *dss_dphy0_ref_clk; + struct clk *dss_dphy1_ref_clk; + struct clk *dss_dphy0_cfg_clk; + struct clk *dss_dphy1_cfg_clk; + struct clk *dss_pclk_dsi0_clk; + struct clk *dss_pclk_dsi1_clk; + struct clk *dss_pclk_pctrl_clk; + + struct hisi_panel_info panel_info; + bool panel_power_on; + bool fb_shutdown; + bool lcd_self_testing; + bool video_ldi_dis_at_vac_start; + unsigned int aod_function; + + struct semaphore blank_sem; + struct semaphore blank_sem0; + struct semaphore offline_composer_sr_sem; + uint32_t offline_composer_sr_refcount; + + void (*sysfs_attrs_append_fnc) (struct hisi_fb_data_type *hisifd, + struct attribute *attr); + int (*sysfs_create_fnc) (struct platform_device *pdev); + void (*sysfs_remove_fnc) (struct platform_device *pdev); + void (*pm_runtime_register) (struct platform_device *pdev); + void (*pm_runtime_unregister) (struct platform_device *pdev); + void (*pm_runtime_get) (struct hisi_fb_data_type *hisifd); + void (*pm_runtime_put) (struct hisi_fb_data_type *hisifd); + void (*bl_register) (struct platform_device *pdev); + void (*bl_unregister) (struct platform_device *pdev); + void (*bl_update) (struct hisi_fb_data_type *hisifd); + void (*bl_cancel) (struct hisi_fb_data_type *hisifd); + void (*vsync_register) (struct platform_device *pdev); + void (*vsync_unregister) (struct platform_device *pdev); + int (*vsync_ctrl_fnc) (struct fb_info *info, void __user *argp); + void (*vsync_isr_handler) (struct hisi_fb_data_type *hisifd); + void (*secure_register) (struct platform_device *pdev); + void (*secure_unregister) (struct platform_device *pdev); + void (*buf_sync_register) (struct platform_device *pdev); + void (*buf_sync_unregister) (struct platform_device *pdev); + void (*buf_sync_signal) (struct hisi_fb_data_type *hisifd); + void (*buf_sync_suspend) (struct hisi_fb_data_type *hisifd); + void (*esd_register) (struct platform_device *pdev); + void (*esd_unregister) (struct platform_device *pdev); + void (*debug_register) (struct platform_device *pdev); + void (*debug_unregister) (struct platform_device *pdev); + int (*cabc_update) (struct hisi_fb_data_type *hisifd); + + bool(*set_fastboot_fnc) (struct fb_info *info); + int (*open_sub_fnc) (struct fb_info *info); + int (*release_sub_fnc) (struct fb_info *info); + int (*on_fnc) (struct hisi_fb_data_type *hisifd); + int (*off_fnc) (struct hisi_fb_data_type *hisifd); + int (*lp_fnc) (struct hisi_fb_data_type *hisifd, bool lp_enter); + int (*esd_fnc) (struct hisi_fb_data_type *hisifd); + int (*sbl_ctrl_fnc) (struct fb_info *info, int value); + void (*sbl_isr_handler) (struct hisi_fb_data_type *hisifd); + int (*mipi_dsi_bit_clk_upt_isr_handler) (struct hisi_fb_data_type *hisifd); + void (*crc_isr_handler) (struct hisi_fb_data_type *hisifd); + void (*ov_ldi_underflow_isr_handle) (struct hisi_fb_data_type *hisifd); + + int (*pan_display_fnc) (struct hisi_fb_data_type *hisifd); + int (*ov_ioctl_handler) (struct hisi_fb_data_type *hisifd, + uint32_t cmd, void __user *argp); + int (*ov_online_play) (struct hisi_fb_data_type *hisifd, + void __user *argp); + void (*ov_wb_isr_handler) (struct hisi_fb_data_type *hisifd); + void (*ov_vactive0_start_isr_handler) (struct hisi_fb_data_type *hisifd); + void (*set_reg) (struct hisi_fb_data_type *hisifd, char __iomem *addr, + uint32_t val, uint8_t bw, uint8_t bs); + + void (*sysfs_attrs_add_fnc) (struct hisi_fb_data_type *hisifd); + + struct hisifb_backlight backlight; + int sbl_enable; + int sbl_lsensor_value; + int sbl_level; + dss_sbl_t sbl; + int color_temperature_flag; + + int sysfs_index; + struct attribute *sysfs_attrs[HISI_FB_SYSFS_ATTRS_NUM]; + struct attribute_group sysfs_attr_group; + + struct hisifb_vsync vsync_ctrl; + struct hisifb_buf_sync buf_sync_ctrl; + struct dss_clk_rate dss_clk_rate; + struct hisifb_esd esd_ctrl; + +#ifdef CONFIG_FAKE_VSYNC_USED + bool fake_vsync_used; + struct hrtimer fake_vsync_hrtimer; +#endif + dss_module_reg_t dss_module; + dss_overlay_t ov_req; + dss_overlay_block_t ov_block_infos[HISI_DSS_OV_BLOCK_NUMS]; + dss_overlay_t ov_req_prev; + dss_overlay_block_t ov_block_infos_prev[HISI_DSS_OV_BLOCK_NUMS]; + dss_overlay_t ov_req_prev_prev; + dss_overlay_block_t ov_block_infos_prev_prev[HISI_DSS_OV_BLOCK_NUMS]; + + dss_rect_t *ov_block_rects[HISI_DSS_OFFLINE_MAX_BLOCK]; + dss_wb_info_t wb_info; + + dss_cmdlist_data_t *cmdlist_data_tmp[HISI_DSS_CMDLIST_DATA_MAX]; + dss_cmdlist_data_t *cmdlist_data; + dss_cmdlist_info_t *cmdlist_info; + int32_t cmdlist_idx; + + dss_copybit_info_t *copybit_info; + + struct gen_pool *mmbuf_gen_pool; + dss_mmbuf_info_t mmbuf_infos[HISI_DSS_CMDLIST_DATA_MAX]; + dss_mmbuf_info_t *mmbuf_info; + struct list_head *mmbuf_list; + + bool dss_module_resource_initialized; + dss_module_reg_t dss_module_default; + + struct dss_rect dirty_region_updt; + uint32_t esd_happened; + uint32_t esd_recover_state; + + struct ion_client *ion_client; + struct ion_handle *ion_handle; + struct iommu_map_format iommu_format; + struct iommu_domain *hisi_domain; + + struct fb_info *fbi; + struct platform_device *pdev; + + wait_queue_head_t vactive0_start_wq; + uint32_t vactive0_start_flag; + uint32_t vactive0_end_flag; + uint32_t ldi_data_gate_en; + + wait_queue_head_t crc_wq; + uint32_t crc_flag; + struct workqueue_struct *dss_debug_wq; + struct work_struct dss_debug_work; + + struct workqueue_struct *ldi_underflow_wq; + struct work_struct ldi_underflow_work; + struct workqueue_struct *rch2_ce_end_wq; + struct work_struct rch2_ce_end_work; + struct workqueue_struct *rch4_ce_end_wq; + struct work_struct rch4_ce_end_work; + struct workqueue_struct *dpp_ce_end_wq; + struct work_struct dpp_ce_end_work; + struct workqueue_struct *hiace_end_wq; + struct work_struct hiace_end_work; + + dss_rect_t res_updt_rect; + dss_rect_t resolution_rect; + + uint32_t frame_count; + uint32_t frame_update_flag; + bool fb_mem_free_flag; + + uint8_t core_clk_upt_support; + + uint32_t vactive_start_event; + + uint32_t vsync_ctrl_type; + struct notifier_block nb; + struct notifier_block lcd_int_nb; +}; + +/****************************************************************************** + ** FUNCTIONS PROTOTYPES + */ +extern int g_primary_lcd_xres; +extern int g_primary_lcd_yres; +extern uint64_t g_pxl_clk_rate; + +extern uint32_t g_online_cmdlist_idxs; +extern uint32_t g_offline_cmdlist_idxs; + +extern uint32_t g_dss_version_tag; +extern uint32_t g_dss_module_resource_initialized; +extern uint32_t g_logo_buffer_base; +extern uint32_t g_logo_buffer_size; +extern uint32_t g_underflow_stop_perf_stat; + +/* for debug */ +extern int g_debug_ldi_underflow; +extern int g_debug_ldi_underflow_clear; + +extern int g_debug_mmu_error; +extern int g_debug_set_reg_val; +extern int g_debug_online_vsync; +extern int g_debug_ovl_online_composer; +extern int g_debug_ovl_online_composer_hold; +extern int g_debug_ovl_online_composer_return; +extern int g_debug_ovl_online_composer_timediff; +extern int g_debug_ovl_online_composer_time_threshold; + +extern int g_debug_ovl_offline_composer; +extern int g_debug_ovl_block_composer; +extern int g_debug_ovl_offline_composer_hold; +extern int g_debug_ovl_offline_composer_timediff; +extern int g_debug_ovl_offline_composer_time_threshold; +extern int g_debug_ovl_offline_block_num; +extern int g_debug_ovl_copybit_composer; +extern int g_debug_ovl_copybit_composer_hold; +extern int g_debug_ovl_copybit_composer_timediff; +extern int g_debug_ovl_copybit_composer_time_threshold; + +extern int g_debug_ovl_cmdlist; +extern int g_dump_cmdlist_content; +extern int g_enable_ovl_cmdlist_online; +extern int g_enable_ovl_cmdlist_offline; +extern int g_rdma_stretch_threshold; +extern int g_enable_dirty_region_updt; +extern int g_debug_dirty_region_updt; +extern int g_enable_crc_debug; +extern int g_ldi_data_gate_en; +extern int g_debug_need_save_file; +extern int g_debug_ovl_credit_step; +extern int g_debug_layerbuf_sync; +extern int g_enable_dss_idle; +extern int g_debug_dump_mmbuf; +extern uint32_t g_mmbuf_addr_test; +extern uint32_t g_dss_min_bandwidth_inbusbusy; + +extern int g_err_status; +extern int g_debug_enable_lcd_sleep_in; + +extern struct fb_info *fbi_list[HISI_FB_MAX_FBI_LIST]; +extern struct hisi_fb_data_type *hisifd_list[HISI_FB_MAX_FBI_LIST]; + +uint32_t get_panel_xres(struct hisi_fb_data_type *hisifd); +uint32_t get_panel_yres(struct hisi_fb_data_type *hisifd); + +bool is_dss_idle_enable(void); + +/* fb buffer */ +unsigned long hisifb_alloc_fb_buffer(struct hisi_fb_data_type *hisifd); +void hisifb_free_fb_buffer(struct hisi_fb_data_type *hisifd); +void hisifb_free_logo_buffer(struct hisi_fb_data_type *hisifd); + +int hisi_fb_blank_sub(int blank_mode, struct fb_info *info); + +/* backlight */ +void hisifb_backlight_update(struct hisi_fb_data_type *hisifd); +void hisifb_backlight_cancel(struct hisi_fb_data_type *hisifd); +void hisifb_backlight_register(struct platform_device *pdev); +void hisifb_backlight_unregister(struct platform_device *pdev); +void hisifb_set_backlight(struct hisi_fb_data_type *hisifd, uint32_t bkl_lvl); + +/* vsync */ +void hisifb_frame_updated(struct hisi_fb_data_type *hisifd); +#ifdef CONFIG_FAKE_VSYNC_USED +enum hrtimer_restart hisifb_fake_vsync(struct hrtimer *timer); +#endif +void hisifb_set_vsync_activate_state(struct hisi_fb_data_type *hisifd, + bool infinite); +void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd); +void hisifb_deactivate_vsync(struct hisi_fb_data_type *hisifd); +int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp); +int hisifb_vsync_resume(struct hisi_fb_data_type *hisifd); +int hisifb_vsync_suspend(struct hisi_fb_data_type *hisifd); +void hisifb_vsync_isr_handler(struct hisi_fb_data_type *hisifd); +void hisifb_vsync_register(struct platform_device *pdev); +void hisifb_vsync_unregister(struct platform_device *pdev); +/* buffer sync */ +int hisifb_layerbuf_lock(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, struct list_head *lock_list); +void hisifb_layerbuf_flush(struct hisi_fb_data_type *hisifd, + struct list_head *lock_list); +void hisifb_layerbuf_unlock(struct hisi_fb_data_type *hisifd, + struct list_head *pfree_list); +void hisifb_layerbuf_lock_exception(struct hisi_fb_data_type *hisifd, + struct list_head *lock_list); + +int hisifb_buf_sync_wait(int fence_fd); +int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd); +void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd); +int hisifb_buf_sync_create_fence(struct hisi_fb_data_type *hisifd, + unsigned value); +void hisifb_buf_sync_register(struct platform_device *pdev); +void hisifb_buf_sync_unregister(struct platform_device *pdev); + +/* control */ +int hisifb_ctrl_on(struct hisi_fb_data_type *hisifd); +int hisifb_ctrl_off(struct hisi_fb_data_type *hisifd); +int hisifb_ctrl_dss_clk_rate_set(struct fb_info *info, void __user *argp); +void hisifb_sysfs_attrs_add(struct hisi_fb_data_type *hisifd); + +void set_reg(char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs); +uint32_t set_bits32(uint32_t old_val, uint32_t val, uint8_t bw, uint8_t bs); +void hisifb_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs); +uint32_t hisifb_line_length(int index, uint32_t xres, int bpp); +void hisifb_get_timestamp(struct timeval *tv); +uint32_t hisifb_timestamp_diff(struct timeval *lasttime, + struct timeval *curtime); +void hisifb_save_file(char *filename, char *buf, uint32_t buf_len); +struct platform_device *hisi_fb_device_alloc(struct hisi_fb_panel_data *pdata, + uint32_t type, uint32_t id); +struct platform_device *hisi_fb_add_device(struct platform_device *pdev); +#endif /* HISI_FB_H */ diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c new file mode 100755 index 000000000000..54c43a3e85a5 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c @@ -0,0 +1,1686 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_mipi_dsi.h" + +#define DEFAULT_MAX_TX_ESC_CLK (10 * 1000000UL) +#define DEFAULT_MIPI_CLK_RATE (192 * 100000L) +#define DEFAULT_PCLK_DSI_RATE (120 * 1000000L) + +#define ROUND1(x,y) ((x) / (y) + ((x) % (y) > 0 ? 1 : 0)) +#define DSS_REDUCE(x) ((x) > 0 ? ((x) - 1) : (x)) + +struct dsi_phy_seq_info { + uint32_t min_range; + uint32_t max_range; + uint32_t rg_pll_vco_750M; + uint32_t rg_hstx_ckg_sel; +}; + +struct dsi_phy_seq_info dphy_seq_info[] = { + {47, 94, 0, 7}, + {94, 188, 0, 6}, + {188, 375, 0, 5}, + {375, 750, 0, 4}, + {750, 1500, 0, 0} +}; + +static void get_dsi_phy_ctrl(struct hisi_fb_data_type *hisifd, + struct mipi_dsi_phy_ctrl *phy_ctrl) +{ + struct hisi_panel_info *pinfo = NULL; + uint32_t dsi_bit_clk = 0; + + uint32_t ui = 0; + uint32_t m_pll = 0; + uint32_t n_pll = 0; + uint32_t m_n_fract = 0; + uint32_t m_n_int = 0; + uint64_t lane_clock = 0; + uint64_t vco_div = 1; + + uint32_t accuracy = 0; + uint32_t unit_tx_byte_clk_hs = 0; + uint32_t clk_post = 0; + uint32_t clk_pre = 0; + uint32_t clk_t_hs_exit = 0; + uint32_t clk_pre_delay = 0; + uint32_t clk_t_hs_prepare = 0; + uint32_t clk_t_lpx = 0; + uint32_t clk_t_hs_zero = 0; + uint32_t clk_t_hs_trial = 0; + uint32_t data_post_delay = 0; + uint32_t data_t_hs_prepare = 0; + uint32_t data_t_hs_zero = 0; + uint32_t data_t_hs_trial = 0; + uint32_t data_t_lpx = 0; + uint32_t clk_pre_delay_reality = 0; + uint32_t clk_t_hs_zero_reality = 0; + uint32_t clk_post_delay_reality = 0; + uint32_t data_t_hs_zero_reality = 0; + uint32_t data_post_delay_reality = 0; + uint32_t data_pre_delay_reality = 0; + + BUG_ON(phy_ctrl == NULL); + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + dsi_bit_clk = pinfo->mipi.dsi_bit_clk_upt; + lane_clock = 2 * dsi_bit_clk; + HISI_FB_DEBUG("Expected : lane_clock = %llu M\n", lane_clock); + + /************************ PLL parameters config *********************/ + if ((320 <= lane_clock) && (lane_clock <= 2500)) { + phy_ctrl->rg_band_sel = 0; + vco_div = 1; + } else if ((80 <= lane_clock) && (lane_clock < 320)) { + phy_ctrl->rg_band_sel = 1; + vco_div = 4; + } else { + HISI_FB_ERR + ("80M <= lane_clock< = 2500M, not support lane_clock = %llu M\n", + lane_clock); + } + + m_n_int = lane_clock * vco_div * 1000000UL / DEFAULT_MIPI_CLK_RATE; + m_n_fract = ((lane_clock * vco_div * 1000000UL * 1000UL / + DEFAULT_MIPI_CLK_RATE) % 1000) * 10 / 1000; + + if (m_n_int % 2 == 0) { + if (m_n_fract * 6 >= 50) { + n_pll = 2; + m_pll = (m_n_int + 1) * n_pll; + } else if (m_n_fract * 6 >= 30) { + n_pll = 3; + m_pll = m_n_int * n_pll + 2; + } else { + n_pll = 1; + m_pll = m_n_int * n_pll; + } + } else { + if (m_n_fract * 6 >= 50) { + n_pll = 1; + m_pll = (m_n_int + 1) * n_pll; + } else if (m_n_fract * 6 >= 30) { + n_pll = 1; + m_pll = (m_n_int + 1) * n_pll; + } else if (m_n_fract * 6 >= 10) { + n_pll = 3; + m_pll = m_n_int * n_pll + 1; + } else { + n_pll = 2; + m_pll = m_n_int * n_pll; + } + } + + if (m_pll <= 8) { + phy_ctrl->rg_pll_fbd_s = 1; + phy_ctrl->rg_pll_enswc = 0; + + if (m_pll % 2 == 0) { + phy_ctrl->rg_pll_fbd_p = m_pll / 2; + } else { + if (n_pll == 1) { + n_pll *= 2; + phy_ctrl->rg_pll_fbd_p = (m_pll * 2) / 2; + } else { + HISI_FB_ERR + ("phy m_pll not support!m_pll = %d\n", m_pll); + return; + } + } + } else if (m_pll <= 300) { + if (m_pll % 2 == 0) { + phy_ctrl->rg_pll_enswc = 0; + } else { + phy_ctrl->rg_pll_enswc = 1; + } + phy_ctrl->rg_pll_fbd_s = 1; + phy_ctrl->rg_pll_fbd_p = m_pll / 2; + } else if (m_pll <= 315) { + phy_ctrl->rg_pll_fbd_p = 150; + phy_ctrl->rg_pll_fbd_s = m_pll - 2 * phy_ctrl->rg_pll_fbd_p; + phy_ctrl->rg_pll_enswc = 1; + } else { + HISI_FB_ERR("phy m_pll not support!m_pll = %d\n", m_pll); + return; + } + + phy_ctrl->rg_pll_pre_p = n_pll; + + lane_clock = m_pll * (DEFAULT_MIPI_CLK_RATE / n_pll) / vco_div; + HISI_FB_DEBUG("Config : lane_clock = %llu\n", lane_clock); + + phy_ctrl->rg_pll_cp = 1; + phy_ctrl->rg_pll_cp_p = 3; + + phy_ctrl->rg_pll_enbwt = 0; + phy_ctrl->rg_pll_chp = 0; + + phy_ctrl->rg_pll_lpf_cs = 0; + phy_ctrl->rg_pll_refsel = 1; + + phy_ctrl->reload_sel = 1; + phy_ctrl->rg_phase_gen_en = 1; + phy_ctrl->pll_power_down = 0; + phy_ctrl->pll_register_override = 1; + + phy_ctrl->rg_vrefsel_vcm = 0x55; + if (pinfo->mipi.rg_vrefsel_vcm_clk_adjust != 0) + phy_ctrl->rg_vrefsel_vcm = (phy_ctrl->rg_vrefsel_vcm & 0x0F) | + ((pinfo->mipi.rg_vrefsel_vcm_clk_adjust & 0x0F) << 4); + + if (pinfo->mipi.rg_vrefsel_vcm_data_adjust != 0) + phy_ctrl->rg_vrefsel_vcm = (phy_ctrl->rg_vrefsel_vcm & 0xF0) | + (pinfo->mipi.rg_vrefsel_vcm_data_adjust & 0x0F); + + phy_ctrl->load_command = 0x5A; + + /******************** clock/data lane parameters config ******************/ + accuracy = 10; + ui = 10 * 1000000000UL * accuracy / lane_clock; + unit_tx_byte_clk_hs = 8 * ui; + + clk_post = 600 * accuracy + 52 * ui + pinfo->mipi.clk_post_adjust * ui; + + clk_pre = 8 * ui + pinfo->mipi.clk_pre_adjust * ui; + + clk_t_hs_exit = 1000 * accuracy + pinfo->mipi.clk_t_hs_exit_adjust * ui; + + clk_pre_delay = 0 + pinfo->mipi.clk_pre_delay_adjust * ui; + + clk_t_hs_trial = + 600 * accuracy + 3 * unit_tx_byte_clk_hs + + pinfo->mipi.clk_t_hs_trial_adjust * ui; + + if (pinfo->mipi.clk_t_hs_prepare_adjust == 0) + pinfo->mipi.clk_t_hs_prepare_adjust = 43; + + clk_t_hs_prepare = + ((380 * accuracy + pinfo->mipi.clk_t_hs_prepare_adjust * ui) <= + (950 * accuracy - 8 * ui)) ? (380 * accuracy + + pinfo->mipi.clk_t_hs_prepare_adjust * + ui) : (950 * accuracy - 8 * ui); + + data_post_delay = 0 + pinfo->mipi.data_post_delay_adjust * ui; + + data_t_hs_trial = + ((600 * accuracy + 4 * ui) >= + (8 * ui) ? (600 * accuracy + 4 * ui) : (8 * ui)) + 8 * ui + + 3 * unit_tx_byte_clk_hs + pinfo->mipi.data_t_hs_trial_adjust * ui; + + if (pinfo->mipi.data_t_hs_prepare_adjust == 0) + pinfo->mipi.data_t_hs_prepare_adjust = 35; + + data_t_hs_prepare = + ((400 * accuracy + 4 * ui + + pinfo->mipi.data_t_hs_prepare_adjust * ui) <= + (850 * accuracy + 6 * ui - 8 * ui)) ? (400 * accuracy + 4 * ui + + pinfo->mipi.data_t_hs_prepare_adjust * + ui) : (850 * accuracy + 6 * ui - 8 * ui); + + clk_t_lpx = (((2000 * accuracy - clk_t_hs_prepare) >= 500 * accuracy) ? + ((2000 * accuracy - clk_t_hs_prepare)) : (500 * accuracy)) + + pinfo->mipi.clk_t_lpx_adjust * ui; + + clk_t_hs_zero = + 3000 * accuracy - clk_t_hs_prepare + 3 * unit_tx_byte_clk_hs + + pinfo->mipi.clk_t_hs_zero_adjust * ui; + + data_t_lpx = clk_t_lpx + pinfo->mipi.data_t_lpx_adjust * ui; + + data_t_hs_zero = 1450 * accuracy + 10 * ui - data_t_hs_prepare + + 3 * unit_tx_byte_clk_hs + pinfo->mipi.data_t_hs_zero_adjust * ui; + + phy_ctrl->clk_pre_delay = ROUND1(clk_pre_delay, unit_tx_byte_clk_hs); + phy_ctrl->clk_t_hs_prepare = + ROUND1(clk_t_hs_prepare, unit_tx_byte_clk_hs); + phy_ctrl->clk_t_lpx = ROUND1(clk_t_lpx, unit_tx_byte_clk_hs); + phy_ctrl->clk_t_hs_zero = ROUND1(clk_t_hs_zero, unit_tx_byte_clk_hs); + phy_ctrl->clk_t_hs_trial = ROUND1(clk_t_hs_trial, unit_tx_byte_clk_hs); + + phy_ctrl->data_post_delay = + ROUND1(data_post_delay, unit_tx_byte_clk_hs); + phy_ctrl->data_t_hs_prepare = + ROUND1(data_t_hs_prepare, unit_tx_byte_clk_hs); + phy_ctrl->data_t_lpx = ROUND1(data_t_lpx, unit_tx_byte_clk_hs); + phy_ctrl->data_t_hs_zero = ROUND1(data_t_hs_zero, unit_tx_byte_clk_hs); + phy_ctrl->data_t_hs_trial = + ROUND1(data_t_hs_trial, unit_tx_byte_clk_hs); + phy_ctrl->data_t_ta_go = 4; + phy_ctrl->data_t_ta_get = 5; + + clk_pre_delay_reality = phy_ctrl->clk_pre_delay + 2; + clk_t_hs_zero_reality = phy_ctrl->clk_t_hs_zero + 8; + data_t_hs_zero_reality = phy_ctrl->data_t_hs_zero + 4; + data_post_delay_reality = phy_ctrl->data_post_delay + 4; + + phy_ctrl->clk_post_delay = + phy_ctrl->data_t_hs_trial + ROUND1(clk_post, unit_tx_byte_clk_hs); + phy_ctrl->data_pre_delay = + clk_pre_delay_reality + phy_ctrl->clk_t_lpx + + phy_ctrl->clk_t_hs_prepare + clk_t_hs_zero_reality + + ROUND1(clk_pre, unit_tx_byte_clk_hs); + + clk_post_delay_reality = phy_ctrl->clk_post_delay + 4; + data_pre_delay_reality = phy_ctrl->data_pre_delay + 2; + + phy_ctrl->clk_lane_lp2hs_time = + clk_pre_delay_reality + phy_ctrl->clk_t_lpx + + phy_ctrl->clk_t_hs_prepare + clk_t_hs_zero_reality + 3; + phy_ctrl->clk_lane_hs2lp_time = + clk_post_delay_reality + phy_ctrl->clk_t_hs_trial + 3; + phy_ctrl->data_lane_lp2hs_time = + data_pre_delay_reality + phy_ctrl->data_t_lpx + + phy_ctrl->data_t_hs_prepare + data_t_hs_zero_reality + 3; + phy_ctrl->data_lane_hs2lp_time = + data_post_delay_reality + phy_ctrl->data_t_hs_trial + 3; + phy_ctrl->phy_stop_wait_time = + clk_post_delay_reality + phy_ctrl->clk_t_hs_trial + + ROUND1(clk_t_hs_exit, unit_tx_byte_clk_hs) - + (data_post_delay_reality + phy_ctrl->data_t_hs_trial) + 3; + + phy_ctrl->lane_byte_clk = lane_clock / 8; + phy_ctrl->clk_division = + (((phy_ctrl->lane_byte_clk / 2) % pinfo->mipi.max_tx_esc_clk) > + 0) ? (phy_ctrl->lane_byte_clk / 2 / pinfo->mipi.max_tx_esc_clk + + 1) : (phy_ctrl->lane_byte_clk / 2 / + pinfo->mipi.max_tx_esc_clk); + + HISI_FB_DEBUG("PHY clock_lane and data_lane config : \n" + "rg_vrefsel_vcm=%u\n" + "clk_pre_delay=%u\n" + "clk_post_delay=%u\n" + "clk_t_hs_prepare=%u\n" + "clk_t_lpx=%u\n" + "clk_t_hs_zero=%u\n" + "clk_t_hs_trial=%u\n" + "data_pre_delay=%u\n" + "data_post_delay=%u\n" + "data_t_hs_prepare=%u\n" + "data_t_lpx=%u\n" + "data_t_hs_zero=%u\n" + "data_t_hs_trial=%u\n" + "data_t_ta_go=%u\n" + "data_t_ta_get=%u\n", + phy_ctrl->rg_vrefsel_vcm, + phy_ctrl->clk_pre_delay, + phy_ctrl->clk_post_delay, + phy_ctrl->clk_t_hs_prepare, + phy_ctrl->clk_t_lpx, + phy_ctrl->clk_t_hs_zero, + phy_ctrl->clk_t_hs_trial, + phy_ctrl->data_pre_delay, + phy_ctrl->data_post_delay, + phy_ctrl->data_t_hs_prepare, + phy_ctrl->data_t_lpx, + phy_ctrl->data_t_hs_zero, + phy_ctrl->data_t_hs_trial, + phy_ctrl->data_t_ta_go, phy_ctrl->data_t_ta_get); + HISI_FB_DEBUG("clk_lane_lp2hs_time=%u\n" + "clk_lane_hs2lp_time=%u\n" + "data_lane_lp2hs_time=%u\n" + "data_lane_hs2lp_time=%u\n" + "phy_stop_wait_time=%u\n", + phy_ctrl->clk_lane_lp2hs_time, + phy_ctrl->clk_lane_hs2lp_time, + phy_ctrl->data_lane_lp2hs_time, + phy_ctrl->data_lane_hs2lp_time, + phy_ctrl->phy_stop_wait_time); +} + +static uint32_t mipi_pixel_clk(struct hisi_fb_data_type *hisifd) +{ + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (pinfo->pxl_clk_rate_div == 0) { + return pinfo->pxl_clk_rate; + } + + if ((pinfo->ifbc_type == IFBC_TYPE_NONE) && !is_dual_mipi_panel(hisifd)) { + pinfo->pxl_clk_rate_div = 1; + } + + return pinfo->pxl_clk_rate / pinfo->pxl_clk_rate_div; +} + +static void mipi_init(struct hisi_fb_data_type *hisifd, char __iomem *mipi_dsi_base) +{ + uint32_t hline_time = 0; + uint32_t hsa_time = 0; + uint32_t hbp_time = 0; + uint64_t pixel_clk = 0; + uint32_t i = 0; + unsigned long dw_jiffies = 0; + uint32_t tmp = 0; + bool is_ready = false; + struct hisi_panel_info *pinfo = NULL; + dss_rect_t rect; + uint32_t cmp_stopstate_val = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mipi_dsi_base == NULL); + + pinfo = &(hisifd->panel_info); + + if (pinfo->mipi.max_tx_esc_clk == 0) { + HISI_FB_ERR("fb%d, max_tx_esc_clk is invalid!", hisifd->index); + pinfo->mipi.max_tx_esc_clk = DEFAULT_MAX_TX_ESC_CLK; + } + + memset(&(pinfo->dsi_phy_ctrl), 0, sizeof(struct mipi_dsi_phy_ctrl)); + get_dsi_phy_ctrl(hisifd, &(pinfo->dsi_phy_ctrl)); + + rect.x = 0; + rect.y = 0; + rect.w = pinfo->xres; + rect.h = pinfo->yres; + + mipi_ifbc_get_rect(hisifd, &rect); + + /*************************Configure the DPHY start*************************/ + set_reg(mipi_dsi_base + MIPIDSI_PHY_IF_CFG_OFFSET, + pinfo->mipi.lane_nums, 2, 0); + set_reg(mipi_dsi_base + MIPIDSI_CLKMGR_CFG_OFFSET, + pinfo->dsi_phy_ctrl.clk_division, 8, 0); + set_reg(mipi_dsi_base + MIPIDSI_CLKMGR_CFG_OFFSET, + pinfo->dsi_phy_ctrl.clk_division, 8, 8); + + outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000001); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010014); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + (pinfo->dsi_phy_ctrl.rg_pll_fbd_s << 4) + + (pinfo->dsi_phy_ctrl.rg_pll_enswc << 3) + + (pinfo->dsi_phy_ctrl.rg_pll_enbwt << 2) + + pinfo->dsi_phy_ctrl.rg_pll_chp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010015); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.rg_pll_fbd_p); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010016); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + (pinfo->dsi_phy_ctrl.rg_pll_cp << 5) + + (pinfo->dsi_phy_ctrl.rg_pll_lpf_cs << 4) + + pinfo->dsi_phy_ctrl.rg_pll_refsel); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010017); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.rg_pll_pre_p); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001D); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.rg_vrefsel_vcm); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001E); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + (pinfo->dsi_phy_ctrl.rg_pll_cp_p << 5) + + (pinfo->dsi_phy_ctrl.reload_sel << 4) + + (pinfo->dsi_phy_ctrl.rg_phase_gen_en << 3) + + (pinfo->dsi_phy_ctrl.rg_band_sel << 2) + + (pinfo->dsi_phy_ctrl.pll_power_down << 1) + + pinfo->dsi_phy_ctrl.pll_register_override); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001F); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.load_command); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010020); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_pre_delay)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010021); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_post_delay)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010022); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_lpx)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010023); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_hs_prepare)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010024); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_hs_zero)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010025); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.clk_t_hs_trial); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000); + + for (i = 0; i <= pinfo->mipi.lane_nums; i++) { + tmp = 0x10030 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_pre_delay)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10031 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_post_delay)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10032 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_lpx)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10033 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_hs_prepare)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10034 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_hs_zero)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10035 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + pinfo->dsi_phy_ctrl.data_t_hs_trial); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10036 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_ta_go)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + + tmp = 0x10037 + (i << 4); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, + DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_ta_get)); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000002); + outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, + 0x00000000); + } + + outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x00000007); + + is_ready = false; + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((tmp & 0x00000001) == 0x00000001) { + is_ready = true; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (!is_ready) { + HISI_FB_INFO + ("fb%d, phylock is not ready!MIPIDSI_PHY_STATUS_OFFSET=0x%x.\n", + hisifd->index, tmp); + } + + if (pinfo->mipi.lane_nums >= DSI_4_LANES) { + cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9) | BIT(11)); + } else if (pinfo->mipi.lane_nums >= DSI_3_LANES) { + cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9)); + } else if (pinfo->mipi.lane_nums >= DSI_2_LANES) { + cmp_stopstate_val = (BIT(4) | BIT(7)); + } else { + cmp_stopstate_val = (BIT(4)); + } + + is_ready = false; + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((tmp & cmp_stopstate_val) == cmp_stopstate_val) { + is_ready = true; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (!is_ready) { + HISI_FB_INFO + ("fb%d, phystopstateclklane is not ready! " + "MIPIDSI_PHY_STATUS_OFFSET=0x%x.\n", + hisifd->index, tmp); + } + + /*************************Configure the DPHY end*************************/ + + if (is_mipi_cmd_panel(hisifd)) { + + set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0); + set_reg(mipi_dsi_base + MIPIDSI_EDPI_CMD_SIZE_OFFSET, rect.w, 16, 0); + + if (pinfo->mipi.hs_wr_to_time == 0) { + set_reg(mipi_dsi_base + MIPIDSI_HS_WR_TO_CNT_OFFSET, + 0x1000002, 25, 0); + } else { + set_reg(mipi_dsi_base + MIPIDSI_HS_WR_TO_CNT_OFFSET, + (0x1 << 24) | (pinfo->mipi.hs_wr_to_time * + pinfo->dsi_phy_ctrl.lane_byte_clk / 1000000000UL), 25, 0); + } + } + + set_reg(mipi_dsi_base + MIPIDSI_PHY_IF_CFG_OFFSET, + pinfo->dsi_phy_ctrl.phy_stop_wait_time, 8, 8); + + /* + ** 2. Configure the DPI Interface: + ** This defines how the DPI interface interacts with the controller. + */ + set_reg(mipi_dsi_base + MIPIDSI_DPI_VCID_OFFSET, pinfo->mipi.vc, 2, 0); + set_reg(mipi_dsi_base + MIPIDSI_DPI_COLOR_CODING_OFFSET, + pinfo->mipi.color_mode, 4, 0); + + set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, + pinfo->ldi.data_en_plr, 1, 0); + set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, + pinfo->ldi.vsync_plr, 1, 1); + set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, + pinfo->ldi.hsync_plr, 1, 2); + set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, 0x0, 1, 3); + set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, 0x0, 1, 4); + + /* + ** 3. Select the Video Transmission Mode: + ** This defines how the processor requires the video line to be + ** transported through the DSI link. + */ + + set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x3f, 6, 8); + /* set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x0, 1, 14); */ + if (is_mipi_video_panel(hisifd)) { + set_reg(mipi_dsi_base + MIPIDSI_DPI_LP_CMD_TIM_OFFSET, 0x4, 8, 16); + set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x1, 1, 15); + } + + if ((pinfo->mipi.dsi_version == DSI_1_2_VERSION) + && (is_mipi_video_panel(hisifd)) + && ((pinfo->ifbc_type == IFBC_TYPE_VESA3X_SINGLE) + || (pinfo->ifbc_type == IFBC_TYPE_VESA3X_DUAL))) { + + set_reg(mipi_dsi_base + MIPIDSI_VID_PKT_SIZE_OFFSET, + rect.w * pinfo->pxl_clk_rate_div, 14, 0); + + if (pinfo->mipi.burst_mode < DSI_BURST_SYNC_PULSES_1) { + HISI_FB_INFO + ("pinfo->mipi.burst_mode = %d. video need config BURST mode\n", + pinfo->mipi.burst_mode); + pinfo->mipi.burst_mode = DSI_BURST_SYNC_PULSES_1; + } + } else { + set_reg(mipi_dsi_base + MIPIDSI_VID_PKT_SIZE_OFFSET, rect.w, 14, 0); + } + + set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, + pinfo->mipi.burst_mode, 2, 0); + set_reg(mipi_dsi_base + MIPIDSI_PCKHDL_CFG_OFFSET, 0x1, 1, 2); + + /* + ** 4. Define the DPI Horizontal timing configuration: + ** + ** Hsa_time = HSA*(PCLK period/Clk Lane Byte Period); + ** Hbp_time = HBP*(PCLK period/Clk Lane Byte Period); + ** Hline_time = (HSA+HBP+HACT+HFP)*(PCLK period/Clk Lane Byte Period); + */ + pixel_clk = mipi_pixel_clk(hisifd); + hsa_time = + pinfo->ldi.h_pulse_width * pinfo->dsi_phy_ctrl.lane_byte_clk / + pixel_clk; + hbp_time = + pinfo->ldi.h_back_porch * pinfo->dsi_phy_ctrl.lane_byte_clk / + pixel_clk; + hline_time = + (pinfo->ldi.h_pulse_width + pinfo->ldi.h_back_porch + rect.w + + pinfo->ldi.h_front_porch) * pinfo->dsi_phy_ctrl.lane_byte_clk / + pixel_clk; + set_reg(mipi_dsi_base + MIPIDSI_VID_HSA_TIME_OFFSET, hsa_time, 12, 0); + set_reg(mipi_dsi_base + MIPIDSI_VID_HBP_TIME_OFFSET, hbp_time, 12, 0); + set_reg(mipi_dsi_base + MIPIDSI_VID_HLINE_TIME_OFFSET, hline_time, 15, 0); + + set_reg(mipi_dsi_base + MIPIDSI_VID_VSA_LINES_OFFSET, + pinfo->ldi.v_pulse_width, 10, 0); + set_reg(mipi_dsi_base + MIPIDSI_VID_VBP_LINES_OFFSET, + pinfo->ldi.v_back_porch, 10, 0); + set_reg(mipi_dsi_base + MIPIDSI_VID_VFP_LINES_OFFSET, + pinfo->ldi.v_front_porch, 10, 0); + set_reg(mipi_dsi_base + MIPIDSI_VID_VACTIVE_LINES_OFFSET, rect.h, 14, 0); + set_reg(mipi_dsi_base + MIPIDSI_TO_CNT_CFG_OFFSET, 0x7FF, 16, 0); + + set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET, + pinfo->dsi_phy_ctrl.clk_lane_lp2hs_time, 10, 0); + set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET, + pinfo->dsi_phy_ctrl.clk_lane_hs2lp_time, 10, 16); + set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_RD_CFG_OFFSET, 0x7FFF, 15, 0); + set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_CFG_OFFSET, + pinfo->dsi_phy_ctrl.data_lane_lp2hs_time, 10, 0); + set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_CFG_OFFSET, + pinfo->dsi_phy_ctrl.data_lane_hs2lp_time, 10, 16); + + set_reg(mipi_dsi_base + MIPIDSI_PWR_UP_OFFSET, 0x1, 1, 0); +} + +int mipi_dsi_clk_enable(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + clk_tmp = hisifd->dss_dphy0_ref_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy0_ref_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy0_ref_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + clk_tmp = hisifd->dss_dphy0_cfg_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy0_cfg_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy0_cfg_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + clk_tmp = hisifd->dss_pclk_dsi0_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dsi0_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dsi0_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + } +#ifdef CONFIG_PCLK_PCTRL_USED + clk_tmp = hisifd->dss_pclk_pctrl_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_pctrl_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_pctrl_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } +#endif + + if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) { + clk_tmp = hisifd->dss_dphy1_ref_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy1_ref_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy1_ref_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + clk_tmp = hisifd->dss_dphy1_cfg_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy1_cfg_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_dphy1_cfg_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + + clk_tmp = hisifd->dss_pclk_dsi1_clk; + if (clk_tmp) { + ret = clk_prepare(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dsi1_clk clk_prepare failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + + ret = clk_enable(clk_tmp); + if (ret) { + HISI_FB_ERR + ("fb%d dss_pclk_dsi1_clk clk_enable failed, error=%d!\n", + hisifd->index, ret); + return -EINVAL; + } + } + } + + return 0; +} + +int mipi_dsi_clk_disable(struct hisi_fb_data_type *hisifd) +{ + struct clk *clk_tmp = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + clk_tmp = hisifd->dss_dphy0_ref_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + clk_tmp = hisifd->dss_dphy0_cfg_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + clk_tmp = hisifd->dss_pclk_dsi0_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + } +#ifdef CONFIG_PCLK_PCTRL_USED + clk_tmp = hisifd->dss_pclk_pctrl_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } +#endif + + if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) { + clk_tmp = hisifd->dss_dphy1_ref_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + clk_tmp = hisifd->dss_dphy1_cfg_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + + clk_tmp = hisifd->dss_pclk_dsi1_clk; + if (clk_tmp) { + clk_disable(clk_tmp); + clk_unprepare(clk_tmp); + } + } + + return 0; +} + +/******************************************************************************* + ** + */ +static int mipi_dsi_on_sub1(struct hisi_fb_data_type *hisifd, + char __iomem *mipi_dsi_base) +{ + BUG_ON(mipi_dsi_base == NULL); + + /* mipi init */ + mipi_init(hisifd, mipi_dsi_base); + + /* switch to cmd mode */ + set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0); + /* cmd mode: low power mode */ + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x7f, 7, 8); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0xf, 4, 16); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x1, 1, 24); + /* disable generate High Speed clock */ + /* delete? */ + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0); + + return 0; +} + +static int mipi_dsi_on_sub2(struct hisi_fb_data_type *hisifd, + char __iomem *mipi_dsi_base) +{ + struct hisi_panel_info *pinfo = NULL; + uint32_t pctrl_dphytx_stopcnt = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mipi_dsi_base == NULL); + + pinfo = &(hisifd->panel_info); + + if (is_mipi_video_panel(hisifd)) { + /* switch to video mode */ + set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x0, 1, 0); + } + + if (is_mipi_cmd_panel(hisifd)) { + /* cmd mode: high speed mode */ + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 7, 8); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 4, 16); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 1, 24); + } + + /* enable EOTP TX */ + set_reg(mipi_dsi_base + MIPIDSI_PCKHDL_CFG_OFFSET, 0x1, 1, 0); + + /* enable generate High Speed clock, non continue */ + if (pinfo->mipi.non_continue_en) { + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x3, 2, 0); + } else { + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x1, 2, 0); + } + + if ((pinfo->mipi.dsi_version == DSI_1_2_VERSION) + && (pinfo->ifbc_type == IFBC_TYPE_VESA3X_SINGLE)) { + set_reg(mipi_dsi_base + MIPIDSI_DSC_PARAMETER_OFFSET, 0x01, 32, + 0); + } + + pctrl_dphytx_stopcnt = (uint64_t) (pinfo->ldi.h_back_porch + + pinfo->ldi.h_front_porch + + pinfo->ldi.h_pulse_width + + 5) * + hisifd->dss_clk_rate.dss_pclk_pctrl_rate / pinfo->pxl_clk_rate; + + outp32(hisifd->pctrl_base + PERI_CTRL29, pctrl_dphytx_stopcnt); + if (is_dual_mipi_panel(hisifd)) { + outp32(hisifd->pctrl_base + PERI_CTRL32, pctrl_dphytx_stopcnt); + } + + return 0; +} + +int mipi_dsi_off_sub(struct hisi_fb_data_type *hisifd, + char __iomem *mipi_dsi_base) +{ + BUG_ON(hisifd == NULL); + BUG_ON(mipi_dsi_base == NULL); + + /* switch to cmd mode */ + set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0); + /* cmd mode: low power mode */ + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x7f, 7, 8); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0xf, 4, 16); + set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x1, 1, 24); + + /* disable generate High Speed clock */ + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0); + + /* shutdown d_phy */ + set_reg(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x0, 3, 0); + + return 0; +} + +static int mipi_dsi_ulps_enter(struct hisi_fb_data_type *hisifd, + char __iomem *mipi_dsi_base) +{ + uint32_t tmp = 0; + uint32_t cmp_ulpsactivenot_val = 0; + uint32_t cmp_stopstate_val = 0; + uint32_t try_times = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mipi_dsi_base == NULL); + + HISI_FB_DEBUG("fb%d, +!\n", hisifd->index); + + if (hisifd->panel_info.mipi.lane_nums >= DSI_4_LANES) { + cmp_ulpsactivenot_val = (BIT(5) | BIT(8) | BIT(10) | BIT(12)); + cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9) | BIT(11)); + } else if (hisifd->panel_info.mipi.lane_nums >= DSI_3_LANES) { + cmp_ulpsactivenot_val = (BIT(5) | BIT(8) | BIT(10)); + cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9)); + } else if (hisifd->panel_info.mipi.lane_nums >= DSI_2_LANES) { + cmp_ulpsactivenot_val = (BIT(5) | BIT(8)); + cmp_stopstate_val = (BIT(4) | BIT(7)); + } else { + cmp_ulpsactivenot_val = (BIT(5)); + cmp_stopstate_val = (BIT(4)); + } + + if (inp32(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET) & (BIT(1))) + cmp_stopstate_val |= (BIT(2)); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & cmp_stopstate_val) != cmp_stopstate_val) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, check DPHY data and clock lane stopstate failed! MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + return 0; + } + + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + + if (mipi_dsi_base == hisifd->mipi_dsi0_base) { + set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x0, 1, 3); + } else { + set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x0, 1, 4); + } + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0); + set_reg(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x4, 4, 0); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & cmp_ulpsactivenot_val) != 0) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, check DPHY data lane ulpsactivenot_status failed! MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + set_reg(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x5, 4, 0); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & BIT(3)) != 0) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, check DPHY clock lane ulpsactivenot_status failed! MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x7); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & BIT(0)) != 0) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, check DPHY clock lane phy_lock failed! MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + + set_reg(hisifd->peri_crg_base + PERDIS3, 0x1, 4, 28); + HISI_FB_DEBUG("fb%d, -!\n", hisifd->index); + + return 0; +} + +static int mipi_dsi_ulps_exit(struct hisi_fb_data_type *hisifd, + char __iomem *mipi_dsi_base) +{ + uint32_t tmp = 0; + uint32_t cmp_ulpsactivenot_val = 0; + uint32_t try_times = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mipi_dsi_base == NULL); + + HISI_FB_DEBUG("fb%d, +!\n", hisifd->index); + + set_reg(hisifd->peri_crg_base + PEREN3, 0x1, 4, 28); + set_reg(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x1, 1, 3); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & BIT(0)) != 1) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, check DPHY clock lane phy_lock failed! MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + + if (hisifd->panel_info.mipi.lane_nums >= DSI_4_LANES) { + cmp_ulpsactivenot_val = + (BIT(3) | BIT(5) | BIT(8) | BIT(10) | BIT(12)); + } else if (hisifd->panel_info.mipi.lane_nums >= DSI_3_LANES) { + cmp_ulpsactivenot_val = (BIT(3) | BIT(5) | BIT(8) | BIT(10)); + } else if (hisifd->panel_info.mipi.lane_nums >= DSI_2_LANES) { + cmp_ulpsactivenot_val = (BIT(3) | BIT(5) | BIT(8)); + } else { + cmp_ulpsactivenot_val = (BIT(3) | BIT(5)); + } + + if (mipi_dsi_base == hisifd->mipi_dsi0_base) { + set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x1, 1, 3); + } else { + set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x1, 1, 4); + } + + outp32(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0xF); + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & cmp_ulpsactivenot_val) != cmp_ulpsactivenot_val) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, failed to request that data lane and clock lane exit ULPS!MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + mdelay(1); + outp32(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x0); + + try_times = 0; + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + while ((tmp & BIT(0)) != 0x1) { + udelay(10); + if (++try_times > 100) { + HISI_FB_ERR + ("fb%d, failed to wait DPHY PLL Lock!MIPIDSI_PHY_STATUS=0x%x.\n", + hisifd->index, tmp); + break; + } + tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + } + + set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x1, 1, 0); + HISI_FB_DEBUG("fb%d, -!\n", hisifd->index); + + return 0; +} + +int mipi_dsi_ulps_cfg(struct hisi_fb_data_type *hisifd, int enable) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (enable) { + mipi_dsi_ulps_exit(hisifd, hisifd->mipi_dsi0_base); + if (is_dual_mipi_panel(hisifd)) + mipi_dsi_ulps_exit(hisifd, hisifd->mipi_dsi1_base); + } else { + mipi_dsi_ulps_enter(hisifd, hisifd->mipi_dsi0_base); + if (is_dual_mipi_panel(hisifd)) + mipi_dsi_ulps_enter(hisifd, hisifd->mipi_dsi1_base); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +void mipi_dsi_reset(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x0, 1, 0); + msleep(2); + set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x1, 1, 0); +} + +/******************************************************************************* + ** + */ +static int mipi_dsi_on(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + /* set LCD init step before LCD on */ + hisifd->panel_info.lcd_init_step = LCD_INIT_POWER_ON; + ret = panel_next_on(pdev); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (is_dual_mipi_panel(hisifd)) + outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x30000000); + else + outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x10000000); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x20000000); + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + + mipi_dsi_clk_enable(hisifd); + if (hisifd->index == PRIMARY_PANEL_IDX) { + mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi0_base); + if (is_dual_mipi_panel(hisifd)) + mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi1_base); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi1_base); + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + + ret = panel_next_on(pdev); + if (hisifd->index == PRIMARY_PANEL_IDX) { + mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi0_base); + if (is_dual_mipi_panel(hisifd)) + mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi1_base); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi1_base); + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + + /* mipi hs video/command mode */ + ret = panel_next_on(pdev); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int mipi_dsi_off(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + /* set LCD uninit step before LCD off */ + hisifd->panel_info.lcd_uninit_step = LCD_UNINIT_MIPI_HS_SEND_SEQUENCE; + ret = panel_next_off(pdev); + + if (hisifd->panel_info.lcd_uninit_step_support) { + /* TODO: add MIPI LP mode here if necessary */ + /* MIPI LP mode end */ + ret = panel_next_off(pdev); + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi0_base); + if (is_dual_mipi_panel(hisifd)) + mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi1_base); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi1_base); + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + + mipi_dsi_clk_disable(hisifd); + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (is_dual_mipi_panel(hisifd)) + outp32(hisifd->peri_crg_base + PERRSTEN3, 0x30000000); + else + outp32(hisifd->peri_crg_base + PERRSTEN3, 0x10000000); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + outp32(hisifd->peri_crg_base + PERRSTEN3, 0x20000000); + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + + if (hisifd->panel_info.lcd_uninit_step_support) { + ret = panel_next_off(pdev); + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int mipi_dsi_remove(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = panel_next_remove(pdev); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (hisifd->dss_dphy0_ref_clk) { + clk_put(hisifd->dss_dphy0_ref_clk); + hisifd->dss_dphy0_ref_clk = NULL; + } + + if (hisifd->dss_dphy0_cfg_clk) { + clk_put(hisifd->dss_dphy0_cfg_clk); + hisifd->dss_dphy0_cfg_clk = NULL; + } + + if (is_dual_mipi_panel(hisifd)) { + if (hisifd->dss_dphy1_ref_clk) { + clk_put(hisifd->dss_dphy1_ref_clk); + hisifd->dss_dphy1_ref_clk = NULL; + } + + if (hisifd->dss_dphy1_cfg_clk) { + clk_put(hisifd->dss_dphy1_cfg_clk); + hisifd->dss_dphy1_cfg_clk = NULL; + } + } + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + if (hisifd->dss_dphy1_ref_clk) { + clk_put(hisifd->dss_dphy1_ref_clk); + hisifd->dss_dphy1_ref_clk = NULL; + } + + if (hisifd->dss_dphy1_cfg_clk) { + clk_put(hisifd->dss_dphy1_cfg_clk); + hisifd->dss_dphy1_cfg_clk = NULL; + } + } else { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + } + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int mipi_dsi_set_backlight(struct platform_device *pdev, + uint32_t bl_level) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = panel_next_set_backlight(pdev, bl_level); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int mipi_dsi_vsync_ctrl(struct platform_device *pdev, int enable) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = panel_next_vsync_ctrl(pdev, enable); + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return ret; +} + +static int mipi_dsi_clk_irq_setup(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + int ret = 0; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ret = + clk_set_rate(hisifd->dss_dphy0_ref_clk, + DEFAULT_MIPI_CLK_RATE); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_dphy0_ref_clk clk_set_rate(%lu) failed, error=%d!\n", + hisifd->index, DEFAULT_MIPI_CLK_RATE, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_dphy0_ref_clk:[%lu]->[%lu].\n", + DEFAULT_MIPI_CLK_RATE, + clk_get_rate(hisifd->dss_dphy0_ref_clk)); + + ret = + clk_set_rate(hisifd->dss_dphy0_cfg_clk, + DEFAULT_MIPI_CLK_RATE); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_dphy0_cfg_clk clk_set_rate(%lu) failed, error=%d!\n", + hisifd->index, DEFAULT_MIPI_CLK_RATE, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_dphy0_cfg_clk:[%lu]->[%lu].\n", + DEFAULT_MIPI_CLK_RATE, + clk_get_rate(hisifd->dss_dphy0_cfg_clk)); + HISI_FB_INFO("dss_pclk_dsi0_clk:[%lu]->[%lu].\n", + DEFAULT_PCLK_DSI_RATE, + clk_get_rate(hisifd->dss_pclk_dsi0_clk)); + } +#ifdef CONFIG_PCLK_PCTRL_USED + ret = clk_set_rate(hisifd->dss_pclk_pctrl_clk, DEFAULT_PCLK_PCTRL_RATE); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_pclk_pctrl clk_set_rate(%lu) failed, error=%d!\n", + hisifd->index, DEFAULT_PCLK_PCTRL_RATE, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_pclk_pctrl_clk:[%lu]->[%lu].\n", + DEFAULT_PCLK_PCTRL_RATE, + clk_get_rate(hisifd->dss_pclk_pctrl_clk)); +#endif + + if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) { + ret = + clk_set_rate(hisifd->dss_dphy1_ref_clk, + DEFAULT_MIPI_CLK_RATE); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_dphy1_ref_clk clk_set_rate(%lu) failed, error=%d!\n", + hisifd->index, DEFAULT_MIPI_CLK_RATE, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_dphy1_ref_clk:[%lu]->[%lu].\n", + DEFAULT_MIPI_CLK_RATE, + clk_get_rate(hisifd->dss_dphy1_ref_clk)); + + ret = + clk_set_rate(hisifd->dss_dphy1_cfg_clk, + DEFAULT_MIPI_CLK_RATE); + if (ret < 0) { + HISI_FB_ERR + ("fb%d dss_dphy1_cfg_clk clk_set_rate(%lu) failed, " + "error=%d!\n", + hisifd->index, DEFAULT_MIPI_CLK_RATE, ret); + return -EINVAL; + } + HISI_FB_INFO("dss_dphy1_cfg_clk:[%lu]->[%lu].\n", + DEFAULT_MIPI_CLK_RATE, + clk_get_rate(hisifd->dss_dphy1_cfg_clk)); + HISI_FB_INFO("dss_pclk_dsi1_clk:[%lu]->[%lu].\n", + DEFAULT_PCLK_DSI_RATE, + clk_get_rate(hisifd->dss_pclk_dsi1_clk)); + } + + return ret; +} + +static int mipi_dsi_probe(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct platform_device *dpp_dev = NULL; + struct hisi_fb_panel_data *pdata = NULL; + int ret = 0; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + ret = mipi_dsi_clk_irq_setup(pdev); + if (ret) { + HISI_FB_ERR("fb%d mipi_dsi_irq_clk_setup failed, error=%d!\n", + hisifd->index, ret); + goto err; + } + /* alloc device */ + dpp_dev = platform_device_alloc(DEV_NAME_DSS_DPE, pdev->id); + if (!dpp_dev) { + HISI_FB_ERR("fb%d platform_device_alloc failed, error=%d!\n", + hisifd->index, ret); + ret = -ENOMEM; + goto err_device_alloc; + } + /* link to the latest pdev */ + hisifd->pdev = dpp_dev; + + /* alloc panel device data */ + ret = platform_device_add_data(dpp_dev, dev_get_platdata(&pdev->dev), + sizeof(struct hisi_fb_panel_data)); + if (ret) { + HISI_FB_ERR("fb%d platform_device_add_data failed error=%d!\n", + hisifd->index, ret); + goto err_device_put; + } + + /* data chain */ + pdata = dev_get_platdata(&dpp_dev->dev); + pdata->on = mipi_dsi_on; + pdata->off = mipi_dsi_off; + pdata->remove = mipi_dsi_remove; + pdata->set_backlight = mipi_dsi_set_backlight; + pdata->vsync_ctrl = mipi_dsi_vsync_ctrl; + pdata->next = pdev; + + /* get/set panel info */ + memcpy(&hisifd->panel_info, pdata->panel_info, + sizeof(struct hisi_panel_info)); + + /* set driver data */ + platform_set_drvdata(dpp_dev, hisifd); + /* device add */ + ret = platform_device_add(dpp_dev); + if (ret) { + HISI_FB_ERR("fb%d platform_device_add failed, error=%d!\n", + hisifd->index, ret); + goto err_device_put; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + + return 0; + + err_device_put: + platform_device_put(dpp_dev); + err_device_alloc: + err: + return ret; +} + +static struct platform_driver this_driver = { + .probe = mipi_dsi_probe, + .remove = NULL, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = DEV_NAME_MIPIDSI, + }, +}; + +static int __init mipi_dsi_driver_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + HISI_FB_ERR("platform_driver_register failed, error=%d!\n", + ret); + return ret; + } + return ret; +} + +module_init(mipi_dsi_driver_init); diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h new file mode 100755 index 000000000000..06fd0d3a22ed --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_MIPI_DSI_H +#define HISI_MIPI_DSI_H + +#include "hisi_fb.h" + +/* mipi dsi panel */ +enum { + DSI_VIDEO_MODE, + DSI_CMD_MODE, +}; + +enum { + DSI_1_1_VERSION = 0, + DSI_1_2_VERSION, +}; + +enum { + DSI_1_LANES = 0, + DSI_2_LANES, + DSI_3_LANES, + DSI_4_LANES, +}; + +enum { + DSI_LANE_NUMS_DEFAULT = 0, + DSI_1_LANES_SUPPORT = BIT(0), + DSI_2_LANES_SUPPORT = BIT(1), + DSI_3_LANES_SUPPORT = BIT(2), + DSI_4_LANES_SUPPORT = BIT(3), +}; + +enum { + DSI_16BITS_1 = 0, + DSI_16BITS_2, + DSI_16BITS_3, + DSI_18BITS_1, + DSI_18BITS_2, + DSI_24BITS_1, + DSI_24BITS_2, + DSI_24BITS_3, + DSI_DSC24_COMPRESSED_DATA = 0xF, +}; + +enum { + DSI_NON_BURST_SYNC_PULSES = 0, + DSI_NON_BURST_SYNC_EVENTS, + DSI_BURST_SYNC_PULSES_1, + DSI_BURST_SYNC_PULSES_2, +}; + +#define DSI_VIDEO_DST_FORMAT_RGB565 0 +#define DSI_VIDEO_DST_FORMAT_RGB666 1 +#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE 2 +#define DSI_VIDEO_DST_FORMAT_RGB888 3 + +#define DSI_CMD_DST_FORMAT_RGB565 0 +#define DSI_CMD_DST_FORMAT_RGB666 1 +#define DSI_CMD_DST_FORMAT_RGB888 2 + +/* dcs read/write */ +#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */ +#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */ +#define DTYPE_DCS_READ 0x06 /* read */ +#define DTYPE_DCS_LWRITE 0x39 /* long write */ +#define DTYPE_DSC_LWRITE 0x0A /* dsc dsi1.2 vase3x long write */ + +/* generic read/write */ +#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */ +#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */ +#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */ +#define DTYPE_GEN_LWRITE 0x29 /* long write */ +#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */ +#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */ +#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */ + +#define DTYPE_TEAR_ON 0x35 /* set tear on */ +#define DTYPE_MAX_PKTSIZE 0x37 /* set max packet size */ +#define DTYPE_NULL_PKT 0x09 /* null packet, no data */ +#define DTYPE_BLANK_PKT 0x19 /* blankiing packet, no data */ + +#define DTYPE_CM_ON 0x02 /* color mode off */ +#define DTYPE_CM_OFF 0x12 /* color mode on */ +#define DTYPE_PERIPHERAL_OFF 0x22 +#define DTYPE_PERIPHERAL_ON 0x32 + +#define DSI_HDR_DTYPE(dtype) ((dtype) & 0x03f) +#define DSI_HDR_VC(vc) (((vc) & 0x03) << 6) +#define DSI_HDR_DATA1(data) (((data) & 0x0ff) << 8) +#define DSI_HDR_DATA2(data) (((data) & 0x0ff) << 16) +#define DSI_HDR_WC(wc) (((wc) & 0x0ffff) << 8) + +#define DSI_PLD_DATA1(data) ((data) & 0x0ff) +#define DSI_PLD_DATA2(data) (((data) & 0x0ff) << 8) +#define DSI_PLD_DATA3(data) (((data) & 0x0ff) << 16) +#define DSI_PLD_DATA4(data) (((data) & 0x0ff) << 24) + +struct dsi_cmd_desc { + int dtype; + int vc; + int wait; + int waittype; + int dlen; + char *payload; +}; + +struct mipi_dsi_read_compare_data { + uint32_t *read_value; + uint32_t *expected_value; + uint32_t *read_mask; + char **reg_name; + int log_on; + struct dsi_cmd_desc *cmds; + int cnt; +}; + +/****************************************************************************** + ** FUNCTIONS PROTOTYPES + */ +void mipi_dsi_max_return_packet_size(struct dsi_cmd_desc *cm, + char __iomem *dsi_base); +void mipi_dsi_sread(uint32_t *out, char __iomem *dsi_base); +void mipi_dsi_lread(uint32_t *out, char __iomem *dsi_base); +uint32_t mipi_dsi_read(uint32_t *out, char __iomem *dsi_base); +int mipi_dsi_swrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base); +int mipi_dsi_lwrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base); +void mipi_dsi_check_0lane_is_ready(char __iomem *dsi_base); +int mipi_dsi_cmds_tx(struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base); +int mipi_dsi_cmds_rx(uint32_t *out, struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base); + +int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data, + char __iomem *dsi_base); + +struct hisi_fb_data_type; +int mipi_dsi_clk_enable(struct hisi_fb_data_type *hisifd); +int mipi_dsi_clk_disable(struct hisi_fb_data_type *hisifd); +void mipi_dsi_reset(struct hisi_fb_data_type *hisifd); + +#endif /* HISI_MIPI_DSI_H */ -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei ` (2 preceding siblings ...) (?) @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- .../video/fbdev/hisi/dss/hisi_block_algorithm.c | 714 +++++ .../video/fbdev/hisi/dss/hisi_block_algorithm.h | 29 + .../video/fbdev/hisi/dss/hisi_dpe_utils_hi3660.c | 1549 ++++++++++ drivers/video/fbdev/hisi/dss/hisi_dss.h | 493 +++ .../video/fbdev/hisi/dss/hisi_dss_regs_hi3660.h | 3164 ++++++++++++++++++++ 5 files changed, 5949 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_block_algorithm.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_block_algorithm.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dpe_utils_hi3660.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dss.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dss_regs_hi3660.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.c b/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.c new file mode 100755 index 000000000000..28dcfbd1fe13 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.c @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_block_algorithm.h" +#include "hisi_overlay_utils.h" + +#define SCF_INPUT_OV (16) + +#define WDMA_ROT_LINEBUF (480) +#define AFBCE_LINEBUF (480) + +#define RCHN_V2_SCF_LINE_BUF (512) +#define SHARPNESS_LINE_BUF (2560) + +#define MAX_OFFLINE_SCF 4 +#define MAX_OFFLINE_LAYER_NUMBER 6 +#define BLOCK_SIZE_INVALID (0xFFFF) + +int rect_across_rect(dss_rect_t rect1, dss_rect_t rect2, + dss_rect_t *cross_rect) +{ + uint32_t center_x = 0; + uint32_t center_y = 0; + + BUG_ON(cross_rect == NULL); + + memset(cross_rect, 0x0, sizeof(dss_rect_t)); + + if (rect1.w == 0 || rect1.h == 0 || rect2.w == 0 || rect2.h == 0) + return 0; + + center_x = + abs(rect2.x + rect2.w - 1 + rect2.x - + (rect1.x + rect1.w - 1 + rect1.x)); + center_y = + abs(rect2.y + rect2.h - 1 + rect2.y - + (rect1.y + rect1.h - 1 + rect1.y)); + + if ((center_x < rect2.w + rect1.w) && (center_y < rect2.h + rect1.h)) { + + cross_rect->x = MAX(rect1.x, rect2.x); + cross_rect->y = MAX(rect1.y, rect2.y); + cross_rect->w = + MIN(rect1.x + rect1.w - 1, + rect2.x + rect2.w - 1) - cross_rect->x + 1; + cross_rect->h = + MIN(rect1.y + rect1.h - 1, + rect2.y + rect2.h - 1) - cross_rect->y + 1; + + return 1; + } + + return 0; +} + +uint32_t calc_dest_block_size(dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block) +{ + uint32_t i = 0; + uint32_t block_width = BLOCK_SIZE_INVALID; + int32_t scf_line_buffer = SCF_LINE_BUF; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + + BUG_ON(pov_req == NULL); + BUG_ON(pov_h_block == NULL); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->need_cap & (CAP_DIM | CAP_BASE)) + continue; + + /* sharpenss line buffer is 1600 for austin and dallas, but 2560 for chicago */ + if ((layer->need_cap & CAP_2D_SHARPNESS) && + (layer->src_rect.w > SHARPNESS_LINE_BUF)) { + block_width = MIN(block_width, SHARPNESS_LINE_BUF); + } + + /* scaler line buffer, default value is 2560, but line buffer of rchn_v2 is 512, + scaler line buffer should be subtracted by 32 according to scale algorithm */ + if (layer->chn_idx == DSS_RCHN_V2) { + scf_line_buffer = RCHN_V2_SCF_LINE_BUF; + } else { + scf_line_buffer = SCF_LINE_BUF; + } + + scf_line_buffer = scf_line_buffer - 32; + + if (layer->src_rect.h != layer->dst_rect.h) { + if (((layer->src_rect.w >= layer->dst_rect.w) + && (layer->dst_rect.w > scf_line_buffer)) + || ((layer->src_rect.w < layer->dst_rect.w) + && (layer->src_rect.w > scf_line_buffer))) { + block_width = MIN(block_width, scf_line_buffer); + } + } + } + + for (i = 0; i < pov_req->wb_layer_nums; i++) { + wb_layer = &(pov_req->wb_layer_infos[i]); + + /* maximum of rot linebuffer is 480 */ + if (wb_layer->transform & HISI_FB_TRANSFORM_ROT_90) { + block_width = MIN(block_width, WDMA_ROT_LINEBUF); + } + + /* maximum of afbce linebuffer is 480 */ + if (wb_layer->need_cap & CAP_AFBCE) { + block_width = MIN(block_width, AFBCE_LINEBUF); + } + } + + return block_width; +} + +int scf_output_suitable(uint32_t x_start, uint32_t x_end, uint32_t pos) +{ + if ((x_start > pos) || (x_end < pos)) + return 0; + + /* if distance between layer start/end and pos, return 1 for adjust */ + if ((pos - x_start < SCF_MIN_OUTPUT) + || (x_end - pos + 1 < SCF_MIN_OUTPUT)) + return 1; + + return 0; +} + +int block_fix_scf_constraint(dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + uint32_t block_size, uint32_t end_pos, + uint32_t *fix_size) +{ + uint32_t i = 0; + uint32_t end = end_pos; + uint32_t scf_layer_num = 0; + + dss_rect_t scf_dst_rect[MAX_OFFLINE_LAYER_NUMBER]; + dss_layer_t *layer = NULL; + + BUG_ON(pov_h_block == NULL); + BUG_ON(fix_size == NULL); + + *fix_size = block_size; + + if (block_size <= SCF_MIN_OUTPUT) { + HISI_FB_ERR("block size[%d] is too small!\n", block_size); + return -1; + } + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) { + continue; + } + + if (scf_layer_num >= MAX_OFFLINE_LAYER_NUMBER) { + HISI_FB_ERR + ("layer number in offline [%d] is more than scf moudle [%d]\n", + scf_layer_num, MAX_OFFLINE_LAYER_NUMBER); + return -1; + } + + /* get all scaler layers for austin and dallas */ + /* get all layers for chicago */ + scf_dst_rect[scf_layer_num].x = layer->dst_rect.x; + scf_dst_rect[scf_layer_num].y = layer->dst_rect.y; + scf_dst_rect[scf_layer_num].w = layer->dst_rect.w; + scf_dst_rect[scf_layer_num].h = layer->dst_rect.h; + scf_layer_num++; + } + + if (scf_layer_num == 0) + return 0; + + REDO: + for (i = 0; i < scf_layer_num; i++) { + if (scf_output_suitable(scf_dst_rect[i].x, + scf_dst_rect[i].x + scf_dst_rect[i].w - + 1, pov_req->wb_ov_rect.x + end)) { + end = end - SCF_MIN_OUTPUT; + goto REDO; + } + } + + *fix_size = block_size - (end_pos - end); + return 0; +} + +int adjust_layers_cap(dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_wb_layer_t *wb_layer) +{ + int i = 0; + int temp = 0; + dss_layer_t *layer = NULL; + bool has_rot = false; + + BUG_ON(pov_h_block == NULL); + BUG_ON(wb_layer == NULL); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &pov_h_block->layer_infos[i]; + + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + temp = layer->dst_rect.x; + layer->dst_rect.x = + pov_req->wb_ov_rect.x + (layer->dst_rect.y - + pov_req->wb_ov_rect.y); + layer->dst_rect.y = + pov_req->wb_ov_rect.y + temp - + pov_req->wb_ov_rect.x; + + temp = layer->dst_rect.w; + layer->dst_rect.w = layer->dst_rect.h; + layer->dst_rect.h = temp; + + if (layer->transform == HISI_FB_TRANSFORM_ROT_90) { + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + + } else if (layer->transform == + HISI_FB_TRANSFORM_ROT_270) { + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + + } else if (layer->transform == + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H)) { + layer->transform = HISI_FB_TRANSFORM_ROT_180; + + } else if (layer->transform == + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V)) { + layer->transform = HISI_FB_TRANSFORM_NOP; + + } else { + ; + } + + has_rot = true; + } + } + + + if (has_rot) { + for (i = 0; i < pov_req->wb_layer_nums; i++) { + wb_layer = &(pov_req->wb_layer_infos[i]); + temp = wb_layer->src_rect.w; + wb_layer->src_rect.w = wb_layer->src_rect.h; + wb_layer->src_rect.h = temp; + + wb_layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + } + } + + return 0; +} + +int get_ov_block_rect(dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_wb_layer_t *wb_layer, int *block_num, + dss_rect_t *ov_block_rects[]) +{ + int ret = 0; + uint32_t block_size = 0xFFFF; + uint32_t current_offset = 0; + uint32_t last_offset = 0; + uint32_t fix_scf_span = 0; + dss_layer_t *layer = NULL; + uint32_t i = 0; + int block_has_layer = 0; + int w = 0; + int h = 0; + + BUG_ON(pov_req == NULL); + BUG_ON(pov_h_block == NULL); + BUG_ON(ov_block_rects == NULL); + BUG_ON(block_num == NULL); + BUG_ON(wb_layer == NULL); + + *block_num = 0; + + /* adjust layer transform cap, source layer dst_rect and writeback layer src_rect */ + adjust_layers_cap(pov_req, pov_h_block, wb_layer); + w = wb_layer->src_rect.w; + h = wb_layer->src_rect.h; + + /* init block size according to source layer dst_rect */ + block_size = calc_dest_block_size(pov_req, pov_h_block); + + /* if block size is invalid or larger than write back width, block is not needed. + Then block num is set to 1, and block rect is set to write back layer rect */ + if ((block_size == BLOCK_SIZE_INVALID) || (block_size >= w)) { + ov_block_rects[*block_num]->x = wb_layer->src_rect.x; + ov_block_rects[*block_num]->y = wb_layer->src_rect.y; + ov_block_rects[*block_num]->w = wb_layer->src_rect.w; + ov_block_rects[*block_num]->h = wb_layer->src_rect.h; + + *block_num = 1; + return ret; + } + + current_offset = block_size; + fix_scf_span = block_size; + + for (current_offset = block_size; last_offset < w; + last_offset = current_offset, current_offset += block_size) { + /* make sure each block of scaler layer is larger than 16 */ + if (block_fix_scf_constraint + (pov_req, pov_h_block, block_size, current_offset, + &fix_scf_span) != 0) { + HISI_FB_ERR("block_fix_scf_constraint err!\n"); + return -3; + } + + /* recalculate the block size, the final value */ + current_offset = current_offset - (block_size - fix_scf_span); + block_has_layer = 0; + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (((last_offset + pov_req->wb_ov_rect.x) <= + (layer->dst_rect.x + layer->dst_rect.w - 1)) + && (layer->dst_rect.x < + (current_offset + pov_req->wb_ov_rect.x))) { + block_has_layer = 1; + if ((*block_num) >= HISI_DSS_OFFLINE_MAX_BLOCK) + return -5; + + /* get the block rectangles */ + ov_block_rects[*block_num]->x = + wb_layer->src_rect.x + last_offset; + ov_block_rects[*block_num]->y = + wb_layer->src_rect.y; + ov_block_rects[*block_num]->w = + MIN(current_offset - last_offset, + w - last_offset); + ov_block_rects[*block_num]->h = h; + + (*block_num)++; + break; + } + } + + if (block_has_layer == 0) { + if ((*block_num) >= HISI_DSS_OFFLINE_MAX_BLOCK) + return -6; + + ov_block_rects[*block_num]->x = + wb_layer->src_rect.x + last_offset; + ov_block_rects[*block_num]->y = wb_layer->src_rect.y; + ov_block_rects[*block_num]->w = + MIN(current_offset - last_offset, w - last_offset); + ov_block_rects[*block_num]->h = h; + + (*block_num)++; + } + + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("ov_block_rects[%d]:[%d:%d:%d:%d], current_offset=%d, " + "fix_scf_span=%d, last_offset=%d, w=%d!\n", + *block_num, ov_block_rects[*block_num - 1]->x, + ov_block_rects[*block_num - 1]->y, + ov_block_rects[*block_num - 1]->w, + ov_block_rects[*block_num - 1]->h, current_offset, + fix_scf_span, last_offset, w); + } + } + + hisifb_adjust_block_rect(*block_num, ov_block_rects, wb_layer); + + return ret; +} + +static int create_h_v_block_layer(dss_layer_t *h_layer, + dss_layer_t *h_v_layer, + dss_rect_t dst_cross_rect, + dss_rect_t ov_block_rect) +{ + int input_startpos = 0; + int input_span = 0; + uint32_t output_startpos = 0; + uint32_t output_span = 0; + int h_ratio = 0; + int acc_hscl = 0; + int scf_read_start = 0; + int scf_read_end = 0; + dss_rect_t rect_transform = { 0 }; + dss_rect_t src_rect = { 0 }; + int scf_int = 0; + int scf_rem = 0; + + dss_rect_t dst_rect = { 0 }; + int first_block = 0; + int last_block = 0; + int scf_in_start = 0; + int scf_in_end = 0; + + BUG_ON(h_layer == NULL); + BUG_ON(h_v_layer == NULL); + + first_block = (h_layer->dst_rect.x >= ov_block_rect.x) ? 1 : 0; + last_block = + ((ov_block_rect.x + ov_block_rect.w) >= + (h_layer->dst_rect.x + h_layer->dst_rect.w)) ? 1 : 0; + + output_startpos = dst_cross_rect.x - h_layer->dst_rect.x; + output_span = dst_cross_rect.w; + input_startpos = output_startpos; + input_span = output_span; + + /* handle arsr2p layer */ +#define ARSR2P_OVERLAPH 16 + + if (h_layer->chn_idx == DSS_RCHN_V0 + && (h_layer->src_rect.w < h_layer->dst_rect.w + || h_layer->src_rect.h != h_layer->dst_rect.h + || (h_layer->need_cap & CAP_2D_SHARPNESS))) { + + if ((!first_block) && (output_startpos % 2)) { + h_v_layer->block_info.arsr2p_left_clip = 1; + dst_cross_rect.x = + dst_cross_rect.x - + h_v_layer->block_info.arsr2p_left_clip; + dst_cross_rect.w = + dst_cross_rect.w + + h_v_layer->block_info.arsr2p_left_clip; + + output_startpos = + output_startpos - + h_v_layer->block_info.arsr2p_left_clip; + output_span = dst_cross_rect.w; + input_startpos = output_startpos; + input_span = output_span; + } + + if (h_layer->src_rect.w > h_layer->dst_rect.w) { + src_rect.x = h_layer->src_rect.x; + src_rect.y = h_layer->src_rect.y; + src_rect.w = h_layer->dst_rect.w; + src_rect.h = h_layer->src_rect.h; + } else { + src_rect = h_layer->src_rect; + } + + h_ratio = + (DSS_WIDTH(src_rect.w) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR - acc_hscl) / h_layer->dst_rect.w; + + scf_int = output_startpos * h_ratio / ARSR2P_INC_FACTOR; + scf_rem = output_startpos * h_ratio % ARSR2P_INC_FACTOR; + scf_in_start = (scf_rem > 0) ? (scf_int + 1) : scf_int; + + scf_int = + (output_startpos + + output_span) * h_ratio / ARSR2P_INC_FACTOR; + scf_rem = + (output_startpos + + output_span) * h_ratio % ARSR2P_INC_FACTOR; + scf_in_end = (scf_rem > 0) ? (scf_int + 1) : scf_int; + + if ((first_block == 1) && (last_block == 1)) { + scf_read_start = 0; + scf_read_end = DSS_WIDTH(src_rect.w); + h_v_layer->block_info.last_tile = 1; + } else if (first_block == 1) { + scf_read_start = 0; + scf_read_end = scf_in_end + ARSR2P_OVERLAPH - 1; + } else { + scf_read_start = scf_in_start - ARSR2P_OVERLAPH; + if (scf_read_start < 0) + scf_read_start = 0; + + if (last_block == 1) { + scf_read_end = DSS_WIDTH(src_rect.w); + h_v_layer->block_info.last_tile = 1; + } else { + scf_read_end = scf_in_end + ARSR2P_OVERLAPH - 1; + } + } + + if (scf_read_end > DSS_WIDTH(src_rect.w)) + scf_read_end = DSS_WIDTH(src_rect.w); + + input_startpos = scf_read_start; + input_span = scf_read_end - scf_read_start + 1; + h_v_layer->block_info.h_ratio_arsr2p = h_ratio; + h_v_layer->block_info.arsr2p_src_x = h_layer->src_rect.x; + h_v_layer->block_info.arsr2p_src_y = h_layer->src_rect.y; + h_v_layer->block_info.arsr2p_dst_x = h_layer->dst_rect.x; + h_v_layer->block_info.arsr2p_dst_y = h_layer->dst_rect.y; + h_v_layer->block_info.arsr2p_dst_w = h_layer->dst_rect.w; + + rect_transform.x = h_layer->src_rect.x + input_startpos; + rect_transform.y = h_layer->src_rect.y; + rect_transform.w = input_span; + rect_transform.h = h_layer->src_rect.h; + h_v_layer->block_info.arsr2p_in_rect = rect_transform; + h_v_layer->src_rect = rect_transform; + rect_across_rect(h_v_layer->src_rect, h_v_layer->src_rect_mask, + &h_v_layer->src_rect_mask); + h_v_layer->dst_rect = dst_cross_rect; + } + /* scaling not in rchn v0 or scaling down in rchn v0 */ + if (((h_layer->src_rect.w != h_layer->dst_rect.w) + && (h_layer->chn_idx != DSS_RCHN_V0)) + || ((h_layer->src_rect.w > h_layer->dst_rect.w) + && (h_layer->chn_idx == DSS_RCHN_V0))) { + /* check if arsr2p input has already extened width */ + if (h_v_layer->block_info.h_ratio_arsr2p) { + dst_rect = rect_transform; + h_v_layer->block_info.both_vscfh_arsr2p_used = 1; + output_startpos = input_startpos; + output_span = dst_rect.w; + input_startpos = output_startpos; + input_span = output_span; + } else { + dst_rect = h_layer->dst_rect; + } + + h_ratio = + (DSS_WIDTH(h_layer->src_rect.w) * SCF_INC_FACTOR + + SCF_INC_FACTOR / 2 - + acc_hscl) / DSS_WIDTH(h_layer->dst_rect.w); + + scf_in_start = output_startpos * h_ratio / SCF_INC_FACTOR; + scf_in_end = + DSS_WIDTH(output_startpos + + output_span) * h_ratio / SCF_INC_FACTOR; + + if ((first_block == 1) && (last_block == 1)) { + acc_hscl = 0; + scf_read_start = 0; + scf_read_end = DSS_WIDTH(h_layer->src_rect.w); + } else if (first_block == 1) { + acc_hscl = 0; + scf_read_start = 0; + scf_read_end = scf_in_end + SCF_INPUT_OV; + } else { + scf_read_start = scf_in_start - SCF_INPUT_OV; + if (scf_read_start < 0) + scf_read_start = 0; + acc_hscl = + output_startpos * h_ratio - + scf_read_start * SCF_INC_FACTOR; + + if (last_block == 1) { + scf_read_end = DSS_WIDTH(h_layer->src_rect.w); + } else { + scf_read_end = scf_in_end + SCF_INPUT_OV; + } + } + + if (scf_read_end > DSS_WIDTH(h_layer->src_rect.w)) + scf_read_end = DSS_WIDTH(h_layer->src_rect.w); + + input_startpos = scf_read_start; + input_span = scf_read_end - scf_read_start + 1; + h_v_layer->block_info.h_ratio = h_ratio; + h_v_layer->block_info.acc_hscl = acc_hscl; + + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("first_block=%d, last_block=%d, output_startpos=%d, output_span=%d, " + "h_ratio=%d, acc_hscl=%d, scf_read_start=%d," + "scf_read_end=%d, input_startpos=%d, input_span=%d\n", + first_block, last_block, output_startpos, + output_span, h_ratio, acc_hscl, scf_read_start, + scf_read_end, input_startpos, input_span); + } + } + + switch (h_v_layer->transform) { + case HISI_FB_TRANSFORM_NOP: + case HISI_FB_TRANSFORM_FLIP_V: + rect_transform.x = h_layer->src_rect.x + input_startpos; + rect_transform.y = h_layer->src_rect.y; + rect_transform.w = input_span; + rect_transform.h = h_layer->src_rect.h; + break; + case HISI_FB_TRANSFORM_ROT_180: + case HISI_FB_TRANSFORM_FLIP_H: + rect_transform.x = + h_layer->src_rect.x + h_layer->src_rect.w - input_startpos - + input_span; + rect_transform.y = h_layer->src_rect.y; + rect_transform.w = input_span; + rect_transform.h = h_layer->src_rect.h; + break; + default: + HISI_FB_ERR("unknown h_v_layer->transform=%d!\n", + h_v_layer->transform); + return -EINVAL; + } + + h_v_layer->src_rect = rect_transform; + rect_across_rect(h_v_layer->src_rect, h_v_layer->src_rect_mask, + &h_v_layer->src_rect_mask); + + if (!h_v_layer->block_info.both_vscfh_arsr2p_used) + h_v_layer->dst_rect = dst_cross_rect; + + return 0; +} + +int get_block_layers(dss_overlay_t *pov_req, dss_overlay_block_t *pov_h_block, + dss_rect_t ov_block_rect, dss_overlay_t *pov_req_h_v) +{ + uint32_t i = 0; + int ret = 0; + dss_rect_t dst_cross_rect; + dss_rect_t wb_ov_rect; + dss_overlay_block_t *pov_h_v_block = NULL; + dss_layer_t *h_layer = NULL; + dss_layer_t *h_v_layer = NULL; + int h_v_layer_idx = 0; + + BUG_ON(pov_req == NULL); + BUG_ON(pov_h_block == NULL); + BUG_ON(pov_req_h_v == NULL); + + if (!ov_block_rect.w || !ov_block_rect.h) { + HISI_FB_ERR("invaild args, ov_block_rect(%d,%d,%d,%d)!\n", + ov_block_rect.x, ov_block_rect.y, ov_block_rect.w, + ov_block_rect.y); + return -1; + } + + pov_h_v_block = (dss_overlay_block_t *) pov_req_h_v->ov_block_infos_ptr; + memcpy(pov_req_h_v, pov_req, sizeof(dss_overlay_t)); + pov_req_h_v->ov_block_infos_ptr = (uint64_t) (pov_h_v_block); + + if (calc_dest_block_size(pov_req, pov_h_block) == BLOCK_SIZE_INVALID) { + pov_req_h_v->ov_block_nums = 1; + memcpy(pov_h_v_block, pov_h_block, sizeof(dss_overlay_block_t)); + return 0; + } + + pov_h_v_block->layer_nums = 0; + h_v_layer_idx = 0; + memcpy(&pov_h_v_block->ov_block_rect, &pov_h_block->ov_block_rect, + sizeof(dss_rect_t)); + wb_ov_rect.x = pov_req->wb_ov_rect.x + ov_block_rect.x; + wb_ov_rect.y = pov_req->wb_ov_rect.y; + wb_ov_rect.w = ov_block_rect.w; + wb_ov_rect.h = ov_block_rect.h; + + for (i = 0; i < pov_h_block->layer_nums; i++) { + h_layer = &(pov_h_block->layer_infos[i]); + + ret = + rect_across_rect(h_layer->dst_rect, wb_ov_rect, + &dst_cross_rect); + if (ret == 0) + continue; + + h_v_layer = &(pov_h_v_block->layer_infos[h_v_layer_idx]); + memcpy(h_v_layer, h_layer, sizeof(dss_layer_t)); + h_v_layer->layer_idx = h_v_layer_idx; + + ret = + create_h_v_block_layer(h_layer, h_v_layer, dst_cross_rect, + wb_ov_rect); + if ((ret != 0) || g_debug_ovl_block_composer) { + HISI_FB_INFO + ("h_layer[%d](transform[%d], wb_ov_rect[%d,%d,%d,%d], " + "src_rect[%d,%d,%d,%d], dst_rect[%d,%d,%d,%d]), " + "h_v_layer[%d](transform[%d], src_rect[%d,%d,%d,%d], " + "dst_rect[%d,%d,%d,%d], dst_cross_rect[%d,%d,%d,%d])\n", + i, h_layer->transform, wb_ov_rect.x, wb_ov_rect.y, + wb_ov_rect.w, wb_ov_rect.h, h_layer->src_rect.x, + h_layer->src_rect.y, h_layer->src_rect.w, + h_layer->src_rect.h, h_layer->dst_rect.x, + h_layer->dst_rect.y, h_layer->dst_rect.w, + h_layer->dst_rect.h, h_v_layer_idx, + h_v_layer->transform, h_v_layer->src_rect.x, + h_v_layer->src_rect.y, h_v_layer->src_rect.w, + h_v_layer->src_rect.h, h_v_layer->dst_rect.x, + h_v_layer->dst_rect.y, h_v_layer->dst_rect.w, + h_v_layer->dst_rect.h, dst_cross_rect.x, + dst_cross_rect.y, dst_cross_rect.w, + dst_cross_rect.h); + } + + if (ret != 0) { + HISI_FB_ERR + ("create_h_v_block_layer failed, h_layer[%d], h_v_layer[%d]!\n", + i, h_v_layer_idx); + break; + } + + h_v_layer_idx++; + pov_h_v_block->layer_nums = h_v_layer_idx; + } + + return ret; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.h b/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.h new file mode 100755 index 000000000000..dcbd01650814 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_block_algorithm.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ + +#ifndef __HISI_BLOCK_ALGORITHM_H__ +#define __HISI_BLOCK_ALGORITHM_H__ + +#include "hisi_dss.h" + +int get_ov_block_rect(dss_overlay_t *pov_req_h, + dss_overlay_block_t *pov_h_block, + dss_wb_layer_t *wb_layer, int *block_num, + dss_rect_t *ov_block_rects[]); +int get_block_layers(dss_overlay_t *pov_req_h, + dss_overlay_block_t *pov_h_block, + dss_rect_t ov_block_rect, dss_overlay_t *pov_req_v_block); +int rect_across_rect(dss_rect_t rect1, dss_rect_t rect2, + dss_rect_t *cross_rect); + +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_dpe_utils_hi3660.c b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils_hi3660.c new file mode 100755 index 000000000000..87b9768de329 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils_hi3660.c @@ -0,0 +1,1549 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_dpe_utils.h" + +DEFINE_SEMAPHORE(hisi_fb_dss_inner_clk_sem); + +static int dss_inner_clk_refcount = 0; + +#define OFFSET_FRACTIONAL_BITS (11) +#define ROUND1(x,y) ((x) / (y) + ((x) % (y) ? 1 : 0)) + +static int get_lcd_frame_rate(struct hisi_panel_info *pinfo) +{ + return pinfo->pxl_clk_rate / (pinfo->xres + pinfo->pxl_clk_rate_div * + (pinfo->ldi.h_back_porch + + pinfo->ldi.h_front_porch + + pinfo->ldi.h_pulse_width)) / + (pinfo->yres + pinfo->ldi.v_back_porch + pinfo->ldi.v_front_porch + + pinfo->ldi.v_pulse_width); +} + +struct dss_clk_rate *get_dss_clk_rate(struct hisi_fb_data_type *hisifd) +{ + struct hisi_panel_info *pinfo = NULL; + struct dss_clk_rate *pdss_clk_rate = NULL; + int frame_rate = 0; + + BUG_ON(hisifd == NULL); + + pinfo = &(hisifd->panel_info); + pdss_clk_rate = &(hisifd->dss_clk_rate); + frame_rate = get_lcd_frame_rate(pinfo); + + if (pdss_clk_rate->dss_pclk_dss_rate == 0) { + if ((pinfo->xres * pinfo->yres) >= (RES_4K_PHONE)) { + pdss_clk_rate->dss_pri_clk_rate = + DEFAULT_DSS_CORE_CLK_08V_RATE; + pdss_clk_rate->dss_pclk_dss_rate = + DEFAULT_PCLK_DSS_RATE; + pdss_clk_rate->dss_pclk_pctrl_rate = + DEFAULT_PCLK_PCTRL_RATE; + hisifd->core_clk_upt_support = 0; + + } else if ((pinfo->xres * pinfo->yres) >= (RES_1440P)) { + if (frame_rate >= 110) { + pdss_clk_rate->dss_pri_clk_rate = + DEFAULT_DSS_CORE_CLK_08V_RATE; + pdss_clk_rate->dss_pclk_dss_rate = + DEFAULT_PCLK_DSS_RATE; + pdss_clk_rate->dss_pclk_pctrl_rate = + DEFAULT_PCLK_PCTRL_RATE; + hisifd->core_clk_upt_support = 0; + } else { + pdss_clk_rate->dss_pri_clk_rate = + DEFAULT_DSS_CORE_CLK_07V_RATE; + pdss_clk_rate->dss_pclk_dss_rate = + DEFAULT_PCLK_DSS_RATE; + pdss_clk_rate->dss_pclk_pctrl_rate = + DEFAULT_PCLK_PCTRL_RATE; + hisifd->core_clk_upt_support = 1; + } + + } else if ((pinfo->xres * pinfo->yres) >= (RES_1080P)) { + pdss_clk_rate->dss_pri_clk_rate = + DEFAULT_DSS_CORE_CLK_07V_RATE; + pdss_clk_rate->dss_pclk_dss_rate = + DEFAULT_PCLK_DSS_RATE; + pdss_clk_rate->dss_pclk_pctrl_rate = + DEFAULT_PCLK_PCTRL_RATE; + hisifd->core_clk_upt_support = 1; + + } else { + pdss_clk_rate->dss_pri_clk_rate = + DEFAULT_DSS_CORE_CLK_07V_RATE; + pdss_clk_rate->dss_pclk_dss_rate = + DEFAULT_PCLK_DSS_RATE; + pdss_clk_rate->dss_pclk_pctrl_rate = + DEFAULT_PCLK_PCTRL_RATE; + hisifd->core_clk_upt_support = 1; + } + } + + return pdss_clk_rate; +} + +int set_dss_clk_rate(struct hisi_fb_data_type *hisifd, + dss_clk_rate_t dss_clk_rate) +{ + int ret = 0; + + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -1; + } + + if ((dss_clk_rate.dss_pri_clk_rate != DEFAULT_DSS_CORE_CLK_08V_RATE) + && (dss_clk_rate.dss_pri_clk_rate != DEFAULT_DSS_CORE_CLK_07V_RATE)) { + HISI_FB_ERR("no support set dss_pri_clk_rate(%llu)!\n", + dss_clk_rate.dss_pri_clk_rate); + return -1; + } + + if (dss_clk_rate.dss_pri_clk_rate == + hisifd->dss_clk_rate.dss_pri_clk_rate) { + return ret; + } + + ret = clk_set_rate(hisifd->dss_pri_clk, dss_clk_rate.dss_pri_clk_rate); + if (ret < 0) { + HISI_FB_ERR("set dss_pri_clk_rate(%llu) failed, error=%d!\n", + dss_clk_rate.dss_pri_clk_rate, ret); + return -1; + } + + hisifd->dss_clk_rate.dss_pri_clk_rate = dss_clk_rate.dss_pri_clk_rate; + + return ret; +} + +void dss_inner_clk_common_enable(struct hisi_fb_data_type *hisifd, + bool fastboot_enable) +{ + char __iomem *dss_base = NULL; + int prev_refcount = 0; + + BUG_ON(hisifd == NULL); + + dss_base = hisifd->dss_base; + + down(&hisi_fb_dss_inner_clk_sem); + + prev_refcount = dss_inner_clk_refcount++; + if (!prev_refcount && !fastboot_enable) { + outp32(dss_base + DSS_CMDLIST_OFFSET + CMD_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG0_SCL_OFFSET + SCF_COEF_MEM_CTRL, + 0x00000088); + outp32(dss_base + DSS_RCH_VG0_SCL_OFFSET + SCF_LB_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG0_ARSR_OFFSET + ARSR2P_LB_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG0_DMA_OFFSET + VPP_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG0_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG0_DMA_OFFSET + AFBCD_MEM_CTRL, + 0x00008888); + + outp32(dss_base + DSS_RCH_VG1_SCL_OFFSET + SCF_COEF_MEM_CTRL, + 0x00000088); + outp32(dss_base + DSS_RCH_VG1_SCL_OFFSET + SCF_LB_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG1_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG1_DMA_OFFSET + AFBCD_MEM_CTRL, + 0x00008888); + + outp32(dss_base + DSS_RCH_VG2_SCL_OFFSET + SCF_COEF_MEM_CTRL, + 0x00000088); + outp32(dss_base + DSS_RCH_VG2_SCL_OFFSET + SCF_LB_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_VG2_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + + outp32(dss_base + DSS_RCH_G0_SCL_OFFSET + SCF_COEF_MEM_CTRL, + 0x00000088); + outp32(dss_base + DSS_RCH_G0_SCL_OFFSET + SCF_LB_MEM_CTRL, + 0x0000008); + outp32(dss_base + DSS_RCH_G0_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_G0_DMA_OFFSET + AFBCD_MEM_CTRL, + 0x00008888); + + outp32(dss_base + DSS_RCH_G1_SCL_OFFSET + SCF_COEF_MEM_CTRL, + 0x00000088); + outp32(dss_base + DSS_RCH_G1_SCL_OFFSET + SCF_LB_MEM_CTRL, + 0x0000008); + outp32(dss_base + DSS_RCH_G1_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_G1_DMA_OFFSET + AFBCD_MEM_CTRL, + 0x00008888); + + outp32(dss_base + DSS_RCH_D0_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_D0_DMA_OFFSET + AFBCD_MEM_CTRL, + 0x00008888); + outp32(dss_base + DSS_RCH_D1_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_D2_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_RCH_D3_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + + outp32(dss_base + DSS_WCH0_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_WCH0_DMA_OFFSET + AFBCE_MEM_CTRL, + 0x00000888); + outp32(dss_base + DSS_WCH0_DMA_OFFSET + ROT_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_WCH1_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_WCH1_DMA_OFFSET + AFBCE_MEM_CTRL, + 0x00000888); + outp32(dss_base + DSS_WCH1_DMA_OFFSET + ROT_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_WCH2_DMA_OFFSET + DMA_BUF_MEM_CTRL, + 0x00000008); + outp32(dss_base + DSS_WCH2_DMA_OFFSET + ROT_MEM_CTRL, + 0x00000008); + } + + HISI_FB_DEBUG("fb%d, dss_inner_clk_refcount=%d\n", + hisifd->index, dss_inner_clk_refcount); + + up(&hisi_fb_dss_inner_clk_sem); +} + +void dss_inner_clk_common_disable(struct hisi_fb_data_type *hisifd) +{ + int new_refcount = 0; + + BUG_ON(hisifd == NULL); + + down(&hisi_fb_dss_inner_clk_sem); + new_refcount = --dss_inner_clk_refcount; + WARN_ON(new_refcount < 0); + if (!new_refcount) { + ; + } + + HISI_FB_DEBUG("fb%d, dss_inner_clk_refcount=%d\n", + hisifd->index, dss_inner_clk_refcount); + up(&hisi_fb_dss_inner_clk_sem); +} + +void dss_inner_clk_pdp_enable(struct hisi_fb_data_type *hisifd, + bool fastboot_enable) +{ + char __iomem *dss_base = NULL; + + BUG_ON(hisifd == NULL); + + dss_base = hisifd->dss_base; + + if (fastboot_enable) return; + + outp32(dss_base + DSS_IFBC_OFFSET + IFBC_MEM_CTRL, 0x00000088); + outp32(dss_base + DSS_DSC_OFFSET + DSC_MEM_CTRL, 0x00000888); + outp32(dss_base + DSS_LDI0_OFFSET + LDI_MEM_CTRL, 0x00000008); + outp32(dss_base + DSS_DBUF0_OFFSET + DBUF_MEM_CTRL, 0x00000008); + outp32(dss_base + DSS_DPP_DITHER_OFFSET + DITHER_MEM_CTRL, 0x00000008); +} + +void dss_inner_clk_pdp_disable(struct hisi_fb_data_type *hisifd) +{ +} + +void dss_inner_clk_sdp_enable(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dss_base = NULL; + + BUG_ON(hisifd == NULL); + dss_base = hisifd->dss_base; + + outp32(dss_base + DSS_LDI1_OFFSET + LDI_MEM_CTRL, 0x00000008); + outp32(dss_base + DSS_DBUF1_OFFSET + DBUF_MEM_CTRL, 0x00000008); +} + +void dss_inner_clk_sdp_disable(struct hisi_fb_data_type *hisifd) +{ +} + +void init_dpp(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dpp_base = NULL; + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + dpp_base = hisifd->dss_base + DSS_DPP_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + outp32(dpp_base + DPP_IMG_SIZE_BEF_SR, + (DSS_HEIGHT(pinfo->yres) << 16) | DSS_WIDTH(pinfo->xres)); + outp32(dpp_base + DPP_IMG_SIZE_AFT_SR, + (DSS_HEIGHT(pinfo->yres) << 16) | DSS_WIDTH(pinfo->xres)); + +#ifdef CONFIG_HISI_FB_COLORBAR_USED + outp32(dpp_base + DPP_CLRBAR_CTRL, (0x30 << 24) | (0 << 1) | 0x1); + set_reg(dpp_base + DPP_CLRBAR_1ST_CLR, 0xFF, 8, 16); + set_reg(dpp_base + DPP_CLRBAR_2ND_CLR, 0xFF, 8, 8); + set_reg(dpp_base + DPP_CLRBAR_3RD_CLR, 0xFF, 8, 0); +#endif +} + +static void init_dsc(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dsc_base = NULL; + struct hisi_panel_info *pinfo = NULL; + struct dsc_panel_info *dsc = NULL; + + uint32_t dsc_en = 0; + uint32_t pic_width = 0; + uint32_t pic_height = 0; + uint32_t chunk_size = 0; + uint32_t groups_per_line = 0; + uint32_t rbs_min = 0; + uint32_t hrd_delay = 0; + uint32_t target_bpp_x16 = 0; + uint32_t num_extra_mux_bits = 0; + uint32_t slice_bits = 0; + uint32_t final_offset = 0; + uint32_t final_scale = 0; + uint32_t nfl_bpg_offset = 0; + uint32_t groups_total = 0; + uint32_t slice_bpg_offset = 0; + uint32_t scale_increment_interval = 0; + uint32_t initial_scale_value = 0; + uint32_t scale_decrement_interval = 0; + uint32_t adjustment_bits = 0; + uint32_t adj_bits_per_grp = 0; + uint32_t bits_per_grp = 0; + uint32_t slices_per_line = 0; + uint32_t pic_line_grp_num = 0; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + dsc = &(pinfo->vesa_dsc); + + dsc_base = hisifd->dss_base + DSS_DSC_OFFSET; + + if ((pinfo->ifbc_type == IFBC_TYPE_VESA2X_SINGLE) || + (pinfo->ifbc_type == IFBC_TYPE_VESA3X_SINGLE)) { + + dsc_en = 0x5; + pic_width = DSS_WIDTH(pinfo->xres); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_VESA_CLK_SEL, + 0); + } else { + + dsc_en = 0xb; + pic_width = DSS_WIDTH(pinfo->xres / 2); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_VESA_CLK_SEL, + 1); + } + + pic_height = DSS_HEIGHT(pinfo->yres); + chunk_size = ROUND1((dsc->slice_width + 1) * dsc->bits_per_pixel, 8); + + groups_per_line = (dsc->slice_width + 3) / 3; + rbs_min = + dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * dsc->bits_per_pixel + + groups_per_line * dsc->first_line_bpg_offset; + hrd_delay = ROUND1(rbs_min, dsc->bits_per_pixel); + + target_bpp_x16 = dsc->bits_per_pixel * 16; + slice_bits = 8 * chunk_size * (dsc->slice_height + 1); + + num_extra_mux_bits = + 3 * (dsc->mux_word_size + (4 * dsc->bits_per_component + 4) - 2); + while ((num_extra_mux_bits > 0) + && ((slice_bits - num_extra_mux_bits) % dsc->mux_word_size)) + num_extra_mux_bits--; + + final_offset = dsc->rc_model_size - + ((dsc->initial_xmit_delay * target_bpp_x16 + 8) >> 4) + + num_extra_mux_bits; + + final_scale = + 8 * dsc->rc_model_size / (dsc->rc_model_size - final_offset); + + nfl_bpg_offset = + ROUND1(dsc->first_line_bpg_offset << OFFSET_FRACTIONAL_BITS, dsc->slice_height); + + groups_total = groups_per_line * (dsc->slice_height + 1); + slice_bpg_offset = + ROUND1((1 << OFFSET_FRACTIONAL_BITS) * + (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits), + groups_total); + + scale_increment_interval = + (1 << OFFSET_FRACTIONAL_BITS) * final_offset / + ((final_scale - 9) * (nfl_bpg_offset + slice_bpg_offset)); + + initial_scale_value = + 8 * dsc->rc_model_size / (dsc->rc_model_size - dsc->initial_offset); + if (groups_per_line < initial_scale_value - 8) { + initial_scale_value = groups_per_line + 8; + } + + if (initial_scale_value > 8) { + scale_decrement_interval = + groups_per_line / (initial_scale_value - 8); + } else { + scale_decrement_interval = 4095; + } + + adjustment_bits = + (8 - (dsc->bits_per_pixel * (dsc->slice_width + 1)) % 8) % 8; + + adj_bits_per_grp = dsc->bits_per_pixel * 3 - 3; + bits_per_grp = dsc->bits_per_pixel * 3; + slices_per_line = (pic_width > dsc->slice_width) ? 1 : 0; + + pic_line_grp_num = + ((dsc->slice_width + 3) / 3) * (slices_per_line + 1) - 1; + + set_reg(dsc_base + DSC_REG_DEFAULT, 0x1, 1, 0); + set_reg(dsc_base + DSC_EN, dsc_en, 4, 0); + set_reg(dsc_base + DSC_CTRL, + dsc->bits_per_component | (dsc->linebuf_depth << 4) | + (dsc->block_pred_enable << 10) | + (0x1 << 11) | (dsc->bits_per_pixel << 16), 26, 0); + + set_reg(dsc_base + DSC_PIC_SIZE, (pic_width << 16) | pic_height, 32, 0); + + set_reg(dsc_base + DSC_SLICE_SIZE, + (dsc->slice_width << 16) | dsc->slice_height, 32, 0); + + set_reg(dsc_base + DSC_CHUNK_SIZE, chunk_size, 16, 0); + + set_reg(dsc_base + DSC_INITIAL_DELAY, dsc->initial_xmit_delay | + ((hrd_delay - dsc->initial_xmit_delay) << 16), 32, 0); + + set_reg(dsc_base + DSC_RC_PARAM0, + initial_scale_value | (scale_increment_interval << 16), 32, 0); + + set_reg(dsc_base + DSC_RC_PARAM1, + (dsc->first_line_bpg_offset << 16) | scale_decrement_interval, + 21, 0); + + set_reg(dsc_base + DSC_RC_PARAM2, + nfl_bpg_offset | (slice_bpg_offset << 16), 32, 0); + + set_reg(dsc_base + DSC_RC_PARAM3, + ((final_offset << 16) | dsc->initial_offset), 32, 0); + + set_reg(dsc_base + DSC_FLATNESS_QP_TH, + ((dsc->flatness_max_qp << 16) | (dsc->flatness_min_qp << 0)), + 24, 0); + + set_reg(dsc_base + DSC_RC_PARAM4, + ((dsc->rc_edge_factor << 20) | (dsc->rc_model_size << 0)), 24, + 0); + + set_reg(dsc_base + DSC_RC_PARAM5, + ((dsc->rc_tgt_offset_lo << 20) | (dsc->rc_tgt_offset_hi << 16) | + (dsc->rc_quant_incr_limit1 << 8) | + (dsc->rc_quant_incr_limit0 << 0)), 24, 0); + + set_reg(dsc_base + DSC_RC_BUF_THRESH0, + ((dsc->rc_buf_thresh0 << 24) | (dsc->rc_buf_thresh1 << 16) | + (dsc->rc_buf_thresh2 << 8) | (dsc->rc_buf_thresh3 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_BUF_THRESH1, + ((dsc->rc_buf_thresh4 << 24) | (dsc->rc_buf_thresh5 << 16) | + (dsc->rc_buf_thresh6 << 8) | + (dsc->rc_buf_thresh7 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_BUF_THRESH2, + ((dsc->rc_buf_thresh8 << 24) | (dsc->rc_buf_thresh9 << 16) | + (dsc->rc_buf_thresh10 << 8) | + (dsc->rc_buf_thresh11 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_BUF_THRESH3, + ((dsc->rc_buf_thresh12 << 24) | + (dsc->rc_buf_thresh13 << 16)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM0, + ((dsc->range_min_qp0 << 27) | (dsc->range_max_qp0 << 22) | + (dsc->range_bpg_offset0 << 16) | (dsc->range_min_qp1 << 11) | + (dsc->range_max_qp1 << 6) | (dsc->range_bpg_offset1 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM1, + ((dsc->range_min_qp2 << 27) | (dsc->range_max_qp2 << 22) | + (dsc->range_bpg_offset2 << 16) | + (dsc->range_min_qp3 << 11) | (dsc->range_max_qp3 << 6) | + (dsc->range_bpg_offset3 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM2, + ((dsc->range_min_qp4 << 27) | (dsc->range_max_qp4 << 22) | + (dsc->range_bpg_offset4 << 16) | + (dsc->range_min_qp5 << 11) | (dsc->range_max_qp5 << 6) | + (dsc->range_bpg_offset5 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM3, + ((dsc->range_min_qp6 << 27) | (dsc->range_max_qp6 << 22) | + (dsc->range_bpg_offset6 << 16) | + (dsc->range_min_qp7 << 11) | (dsc->range_max_qp7 << 6) | + (dsc->range_bpg_offset7 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM4, + ((dsc->range_min_qp8 << 27) | (dsc->range_max_qp8 << 22) | + (dsc->range_bpg_offset8 << 16) | + (dsc->range_min_qp9 << 11) | (dsc->range_max_qp9 << 6) | + (dsc->range_bpg_offset9 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM5, + ((dsc->range_min_qp10 << 27) | (dsc->range_max_qp10 << 22) | + (dsc->range_bpg_offset10 << 16) | + (dsc->range_min_qp11 << 11) | (dsc->range_max_qp11 << 6) | + (dsc->range_bpg_offset11 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM6, + ((dsc->range_min_qp12 << 27) | (dsc->range_max_qp12 << 22) | + (dsc->range_bpg_offset12 << 16) | + (dsc->range_min_qp13 << 11) | (dsc->range_max_qp13 << 6) | + (dsc->range_bpg_offset13 << 0)), 32, 0); + + set_reg(dsc_base + DSC_RC_RANGE_PARAM7, + ((dsc->range_min_qp14 << 27) | (dsc->range_max_qp14 << 22) | + (dsc->range_bpg_offset14 << 16)), 32, 0); + + set_reg(dsc_base + DSC_ADJUSTMENT_BITS, adjustment_bits, 4, 0); + + set_reg(dsc_base + DSC_BITS_PER_GRP, + bits_per_grp | (adj_bits_per_grp << 8), 14, 0); + + set_reg(dsc_base + DSC_MULTI_SLICE_CTL, slices_per_line | + (pic_line_grp_num << 16), 32, 0); + + if ((chunk_size % 3 == 0)) { + set_reg(dsc_base + DSC_OUT_CTRL, 0x0, 1, 0); + + } else if ((chunk_size % 2 == 0)) { + set_reg(dsc_base + DSC_OUT_CTRL, 0x1, 1, 0); + + } else { + HISI_FB_ERR + ("fb%d, chunk_size should be mode by 3 or 2," + " but chunk_size = %u\n", + hisifd->index, chunk_size); + return; + } + + set_reg(dsc_base + DSC_CLK_SEL, 0x0, 32, 0); + set_reg(dsc_base + DSC_CLK_EN, 0x7, 32, 0); + set_reg(dsc_base + DSC_MEM_CTRL, 0x0, 32, 0); + set_reg(dsc_base + DSC_ST_DATAIN, 0x0, 28, 0); + set_reg(dsc_base + DSC_ST_DATAOUT, 0x0, 16, 0); + set_reg(dsc_base + DSC0_ST_SLC_POS, 0x0, 28, 0); + set_reg(dsc_base + DSC1_ST_SLC_POS, 0x0, 28, 0); + set_reg(dsc_base + DSC0_ST_PIC_POS, 0x0, 28, 0); + set_reg(dsc_base + DSC1_ST_PIC_POS, 0x0, 28, 0); + set_reg(dsc_base + DSC0_ST_FIFO, 0x0, 14, 0); + set_reg(dsc_base + DSC1_ST_FIFO, 0x0, 14, 0); + set_reg(dsc_base + DSC0_ST_LINEBUF, 0x0, 24, 0); + set_reg(dsc_base + DSC1_ST_LINEBUF, 0x0, 24, 0); + set_reg(dsc_base + DSC_ST_ITFC, 0x0, 10, 0); + set_reg(dsc_base + DSC_RD_SHADOW_SEL, 0x1, 1, 0); + set_reg(dsc_base + DSC_REG_DEFAULT, 0x0, 1, 0); +} + +void init_ifbc(struct hisi_fb_data_type *hisifd) +{ + char __iomem *ifbc_base = NULL; + struct hisi_panel_info *pinfo = NULL; + uint32_t mipi_idx = 0; + uint32_t comp_mode = 0; + + uint32_t ifbc_out_mode = 0; + uint32_t dpk_mode_sel = 0; + uint32_t dup_mode_sel = 0; + uint32_t porch_num = 0; + uint32_t insert_byte_num = 0; + uint32_t insert_byte = 0; + uint32_t num_pad = 0; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + BUG_ON((pinfo->ifbc_type < IFBC_TYPE_NONE) + || (pinfo->ifbc_type >= IFBC_TYPE_MAX)); + + /* VESA_CLK_SEL is set to 0 for initial, 1 is needed only by vesa dual pipe compress */ + set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_VESA_CLK_SEL, 0, 1, 0); + + if (pinfo->ifbc_type == IFBC_TYPE_NONE) + return; + + if (!HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_IFBC)) + return; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ifbc_base = hisifd->dss_base + DSS_IFBC_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + mipi_idx = is_dual_mipi_panel(hisifd) ? 1 : 0; + comp_mode = g_mipi_ifbc_division[mipi_idx][pinfo->ifbc_type].comp_mode; + + if (is_ifbc_vesa_panel(hisifd)) { + init_dsc(hisifd); + set_reg(ifbc_base + IFBC_CTRL, comp_mode, 3, 0); + return; + } + + if (pinfo->bpp == LCD_RGB888) + ifbc_out_mode = 1; + else if (pinfo->bpp == LCD_RGB565) + ifbc_out_mode = 0; + + if (((pinfo->ifbc_type == IFBC_TYPE_ORISE2X) + && (pinfo->ifbc_cmp_dat_rev0 == 1)) + || ((pinfo->ifbc_type == IFBC_TYPE_RSP3X) + && (pinfo->type != PANEL_MIPI_VIDEO) && (pinfo->xres % 3 != 0))) + if (pinfo->ifbc_auto_sel != 0) { + HISI_FB_ERR("fb%d, auto_sel = %u not support!", + hisifd->index, pinfo->ifbc_auto_sel); + return; + } + + if (pinfo->ifbc_type == IFBC_TYPE_ORISE2X) { + if ((pinfo->xres % 2 != 0) && (pinfo->yres % 2 != 0)) { + HISI_FB_ERR + ("fb%d, IFBC_ORISE2X not support (xres = %u, yres = %u)!", + hisifd->index, pinfo->xres, pinfo->yres); + return; + } + + dpk_mode_sel = 1; + dup_mode_sel = 2; + porch_num = 0; + } else if (pinfo->ifbc_type == IFBC_TYPE_ORISE3X) { + dpk_mode_sel = 0; + dup_mode_sel = 3; + porch_num = 5; + } else if (pinfo->ifbc_type == IFBC_TYPE_HIMAX2X) { + if ((pinfo->xres % 2 != 0) && (pinfo->yres % 2 != 0)) { + HISI_FB_ERR + ("fb%d, IFBC_HIMAX2X not support (xres = %u, yres = %u)!", + hisifd->index, pinfo->xres, pinfo->yres); + return; + } + + dpk_mode_sel = 1; + dup_mode_sel = 2; + porch_num = 0; + } else if (pinfo->ifbc_type == IFBC_TYPE_RSP2X) { + dpk_mode_sel = 1; + dup_mode_sel = 0; + porch_num = 0; + + if ((pinfo->type == PANEL_MIPI_CMD) || + (pinfo->type == PANEL_DUAL_MIPI_CMD)) { + num_pad = (4 - pinfo->xres % 4) % 4; + } else { + num_pad = 0; + } + } else if (pinfo->ifbc_type == IFBC_TYPE_RSP3X) { + if ((pinfo->yres % 2 != 0) || (pinfo->yres < 8)) { + HISI_FB_ERR + ("fb%d, IFBC_RSP3X not support (xres = %u, yres = %u)!", + hisifd->index, pinfo->xres, pinfo->yres); + return; + } + + dpk_mode_sel = 2; + dup_mode_sel = 1; + porch_num = 0; + + insert_byte = DSS_WIDTH(pinfo->xres) / (mipi_idx + 1) + 1; + + if ((pinfo->type == PANEL_MIPI_VIDEO) || + (pinfo->type == PANEL_DUAL_MIPI_VIDEO)) { + insert_byte_num = (3 - insert_byte % 3) % 3; + num_pad = (8 - pinfo->xres % 8) % 8; + } else if ((pinfo->type == PANEL_MIPI_CMD) || + (pinfo->type == PANEL_DUAL_MIPI_CMD)) { + insert_byte_num = 0; + num_pad = (4 - pinfo->xres % 4) % 4; + } + } + set_reg(ifbc_base + IFBC_SIZE, + ((DSS_WIDTH(pinfo->xres) << 16) | DSS_HEIGHT(pinfo->yres)), 32, 0); + + set_reg(ifbc_base + IFBC_CTRL, comp_mode, 3, 0); + set_reg(ifbc_base + IFBC_CTRL, ifbc_out_mode, 1, 3); + set_reg(ifbc_base + IFBC_CTRL, pinfo->ifbc_cmp_dat_rev0, 1, 4); + set_reg(ifbc_base + IFBC_CTRL, pinfo->ifbc_cmp_dat_rev1, 1, 5); + set_reg(ifbc_base + IFBC_CTRL, pinfo->ifbc_auto_sel, 1, 6); + + if (pinfo->ifbc_auto_sel == 0) { + set_reg(ifbc_base + IFBC_CTRL, dpk_mode_sel, 3, 7); + set_reg(ifbc_base + IFBC_CTRL, dup_mode_sel, 3, 10); + set_reg(ifbc_base + IFBC_CTRL, porch_num, 8, 13); + set_reg(ifbc_base + IFBC_INSERT, + insert_byte_num | (insert_byte << 16), 32, 0); + + set_reg(ifbc_base + IFBC_PAD, num_pad, 3, 0); + } + + if (pinfo->ifbc_type == IFBC_TYPE_ORISE3X) { + if (pinfo->ifbc_orise_ctr == 1) { + set_reg(ifbc_base + IFBC_CORE_GT, 0x0, 2, 0); + + if (pinfo->ifbc_orise_ctl == IFBC_ORISE_CTL_8LINE) { + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0208, 32, 0); + + } else if (pinfo->ifbc_orise_ctl == IFBC_ORISE_CTL_16LINE) { + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0210, 32, 0); + } else if (pinfo->ifbc_orise_ctl == IFBC_ORISE_CTL_32LINE) { + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0220, 32, 0); + } else { + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0200, 32, 0); + } + + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0300, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0419, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0500, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x063f, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0700, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0801, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0900, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0a64, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0b00, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0c5c, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0d00, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0e01, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x0f00, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x10a0, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x1100, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x125f, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x1300, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x14a0, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x1500, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x16ff, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x1700, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x200c, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x2100, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4000, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4100, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4200, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4300, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4800, 32, 0); + set_reg(ifbc_base + IFBC_ORISE_CTL, 0x4900, 32, 0); + } else { + set_reg(ifbc_base + IFBC_CORE_GT, 0x2, 2, 0); + } + } + + set_reg(ifbc_base + IFBC_CLK_SEL, 0x0, 32, 0); + set_reg(ifbc_base + IFBC_EN, 0x3, 2, 0); +} + +void init_post_scf(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dpp_base = NULL; + char __iomem *scf_lut_base = NULL; + + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(hisifd == NULL); + + pinfo = &(hisifd->panel_info); + + dpp_base = hisifd->dss_base + DSS_DPP_OFFSET; + scf_lut_base = hisifd->dss_base + DSS_POST_SCF_LUT_OFFSET; + + if (!HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_POST_SCF)) { + return; + } + + /* ARSR1P memory shutdown + outp32(dpp_base + DPP_ARSR1P_MEM_CTRL, 0X4); */ + + pinfo->post_scf_support = 1; + hisi_dss_post_scl_load_filter_coef(hisifd, false, scf_lut_base, + SCL_COEF_RGB_IDX); + + return; +} + +void init_dbuf(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dbuf_base = NULL; + struct hisi_panel_info *pinfo = NULL; + int sram_valid_num = 0; + int sram_max_mem_depth = 0; + int sram_min_support_depth = 0; + + uint32_t thd_rqos_in = 0; + uint32_t thd_rqos_out = 0; + uint32_t thd_wqos_in = 0; + uint32_t thd_wqos_out = 0; + uint32_t thd_cg_in = 0; + uint32_t thd_cg_out = 0; + uint32_t thd_wr_wait = 0; + uint32_t thd_cg_hold = 0; + uint32_t thd_flux_req_befdfs_in = 0; + uint32_t thd_flux_req_befdfs_out = 0; + uint32_t thd_flux_req_aftdfs_in = 0; + uint32_t thd_flux_req_aftdfs_out = 0; + uint32_t thd_dfs_ok = 0; + uint32_t dfs_ok_mask = 0; + uint32_t thd_flux_req_sw_en = 1; + + int dfs_time = 0; + int dfs_time_min = 0; + int depth = 0; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + dbuf_base = hisifd->dss_base + DSS_DBUF0_OFFSET; + if (!HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_DBUF)) { + return; + } + + if (pinfo->xres * pinfo->yres >= RES_4K_PHONE) { + dfs_time_min = DFS_TIME_MIN_4K; + } else { + dfs_time_min = DFS_TIME_MIN; + } + + dfs_time = DFS_TIME; + depth = DBUF0_DEPTH; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + dbuf_base = hisifd->dss_base + DSS_DBUF1_OFFSET; + + dfs_time = DFS_TIME; + dfs_time_min = DFS_TIME_MIN; + depth = DBUF1_DEPTH; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + /* + ** int K = 0; + ** int Tp = 1000000 / pinfo->pxl_clk_rate; + ** K = (pinfo->ldi.h_pulse_width + pinfo->ldi.h_back_porch + pinfo->xres + + ** pinfo->ldi.h_front_porch) / pinfo->xres; + ** thd_cg_out = dfs_time / (Tp * K * 6); + */ + if (pinfo->pxl_clk_rate_div <= 0) + pinfo->pxl_clk_rate_div = 1; + + thd_cg_out = (dfs_time * pinfo->pxl_clk_rate * pinfo->xres) / + (((pinfo->ldi.h_pulse_width + pinfo->ldi.h_back_porch + + pinfo->ldi.h_front_porch) * pinfo->pxl_clk_rate_div + + pinfo->xres) * 6 * 1000000UL); + sram_valid_num = thd_cg_out / depth; + thd_cg_in = (sram_valid_num + 1) * depth - 1; + + sram_max_mem_depth = (sram_valid_num + 1) * depth; + + thd_rqos_in = thd_cg_out * 85 / 100; + thd_rqos_out = thd_cg_out; + thd_flux_req_befdfs_in = GET_FLUX_REQ_IN(sram_max_mem_depth); + thd_flux_req_befdfs_out = GET_FLUX_REQ_OUT(sram_max_mem_depth); + + sram_min_support_depth = + dfs_time_min * pinfo->xres / (1000000 / 60 / + (pinfo->yres + + pinfo->ldi.v_back_porch + + pinfo->ldi.v_front_porch + + pinfo->ldi.v_pulse_width) * + (DBUF_WIDTH_BIT / 3 / BITS_PER_BYTE)); + + /* thd_flux_req_aftdfs_in =[(sram_valid_num+1)*depth - 50*HSIZE/((1000000/60/(VSIZE+VFP+VBP+VSW))*6)]/3 */ + thd_flux_req_aftdfs_in = + (sram_max_mem_depth - sram_min_support_depth) / 3; + /* thd_flux_req_aftdfs_out = 2*[(sram_valid_num+1)* depth - 50*HSIZE/((1000000/60/(VSIZE+VFP+VBP+VSW))*6)]/3 */ + thd_flux_req_aftdfs_out = + 2 * (sram_max_mem_depth - sram_min_support_depth) / 3; + + thd_dfs_ok = thd_flux_req_befdfs_in; + + HISI_FB_DEBUG("sram_valid_num=%d,\n" + "thd_rqos_in=0x%x\n" + "thd_rqos_out=0x%x\n" + "thd_cg_in=0x%x\n" + "thd_cg_out=0x%x\n" + "thd_flux_req_befdfs_in=0x%x\n" + "thd_flux_req_befdfs_out=0x%x\n" + "thd_flux_req_aftdfs_in=0x%x\n" + "thd_flux_req_aftdfs_out=0x%x\n" + "thd_dfs_ok=0x%x\n", + sram_valid_num, + thd_rqos_in, + thd_rqos_out, + thd_cg_in, + thd_cg_out, + thd_flux_req_befdfs_in, + thd_flux_req_befdfs_out, + thd_flux_req_aftdfs_in, + thd_flux_req_aftdfs_out, thd_dfs_ok); + + outp32(dbuf_base + DBUF_FRM_SIZE, pinfo->xres * pinfo->yres); + outp32(dbuf_base + DBUF_FRM_HSIZE, DSS_WIDTH(pinfo->xres)); + outp32(dbuf_base + DBUF_SRAM_VALID_NUM, sram_valid_num); + + outp32(dbuf_base + DBUF_THD_RQOS, (thd_rqos_out << 16) | thd_rqos_in); + outp32(dbuf_base + DBUF_THD_WQOS, (thd_wqos_out << 16) | thd_wqos_in); + outp32(dbuf_base + DBUF_THD_CG, (thd_cg_out << 16) | thd_cg_in); + outp32(dbuf_base + DBUF_THD_OTHER, (thd_cg_hold << 16) | thd_wr_wait); + outp32(dbuf_base + DBUF_THD_FLUX_REQ_BEF, + (thd_flux_req_befdfs_out << 16) | thd_flux_req_befdfs_in); + outp32(dbuf_base + DBUF_THD_FLUX_REQ_AFT, + (thd_flux_req_aftdfs_out << 16) | thd_flux_req_aftdfs_in); + outp32(dbuf_base + DBUF_THD_DFS_OK, thd_dfs_ok); + outp32(dbuf_base + DBUF_FLUX_REQ_CTRL, + (dfs_ok_mask << 1) | thd_flux_req_sw_en); + + outp32(dbuf_base + DBUF_DFS_LP_CTRL, 0x1); +} + +static void init_ldi_pxl_div(struct hisi_fb_data_type *hisifd) +{ + struct hisi_panel_info *pinfo = NULL; + char __iomem *ldi_base = NULL; + uint32_t ifbc_type = 0; + uint32_t mipi_idx = 0; + uint32_t pxl0_div2_gt_en = 0; + uint32_t pxl0_div4_gt_en = 0; + uint32_t pxl0_divxcfg = 0; + uint32_t pxl0_dsi_gt_en = 0; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (hisifd->index == EXTERNAL_PANEL_IDX) + return; + + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + + ifbc_type = pinfo->ifbc_type; + BUG_ON((ifbc_type < IFBC_TYPE_NONE) || (ifbc_type >= IFBC_TYPE_MAX)); + + mipi_idx = is_dual_mipi_panel(hisifd) ? 1 : 0; + + pxl0_div2_gt_en = + g_mipi_ifbc_division[mipi_idx][ifbc_type].pxl0_div2_gt_en; + pxl0_div4_gt_en = + g_mipi_ifbc_division[mipi_idx][ifbc_type].pxl0_div4_gt_en; + pxl0_divxcfg = g_mipi_ifbc_division[mipi_idx][ifbc_type].pxl0_divxcfg; + pxl0_dsi_gt_en = + g_mipi_ifbc_division[mipi_idx][ifbc_type].pxl0_dsi_gt_en; + + set_reg(ldi_base + LDI_PXL0_DIV2_GT_EN, pxl0_div2_gt_en, 1, 0); + set_reg(ldi_base + LDI_PXL0_DIV4_GT_EN, pxl0_div4_gt_en, 1, 0); + set_reg(ldi_base + LDI_PXL0_GT_EN, 0x1, 1, 0); + set_reg(ldi_base + LDI_PXL0_DSI_GT_EN, pxl0_dsi_gt_en, 2, 0); + set_reg(ldi_base + LDI_PXL0_DIVXCFG, pxl0_divxcfg, 3, 0); +} + +void init_ldi(struct hisi_fb_data_type *hisifd, bool fastboot_enable) +{ + char __iomem *ldi_base = NULL; + struct hisi_panel_info *pinfo = NULL; + dss_rect_t rect = { 0, 0, 0, 0 }; + uint32_t te0_enable = 0; + uint32_t te1_enable = 0; + uint32_t te_source = 0; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + te0_enable = 1; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + te1_enable = 1; + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + rect.x = 0; + rect.y = 0; + rect.w = pinfo->xres; + rect.h = pinfo->yres; + mipi_ifbc_get_rect(hisifd, &rect); + + init_ldi_pxl_div(hisifd); + + if (is_dual_mipi_panel(hisifd)) { + if (is_mipi_video_panel(hisifd)) { + outp32(ldi_base + LDI_DPI1_HRZ_CTRL0, + (pinfo->ldi.h_back_porch + + DSS_WIDTH(pinfo->ldi.h_pulse_width)) << 16); + outp32(ldi_base + LDI_DPI1_HRZ_CTRL1, 0); + outp32(ldi_base + LDI_DPI1_HRZ_CTRL2, + DSS_WIDTH(rect.w)); + } else { + outp32(ldi_base + LDI_DPI1_HRZ_CTRL0, + pinfo->ldi.h_back_porch << 16); + outp32(ldi_base + LDI_DPI1_HRZ_CTRL1, + DSS_WIDTH(pinfo->ldi.h_pulse_width)); + outp32(ldi_base + LDI_DPI1_HRZ_CTRL2, + DSS_WIDTH(rect.w)); + } + + outp32(ldi_base + LDI_OVERLAP_SIZE, + pinfo->ldi.dpi0_overlap_size | + (pinfo->ldi.dpi1_overlap_size << 16)); + + /* dual_mode_en */ + set_reg(ldi_base + LDI_CTRL, 1, 1, 5); + + /* split mode */ + set_reg(ldi_base + LDI_CTRL, 0, 1, 16); + + /* dual lcd: 0x1, dual mipi: 0x0 */ + set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_DSI1_CLK_SEL, + 0x0, 1, 0); + } + if (is_mipi_video_panel(hisifd)) { + outp32(ldi_base + LDI_DPI0_HRZ_CTRL0, + pinfo->ldi.h_front_porch | + ((pinfo->ldi.h_back_porch + + DSS_WIDTH(pinfo->ldi.h_pulse_width)) << 16)); + + outp32(ldi_base + LDI_DPI0_HRZ_CTRL1, 0); + outp32(ldi_base + LDI_DPI0_HRZ_CTRL2, DSS_WIDTH(rect.w)); + } else { + outp32(ldi_base + LDI_DPI0_HRZ_CTRL0, + pinfo->ldi.h_front_porch | (pinfo->ldi.h_back_porch << 16)); + outp32(ldi_base + LDI_DPI0_HRZ_CTRL1, + DSS_WIDTH(pinfo->ldi.h_pulse_width)); + outp32(ldi_base + LDI_DPI0_HRZ_CTRL2, DSS_WIDTH(rect.w)); + } + outp32(ldi_base + LDI_VRT_CTRL0, + pinfo->ldi.v_front_porch | (pinfo->ldi.v_back_porch << 16)); + outp32(ldi_base + LDI_VRT_CTRL1, DSS_HEIGHT(pinfo->ldi.v_pulse_width)); + outp32(ldi_base + LDI_VRT_CTRL2, DSS_HEIGHT(rect.h)); + + outp32(ldi_base + LDI_PLR_CTRL, + pinfo->ldi.vsync_plr | (pinfo->ldi.hsync_plr << 1) | + (pinfo->ldi.pixelclk_plr << 2) | (pinfo->ldi.data_en_plr << 3)); + + set_reg(ldi_base + LDI_CTRL, pinfo->bpp, 2, 3); + set_reg(ldi_base + LDI_CTRL, pinfo->bgr_fmt, 1, 13); + + outp32(ldi_base + LDI_VINACT_MSK_LEN, pinfo->ldi.v_front_porch); + outp32(ldi_base + LDI_CMD_EVENT_SEL, 0x1); + + /* for 1Hz LCD and mipi command LCD */ + if (is_mipi_cmd_panel(hisifd)) { + set_reg(ldi_base + LDI_DSI_CMD_MOD_CTRL, 0x1, 1, 0); + + /* DSI_TE_CTRL + * te_source = 0, select te_pin + * te_source = 1, select te_triger + */ + te_source = 0; + + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x1, 1, 0); + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x0, 2, 1); + set_reg(ldi_base + LDI_DSI_TE_CTRL, te_source, 1, 3); + if (te_source == 0) { + set_reg(ldi_base + LDI_DSI_TE_CTRL, te0_enable, 1, 6); + set_reg(ldi_base + LDI_DSI_TE_CTRL, te1_enable, 1, 7); + } else { + set_reg(ldi_base + LDI_DSI_TE_CTRL, te0_enable, 1, 4); + set_reg(ldi_base + LDI_DSI_TE_CTRL, te1_enable, 1, 5); + } + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x0, 1, 8); + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x0, 4, 9); + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x0, 4, 13); + set_reg(ldi_base + LDI_DSI_TE_CTRL, 0x1, 1, 17); + + /* TBD:(dsi_te_hs_num+vactive)*htotal/clk_pxl0_div+0.00004<1/60+vs_te_time+(vactive*hotal) /clk_ddic_rd */ + set_reg(ldi_base + LDI_DSI_TE_HS_NUM, 0x0, 32, 0); + set_reg(ldi_base + LDI_DSI_TE_HS_WD, 0x24024, 32, 0); + + /* dsi_te0_vs_wd = lcd_te_width / T_pxl_clk, experience lcd_te_width = 2us */ + if (pinfo->pxl_clk_rate_div == 0) { + HISI_FB_ERR("pxl_clk_rate_div is NULL, not support !\n"); + pinfo->pxl_clk_rate_div = 1; + } + set_reg(ldi_base + LDI_DSI_TE_VS_WD, + (0x3FC << 12) | (2 * pinfo->pxl_clk_rate / + pinfo->pxl_clk_rate_div / 1000000), 32, 0); + } else { + set_reg(ldi_base + LDI_DSI_CMD_MOD_CTRL, 0x1, 1, 1); + } + +#ifdef CONFIG_HISI_FB_COLORBAR_USED + set_reg(ldi_base + LDI_CTRL, DSS_WIDTH(0x3c), 7, 6); + set_reg(ldi_base + LDI_WORK_MODE, 0x0, 1, 1); + set_reg(ldi_base + LDI_WORK_MODE, 0x0, 1, 0); +#else + set_reg(ldi_base + LDI_WORK_MODE, 0x1, 1, 0); +#endif + + if (is_mipi_cmd_panel(hisifd)) { + set_reg(ldi_base + LDI_FRM_MSK, + (hisifd->frame_update_flag == 1) ? 0x0 : 0x1, 1, 0); + } + + if (!fastboot_enable) + set_reg(ldi_base + LDI_CTRL, 0x0, 1, 0); + + HISI_FB_DEBUG("-.!\n"); +} + +void deinit_ldi(struct hisi_fb_data_type *hisifd) +{ + char __iomem *ldi_base = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + set_reg(ldi_base + LDI_CTRL, 0, 1, 0); +} + +void enable_ldi(struct hisi_fb_data_type *hisifd) +{ + char __iomem *ldi_base = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + /* ldi enable */ + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); +} + +void disable_ldi(struct hisi_fb_data_type *hisifd) +{ + char __iomem *ldi_base = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + /* ldi disable */ + set_reg(ldi_base + LDI_CTRL, 0x0, 1, 0); +} + +/* set pixel clock to the exact value which is larger than 288M */ +int dpe_recover_pxl_clock(struct hisi_fb_data_type *hisifd) +{ + if ((hisifd->panel_info.pxl_clk_rate > DSS_MAX_PXL0_CLK_288M) + && (hisifd->index == PRIMARY_PANEL_IDX)) { + if (clk_set_rate(hisifd->dss_pxl0_clk, + hisifd->panel_info.pxl_clk_rate) < 0) { + HISI_FB_ERR + ("fb%d dss_pxl0_clk clk_set_rate(%llu) failed!\n", + hisifd->index, hisifd->panel_info.pxl_clk_rate); + return -1; + } + } + + return 0; +} + +void ldi_frame_update(struct hisi_fb_data_type *hisifd, bool update) +{ + char __iomem *ldi_base = NULL; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + + if (is_mipi_cmd_panel(hisifd)) { + set_reg(ldi_base + LDI_FRM_MSK, (update ? 0x0 : 0x1), 1, 0); + if (update) + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); + } + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + } +} + +void single_frame_update(struct hisi_fb_data_type *hisifd) +{ + char __iomem *ldi_base = NULL; + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + if (is_mipi_cmd_panel(hisifd)) { + set_reg(ldi_base + LDI_FRM_MSK_UP, 0x1, 1, 0); + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); + } else { + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); + } + + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + + if (is_mipi_cmd_panel(hisifd)) { + set_reg(ldi_base + LDI_FRM_MSK_UP, 0x1, 1, 0); + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); + } else { + set_reg(ldi_base + LDI_CTRL, 0x1, 1, 0); + } + } else { + ; + } +} + +void dpe_interrupt_clear(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dss_base = 0; + uint32_t clear = 0; + + BUG_ON(hisifd == NULL); + + dss_base = hisifd->dss_base; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + clear = ~0; + outp32(dss_base + GLB_CPU_PDP_INTS, clear); + outp32(dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS, clear); + outp32(dss_base + DSS_DPP_OFFSET + DPP_INTS, clear); + + outp32(dss_base + DSS_DBG_OFFSET + DBG_MCTL_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_WCH0_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_WCH1_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH0_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH1_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH2_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH3_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH4_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH5_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH6_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH7_INTS, clear); + outp32(dss_base + DSS_DBG_OFFSET + DBG_DSS_GLB_INTS, clear); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + clear = ~0; + outp32(dss_base + GLB_CPU_SDP_INTS, clear); + outp32(dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INTS, clear); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + clear = ~0; + outp32(dss_base + GLB_CPU_OFF_INTS, clear); + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + } + +} + +void dpe_interrupt_unmask(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dss_base = 0; + uint32_t unmask = 0; + struct hisi_panel_info *pinfo = NULL; + + BUG_ON(hisifd == NULL); + + pinfo = &(hisifd->panel_info); + dss_base = hisifd->dss_base; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + unmask = ~0; + /* unmask &= ~(BIT_DPP_INTS | BIT_ITF0_INTS | BIT_DSS_GLB_INTS | BIT_MMU_IRPT_NS); */ + unmask &= ~(BIT_DPP_INTS | BIT_ITF0_INTS | BIT_MMU_IRPT_NS); + outp32(dss_base + GLB_CPU_PDP_INT_MSK, unmask); + + unmask = ~0; + if (is_mipi_cmd_panel(hisifd)) { + unmask &= + ~(BIT_LCD_TE0_PIN | BIT_VACTIVE0_START | + BIT_VACTIVE0_END | BIT_FRM_END); + } else { + unmask &= + ~(BIT_VSYNC | BIT_VACTIVE0_START | BIT_VACTIVE0_END + | BIT_FRM_END); + } + outp32(dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, + unmask); + + unmask = ~0; + /* unmask &= ~(BIT_CE_END_IND | BIT_BACKLIGHT_INTP); */ + if ((pinfo->acm_ce_support == 1) + && HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_ACE)) + unmask &= ~(BIT_CE_END_IND); + if (pinfo->hiace_support == 1) + unmask &= ~(BIT_HIACE_IND); + + outp32(dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, unmask); + + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + unmask = ~0; + /* unmask &= ~(BIT_SDP_ITF1_INTS | BIT_SDP_DSS_GLB_INTS | BIT_SDP_MMU_IRPT_NS); */ + unmask &= ~(BIT_SDP_ITF1_INTS | BIT_SDP_MMU_IRPT_NS); + outp32(dss_base + GLB_CPU_SDP_INT_MSK, unmask); + + unmask = ~0; + unmask &= ~(BIT_VSYNC | BIT_VACTIVE0_START | BIT_VACTIVE0_END); + outp32(dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, + unmask); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + unmask = ~0; + unmask &= + ~(BIT_OFF_WCH0_INTS | BIT_OFF_WCH1_INTS | + BIT_OFF_WCH0_WCH1_FRM_END_INT | BIT_OFF_MMU_IRPT_NS); + outp32(dss_base + GLB_CPU_OFF_INT_MSK, unmask); + + unmask = ~0; + unmask &= ~(BIT_OFF_CAM_WCH2_FRMEND_INTS); + outp32(dss_base + GLB_CPU_OFF_CAM_INT_MSK, unmask); + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + } + +} + +void dpe_interrupt_mask(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dss_base = 0; + uint32_t mask = 0; + + BUG_ON(hisifd == NULL); + + dss_base = hisifd->dss_base; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + mask = ~0; + outp32(dss_base + GLB_CPU_PDP_INT_MSK, mask); + outp32(dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, mask); + outp32(dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_DSS_GLB_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_MCTL_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_WCH0_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_WCH1_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH0_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH1_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH2_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH3_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH4_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH5_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH6_INT_MSK, mask); + outp32(dss_base + DSS_DBG_OFFSET + DBG_RCH7_INT_MSK, mask); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + mask = ~0; + outp32(dss_base + GLB_CPU_SDP_INT_MSK, mask); + outp32(dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, mask); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + mask = ~0; + outp32(dss_base + GLB_CPU_OFF_INT_MSK, mask); + outp32(dss_base + GLB_CPU_OFF_CAM_INT_MSK, mask); + } else { + HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index); + } + +} + +void ldi_data_gate(struct hisi_fb_data_type *hisifd, bool enble) +{ + char __iomem *ldi_base = NULL; + + BUG_ON(hisifd == NULL); + + if (!is_mipi_cmd_panel(hisifd)) { + hisifd->ldi_data_gate_en = (enble ? 1 : 0); + return; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return; + } + + if (g_ldi_data_gate_en == 1) { + hisifd->ldi_data_gate_en = (enble ? 1 : 0); + set_reg(ldi_base + LDI_CTRL, (enble ? 0x1 : 0x0), 1, 2); + } else { + hisifd->ldi_data_gate_en = 0; + set_reg(ldi_base + LDI_CTRL, 0x0, 1, 2); + } + + HISI_FB_DEBUG("ldi_data_gate_en=%d!\n", hisifd->ldi_data_gate_en); +} + +/* dpp csc config */ +#define CSC_ROW (3) +#define CSC_COL (5) + +/* + ** Rec.601 for Computer + ** [ p00 p01 p02 cscidc2 cscodc2 ] + ** [ p10 p11 p12 cscidc1 cscodc1 ] + ** [ p20 p21 p22 cscidc0 cscodc0 ] + */ +static int CSC10B_YUV2RGB709_WIDE_MPREC0[CSC_ROW][CSC_COL] = { + {0x400, 0x000, 0x64d, 0x000, 0x000}, + {0x400, 0x1f40, 0x1e21, 0x5fe, 0x000}, + {0x400, 0x76c, 0x000, 0x5fe, 0x000} +}; + +static int CSC10B_RGB2YUV709_WIDE_MPREC2[CSC_ROW][CSC_COL] = { + {0x367, 0xb71, 0x128, 0x000, 0x000}, + {0x1e2b, 0x19d5, 0x800, 0x000, 0x202}, + {0x800, 0x18bc, 0x1f44, 0x000, 0x202}, +}; + +static void init_csc10b(struct hisi_fb_data_type *hisifd, + char __iomem *dpp_csc10b_base) +{ + int (*csc_coe)[CSC_COL]; + + if (hisifd == NULL || dpp_csc10b_base == NULL) { + HISI_FB_ERR("hisifd or dpp_csc10b_base is NULL!\n"); + return; + } + + if (dpp_csc10b_base == + (hisifd->dss_base + DSS_DPP_CSC_RGB2YUV10B_OFFSET)) { + csc_coe = CSC10B_RGB2YUV709_WIDE_MPREC2; + outp32(dpp_csc10b_base + CSC10B_MPREC, 0x2); + } else if (dpp_csc10b_base == + (hisifd->dss_base + DSS_DPP_CSC_YUV2RGB10B_OFFSET)) { + csc_coe = CSC10B_YUV2RGB709_WIDE_MPREC0; + outp32(dpp_csc10b_base + CSC10B_MPREC, 0x0); + } else { + return; + } + + outp32(dpp_csc10b_base + CSC10B_IDC0, csc_coe[2][3]); + outp32(dpp_csc10b_base + CSC10B_IDC1, csc_coe[1][3]); + outp32(dpp_csc10b_base + CSC10B_IDC2, csc_coe[0][3]); + outp32(dpp_csc10b_base + CSC10B_ODC0, csc_coe[2][4]); + outp32(dpp_csc10b_base + CSC10B_ODC1, csc_coe[1][4]); + outp32(dpp_csc10b_base + CSC10B_ODC2, csc_coe[0][4]); + outp32(dpp_csc10b_base + CSC10B_P00, csc_coe[0][0]); + outp32(dpp_csc10b_base + CSC10B_P01, csc_coe[0][1]); + outp32(dpp_csc10b_base + CSC10B_P02, csc_coe[0][2]); + outp32(dpp_csc10b_base + CSC10B_P10, csc_coe[1][0]); + outp32(dpp_csc10b_base + CSC10B_P11, csc_coe[1][1]); + outp32(dpp_csc10b_base + CSC10B_P12, csc_coe[1][2]); + outp32(dpp_csc10b_base + CSC10B_P20, csc_coe[2][0]); + outp32(dpp_csc10b_base + CSC10B_P21, csc_coe[2][1]); + outp32(dpp_csc10b_base + CSC10B_P22, csc_coe[2][2]); + + outp32(dpp_csc10b_base + CSC10B_MODULE_EN, 0x1); +} + +void init_dpp_csc(struct hisi_fb_data_type *hisifd) +{ + struct hisi_panel_info *pinfo = NULL; + + if (hisifd == NULL) { + HISI_FB_ERR("init_dpp_csc hisifd is NULL!\n"); + return; + } + + pinfo = &(hisifd->panel_info); + + if (pinfo->acm_support || pinfo->arsr1p_sharpness_support + || pinfo->post_scf_support) { + init_csc10b(hisifd, + hisifd->dss_base + DSS_DPP_CSC_RGB2YUV10B_OFFSET); + init_csc10b(hisifd, + hisifd->dss_base + DSS_DPP_CSC_YUV2RGB10B_OFFSET); + + set_reg(hisifd->dss_base + DSS_DPP_BITEXT0_OFFSET + + BIT_EXT0_CTL, 1, 1, 0); + } +} + +void init_acm(struct hisi_fb_data_type *hisifd) +{ + char __iomem *acm_base = NULL; + struct hisi_panel_info *pinfo = NULL; + + if (hisifd == NULL) { + HISI_FB_DEBUG("init_acm hisifd is NULL!\n"); + return; + } + + pinfo = &(hisifd->panel_info); + acm_base = hisifd->dss_base + DSS_DPP_ACM_OFFSET; + + if (pinfo->acm_support != 1) { + outp32(acm_base + ACM_MEM_CTRL, 0x4); + HISI_FB_DEBUG("fb%d, not support acm!\n", hisifd->index); + return; + } + /* not support */ + outp32(acm_base + ACM_MEM_CTRL, 0x4); +} + +void init_igm_gmp_xcc_gm(struct hisi_fb_data_type *hisifd) +{ + char __iomem *dpp_base = NULL; + char __iomem *lcp_base = NULL; + char __iomem *gamma_base = NULL; + + if (hisifd == NULL) { + HISI_FB_ERR("init_degmma_xcc_gmp hisifd is NULL!\n"); + return; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + dpp_base = hisifd->dss_base + DSS_DPP_OFFSET; + lcp_base = hisifd->dss_base + DSS_DPP_LCP_OFFSET; + gamma_base = hisifd->dss_base + DSS_DPP_GAMA_OFFSET; + } else { + HISI_FB_ERR("fb%d, not support!\n", hisifd->index); + return; + } + outp32(lcp_base + LCP_DEGAMA_MEM_CTRL, 0x4); + outp32(lcp_base + LCP_GMP_MEM_CTRL, 0x4); + outp32(gamma_base + GAMA_MEM_CTRL, 0x4); +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_dss.h b/drivers/video/fbdev/hisi/dss/hisi_dss.h new file mode 100755 index 000000000000..8bcb1192c64e --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_dss.h @@ -0,0 +1,493 @@ +/* include/linux/hisi_dss.h + * + * Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ + +#ifndef _HISI_DSS_H_ +#define _HISI_DSS_H_ + +#include <linux/types.h> +#include <linux/fb.h> + +#define HISIFB_IOCTL_MAGIC 'M' + +#define FB_ACCEL_HI62xx 0x1 +#define FB_ACCEL_HI363x 0x2 +#define FB_ACCEL_HI365x 0x4 +#define FB_ACCEL_HI625x 0x8 +#define FB_ACCEL_HI366x 0x10 +#define FB_ACCEL_PLATFORM_TYPE_FPGA 0x10000000 +#define FB_ACCEL_PLATFORM_TYPE_ASIC 0x20000000 + +#define HISIFB_LCD_DIRTY_REGION_INFO_GET _IOW(HISIFB_IOCTL_MAGIC, 801, struct lcd_dirty_region_info) +#define HISIFB_PLATFORM_TYPE_GET _IOW(HISIFB_IOCTL_MAGIC, 802, int) + +#define HISIFB_VSYNC_CTRL _IOW(HISIFB_IOCTL_MAGIC, 0x02, unsigned int) +#define HISIFB_DSS_CLK_RATE_SET _IOW(HISIFB_IOCTL_MAGIC, 0x04, struct dss_clk_rate) +#define HISIFB_DIRTY_REGION_UPDT_SET _IOW(HISIFB_IOCTL_MAGIC, 0x06, int) +#define HISIFB_DSS_MMBUF_ALLOC _IOW(HISIFB_IOCTL_MAGIC, 0x08, struct dss_mmbuf) +#define HISIFB_DSS_MMBUF_FREE _IOW(HISIFB_IOCTL_MAGIC, 0x09, struct dss_mmbuf) +#define HISIFB_DSS_VOLTAGE_GET _IOW(HISIFB_IOCTL_MAGIC, 0x10, struct dss_clk_rate) +#define HISIFB_DSS_VOLTAGE_SET _IOW(HISIFB_IOCTL_MAGIC, 0x11, struct dss_clk_rate) + +#define HISIFB_OV_ONLINE_PLAY _IOW(HISIFB_IOCTL_MAGIC, 0x21, struct dss_overlay) + +#define HISIFB_IDLE_IS_ALLOWED _IOW(HISIFB_IOCTL_MAGIC, 0x42, int) + +#ifndef BIT +#define BIT(x) (1<<(x)) +#endif + +/* for fb0 fb1 fb2 and so on */ +#define PRIMARY_PANEL_IDX (0) +#define EXTERNAL_PANEL_IDX (1) +#define AUXILIARY_PANEL_IDX (2) + +/* lcd fps scence */ +#define LCD_FPS_SCENCE_NORMAL (0) +#define LCD_FPS_SCENCE_IDLE BIT(0) +#define LCD_FPS_SCENCE_VIDEO BIT(1) +#define LCD_FPS_SCENCE_GAME BIT(2) +#define LCD_FPS_SCENCE_WEB BIT(3) +#define LCD_FPS_SCENCE_EBOOK BIT(4) + +#define DSS_WCH_MAX (2) + +/* for YUV */ +#define MAX_PLANES (3) + +enum dss_wb_compose_type { + DSS_WB_COMPOSE_PRIMARY = 0, + DSS_WB_COMPOSE_COPYBIT, + DSS_WB_COMPOSE_TYPE_MAX, +}; + +enum hisi_fb_pixel_format { + HISI_FB_PIXEL_FORMAT_RGB_565 = 0, + HISI_FB_PIXEL_FORMAT_RGBX_4444, + HISI_FB_PIXEL_FORMAT_RGBA_4444, + HISI_FB_PIXEL_FORMAT_RGBX_5551, + HISI_FB_PIXEL_FORMAT_RGBA_5551, + HISI_FB_PIXEL_FORMAT_RGBX_8888, + HISI_FB_PIXEL_FORMAT_RGBA_8888, + + HISI_FB_PIXEL_FORMAT_BGR_565, + HISI_FB_PIXEL_FORMAT_BGRX_4444, + HISI_FB_PIXEL_FORMAT_BGRA_4444, + HISI_FB_PIXEL_FORMAT_BGRX_5551, + HISI_FB_PIXEL_FORMAT_BGRA_5551, + HISI_FB_PIXEL_FORMAT_BGRX_8888, + HISI_FB_PIXEL_FORMAT_BGRA_8888, + + HISI_FB_PIXEL_FORMAT_YUV_422_I, + + /* YUV Semi-planar */ + HISI_FB_PIXEL_FORMAT_YCbCr_422_SP, /* NV16 */ + HISI_FB_PIXEL_FORMAT_YCrCb_422_SP, + HISI_FB_PIXEL_FORMAT_YCbCr_420_SP, + HISI_FB_PIXEL_FORMAT_YCrCb_420_SP, /* NV21 */ + + /* YUV Planar */ + HISI_FB_PIXEL_FORMAT_YCbCr_422_P, + HISI_FB_PIXEL_FORMAT_YCrCb_422_P, + HISI_FB_PIXEL_FORMAT_YCbCr_420_P, + HISI_FB_PIXEL_FORMAT_YCrCb_420_P, /* HISI_FB_PIXEL_FORMAT_YV12 */ + + /* YUV Package */ + HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg, + HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg, + HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg, + HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg, + HISI_FB_PIXEL_FORMAT_MAX, +}; + +enum hisi_fb_blending { + HISI_FB_BLENDING_NONE = 0, + HISI_FB_BLENDING_PREMULT = 1, + HISI_FB_BLENDING_COVERAGE = 2, + HISI_FB_BLENDING_MAX = 3, +}; + +enum hisi_fb_transform { + HISI_FB_TRANSFORM_NOP = 0x0, + /* flip source image horizontally (around the vertical axis) */ + HISI_FB_TRANSFORM_FLIP_H = 0x01, + /* flip source image vertically (around the horizontal axis) */ + HISI_FB_TRANSFORM_FLIP_V = 0x02, + /* rotate source image 90 degrees clockwise */ + HISI_FB_TRANSFORM_ROT_90 = 0x04, + /* rotate source image 180 degrees */ + HISI_FB_TRANSFORM_ROT_180 = 0x03, + /* rotate source image 270 degrees clockwise */ + HISI_FB_TRANSFORM_ROT_270 = 0x07, +}; + +enum dss_csc_mode { + DSS_CSC_601_WIDE = 0, + DSS_CSC_601_NARROW, + DSS_CSC_709_WIDE, + DSS_CSC_709_NARROW, + DSS_CSC_MOD_MAX, +}; + +enum dss_afbc_scramble_mode { + DSS_AFBC_SCRAMBLE_NONE = 0, + DSS_AFBC_SCRAMBLE_MODE1, + DSS_AFBC_SCRAMBLE_MODE2, + DSS_AFBC_SCRAMBLE_MODE3, + DSS_AFBC_SCRAMBLE_MODE_MAX, +}; + +enum dss_chn_idx { + DSS_RCHN_NONE = -1, + DSS_RCHN_D2 = 0, + DSS_RCHN_D3, + DSS_RCHN_V0, + DSS_RCHN_G0, + DSS_RCHN_V1, + DSS_RCHN_G1, + DSS_RCHN_D0, + DSS_RCHN_D1, + + DSS_WCHN_W0, + DSS_WCHN_W1, + + DSS_CHN_MAX, + + DSS_RCHN_V2 = DSS_CHN_MAX, + DSS_WCHN_W2, + + DSS_COPYBIT_MAX, +}; + +enum dss_ovl_idx { + DSS_OVL0 = 0, + DSS_OVL1, + DSS_OVL2, + DSS_OVL3, + DSS_OVL_IDX_MAX, +}; + +/* dss capability priority description */ +#define CAP_1D_SHARPNESS BIT(13) +#define CAP_2D_SHARPNESS BIT(12) +#define CAP_TILE BIT(11) +#define CAP_AFBCD BIT(10) +#define CAP_AFBCE BIT(9) +#define CAP_YUV_DEINTERLACE BIT(8) +#define CAP_YUV_PLANAR BIT(7) +#define CAP_YUV_SEMI_PLANAR BIT(6) +#define CAP_YUV_PACKAGE BIT(5) +#define CAP_SCL BIT(4) +#define CAP_ROT BIT(3) +#define CAP_PURE_COLOR BIT(2) +#define CAP_DIM BIT(1) +#define CAP_BASE BIT(0) + +/*this head file to save the structs that both ade and dss will use +**note: if the left_align is 8,right_align is 8,and w_min is larger than 802,then w_min should be set to 808, +**make sure that it is 8 align,if w_min is set to 802,there will be an error.left_align,right_align,top_align +**bottom_align,w_align,h_align,w_min and h_min's valid value should be larger than 0,top_start and bottom_start +**maybe equal to 0. if it's not surpport partial update, these value should set to invalid value(-1). +*/ +typedef struct lcd_dirty_region_info { + int left_align; + int right_align; + int top_align; + int bottom_align; + + int w_align; + int h_align; + int w_min; + int h_min; + + int top_start; + int bottom_start; +} lcd_dirty_region_info_t; + +typedef struct dss_rect { + int32_t x; + int32_t y; + int32_t w; + int32_t h; +} dss_rect_t; + +typedef struct dss_rect_ltrb { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} dss_rect_ltrb_t; + +typedef struct dss_mmbuf { + uint32_t addr; + int32_t size; +} dss_mmbuf_t; + +typedef struct dss_img { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t bpp; /* bytes per pixel */ + uint32_t buf_size; + uint32_t stride; + uint32_t stride_plane1; + uint32_t stride_plane2; + uint64_t phy_addr; + uint64_t vir_addr; + uint32_t offset_plane1; + uint32_t offset_plane2; + + uint64_t afbc_header_addr; + uint64_t afbc_payload_addr; + uint32_t afbc_header_stride; + uint32_t afbc_payload_stride; + uint32_t afbc_scramble_mode; + uint32_t mmbuf_base; + uint32_t mmbuf_size; + + uint32_t mmu_enable; + uint32_t csc_mode; + uint32_t secure_mode; + int32_t shared_fd; + uint32_t reserved0; +} dss_img_t; + +typedef struct dss_block_info { + int32_t first_tile; + int32_t last_tile; + uint32_t acc_hscl; + uint32_t h_ratio; + uint32_t v_ratio; + uint32_t h_ratio_arsr2p; + uint32_t arsr2p_left_clip; + uint32_t both_vscfh_arsr2p_used; + dss_rect_t arsr2p_in_rect; + uint32_t arsr2p_src_x; + uint32_t arsr2p_src_y; + uint32_t arsr2p_dst_x; + uint32_t arsr2p_dst_y; + uint32_t arsr2p_dst_w; + int32_t h_v_order; +} dss_block_info_t; + +typedef struct dss_layer { + dss_img_t img; + dss_rect_t src_rect; + dss_rect_t src_rect_mask; + dss_rect_t dst_rect; + uint32_t transform; + int32_t blending; + uint32_t glb_alpha; + uint32_t color; /* background color or dim color */ + int32_t layer_idx; + int32_t chn_idx; + uint32_t need_cap; + int32_t acquire_fence; + + dss_block_info_t block_info; +} dss_layer_t; + +typedef struct dss_wb_layer { + dss_img_t dst; + dss_rect_t src_rect; + dss_rect_t dst_rect; + uint32_t transform; + int32_t chn_idx; + uint32_t need_cap; + uint32_t reserved0; + + int32_t acquire_fence; + int32_t release_fence; +} dss_wb_layer_t; + +/* + ** dss error status + */ +#define DSS_PDP_LDI_UNDERFLOW BIT(0) +#define DSS_SDP_LDI_UNDERFLOW BIT(1) +#define DSS_PDP_SMMU_ERR BIT(2) +#define DSS_SDP_SMMU_ERR BIT(3) + +/* + ** crc enable status + */ +enum dss_crc_enable_status { + DSS_CRC_NONE = 0, + DSS_CRC_OV_EN = 1, + DSS_CRC_LDI_EN, + DSS_CRC_SUM_EN, +}; + +/* + ** sec enable status + */ +enum dss_sec_enable_status { + DSS_SEC_STOP = 0, + DSS_SEC_RUN = 1, +}; + +typedef struct dss_crc_info { + uint32_t crc_ov_result; + uint32_t crc_ldi_result; + uint32_t crc_sum_result; + uint32_t crc_ov_frm; + uint32_t crc_ldi_frm; + uint32_t crc_sum_frm; + + uint32_t err_status; + uint32_t reserved0; +} dss_crc_info_t; + +enum dss_to_be_continued_type { + DSS_LAYER_SERIAL_COMPOSE = 0, + DSS_LAYER_PARALLEL_COMPOSE = 1, +}; + +/* Max multi-src channel number of the DSS. */ +#define MAX_DSS_SRC_NUM (7) +#define MAX_DSS_DST_NUM (2) + +#define HISI_DSS_OV_BLOCK_NUMS (23) + +typedef struct dss_overlay_block { + dss_layer_t layer_infos[MAX_DSS_SRC_NUM]; + dss_rect_t ov_block_rect; + uint32_t layer_nums; + uint32_t reserved0; +} dss_overlay_block_t; + +typedef struct dss_overlay { + dss_wb_layer_t wb_layer_infos[MAX_DSS_DST_NUM]; + dss_rect_t wb_ov_rect; + uint32_t wb_layer_nums; + uint32_t wb_compose_type; + + uint64_t ov_block_infos_ptr; + uint32_t ov_block_nums; + int32_t ovl_idx; + uint32_t wb_enable; + uint32_t frame_no; + + dss_rect_t dirty_rect; + + struct dss_rect res_updt_rect; + + dss_crc_info_t crc_info; + int32_t crc_enable_status; + uint32_t sec_enable_status; + + uint32_t to_be_continued; + int32_t release_fence; +} dss_overlay_t; + +typedef struct dss_clk_rate { + uint64_t dss_pri_clk_rate; + uint64_t dss_pclk_dss_rate; + uint64_t dss_pclk_pctrl_rate; + uint32_t dss_voltage_value; +} dss_clk_rate_t; + +typedef struct ce_algorithm_parameter { + int iDiffMaxTH; + int iDiffMinTH; + int iAlphaMinTH; + int iFlatDiffTH; + int iBinDiffMaxTH; + + int iDarkPixelMinTH; + int iDarkPixelMaxTH; + int iDarkAvePixelMinTH; + int iDarkAvePixelMaxTH; + int iWhitePixelTH; + int fweight; + int fDarkRatio; + int fWhiteRatio; + + int iDarkPixelTH; + int fDarkSlopeMinTH; + int fDarkSlopeMaxTH; + int fDarkRatioMinTH; + int fDarkRatioMaxTH; + + int iBrightPixelTH; + int fBrightSlopeMinTH; + int fBrightSlopeMaxTH; + int fBrightRatioMinTH; + int fBrightRatioMaxTH; + + int iZeroPos0MaxTH; + int iZeroPos1MaxTH; + + int iDarkFMaxTH; + int iDarkFMinTH; + int iPos0MaxTH; + int iPos0MinTH; + + int fKeepRatio; +} ce_algorithm_parameter_t; + +typedef struct ce_parameter { + int width; + int height; + int hist_mode; + int mode; + int result; + uint32_t reserved0; + uint32_t *histogram; + uint8_t *lut_table; + void *service; + ce_algorithm_parameter_t ce_alg_param; +} ce_parameter_t; + +typedef struct hiace_alg_parameter { + int iGlobalHistBlackPos; + int iGlobalHistWhitePos; + int iGlobalHistBlackWeight; + int iGlobalHistWhiteWeight; + int iGlobalHistZeroCutRatio; + int iGlobalHistSlopeCutRatio; + + char Classifieresult[1024]; + int iResultLen; + + int iDoLCE; + int iDoSRE; + int iDoAPLC; + + int iLaSensorSREOnTH; + int iWidth; + int iHeight; + int bitWidth; + int iMode; + int iLevel; + int ilhist_sft; + + int iMaxLcdLuminance; + int iMinLcdLuminance; + int iMaxBackLight; + int iMinBackLight; + int iAmbientLight; + int iBackLight; + long lTimestamp; + + char chCfgName[512]; +} hiace_alg_parameter_t; + +typedef struct hiace_interface_set { + int result; + unsigned int *lut; + int backlight; +} hiace_interface_set_t; + +#endif /*_HISI_DSS_H_*/ diff --git a/drivers/video/fbdev/hisi/dss/hisi_dss_regs_hi3660.h b/drivers/video/fbdev/hisi/dss/hisi_dss_regs_hi3660.h new file mode 100755 index 000000000000..a5490bb63dc3 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_dss_regs_hi3660.h @@ -0,0 +1,3164 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_DSS_REGS_H +#define HISI_DSS_REGS_H + +#include "hisi_fb.h" + +/* MACROS */ +#define DSS_WIDTH(width) ((width) - 1) +#define DSS_HEIGHT(height) ((height) - 1) + +#define RES_540P (960 * 540) +#define RES_720P (1280 * 720) +#define RES_1080P (1920 * 1080) +#define RES_1200P (1920 * 1200) +#define RES_1440P (2560 * 1440) +#define RES_1600P (2560 * 1600) +#define RES_4K_PHONE (3840 * 2160) +#define RES_4K_PAD (3840 * 2400) + +#define DFC_MAX_CLIP_NUM (31) + +/* for DFS */ +/* 1480 * 144bits */ +#define DFS_TIME (80) +#define DFS_TIME_MIN (50) +#define DFS_TIME_MIN_4K (10) +#define DBUF0_DEPTH (1408) +#define DBUF1_DEPTH (512) +#define DBUF_WIDTH_BIT (144) + +#define GET_THD_RQOS_IN(max_depth) ((max_depth) * 10 / 100) +#define GET_THD_RQOS_OUT(max_depth) ((max_depth) * 30 / 100) +#define GET_THD_WQOS_IN(max_depth) ((max_depth) * 95 / 100) +#define GET_THD_WQOS_OUT(max_depth) ((max_depth) * 70 / 100) +#define GET_THD_CG_IN(max_depth) ((max_depth) -1) +#define GET_THD_CG_OUT(max_depth) ((max_depth) * 70 / 100) +#define GET_FLUX_REQ_IN(max_depth) ((max_depth) * 50 / 100) +#define GET_FLUX_REQ_OUT(max_depth) ((max_depth) * 90 / 100) +#define GET_THD_OTHER_DFS_CG_HOLD(max_depth) (0x20) +#define GET_THD_OTHER_WR_WAIT(max_depth) ((max_depth) * 90 / 100) + +#define GET_RDMA_ROT_HQOS_ASSERT_LEV(max_depth) ((max_depth) * 30 /100) +#define GET_RDMA_ROT_HQOS_REMOVE_LEV(max_depth) ((max_depth)* 60 / 100) + +enum lcd_orientation { + LCD_LANDSCAPE = 0, + LCD_PORTRAIT, +}; + +enum lcd_format { + LCD_RGB888 = 0, + LCD_RGB101010, + LCD_RGB565, +}; + +enum lcd_rgb_order { + LCD_RGB = 0, + LCD_BGR, +}; + +enum dss_addr { + DSS_ADDR_PLANE0 = 0, + DSS_ADDR_PLANE1, + DSS_ADDR_PLANE2, +}; + +enum dss_transform { + DSS_TRANSFORM_NOP = 0x0, + DSS_TRANSFORM_FLIP_H = 0x01, + DSS_TRANSFORM_FLIP_V = 0x02, + DSS_TRANSFORM_ROT = 0x04, +}; + +enum dss_dfc_format { + DFC_PIXEL_FORMAT_RGB_565 = 0, + DFC_PIXEL_FORMAT_XRGB_4444, + DFC_PIXEL_FORMAT_ARGB_4444, + DFC_PIXEL_FORMAT_XRGB_5551, + DFC_PIXEL_FORMAT_ARGB_5551, + DFC_PIXEL_FORMAT_XRGB_8888, + DFC_PIXEL_FORMAT_ARGB_8888, + DFC_PIXEL_FORMAT_BGR_565, + DFC_PIXEL_FORMAT_XBGR_4444, + DFC_PIXEL_FORMAT_ABGR_4444, + DFC_PIXEL_FORMAT_XBGR_5551, + DFC_PIXEL_FORMAT_ABGR_5551, + DFC_PIXEL_FORMAT_XBGR_8888, + DFC_PIXEL_FORMAT_ABGR_8888, + + DFC_PIXEL_FORMAT_YUV444, + DFC_PIXEL_FORMAT_YVU444, + DFC_PIXEL_FORMAT_YUYV422, + DFC_PIXEL_FORMAT_YVYU422, + DFC_PIXEL_FORMAT_VYUY422, + DFC_PIXEL_FORMAT_UYVY422, +}; + +enum dss_dma_format { + DMA_PIXEL_FORMAT_RGB_565 = 0, + DMA_PIXEL_FORMAT_ARGB_4444, + DMA_PIXEL_FORMAT_XRGB_4444, + DMA_PIXEL_FORMAT_ARGB_5551, + DMA_PIXEL_FORMAT_XRGB_5551, + DMA_PIXEL_FORMAT_ARGB_8888, + DMA_PIXEL_FORMAT_XRGB_8888, + + DMA_PIXEL_FORMAT_RESERVED0, + + DMA_PIXEL_FORMAT_YUYV_422_Pkg, + DMA_PIXEL_FORMAT_YUV_420_SP_HP, + DMA_PIXEL_FORMAT_YUV_420_P_HP, + DMA_PIXEL_FORMAT_YUV_422_SP_HP, + DMA_PIXEL_FORMAT_YUV_422_P_HP, + DMA_PIXEL_FORMAT_AYUV_4444, +}; + +enum dss_buf_format { + DSS_BUF_LINEAR = 0, + DSS_BUF_TILE, +}; + +enum dss_blend_mode { + DSS_BLEND_CLEAR = 0, + DSS_BLEND_SRC, + DSS_BLEND_DST, + DSS_BLEND_SRC_OVER_DST, + DSS_BLEND_DST_OVER_SRC, + DSS_BLEND_SRC_IN_DST, + DSS_BLEND_DST_IN_SRC, + DSS_BLEND_SRC_OUT_DST, + DSS_BLEND_DST_OUT_SRC, + DSS_BLEND_SRC_ATOP_DST, + DSS_BLEND_DST_ATOP_SRC, + DSS_BLEND_SRC_XOR_DST, + DSS_BLEND_SRC_ADD_DST, + DSS_BLEND_FIX_OVER, + DSS_BLEND_FIX_PER0, + DSS_BLEND_FIX_PER1, + DSS_BLEND_FIX_PER2, + DSS_BLEND_FIX_PER3, + DSS_BLEND_FIX_PER4, + DSS_BLEND_FIX_PER5, + DSS_BLEND_FIX_PER6, + DSS_BLEND_FIX_PER7, + DSS_BLEND_FIX_PER8, + DSS_BLEND_FIX_PER9, + DSS_BLEND_FIX_PER10, + DSS_BLEND_FIX_PER11, + DSS_BLEND_FIX_PER12, + DSS_BLEND_FIX_PER13, + DSS_BLEND_FIX_PER14, + DSS_BLEND_FIX_PER15, + DSS_BLEND_FIX_PER16, + DSS_BLEND_FIX_PER17, + + DSS_BLEND_MAX, +}; + +enum dss_chn_module { + MODULE_MIF_CHN, + MODULE_AIF0_CHN, + MODULE_AIF1_CHN, + MODULE_MCTL_CHN_MUTEX, + MODULE_MCTL_CHN_FLUSH_EN, + MODULE_MCTL_CHN_OV_OEN, + MODULE_MCTL_CHN_STARTY, + MODULE_MCTL_CHN_MOD_DBG, + MODULE_DMA, + MODULE_DFC, + MODULE_SCL, + MODULE_SCL_LUT, + MODULE_ARSR2P, + MODULE_ARSR2P_LUT, + MODULE_POST_CLIP, + MODULE_PCSC, + MODULE_CSC, + MODULE_CHN_MAX, +}; + +enum dss_chn_cap { + MODULE_CAP_ROT, + MODULE_CAP_SCL, + MODULE_CAP_CSC, + MODULE_CAP_SHARPNESS_1D, + MODULE_CAP_SHARPNESS_2D, + MODULE_CAP_CE, + MODULE_CAP_AFBCD, + MODULE_CAP_AFBCE, + MODULE_CAP_YUV_PLANAR, + MODULE_CAP_YUV_SEMI_PLANAR, + MODULE_CAP_YUV_PACKAGE, + MODULE_CAP_MAX, +}; + +enum dss_ovl_module { + MODULE_OVL_BASE, + MODULE_MCTL_BASE, + MODULE_OVL_MAX, +}; + +enum dss_axi_idx { + AXI_CHN0 = 0, + AXI_CHN1, + AXI_CHN_MAX, +}; + +#define AXI0_MAX_DSS_CHN_THRESHOLD (3) +#define AXI1_MAX_DSS_CHN_THRESHOLD (3) + +#define DEFAULT_AXI_CLK_RATE0 (120 * 1000000) +#define DEFAULT_AXI_CLK_RATE1 (240 * 1000000) +#define DEFAULT_AXI_CLK_RATE2 (360 * 1000000) +#define DEFAULT_AXI_CLK_RATE3 (480 * 1000000) +#define DEFAULT_AXI_CLK_RATE4 (667 * 1000000) +#define DEFAULT_AXI_CLK_RATE5 (800 * 1000000) + +enum dss_rdma_idx { + DSS_RDMA0 = 0, + DSS_RDMA1, + DSS_RDMA2, + DSS_RDMA3, + DSS_RDMA4, + DSS_RDMA_MAX, +}; + +/******************************************************************************* + ** + */ + +#define PEREN0 (0x000) +#define PERDIS0 (0x004) +#define PEREN2 (0x020) +#define PERDIS2 (0x024) +#define PERCLKEN2 (0x028) +#define PERSTAT2 (0x02C) +#define PEREN3 (0x030) +#define PERDIS3 (0x034) +#define PERCLKEN3 (0x038) +#define PERSTAT3 (0x03C) +#define PEREN5 (0x050) +#define PERDIS5 (0x054) +#define PERCLKEN5 (0x058) +#define PERSTAT5 (0x05C) +#define PERRSTDIS0 (0x064) +#define PERRSTEN2 (0x078) +#define PERRSTDIS2 (0x07C) +#define PERRSTEN3 (0x084) +#define PERRSTDIS3 (0x088) +#define PERRSTSTAT3 (0x08c) +#define PERRSTEN4 (0x090) +#define PERRSTDIS4 (0x094) +#define PERRSTSTAT4 (0x098) +#define CLKDIV3 (0x0B4) +#define CLKDIV5 (0x0BC) +#define CLKDIV10 (0x0D0) +#define CLKDIV18 (0x0F0) +#define CLKDIV20 (0x0F8) +#define ISOEN (0x144) +#define ISODIS (0x148) +#define ISOSTAT (0x14c) +#define PERPWREN (0x150) +#define PERPWRDIS (0x154) +#define PERPWRSTAT (0x158) +#define PERI_AUTODIV8 (0x380) +#define PERI_AUTODIV9 (0x384) +#define PERI_AUTODIV10 (0x388) + + +#define NOC_POWER_IDLEREQ (0x380) +#define NOC_POWER_IDLEACK (0x384) +#define NOC_POWER_IDLE (0x388) + + +#define SCPWREN (0x0D0) +#define SCPEREN1 (0x040) +#define SCPERDIS1 (0x044) +#define SCPERCLKEN1 (0x048) +#define SCPERRSTDIS1 (0x090) +#define SCISODIS (0x0C4) +#define SCCLKDIV2 (0x258) + + +#define PERI_CTRL23 (0x060) +#define PERI_CTRL29 (0x078) +#define PERI_CTRL30 (0x07C) +#define PERI_CTRL32 (0x084) +#define PERI_STAT0 (0x094) +#define PERI_STAT1 (0x098) +#define PERI_STAT16 (0x0D4) + + +#define PCTRL_DPHYTX_ULPSEXIT1 BIT(4) +#define PCTRL_DPHYTX_ULPSEXIT0 BIT(3) + + + + + + + + +#define PCTRL_DPHYTX_CTRL1 BIT(1) +#define PCTRL_DPHYTX_CTRL0 BIT(0) + +/******************************************************************************* + ** + */ + + +#define BIT_DSS_GLB_INTS BIT(30) +#define BIT_MMU_IRPT_S BIT(29) +#define BIT_MMU_IRPT_NS BIT(28) +#define BIT_DBG_MCTL_INTS BIT(27) +#define BIT_DBG_WCH1_INTS BIT(26) +#define BIT_DBG_WCH0_INTS BIT(25) +#define BIT_DBG_RCH7_INTS BIT(24) +#define BIT_DBG_RCH6_INTS BIT(23) +#define BIT_DBG_RCH5_INTS BIT(22) +#define BIT_DBG_RCH4_INTS BIT(21) +#define BIT_DBG_RCH3_INTS BIT(20) +#define BIT_DBG_RCH2_INTS BIT(19) +#define BIT_DBG_RCH1_INTS BIT(18) +#define BIT_DBG_RCH0_INTS BIT(17) +#define BIT_ITF0_INTS BIT(16) +#define BIT_DPP_INTS BIT(15) +#define BIT_CMDLIST13 BIT(14) +#define BIT_CMDLIST12 BIT(13) +#define BIT_CMDLIST11 BIT(12) +#define BIT_CMDLIST10 BIT(11) +#define BIT_CMDLIST9 BIT(10) +#define BIT_CMDLIST8 BIT(9) +#define BIT_CMDLIST7 BIT(8) +#define BIT_CMDLIST6 BIT(7) +#define BIT_CMDLIST5 BIT(6) +#define BIT_CMDLIST4 BIT(5) +#define BIT_CMDLIST3 BIT(4) +#define BIT_CMDLIST2 BIT(3) +#define BIT_CMDLIST1 BIT(2) +#define BIT_CMDLIST0 BIT(1) + + + +#define BIT_SDP_DSS_GLB_INTS BIT(29) +#define BIT_SDP_MMU_IRPT_S BIT(28) +#define BIT_SDP_MMU_IRPT_NS BIT(27) +#define BIT_SDP_DBG_MCTL_INTS BIT(26) +#define BIT_SDP_DBG_WCH1_INTS BIT(25) +#define BIT_SDP_DBG_WCH0_INTS BIT(24) +#define BIT_SDP_DBG_RCH7_INTS BIT(23) +#define BIT_SDP_DBG_RCH6_INTS BIT(22) +#define BIT_SDP_DBG_RCH5_INTS BIT(21) +#define BIT_SDP_DBG_RCH4_INTS BIT(20) +#define BIT_SDP_DBG_RCH3_INTS BIT(19) +#define BIT_SDP_DBG_RCH2_INTS BIT(18) +#define BIT_SDP_DBG_RCH1_INTS BIT(17) +#define BIT_SDP_DBG_RCH0_INTS BIT(16) +#define BIT_SDP_ITF1_INTS BIT(15) +#define BIT_SDP_CMDLIST13 BIT(14) +#define BIT_SDP_CMDLIST12 BIT(13) +#define BIT_SDP_CMDLIST11 BIT(12) +#define BIT_SDP_CMDLIST10 BIT(11) +#define BIT_SDP_CMDLIST9 BIT(10) +#define BIT_SDP_CMDLIST8 BIT(9) +#define BIT_SDP_CMDLIST7 BIT(8) +#define BIT_SDP_CMDLIST6 BIT(7) +#define BIT_SDP_CMDLIST5 BIT(6) +#define BIT_SDP_CMDLIST4 BIT(5) +#define BIT_SDP_CMDLIST3 BIT(4) +#define BIT_SDP_SDP_CMDLIST2 BIT(3) +#define BIT_SDP_CMDLIST1 BIT(2) +#define BIT_SDP_CMDLIST0 BIT(1) +#define BIT_SDP_RCH_CE_INTS BIT(0) + + + +#define BIT_OFF_DSS_GLB_INTS BIT(31) +#define BIT_OFF_MMU_IRPT_S BIT(30) +#define BIT_OFF_MMU_IRPT_NS BIT(29) +#define BIT_OFF_DBG_MCTL_INTS BIT(28) +#define BIT_OFF_DBG_WCH1_INTS BIT(27) +#define BIT_OFF_DBG_WCH0_INTS BIT(26) +#define BIT_OFF_DBG_RCH7_INTS BIT(25) +#define BIT_OFF_DBG_RCH6_INTS BIT(24) +#define BIT_OFF_DBG_RCH5_INTS BIT(23) +#define BIT_OFF_DBG_RCH4_INTS BIT(22) +#define BIT_OFF_DBG_RCH3_INTS BIT(21) +#define BIT_OFF_DBG_RCH2_INTS BIT(20) +#define BIT_OFF_DBG_RCH1_INTS BIT(19) +#define BIT_OFF_DBG_RCH0_INTS BIT(18) +#define BIT_OFF_WCH1_INTS BIT(17) +#define BIT_OFF_WCH0_INTS BIT(16) +#define BIT_OFF_WCH0_WCH1_FRM_END_INT BIT(15) +#define BIT_OFF_CMDLIST13 BIT(14) +#define BIT_OFF_CMDLIST12 BIT(13) +#define BIT_OFF_CMDLIST11 BIT(12) +#define BIT_OFF_CMDLIST10 BIT(11) +#define BIT_OFF_CMDLIST9 BIT(10) +#define BIT_OFF_CMDLIST8 BIT(9) +#define BIT_OFF_CMDLIST7 BIT(8) +#define BIT_OFF_CMDLIST6 BIT(7) +#define BIT_OFF_CMDLIST5 BIT(6) +#define BIT_OFF_CMDLIST4 BIT(5) +#define BIT_OFF_CMDLIST3 BIT(4) +#define BIT_OFF_CMDLIST2 BIT(3) +#define BIT_OFF_CMDLIST1 BIT(2) +#define BIT_OFF_CMDLIST0 BIT(1) +#define BIT_OFF_RCH_CE_INTS BIT(0) + + + +#define BIT_OFF_CAM_DBG_WCH2_INTS BIT(4) +#define BIT_OFF_CAM_DBG_RCH8_INTS BIT(3) +#define BIT_OFF_CAM_WCH2_FRMEND_INTS BIT(2) +#define BIT_OFF_CAM_CMDLIST15_INTS BIT(1) +#define BIT_OFF_CAM_CMDLIST14_INTS BIT(0) + + + + + +#define BIT_VACTIVE_CNT BIT(14) +#define BIT_DSI_TE_TRI BIT(13) +#define BIT_LCD_TE0_PIN BIT(12) +#define BIT_LCD_TE1_PIN BIT(11) +#define BIT_VACTIVE1_END BIT(10) +#define BIT_VACTIVE1_START BIT(9) +#define BIT_VACTIVE0_END BIT(8) +#define BIT_VACTIVE0_START BIT(7) +#define BIT_VFRONTPORCH BIT(6) +#define BIT_VBACKPORCH BIT(5) +#define BIT_VSYNC BIT(4) +#define BIT_VFRONTPORCH_END BIT(3) +#define BIT_LDI_UNFLOW BIT(2) +#define BIT_FRM_END BIT(1) +#define BIT_FRM_START BIT(0) + + +#define BIT_CTL_FLUSH_EN BIT(21) +#define BIT_SCF_FLUSH_EN BIT(19) +#define BIT_DPP0_FLUSH_EN BIT(18) +#define BIT_DBUF1_FLUSH_EN BIT(17) +#define BIT_DBUF0_FLUSH_EN BIT(16) +#define BIT_OV3_FLUSH_EN BIT(15) +#define BIT_OV2_FLUSH_EN BIT(14) +#define BIT_OV1_FLUSH_EN BIT(13) +#define BIT_OV0_FLUSH_EN BIT(12) +#define BIT_WB1_FLUSH_EN BIT(11) +#define BIT_WB0_FLUSH_EN BIT(10) +#define BIT_DMA3_FLUSH_EN BIT(9) +#define BIT_DMA2_FLUSH_EN BIT(8) +#define BIT_DMA1_FLUSH_EN BIT(7) +#define BIT_DMA0_FLUSH_EN BIT(6) +#define BIT_RGB1_FLUSH_EN BIT(4) +#define BIT_RGB0_FLUSH_EN BIT(3) +#define BIT_VIG1_FLUSH_EN BIT(1) +#define BIT_VIG0_FLUSH_EN BIT(0) + + + +#define BIT_BUS_DBG_INT BIT(5) +#define BIT_CRC_SUM_INT BIT(4) +#define BIT_CRC_ITF1_INT BIT(3) +#define BIT_CRC_ITF0_INT BIT(2) +#define BIT_CRC_OV1_INT BIT(1) +#define BIT_CRC_OV0_INT BIT(0) + + +#define BIT_SBL_SEND_FRAME_OUT BIT(19) +#define BIT_SBL_STOP_FRAME_OUT BIT(18) +#define BIT_SBL_BACKLIGHT_OUT BIT(17) +#define BIT_SBL_DARKENH_OUT BIT(16) +#define BIT_SBL_BRIGHTPTR_OUT BIT(15) +#define BIT_STRENGTH_INROI_OUT BIT(14) +#define BIT_STRENGTH_OUTROI_OUT BIT(13) +#define BIT_DONE_OUT BIT(12) +#define BIT_PPROC_DONE_OUT BIT(11) + +#define BIT_HIACE_IND BIT(8) +#define BIT_STRENGTH_INTP BIT(7) +#define BIT_BACKLIGHT_INTP BIT(6) +#define BIT_CE_END_IND BIT(5) +#define BIT_CE_CANCEL_IND BIT(4) +#define BIT_CE_LUT1_RW_COLLIDE_IND BIT(3) +#define BIT_CE_LUT0_RW_COLLIDE_IND BIT(2) +#define BIT_CE_HIST1_RW_COLLIDE_IND BIT(1) +#define BIT_CE_HIST0_RW_COLLIDE_IND BIT(0) + +/******************************************************************************* + ** MODULE BASE ADDRESS + */ + +#define DSS_MIPI_DSI0_OFFSET (0x00001000) +#define DSS_MIPI_DSI1_OFFSET (0x00001400) + +#define DSS_GLB0_OFFSET (0x12000) + +#define DSS_DBG_OFFSET (0x11000) + + +#define DSS_CMDLIST_OFFSET (0x2000) + + +#define DSS_SMMU_OFFSET (0x8000) + + +#define DSS_VBIF0_AIF (0x7000) +#define DSS_VBIF1_AIF (0x9000) + + +#define DSS_MIF_OFFSET (0xA000) + + +#define DSS_MCTRL_SYS_OFFSET (0x10000) + + +#define DSS_MCTRL_CTL0_OFFSET (0x10800) +#define DSS_MCTRL_CTL1_OFFSET (0x10900) +#define DSS_MCTRL_CTL2_OFFSET (0x10A00) +#define DSS_MCTRL_CTL3_OFFSET (0x10B00) +#define DSS_MCTRL_CTL4_OFFSET (0x10C00) +#define DSS_MCTRL_CTL5_OFFSET (0x10D00) + + +#define DSS_RCH_VG0_DMA_OFFSET (0x20000) +#define DSS_RCH_VG0_DFC_OFFSET (0x20100) +#define DSS_RCH_VG0_SCL_OFFSET (0x20200) +#define DSS_RCH_VG0_ARSR_OFFSET (0x20300) +#define DSS_RCH_VG0_POST_CLIP_OFFSET (0x203A0) +#define DSS_RCH_VG0_PCSC_OFFSET (0x20400) +#define DSS_RCH_VG0_CSC_OFFSET (0x20500) +#define DSS_RCH_VG0_DEBUG_OFFSET (0x20600) +#define DSS_RCH_VG0_VPP_OFFSET (0x20700) +#define DSS_RCH_VG0_DMA_BUF_OFFSET (0x20800) +#define DSS_RCH_VG0_AFBCD_OFFSET (0x20900) +#define DSS_RCH_VG0_REG_DEFAULT_OFFSET (0x20A00) +#define DSS_RCH_VG0_SCL_LUT_OFFSET (0x21000) +#define DSS_RCH_VG0_ARSR_LUT_OFFSET (0x25000) + +#define DSS_RCH_VG1_DMA_OFFSET (0x28000) +#define DSS_RCH_VG1_DFC_OFFSET (0x28100) +#define DSS_RCH_VG1_SCL_OFFSET (0x28200) +#define DSS_RCH_VG1_POST_CLIP_OFFSET (0x283A0) +#define DSS_RCH_VG1_CSC_OFFSET (0x28500) +#define DSS_RCH_VG1_DEBUG_OFFSET (0x28600) +#define DSS_RCH_VG1_VPP_OFFSET (0x28700) +#define DSS_RCH_VG1_DMA_BUF_OFFSET (0x28800) +#define DSS_RCH_VG1_AFBCD_OFFSET (0x28900) +#define DSS_RCH_VG1_REG_DEFAULT_OFFSET (0x28A00) +#define DSS_RCH_VG1_SCL_LUT_OFFSET (0x29000) + +#define DSS_RCH_VG2_DMA_OFFSET (0x30000) +#define DSS_RCH_VG2_DFC_OFFSET (0x30100) +#define DSS_RCH_VG2_SCL_OFFSET (0x30200) +#define DSS_RCH_VG2_POST_CLIP_OFFSET (0x303A0) +#define DSS_RCH_VG2_CSC_OFFSET (0x30500) +#define DSS_RCH_VG2_DEBUG_OFFSET (0x30600) +#define DSS_RCH_VG2_VPP_OFFSET (0x30700) +#define DSS_RCH_VG2_DMA_BUF_OFFSET (0x30800) +#define DSS_RCH_VG2_AFBCD_OFFSET (0x30900) +#define DSS_RCH_VG2_REG_DEFAULT_OFFSET (0x30A00) +#define DSS_RCH_VG2_SCL_LUT_OFFSET (0x31000) + + +#define DSS_RCH_G0_DMA_OFFSET (0x38000) +#define DSS_RCH_G0_DFC_OFFSET (0x38100) +#define DSS_RCH_G0_SCL_OFFSET (0x38200) +#define DSS_RCH_G0_POST_CLIP_OFFSET (0x383A0) +#define DSS_RCH_G0_CSC_OFFSET (0x38500) +#define DSS_RCH_G0_DEBUG_OFFSET (0x38600) +#define DSS_RCH_G0_DMA_BUF_OFFSET (0x38800) +#define DSS_RCH_G0_AFBCD_OFFSET (0x38900) +#define DSS_RCH_G0_REG_DEFAULT_OFFSET (0x38A00) + +#define DSS_RCH_G1_DMA_OFFSET (0x40000) +#define DSS_RCH_G1_DFC_OFFSET (0x40100) +#define DSS_RCH_G1_SCL_OFFSET (0x40200) +#define DSS_RCH_G1_POST_CLIP_OFFSET (0x403A0) +#define DSS_RCH_G1_CSC_OFFSET (0x40500) +#define DSS_RCH_G1_DEBUG_OFFSET (0x40600) +#define DSS_RCH_G1_DMA_BUF_OFFSET (0x40800) +#define DSS_RCH_G1_AFBCD_OFFSET (0x40900) +#define DSS_RCH_G1_REG_DEFAULT_OFFSET (0x40A00) + + +#define DSS_RCH_D2_DMA_OFFSET (0x50000) +#define DSS_RCH_D2_DFC_OFFSET (0x50100) +#define DSS_RCH_D2_CSC_OFFSET (0x50500) +#define DSS_RCH_D2_DEBUG_OFFSET (0x50600) +#define DSS_RCH_D2_DMA_BUF_OFFSET (0x50800) +#define DSS_RCH_D2_AFBCD_OFFSET (0x50900) + +#define DSS_RCH_D3_DMA_OFFSET (0x51000) +#define DSS_RCH_D3_DFC_OFFSET (0x51100) +#define DSS_RCH_D3_CSC_OFFSET (0x51500) +#define DSS_RCH_D3_DEBUG_OFFSET (0x51600) +#define DSS_RCH_D3_DMA_BUF_OFFSET (0x51800) +#define DSS_RCH_D3_AFBCD_OFFSET (0x51900) + +#define DSS_RCH_D0_DMA_OFFSET (0x52000) +#define DSS_RCH_D0_DFC_OFFSET (0x52100) +#define DSS_RCH_D0_CSC_OFFSET (0x52500) +#define DSS_RCH_D0_DEBUG_OFFSET (0x52600) +#define DSS_RCH_D0_DMA_BUF_OFFSET (0x52800) +#define DSS_RCH_D0_AFBCD_OFFSET (0x52900) + +#define DSS_RCH_D1_DMA_OFFSET (0x53000) +#define DSS_RCH_D1_DFC_OFFSET (0x53100) +#define DSS_RCH_D1_CSC_OFFSET (0x53500) +#define DSS_RCH_D1_DEBUG_OFFSET (0x53600) +#define DSS_RCH_D1_DMA_BUF_OFFSET (0x53800) +#define DSS_RCH_D1_AFBCD_OFFSET (0x53900) + + +#define DSS_WCH0_DMA_OFFSET (0x5A000) +#define DSS_WCH0_DFC_OFFSET (0x5A100) +#define DSS_WCH0_CSC_OFFSET (0x5A500) +#define DSS_WCH0_ROT_OFFSET (0x5A500) +#define DSS_WCH0_DEBUG_OFFSET (0x5A600) +#define DSS_WCH0_DMA_BUFFER_OFFSET (0x5A800) +#define DSS_WCH0_AFBCE_OFFSET (0x5A900) + +#define DSS_WCH1_DMA_OFFSET (0x5C000) +#define DSS_WCH1_DFC_OFFSET (0x5C100) +#define DSS_WCH1_CSC_OFFSET (0x5C500) +#define DSS_WCH1_ROT_OFFSET (0x5C500) +#define DSS_WCH1_DEBUG_OFFSET (0x5C600) +#define DSS_WCH1_DMA_BUFFER_OFFSET (0x5C800) +#define DSS_WCH1_AFBCE_OFFSET (0x5C900) + +#define DSS_WCH2_DMA_OFFSET (0x5E000) +#define DSS_WCH2_DFC_OFFSET (0x5E100) +#define DSS_WCH2_CSC_OFFSET (0x5E500) +#define DSS_WCH2_ROT_OFFSET (0x5E500) +#define DSS_WCH2_DEBUG_OFFSET (0x5E600) +#define DSS_WCH2_DMA_BUFFER_OFFSET (0x5E800) +#define DSS_WCH2_AFBCE_OFFSET (0x5E900) + + +#define DSS_OVL0_OFFSET (0x60000) +#define DSS_OVL1_OFFSET (0x60400) +#define DSS_OVL2_OFFSET (0x60800) +#define DSS_OVL3_OFFSET (0x60C00) + + +#define DSS_DBUF0_OFFSET (0x6D000) +#define DSS_DBUF1_OFFSET (0x6E000) + + +#define DSS_HI_ACE_OFFSET (0x6F000) + + +#define DSS_DPP_OFFSET (0x70000) +#define DSS_TOP_OFFSET (0x70000) +#define DSS_DPP_COLORBAR_OFFSET (0x70100) +#define DSS_DPP_DITHER_OFFSET (0x70200) +#define DSS_DPP_CSC_RGB2YUV10B_OFFSET (0x70300) +#define DSS_DPP_CSC_YUV2RGB10B_OFFSET (0x70400) +#define DSS_DPP_DEGAMA_OFFSET (0x70500) +#define DSS_DPP_GAMA_OFFSET (0x70600) +#define DSS_DPP_ACM_OFFSET (0x70700) +#define DSS_DPP_ACE_OFFSET (0x70800) +#define DSS_DPP_LCP_OFFSET (0x70900) +#define DSS_DPP_ARSR1P_OFFSET (0x70A00) +#define DSS_DPP_BITEXT0_OFFSET (0x70B00) +#define DSS_DPP_GAMA_LUT_OFFSET (0x71000) +#define DSS_DPP_ACM_LUT_OFFSET (0x72000) +#define DSS_DPP_LCP_LUT_OFFSET (0x73000) +#define DSS_DPP_ACE_LUT_OFFSET (0x79000) +#define DSS_DPP_ARSR1P_LUT_OFFSET (0x7B000) + + +#define DSS_POST_SCF_OFFSET DSS_DPP_ARSR1P_OFFSET +#define DSS_POST_SCF_LUT_OFFSET DSS_DPP_ARSR1P_LUT_OFFSET + +#define DSS_DPP_SBL_OFFSET (0x7C000) +#define DSS_LDI0_OFFSET (0x7D000) +#define DSS_IFBC_OFFSET (0x7D800) +#define DSS_DSC_OFFSET (0x7DC00) +#define DSS_LDI1_OFFSET (0x7E000) + +/******************************************************************************* + ** GLB + */ +#define GLB_DSS_TAG (DSS_GLB0_OFFSET + 0x0000) + +#define GLB_APB_CTL (DSS_GLB0_OFFSET + 0x0004) + +#define GLB_DSS_AXI_RST_EN (DSS_GLB0_OFFSET + 0x0118) +#define GLB_DSS_APB_RST_EN (DSS_GLB0_OFFSET + 0x011C) +#define GLB_DSS_CORE_RST_EN (DSS_GLB0_OFFSET + 0x0120) +#define GLB_PXL0_DIV2_RST_EN (DSS_GLB0_OFFSET + 0x0124) +#define GLB_PXL0_DIV4_RST_EN (DSS_GLB0_OFFSET + 0x0128) +#define GLB_PXL0_RST_EN (DSS_GLB0_OFFSET + 0x012C) +#define GLB_PXL0_DSI_RST_EN (DSS_GLB0_OFFSET + 0x0130) +#define GLB_DSS_PXL1_RST_EN (DSS_GLB0_OFFSET + 0x0134) +#define GLB_MM_AXI_CLK_RST_EN (DSS_GLB0_OFFSET + 0x0138) +#define GLB_AFBCD0_IP_RST_EN (DSS_GLB0_OFFSET + 0x0140) +#define GLB_AFBCD1_IP_RST_EN (DSS_GLB0_OFFSET + 0x0144) +#define GLB_AFBCD2_IP_RST_EN (DSS_GLB0_OFFSET + 0x0148) +#define GLB_AFBCD3_IP_RST_EN (DSS_GLB0_OFFSET + 0x014C) +#define GLB_AFBCD4_IP_RST_EN (DSS_GLB0_OFFSET + 0x0150) +#define GLB_AFBCD5_IP_RST_EN (DSS_GLB0_OFFSET + 0x0154) +#define GLB_AFBCD6_IP_RST_EN (DSS_GLB0_OFFSET + 0x0158) +#define GLB_AFBCD7_IP_RST_EN (DSS_GLB0_OFFSET + 0x015C) +#define GLB_AFBCE0_IP_RST_EN (DSS_GLB0_OFFSET + 0x0160) +#define GLB_AFBCE1_IP_RST_EN (DSS_GLB0_OFFSET + 0x0164) + + +#define GLB_MCU_PDP_INTS (DSS_GLB0_OFFSET + 0x20C) +#define GLB_MCU_PDP_INT_MSK (DSS_GLB0_OFFSET + 0x210) +#define GLB_MCU_SDP_INTS (DSS_GLB0_OFFSET + 0x214) +#define GLB_MCU_SDP_INT_MSK (DSS_GLB0_OFFSET + 0x218) +#define GLB_MCU_OFF_INTS (DSS_GLB0_OFFSET + 0x21C) +#define GLB_MCU_OFF_INT_MSK (DSS_GLB0_OFFSET + 0x220) +#define GLB_MCU_OFF_CAM_INTS (DSS_GLB0_OFFSET + 0x2B4) +#define GLB_MCU_OFF_CAM_INT_MSK (DSS_GLB0_OFFSET + 0x2B8) +#define GLB_CPU_PDP_INTS (DSS_GLB0_OFFSET + 0x224) +#define GLB_CPU_PDP_INT_MSK (DSS_GLB0_OFFSET + 0x228) +#define GLB_CPU_SDP_INTS (DSS_GLB0_OFFSET + 0x22C) +#define GLB_CPU_SDP_INT_MSK (DSS_GLB0_OFFSET + 0x230) +#define GLB_CPU_OFF_INTS (DSS_GLB0_OFFSET + 0x234) +#define GLB_CPU_OFF_INT_MSK (DSS_GLB0_OFFSET + 0x238) +#define GLB_CPU_OFF_CAM_INTS (DSS_GLB0_OFFSET + 0x2AC) +#define GLB_CPU_OFF_CAM_INT_MSK (DSS_GLB0_OFFSET + 0x2B0) + + +#define GLB_MODULE_CLK_SEL (DSS_GLB0_OFFSET + 0x0300) +#define GLB_MODULE_CLK_EN (DSS_GLB0_OFFSET + 0x0304) + +#define GLB_GLB0_DBG_SEL (DSS_GLB0_OFFSET + 0x310) +#define GLB_GLB1_DBG_SEL (DSS_GLB0_OFFSET + 0x314) +#define GLB_DBG_IRQ_CPU (DSS_GLB0_OFFSET + 0x320) +#define GLB_DBG_IRQ_MCU (DSS_GLB0_OFFSET + 0x324) + +#define GLB_TP_SEL (DSS_GLB0_OFFSET + 0x0400) +#define GLB_CRC_DBG_LDI0 (DSS_GLB0_OFFSET + 0x0404) +#define GLB_CRC_DBG_LDI1 (DSS_GLB0_OFFSET + 0x0408) +#define GLB_CRC_LDI0_EN (DSS_GLB0_OFFSET + 0x040C) +#define GLB_CRC_LDI0_FRM (DSS_GLB0_OFFSET + 0x0410) +#define GLB_CRC_LDI1_EN (DSS_GLB0_OFFSET + 0x0414) +#define GLB_CRC_LDI1_FRM (DSS_GLB0_OFFSET + 0x0418) + +#define GLB_DSS_MEM_CTRL (DSS_GLB0_OFFSET + 0x0600) +#define GLB_DSS_PM_CTRL (DSS_GLB0_OFFSET + 0x0604) + +/******************************************************************************* + ** DBG + */ +#define DBG_CRC_DBG_OV0 (0x0000) +#define DBG_CRC_DBG_OV1 (0x0004) +#define DBG_CRC_DBG_SUM (0x0008) +#define DBG_CRC_OV0_EN (0x000C) +#define DBG_DSS_GLB_DBG_O (0x0010) +#define DBG_DSS_GLB_DBG_I (0x0014) +#define DBG_CRC_OV0_FRM (0x0018) +#define DBG_CRC_OV1_EN (0x001C) +#define DBG_CRC_OV1_FRM (0x0020) +#define DBG_CRC_SUM_EN (0x0024) +#define DBG_CRC_SUM_FRM (0x0028) + +#define DBG_MCTL_INTS (0x023C) +#define DBG_MCTL_INT_MSK (0x0240) +#define DBG_WCH0_INTS (0x0244) +#define DBG_WCH0_INT_MSK (0x0248) +#define DBG_WCH1_INTS (0x024C) +#define DBG_WCH1_INT_MSK (0x0250) +#define DBG_RCH0_INTS (0x0254) +#define DBG_RCH0_INT_MSK (0x0258) +#define DBG_RCH1_INTS (0x025C) +#define DBG_RCH1_INT_MSK (0x0260) +#define DBG_RCH2_INTS (0x0264) +#define DBG_RCH2_INT_MSK (0x0268) +#define DBG_RCH3_INTS (0x026C) +#define DBG_RCH3_INT_MSK (0x0270) +#define DBG_RCH4_INTS (0x0274) +#define DBG_RCH4_INT_MSK (0x0278) +#define DBG_RCH5_INTS (0x027C) +#define DBG_RCH5_INT_MSK (0x0280) +#define DBG_RCH6_INTS (0x0284) +#define DBG_RCH6_INT_MSK (0x0288) +#define DBG_RCH7_INTS (0x028C) +#define DBG_RCH7_INT_MSK (0x0290) +#define DBG_DSS_GLB_INTS (0x0294) +#define DBG_DSS_GLB_INT_MSK (0x0298) +#define DBG_WCH2_INTS (0x029C) +#define DBG_WCH2_INT_MSK (0x02A0) +#define DBG_RCH8_INTS (0x02A4) +#define DBG_RCH8_INT_MSK (0x02A8) + +/******************************************************************************* + ** CMDLIST + */ + +#define CMDLIST_CH0_PENDING_CLR (0x0000) +#define CMDLIST_CH0_CTRL (0x0004) +#define CMDLIST_CH0_STATUS (0x0008) +#define CMDLIST_CH0_STAAD (0x000C) +#define CMDLIST_CH0_CURAD (0x0010) +#define CMDLIST_CH0_INTE (0x0014) +#define CMDLIST_CH0_INTC (0x0018) +#define CMDLIST_CH0_INTS (0x001C) +#define CMDLIST_CH0_SCENE (0x0020) +#define CMDLIST_CH0_DBG (0x0028) + +#define CMDLIST_DBG (0x0700) +#define CMDLIST_BUF_DBG_EN (0x0704) +#define CMDLIST_BUF_DBG_CNT_CLR (0x0708) +#define CMDLIST_BUF_DBG_CNT (0x070C) +#define CMDLIST_TIMEOUT_TH (0x0710) +#define CMDLIST_START (0x0714) +#define CMDLIST_ADDR_MASK_EN (0x0718) +#define CMDLIST_ADDR_MASK_DIS (0x071C) +#define CMDLIST_ADDR_MASK_STATUS (0x0720) +#define CMDLIST_TASK_CONTINUE (0x0724) +#define CMDLIST_TASK_STATUS (0x0728) +#define CMDLIST_CTRL (0x072C) +#define CMDLIST_SECU (0x0730) +#define CMDLIST_INTS (0x0734) +#define CMDLIST_SWRST (0x0738) +#define CMD_MEM_CTRL (0x073C) +#define CMD_CLK_SEL (0x0740) +#define CMD_CLK_EN (0x0744) + +#define HISI_DSS_MIN_ROT_AFBCE_BLOCK_SIZE (256) +#define HISI_DSS_MAX_ROT_AFBCE_BLOCK_SIZE (480) + + +#define BIT_CMDLIST_CH_TASKDONE_INTS BIT(7) +#define BIT_CMDLIST_CH_TIMEOUT_INTS BIT(6) +#define BIT_CMDLIST_CH_BADCMD_INTS BIT(5) +#define BIT_CMDLIST_CH_START_INTS BIT(4) +#define BIT_CMDLIST_CH_PENDING_INTS BIT(3) +#define BIT_CMDLIST_CH_AXIERR_INTS BIT(2) +#define BIT_CMDLIST_CH_ALLDONE_INTS BIT(1) +#define BIT_CMDLIST_CH_ONEDONE_INTS BIT(0) + +#define BIT_CMDLIST_CH15_INTS BIT(15) +#define BIT_CMDLIST_CH14_INTS BIT(14) +#define BIT_CMDLIST_CH13_INTS BIT(13) +#define BIT_CMDLIST_CH12_INTS BIT(12) +#define BIT_CMDLIST_CH11_INTS BIT(11) +#define BIT_CMDLIST_CH10_INTS BIT(10) +#define BIT_CMDLIST_CH9_INTS BIT(9) +#define BIT_CMDLIST_CH8_INTS BIT(8) +#define BIT_CMDLIST_CH7_INTS BIT(7) +#define BIT_CMDLIST_CH6_INTS BIT(6) +#define BIT_CMDLIST_CH5_INTS BIT(5) +#define BIT_CMDLIST_CH4_INTS BIT(4) +#define BIT_CMDLIST_CH3_INTS BIT(3) +#define BIT_CMDLIST_CH2_INTS BIT(2) +#define BIT_CMDLIST_CH1_INTS BIT(1) +#define BIT_CMDLIST_CH0_INTS BIT(0) + +/******************************************************************************* + ** AIF + */ +#define AIF0_CH0_OFFSET (DSS_VBIF0_AIF + 0x00) +#define AIF0_CH0_ADD_OFFSET (DSS_VBIF0_AIF + 0x04) +#define AIF0_CH1_OFFSET (DSS_VBIF0_AIF + 0x20) +#define AIF0_CH1_ADD_OFFSET (DSS_VBIF0_AIF + 0x24) +#define AIF0_CH2_OFFSET (DSS_VBIF0_AIF + 0x40) +#define AIF0_CH2_ADD_OFFSET (DSS_VBIF0_AIF + 0x44) +#define AIF0_CH3_OFFSET (DSS_VBIF0_AIF + 0x60) +#define AIF0_CH3_ADD_OFFSET (DSS_VBIF0_AIF + 0x64) +#define AIF0_CH4_OFFSET (DSS_VBIF0_AIF + 0x80) +#define AIF0_CH4_ADD_OFFSET (DSS_VBIF0_AIF + 0x84) +#define AIF0_CH5_OFFSET (DSS_VBIF0_AIF + 0xA0) +#define AIF0_CH5_ADD_OFFSET (DSS_VBIF0_AIF + 0xa4) +#define AIF0_CH6_OFFSET (DSS_VBIF0_AIF + 0xC0) +#define AIF0_CH6_ADD_OFFSET (DSS_VBIF0_AIF + 0xc4) +#define AIF0_CH7_OFFSET (DSS_VBIF0_AIF + 0xE0) +#define AIF0_CH7_ADD_OFFSET (DSS_VBIF0_AIF + 0xe4) +#define AIF0_CH8_OFFSET (DSS_VBIF0_AIF + 0x100) +#define AIF0_CH8_ADD_OFFSET (DSS_VBIF0_AIF + 0x104) +#define AIF0_CH9_OFFSET (DSS_VBIF0_AIF + 0x120) +#define AIF0_CH9_ADD_OFFSET (DSS_VBIF0_AIF + 0x124) +#define AIF0_CH10_OFFSET (DSS_VBIF0_AIF + 0x140) +#define AIF0_CH10_ADD_OFFSET (DSS_VBIF0_AIF + 0x144) +#define AIF0_CH11_OFFSET (DSS_VBIF0_AIF + 0x160) +#define AIF0_CH11_ADD_OFFSET (DSS_VBIF0_AIF + 0x164) +#define AIF0_CH12_OFFSET (DSS_VBIF0_AIF + 0x180) +#define AIF0_CH12_ADD_OFFSET (DSS_VBIF0_AIF + 0x184) + +#define AIF1_CH0_OFFSET (DSS_VBIF1_AIF + 0x00) +#define AIF1_CH0_ADD_OFFSET (DSS_VBIF1_AIF + 0x04) +#define AIF1_CH1_OFFSET (DSS_VBIF1_AIF + 0x20) +#define AIF1_CH1_ADD_OFFSET (DSS_VBIF1_AIF + 0x24) +#define AIF1_CH2_OFFSET (DSS_VBIF1_AIF + 0x40) +#define AIF1_CH2_ADD_OFFSET (DSS_VBIF1_AIF + 0x44) +#define AIF1_CH3_OFFSET (DSS_VBIF1_AIF + 0x60) +#define AIF1_CH3_ADD_OFFSET (DSS_VBIF1_AIF + 0x64) +#define AIF1_CH4_OFFSET (DSS_VBIF1_AIF + 0x80) +#define AIF1_CH4_ADD_OFFSET (DSS_VBIF1_AIF + 0x84) +#define AIF1_CH5_OFFSET (DSS_VBIF1_AIF + 0xA0) +#define AIF1_CH5_ADD_OFFSET (DSS_VBIF1_AIF + 0xa4) +#define AIF1_CH6_OFFSET (DSS_VBIF1_AIF + 0xC0) +#define AIF1_CH6_ADD_OFFSET (DSS_VBIF1_AIF + 0xc4) +#define AIF1_CH7_OFFSET (DSS_VBIF1_AIF + 0xE0) +#define AIF1_CH7_ADD_OFFSET (DSS_VBIF1_AIF + 0xe4) +#define AIF1_CH8_OFFSET (DSS_VBIF1_AIF + 0x100) +#define AIF1_CH8_ADD_OFFSET (DSS_VBIF1_AIF + 0x104) +#define AIF1_CH9_OFFSET (DSS_VBIF1_AIF + 0x120) +#define AIF1_CH9_ADD_OFFSET (DSS_VBIF1_AIF + 0x124) +#define AIF1_CH10_OFFSET (DSS_VBIF1_AIF + 0x140) +#define AIF1_CH10_ADD_OFFSET (DSS_VBIF1_AIF + 0x144) +#define AIF1_CH11_OFFSET (DSS_VBIF1_AIF + 0x160) +#define AIF1_CH11_ADD_OFFSET (DSS_VBIF1_AIF + 0x164) +#define AIF1_CH12_OFFSET (DSS_VBIF1_AIF + 0x180) +#define AIF1_CH12_ADD_OFFSET (DSS_VBIF1_AIF + 0x184) + +/* aif dmax */ + +#define AIF_CH_CTL (0x0000) + +#define AIF_CH_CTL_ADD (0x0004) + + +/* aif common */ +#define AXI0_RID_MSK0 (0x0800) +#define AXI0_RID_MSK1 (0x0804) +#define AXI0_WID_MSK (0x0808) +#define AXI0_R_QOS_MAP (0x080c) +#define AXI1_RID_MSK0 (0x0810) +#define AXI1_RID_MSK1 (0x0814) +#define AXI1_WID_MSK (0x0818) +#define AXI1_R_QOS_MAP (0x081c) +#define AIF_CLK_SEL0 (0x0820) +#define AIF_CLK_SEL1 (0x0824) +#define AIF_CLK_EN0 (0x0828) +#define AIF_CLK_EN1 (0x082c) +#define MONITOR_CTRL (0x0830) +#define MONITOR_TIMER_INI (0x0834) +#define DEBUG_BUF_BASE (0x0838) +#define DEBUG_CTRL (0x083C) +#define AIF_SHADOW_READ (0x0840) +#define AIF_MEM_CTRL (0x0844) +#define AIF_MONITOR_EN (0x0848) +#define AIF_MONITOR_CTRL (0x084C) +#define AIF_MONITOR_SAMPLE_MUN (0x0850) +#define AIF_MONITOR_SAMPLE_TIME (0x0854) +#define AIF_MONITOR_SAMPLE_FLOW (0x0858) + +/* aif debug */ +#define AIF_MONITOR_READ_DATA (0x0880) +#define AIF_MONITOR_WRITE_DATA (0x0884) +#define AIF_MONITOR_WINDOW_CYCLE (0x0888) +#define AIF_MONITOR_WBURST_CNT (0x088C) +#define AIF_MONITOR_MIN_WR_CYCLE (0x0890) +#define AIF_MONITOR_MAX_WR_CYCLE (0x0894) +#define AIF_MONITOR_AVR_WR_CYCLE (0x0898) +#define AIF_MONITOR_MIN_WRW_CYCLE (0x089C) +#define AIF_MONITOR_MAX_WRW_CYCLE (0x08A0) +#define AIF_MONITOR_AVR_WRW_CYCLE (0x08A4) +#define AIF_MONITOR_RBURST_CNT (0x08A8) +#define AIF_MONITOR_MIN_RD_CYCLE (0x08AC) +#define AIF_MONITOR_MAX_RD_CYCLE (0x08B0) +#define AIF_MONITOR_AVR_RD_CYCLE (0x08B4) +#define AIF_MONITOR_MIN_RDW_CYCLE (0x08B8) +#define AIF_MONITOR_MAX_RDW_CYCLE (0x08BC) +#define AIF_MONITOR_AVR_RDW_CYCLE (0x08C0) +#define AIF_CH_STAT_0 (0x08C4) +#define AIF_CH_STAT_1 (0x08C8) + +#define AIF_MODULE_CLK_SEL (0x0A04) +#define AIF_MODULE_CLK_EN (0x0A08) + +typedef struct dss_aif { + uint32_t aif_ch_ctl; + uint32_t aif_ch_ctl_add; +} dss_aif_t; + +typedef struct dss_aif_bw { + uint64_t bw; + uint8_t chn_idx; + int8_t axi_sel; + uint8_t is_used; +} dss_aif_bw_t; + +/******************************************************************************* + ** MIF + */ +#define MIF_ENABLE (0x0000) +#define MIF_MEM_CTRL (0x0004) + +#define MIF_CTRL0 (0x000) +#define MIF_CTRL1 (0x004) +#define MIF_CTRL2 (0x008) +#define MIF_CTRL3 (0x00C) +#define MIF_CTRL4 (0x010) +#define MIF_CTRL5 (0x014) +#define REG_DEFAULT (0x0500) +#define MIF_SHADOW_READ (0x0504) +#define MIF_CLK_CTL (0x0508) + +#define MIF_STAT0 (0x0600) + +#define MIF_STAT1 (0x0604) + +#define MIF_STAT2 (0x0608) + +#define MIF_CTRL_OFFSET (0x20) +#define MIF_CH0_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*1) +#define MIF_CH1_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*2) +#define MIF_CH2_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*3) +#define MIF_CH3_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*4) +#define MIF_CH4_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*5) +#define MIF_CH5_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*6) +#define MIF_CH6_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*7) +#define MIF_CH7_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*8) +#define MIF_CH8_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*9) +#define MIF_CH9_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*10) +#define MIF_CH10_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*11) +#define MIF_CH11_OFFSET (DSS_MIF_OFFSET + MIF_CTRL_OFFSET*12) +#define MIF_CTRL_NUM (12) + +#define LITTLE_LAYER_BUF_SIZE (256 * 1024) +#define MIF_STRIDE_UNIT (4 * 1024) + +typedef struct dss_mif { + uint32_t mif_ctrl1; + uint32_t mif_ctrl2; + uint32_t mif_ctrl3; + uint32_t mif_ctrl4; + uint32_t mif_ctrl5; +} dss_mif_t; + +/* + ** stretch blt, linear/tile, rotation, pixel format + ** 0 0 000 + */ +enum dss_mmu_tlb_tag_org { + MMU_TLB_TAG_ORG_0x0 = 0x0, + MMU_TLB_TAG_ORG_0x1 = 0x1, + MMU_TLB_TAG_ORG_0x2 = 0x2, + MMU_TLB_TAG_ORG_0x3 = 0x3, + MMU_TLB_TAG_ORG_0x4 = 0x4, + MMU_TLB_TAG_ORG_0x7 = 0x7, + + MMU_TLB_TAG_ORG_0x8 = 0x8, + MMU_TLB_TAG_ORG_0x9 = 0x9, + MMU_TLB_TAG_ORG_0xA = 0xA, + MMU_TLB_TAG_ORG_0xB = 0xB, + MMU_TLB_TAG_ORG_0xC = 0xC, + MMU_TLB_TAG_ORG_0xF = 0xF, + + MMU_TLB_TAG_ORG_0x10 = 0x10, + MMU_TLB_TAG_ORG_0x11 = 0x11, + MMU_TLB_TAG_ORG_0x12 = 0x12, + MMU_TLB_TAG_ORG_0x13 = 0x13, + MMU_TLB_TAG_ORG_0x14 = 0x14, + MMU_TLB_TAG_ORG_0x17 = 0x17, + + MMU_TLB_TAG_ORG_0x18 = 0x18, + MMU_TLB_TAG_ORG_0x19 = 0x19, + MMU_TLB_TAG_ORG_0x1A = 0x1A, + MMU_TLB_TAG_ORG_0x1B = 0x1B, + MMU_TLB_TAG_ORG_0x1C = 0x1C, + MMU_TLB_TAG_ORG_0x1F = 0x1F, +}; + +/******************************************************************************* + **SMMU + */ +#define SMMU_SCR (0x0000) +#define SMMU_MEMCTRL (0x0004) +#define SMMU_LP_CTRL (0x0008) +#define SMMU_PRESS_REMAP (0x000C) +#define SMMU_INTMASK_NS (0x0010) +#define SMMU_INTRAW_NS (0x0014) +#define SMMU_INTSTAT_NS (0x0018) +#define SMMU_INTCLR_NS (0x001C) + +#define SMMU_SMRx_NS (0x0020) +#define SMMU_RLD_EN0_NS (0x01F0) +#define SMMU_RLD_EN1_NS (0x01F4) +#define SMMU_RLD_EN2_NS (0x01F8) +#define SMMU_CB_SCTRL (0x0200) +#define SMMU_CB_TTBR0 (0x0204) +#define SMMU_CB_TTBR1 (0x0208) +#define SMMU_CB_TTBCR (0x020C) +#define SMMU_OFFSET_ADDR_NS (0x0210) +#define SMMU_SCACHEI_ALL (0x0214) +#define SMMU_SCACHEI_L1 (0x0218) +#define SMMU_SCACHEI_L2L3 (0x021C) +#define SMMU_FAMA_CTRL0 (0x0220) +#define SMMU_FAMA_CTRL1 (0x0224) +#define SMMU_ADDR_MSB (0x0300) +#define SMMU_ERR_RDADDR (0x0304) +#define SMMU_ERR_WRADDR (0x0308) +#define SMMU_FAULT_ADDR_TCU (0x0310) +#define SMMU_FAULT_ID_TCU (0x0314) + +#define SMMU_FAULT_ADDR_TBUx (0x0320) +#define SMMU_FAULT_ID_TBUx (0x0324) +#define SMMU_FAULT_INFOx (0x0328) +#define SMMU_DBGRPTR_TLB (0x0380) +#define SMMU_DBGRDATA_TLB (0x0380) +#define SMMU_DBGRDATA0_CACHE (0x038C) +#define SMMU_DBGRDATA1_CACHE (0x0390) +#define SMMU_DBGAXI_CTRL (0x0394) +#define SMMU_OVA_ADDR (0x0398) +#define SMMU_OPA_ADDR (0x039C) +#define SMMU_OVA_CTRL (0x03A0) +#define SMMU_OPREF_ADDR (0x03A4) +#define SMMU_OPREF_CTRL (0x03A8) +#define SMMU_OPREF_CNT (0x03AC) + +#define SMMU_SMRx_S (0x0500) +#define SMMU_RLD_EN0_S (0x06F0) +#define SMMU_RLD_EN1_S (0x06F4) +#define SMMU_RLD_EN2_S (0x06F8) +#define SMMU_INTMAS_S (0x0700) +#define SMMU_INTRAW_S (0x0704) +#define SMMU_INTSTAT_S (0x0708) +#define SMMU_INTCLR_S (0x070C) +#define SMMU_SCR_S (0x0710) +#define SMMU_SCB_SCTRL (0x0714) +#define SMMU_SCB_TTBR (0x0718) +#define SMMU_SCB_TTBCR (0x071C) +#define SMMU_OFFSET_ADDR_S (0x0720) + +#define SMMU_SID_NUM (64) + +typedef struct dss_smmu { + uint32_t smmu_scr; + uint32_t smmu_memctrl; + uint32_t smmu_lp_ctrl; + uint32_t smmu_press_remap; + uint32_t smmu_intmask_ns; + uint32_t smmu_intraw_ns; + uint32_t smmu_intstat_ns; + uint32_t smmu_intclr_ns; + uint32_t smmu_smrx_ns[SMMU_SID_NUM]; + uint32_t smmu_rld_en0_ns; + uint32_t smmu_rld_en1_ns; + uint32_t smmu_rld_en2_ns; + uint32_t smmu_cb_sctrl; + uint32_t smmu_cb_ttbr0; + uint32_t smmu_cb_ttbr1; + uint32_t smmu_cb_ttbcr; + uint32_t smmu_offset_addr_ns; + uint32_t smmu_scachei_all; + uint32_t smmu_scachei_l1; + uint32_t smmu_scachei_l2l3; + uint32_t smmu_fama_ctrl0_ns; + uint32_t smmu_fama_ctrl1_ns; + uint32_t smmu_addr_msb; + uint32_t smmu_err_rdaddr; + uint32_t smmu_err_wraddr; + uint32_t smmu_fault_addr_tcu; + uint32_t smmu_fault_id_tcu; + uint32_t smmu_fault_addr_tbux; + uint32_t smmu_fault_id_tbux; + uint32_t smmu_fault_infox; + uint32_t smmu_dbgrptr_tlb; + uint32_t smmu_dbgrdata_tlb; + uint32_t smmu_dbgrptr_cache; + uint32_t smmu_dbgrdata0_cache; + uint32_t smmu_dbgrdata1_cache; + uint32_t smmu_dbgaxi_ctrl; + uint32_t smmu_ova_addr; + uint32_t smmu_opa_addr; + uint32_t smmu_ova_ctrl; + uint32_t smmu_opref_addr; + uint32_t smmu_opref_ctrl; + uint32_t smmu_opref_cnt; + uint32_t smmu_smrx_s[SMMU_SID_NUM]; + uint32_t smmu_rld_en0_s; + uint32_t smmu_rld_en1_s; + uint32_t smmu_rld_en2_s; + uint32_t smmu_intmas_s; + uint32_t smmu_intraw_s; + uint32_t smmu_intstat_s; + uint32_t smmu_intclr_s; + uint32_t smmu_scr_s; + uint32_t smmu_scb_sctrl; + uint32_t smmu_scb_ttbr; + uint32_t smmu_scb_ttbcr; + uint32_t smmu_offset_addr_s; + + uint8_t smmu_smrx_ns_used[DSS_CHN_MAX_DEFINE]; +} dss_smmu_t; + +/******************************************************************************* + ** RDMA + */ + + +#define DMA_OFT_X0 (0x0000) +#define DMA_OFT_Y0 (0x0004) +#define DMA_OFT_X1 (0x0008) +#define DMA_OFT_Y1 (0x000C) +#define DMA_MASK0 (0x0010) +#define DMA_MASK1 (0x0014) +#define DMA_STRETCH_SIZE_VRT (0x0018) +#define DMA_CTRL (0x001C) +#define DMA_TILE_SCRAM (0x0020) + +#define DMA_PULSE (0x0028) +#define DMA_CORE_GT (0x002C) +#define RWCH_CFG0 (0x0030) + + +#define WDMA_DMA_SW_MASK_EN (0x004C) +#define WDMA_DMA_START_MASK0 (0x0050) +#define WDMA_DMA_END_MASK0 (0x0054) +#define WDMA_DMA_START_MASK1 (0x0058) +#define WDMA_DMA_END_MASK1 (0x005C) + + +#define DMA_DATA_ADDR0 (0x0060) +#define DMA_STRIDE0 (0x0064) +#define DMA_STRETCH_STRIDE0 (0x0068) +#define DMA_DATA_NUM0 (0x006C) + +#define DMA_TEST0 (0x0070) +#define DMA_TEST1 (0x0074) +#define DMA_TEST3 (0x0078) +#define DMA_TEST4 (0x007C) +#define DMA_STATUS_Y (0x0080) + + +#define DMA_DATA_ADDR1 (0x0084) +#define DMA_STRIDE1 (0x0088) +#define DMA_STRETCH_STRIDE1 (0x008C) +#define DMA_DATA_NUM1 (0x0090) + +#define DMA_TEST0_U (0x0094) +#define DMA_TEST1_U (0x0098) +#define DMA_TEST3_U (0x009C) +#define DMA_TEST4_U (0x00A0) +#define DMA_STATUS_U (0x00A4) + + +#define DMA_DATA_ADDR2 (0x00A8) +#define DMA_STRIDE2 (0x00AC) +#define DMA_STRETCH_STRIDE2 (0x00B0) +#define DMA_DATA_NUM2 (0x00B4) + +#define DMA_TEST0_V (0x00B8) +#define DMA_TEST1_V (0x00BC) +#define DMA_TEST3_V (0x00C0) +#define DMA_TEST4_V (0x00C4) +#define DMA_STATUS_V (0x00C8) + + +#define CH_RD_SHADOW (0x00D0) +#define CH_CTL (0x00D4) +#define CH_SECU_EN (0x00D8) +#define CH_SW_END_REQ (0x00DC) +#define CH_CLK_SEL (0x00E0) +#define CH_CLK_EN (0x00E4) + +/******************************************************************************* + ** DFC + */ +#define DFC_DISP_SIZE (0x0000) +#define DFC_PIX_IN_NUM (0x0004) +#define DFC_GLB_ALPHA (0x0008) +#define DFC_DISP_FMT (0x000C) +#define DFC_CLIP_CTL_HRZ (0x0010) +#define DFC_CLIP_CTL_VRZ (0x0014) +#define DFC_CTL_CLIP_EN (0x0018) +#define DFC_ICG_MODULE (0x001C) +#define DFC_DITHER_ENABLE (0x0020) +#define DFC_PADDING_CTL (0x0024) + +typedef struct dss_dfc { + uint32_t disp_size; + uint32_t pix_in_num; + uint32_t disp_fmt; + uint32_t clip_ctl_hrz; + uint32_t clip_ctl_vrz; + uint32_t ctl_clip_en; + uint32_t icg_module; + uint32_t dither_enable; + uint32_t padding_ctl; +} dss_dfc_t; + +/******************************************************************************* + ** SCF + */ +#define DSS_SCF_H0_Y_COEF_OFFSET (0x0000) +#define DSS_SCF_Y_COEF_OFFSET (0x2000) +#define DSS_SCF_UV_COEF_OFFSET (0x2800) + +#define SCF_EN_HSCL_STR (0x0000) +#define SCF_EN_VSCL_STR (0x0004) +#define SCF_H_V_ORDER (0x0008) +#define SCF_SCF_CORE_GT (0x000C) +#define SCF_INPUT_WIDTH_HEIGHT (0x0010) +#define SCF_OUTPUT_WIDTH_HEIGHT (0x0014) +#define SCF_COEF_MEM_CTRL (0x0018) +#define SCF_EN_HSCL (0x001C) +#define SCF_EN_VSCL (0x0020) +#define SCF_ACC_HSCL (0x0024) +#define SCF_ACC_HSCL1 (0x0028) +#define SCF_INC_HSCL (0x0034) +#define SCF_ACC_VSCL (0x0038) +#define SCF_ACC_VSCL1 (0x003C) +#define SCF_INC_VSCL (0x0048) +#define SCF_EN_NONLINEAR (0x004C) +#define SCF_EN_MMP (0x007C) +#define SCF_DB_H0 (0x0080) +#define SCF_DB_H1 (0x0084) +#define SCF_DB_V0 (0x0088) +#define SCF_DB_V1 (0x008C) +#define SCF_LB_MEM_CTRL (0x0090) +#define SCF_RD_SHADOW (0x00F0) +#define SCF_CLK_SEL (0x00F8) +#define SCF_CLK_EN (0x00FC) + +/* MACROS */ +#define SCF_MIN_INPUT (16) +#define SCF_MIN_OUTPUT (16) + +/* Threshold for SCF Stretch and SCF filter */ +#define RDMA_STRETCH_THRESHOLD (2) +#define SCF_INC_FACTOR (1 << 18) +#define SCF_UPSCALE_MAX (60) +#define SCF_DOWNSCALE_MAX (60) +#define SCF_EDGE_FACTOR (3) +#define ARSR2P_INC_FACTOR (65536) + +typedef struct dss_scl { + uint32_t en_hscl_str; + uint32_t en_vscl_str; + uint32_t h_v_order; + uint32_t input_width_height; + uint32_t output_width_height; + uint32_t en_hscl; + uint32_t en_vscl; + uint32_t acc_hscl; + uint32_t inc_hscl; + uint32_t inc_vscl; + uint32_t en_mmp; + uint32_t scf_ch_core_gt; + uint32_t fmt; +} dss_scl_t; + +enum scl_coef_lut_idx { + SCL_COEF_NONE_IDX = -1, + SCL_COEF_YUV_IDX = 0, + SCL_COEF_RGB_IDX = 1, + SCL_COEF_IDX_MAX = 2, +}; + +/******************************************************************************* + ** ARSR2P v0 + */ +#define ARSR2P_INPUT_WIDTH_HEIGHT (0x000) +#define ARSR2P_OUTPUT_WIDTH_HEIGHT (0x004) +#define ARSR2P_IHLEFT (0x008) +#define ARSR2P_IHRIGHT (0x00C) +#define ARSR2P_IVTOP (0x010) +#define ARSR2P_IVBOTTOM (0x014) +#define ARSR2P_IHINC (0x018) +#define ARSR2P_IVINC (0x01C) +#define ARSR2P_UV_OFFSET (0x020) +#define ARSR2P_MODE (0x024) +#define ARSR2P_SKIN_THRES_Y (0x028) +#define ARSR2P_SKIN_THRES_U (0x02C) +#define ARSR2P_SKIN_THRES_V (0x030) +#define ARSR2P_SKIN_CFG0 (0x034) +#define ARSR2P_SKIN_CFG1 (0x038) +#define ARSR2P_SKIN_CFG2 (0x03C) +#define ARSR2P_SHOOT_CFG1 (0x040) +#define ARSR2P_SHOOT_CFG2 (0x044) +#define ARSR2P_SHARP_CFG1 (0x048) +#define ARSR2P_SHARP_CFG2 (0x04C) +#define ARSR2P_SHARP_CFG3 (0x050) +#define ARSR2P_SHARP_CFG4 (0x054) +#define ARSR2P_SHARP_CFG5 (0x058) +#define ARSR2P_SHARP_CFG6 (0x05C) +#define ARSR2P_SHARP_CFG7 (0x060) +#define ARSR2P_SHARP_CFG8 (0x064) +#define ARSR2P_SHARP_CFG9 (0x068) +#define ARSR2P_TEXTURW_ANALYSTS (0x06C) +#define ARSR2P_INTPLSHOOTCTRL (0x070) +#define ARSR2P_DEBUG0 (0x074) +#define ARSR2P_DEBUG1 (0x078) +#define ARSR2P_DEBUG2 (0x07C) +#define ARSR2P_DEBUG3 (0x080) +#define ARSR2P_LB_MEM_CTRL (0x084) +#define ARSR2P_IHLEFT1 (0x088) +#define ARSR2P_IHRIGHT1 (0x090) +#define ARSR2P_IVBOTTOM1 (0x094) + +#define ARSR2P_LUT_COEFY_V_OFFSET (0x0000) +#define ARSR2P_LUT_COEFY_H_OFFSET (0x0100) +#define ARSR2P_LUT_COEFA_V_OFFSET (0x0300) +#define ARSR2P_LUT_COEFA_H_OFFSET (0x0400) +#define ARSR2P_LUT_COEFUV_V_OFFSET (0x0600) +#define ARSR2P_LUT_COEFUV_H_OFFSET (0x0700) + +typedef struct dss_arsr2p_effect { + uint32_t skin_thres_y; + uint32_t skin_thres_u; + uint32_t skin_thres_v; + uint32_t skin_cfg0; + uint32_t skin_cfg1; + uint32_t skin_cfg2; + uint32_t shoot_cfg1; + uint32_t shoot_cfg2; + uint32_t sharp_cfg1; + uint32_t sharp_cfg2; + uint32_t sharp_cfg3; + uint32_t sharp_cfg4; + uint32_t sharp_cfg5; + uint32_t sharp_cfg6; + uint32_t sharp_cfg7; + uint32_t sharp_cfg8; + uint32_t sharp_cfg9; + uint32_t texturw_analysts; + uint32_t intplshootctrl; +} dss_arsr2p_effect_t; + +typedef struct dss_arsr2p { + uint32_t arsr_input_width_height; + uint32_t arsr_output_width_height; + uint32_t ihleft; + uint32_t ihright; + uint32_t ivtop; + uint32_t ivbottom; + uint32_t ihinc; + uint32_t ivinc; + uint32_t offset; + uint32_t mode; + dss_arsr2p_effect_t arsr2p_effect; + uint32_t ihleft1; + uint32_t ihright1; + uint32_t ivbottom1; +} dss_arsr2p_t; + +/******************************************************************************* + ** POST_CLIP v g + */ +#define POST_CLIP_DISP_SIZE (0x0000) +#define POST_CLIP_CTL_HRZ (0x0010) +#define POST_CLIP_CTL_VRZ (0x0014) +#define POST_CLIP_EN (0x0018) + +typedef struct dss_post_clip { + uint32_t disp_size; + uint32_t clip_ctl_hrz; + uint32_t clip_ctl_vrz; + uint32_t ctl_clip_en; +} dss_post_clip_t; + +/******************************************************************************* + ** PCSC v + */ +#define PCSC_IDC0 (0x0000) +#define PCSC_IDC2 (0x0004) +#define PCSC_ODC0 (0x0008) +#define PCSC_ODC2 (0x000C) +#define PCSC_P0 (0x0010) +#define PCSC_P1 (0x0014) +#define PCSC_P2 (0x0018) +#define PCSC_P3 (0x001C) +#define PCSC_P4 (0x0020) +#define PCSC_ICG_MODULE (0x0024) +#define PCSC_MPREC (0x0028) + +typedef struct dss_pcsc { + uint32_t pcsc_idc0; +} dss_pcsc_t; + +/******************************************************************************* + ** CSC + */ +#define CSC_IDC0 (0x0000) +#define CSC_IDC2 (0x0004) +#define CSC_ODC0 (0x0008) +#define CSC_ODC2 (0x000C) +#define CSC_P0 (0x0010) +#define CSC_P1 (0x0014) +#define CSC_P2 (0x0018) +#define CSC_P3 (0x001C) +#define CSC_P4 (0x0020) +#define CSC_ICG_MODULE (0x0024) +#define CSC_MPREC (0x0028) + +typedef struct dss_csc { + uint32_t idc0; + uint32_t idc2; + uint32_t odc0; + uint32_t odc2; + uint32_t p0; + uint32_t p1; + uint32_t p2; + uint32_t p3; + uint32_t p4; + uint32_t icg_module; + uint32_t mprec; +} dss_csc_t; + +/******************************************************************************* + **channel DEBUG + */ +#define CH_DEBUG_SEL (0x600) + +/******************************************************************************* + ** VPP + */ +#define VPP_CTRL (0x700) +#define VPP_MEM_CTRL (0x704) + +/******************************************************************************* + **DMA BUF + */ +#define DMA_BUF_CTRL (0x800) +#define DMA_BUF_SIZE (0x850) +#define DMA_BUF_MEM_CTRL (0x854) +#define DMA_BUF_DBG0 (0x0838) +#define DMA_BUF_DBG1 (0x083c) + + +#define AFBCD_HREG_HDR_PTR_LO (0x900) +#define AFBCD_HREG_PIC_WIDTH (0x904) +#define AFBCD_HREG_PIC_HEIGHT (0x90C) +#define AFBCD_HREG_FORMAT (0x910) +#define AFBCD_CTL (0x914) +#define AFBCD_STR (0x918) +#define AFBCD_LINE_CROP (0x91C) +#define AFBCD_INPUT_HEADER_STRIDE (0x920) +#define AFBCD_PAYLOAD_STRIDE (0x924) +#define AFBCD_MM_BASE_0 (0x928) +#define AFBCD_AFBCD_PAYLOAD_POINTER (0x930) +#define AFBCD_HEIGHT_BF_STR (0x934) +#define AFBCD_OS_CFG (0x938) +#define AFBCD_MEM_CTRL (0x93C) +#define AFBCD_SCRAMBLE_MODE (0x940) +#define AFBCD_HEADER_POINTER_OFFSET (0x944) +#define AFBCD_MONITOR_REG1_OFFSET (0x948) +#define AFBCD_MONITOR_REG2_OFFSET (0x94C) +#define AFBCD_MONITOR_REG3_OFFSET (0x950) +#define AFBCD_DEBUG_REG0_OFFSET (0x954) + + +#define AFBCE_HREG_PIC_BLKS (0x900) +#define AFBCE_HREG_FORMAT (0x904) +#define AFBCE_HREG_HDR_PTR_LO (0x908) +#define AFBCE_HREG_PLD_PTR_LO (0x90C) +#define AFBCE_PICTURE_SIZE (0x910) +#define AFBCE_CTL (0x914) +#define AFBCE_HEADER_SRTIDE (0x918) +#define AFBCE_PAYLOAD_STRIDE (0x91C) +#define AFBCE_ENC_OS_CFG (0x920) +#define AFBCE_MEM_CTRL (0x924) +#define AFBCE_QOS_CFG (0x928) +#define AFBCE_THRESHOLD (0x92C) +#define AFBCE_SCRAMBLE_MODE (0x930) +#define AFBCE_HEADER_POINTER_OFFSET (0x934) + + +#define ROT_FIRST_LNS (0x530) +#define ROT_STATE (0x534) +#define ROT_MEM_CTRL (0x538) +#define ROT_SIZE (0x53C) +#define ROT_CPU_CTL0 (0x540) +#define ROT_CPU_START0 (0x544) +#define ROT_CPU_ADDR0 (0x548) +#define ROT_CPU_RDATA0 (0x54C) +#define ROT_CPU_RDATA1 (0x550) +#define ROT_CPU_WDATA0 (0x554) +#define ROT_CPU_WDATA1 (0x558) +#define ROT_CPU_CTL1 (0x55C) +#define ROT_CPU_START1 (0x560) +#define ROT_CPU_ADDR1 (0x564) +#define ROT_CPU_RDATA2 (0x568) +#define ROT_CPU_RDATA3 (0x56C) +#define ROT_CPU_WDATA2 (0x570) +#define ROT_CPU_WDATA3 (0x574) + + +#define CH_REG_DEFAULT (0x0A00) + +/* MACROS */ +#define MIN_INTERLEAVE (7) +#define MAX_TILE_SURPORT_NUM (6) + +/* DMA aligned limited: 128bits aligned */ +#define DMA_ALIGN_BYTES (128 / BITS_PER_BYTE) +#define DMA_ADDR_ALIGN (128 / BITS_PER_BYTE) +#define DMA_STRIDE_ALIGN (128 / BITS_PER_BYTE) + +#define TILE_DMA_ADDR_ALIGN (256 * 1024) + +#define DMA_IN_WIDTH_MAX (2048) +#define DMA_IN_HEIGHT_MAX (8192) + +#define AFBC_PIC_WIDTH_MIN (16) +#define AFBC_PIC_WIDTH_MAX (8192) +#define AFBC_PIC_HEIGHT_MIN (16) +#define AFBC_PIC_HEIGHT_MAX (4096) + +#define AFBCD_TOP_CROP_MAX (15) +#define AFBCD_BOTTOM_CROP_MAX (15) + + +#define AFBC_HEADER_STRIDE_BLOCK (16) + +#define AFBC_PAYLOAD_STRIDE_BLOCK (1024) + +#define AFBC_SUPER_GRAPH_HEADER_ADDR_ALIGN (128) +#define AFBC_HEADER_ADDR_ALIGN (64) +#define AFBC_HEADER_STRIDE_ALIGN (64) + +#define AFBC_PAYLOAD_ADDR_ALIGN_32 (1024) +#define AFBC_PAYLOAD_STRIDE_ALIGN_32 (1024) +#define AFBC_PAYLOAD_ADDR_ALIGN_16 (512) +#define AFBC_PAYLOAD_STRIDE_ALIGN_16 (512) + + +#define AFBC_BLOCK_ALIGN (16) + +#define AFBCE_IN_WIDTH_MAX (512) +#define WROT_IN_WIDTH_MAX (512) + +#define MMBUF_BASE (0x40) +#define MMBUF_LINE_NUM (8) +#define MMBUF_ADDR_ALIGN (64) + +enum DSS_AFBC_HALF_BLOCK_MODE { + AFBC_HALF_BLOCK_UPPER_LOWER_ALL = 0, + AFBC_HALF_BLOCK_LOWER_UPPER_ALL, + AFBC_HALF_BLOCK_UPPER_ONLY, + AFBC_HALF_BLOCK_LOWER_ONLY, +}; + +typedef struct dss_rdma { + uint32_t oft_x0; + uint32_t oft_y0; + uint32_t oft_x1; + uint32_t oft_y1; + uint32_t mask0; + uint32_t mask1; + uint32_t stretch_size_vrt; + uint32_t ctrl; + uint32_t tile_scram; + + uint32_t data_addr0; + uint32_t stride0; + uint32_t stretch_stride0; + uint32_t data_num0; + + uint32_t data_addr1; + uint32_t stride1; + uint32_t stretch_stride1; + uint32_t data_num1; + + uint32_t data_addr2; + uint32_t stride2; + uint32_t stretch_stride2; + uint32_t data_num2; + + uint32_t ch_rd_shadow; + uint32_t ch_ctl; + + uint32_t dma_buf_ctrl; + + uint32_t vpp_ctrl; + uint32_t vpp_mem_ctrl; + + uint32_t afbcd_hreg_hdr_ptr_lo; + uint32_t afbcd_hreg_pic_width; + uint32_t afbcd_hreg_pic_height; + uint32_t afbcd_hreg_format; + uint32_t afbcd_ctl; + uint32_t afbcd_str; + uint32_t afbcd_line_crop; + uint32_t afbcd_input_header_stride; + uint32_t afbcd_payload_stride; + uint32_t afbcd_mm_base_0; + + uint32_t afbcd_afbcd_payload_pointer; + uint32_t afbcd_height_bf_str; + uint32_t afbcd_os_cfg; + uint32_t afbcd_mem_ctrl; + uint32_t afbcd_scramble_mode; + uint32_t afbcd_header_pointer_offset; + + uint8_t vpp_used; + uint8_t afbc_used; +} dss_rdma_t; + +typedef struct dss_wdma { + uint32_t oft_x0; + uint32_t oft_y0; + uint32_t oft_x1; + uint32_t oft_y1; + + uint32_t mask0; + uint32_t mask1; + uint32_t stretch_size_vrt; + uint32_t ctrl; + uint32_t tile_scram; + + uint32_t sw_mask_en; + uint32_t start_mask0; + uint32_t end_mask0; + uint32_t start_mask1; + uint32_t end_mask1; + + uint32_t data_addr; + uint32_t stride0; + uint32_t data1_addr; + uint32_t stride1; + + uint32_t stretch_stride; + uint32_t data_num; + + uint32_t ch_rd_shadow; + uint32_t ch_ctl; + uint32_t ch_secu_en; + uint32_t ch_sw_end_req; + + uint32_t dma_buf_ctrl; + uint32_t dma_buf_size; + + uint32_t rot_size; + + uint32_t afbce_hreg_pic_blks; + uint32_t afbce_hreg_format; + uint32_t afbce_hreg_hdr_ptr_lo; + uint32_t afbce_hreg_pld_ptr_lo; + uint32_t afbce_picture_size; + uint32_t afbce_ctl; + uint32_t afbce_header_srtide; + uint32_t afbce_payload_stride; + uint32_t afbce_enc_os_cfg; + uint32_t afbce_mem_ctrl; + uint32_t afbce_qos_cfg; + uint32_t afbce_threshold; + uint32_t afbce_scramble_mode; + uint32_t afbce_header_pointer_offset; + + uint8_t afbc_used; + uint8_t rot_used; +} dss_wdma_t; + +/******************************************************************************* + ** CE + +#define CE_HIST_RESET (0x00) +#define CE_HIST_CTL (0x04) +#define CE_HIST_FRAME_CNT (0x08) +#define CE_SIZE (0x0C) +#define CE_NO_STAT_LINES (0x10) +#define CE_BLACK_REGION_THRE (0x14) +#define CE_WHITE_REGION_THRE (0x18) +#define CE_LUT_SEL (0x1C) +#define CE_LUT_ENABLE (0x20) +#define CE_LUT_USING_IND (0x54) +#define CE_STATE_IND (0x58) +#define CE_MEM_CTRL (0x5C) + +#define CE_TOTALGRAY (0x30) +#define CE_TOTALPIXL (0x34) +#define CE_MEAN (0x38) +#define CE_PEC0_3 (0x3C) +#define CE_PEC4_7 (0x40) +#define CE_PEC8 (0x44) +#define CE_BLACK_NUM (0x48) +#define CE_WHITE_NUM (0x4C) +#define CE_HIST_RPT_IND (0x50) + +typedef struct dss_ce { +uint32_t hist_reset; +uint32_t hist_ctl; +uint32_t hist_frame_cnt; +uint32_t size; +uint32_t no_stat_lines; +uint32_t black_region_thre; +uint32_t white_region_thre; +uint32_t lut_sel; +uint32_t lut_enable; +uint32_t mem_ctrl; + +uint32_t totalgray; +uint32_t totalpixl; +uint32_t mean; +uint32_t pec0_3; +uint32_t pec4_7; +uint32_t pec8; +uint32_t black_num; +uint32_t white_num; +uint32_t hist_rpt_ind; +char __iomem *lut_base; +uint8_t *lut_table; +} dss_ce_t;*/ + +/******************************************************************************* + ** MCTL MUTEX0 1 2 3 4 5 + */ +#define MCTL_CTL_EN (0x0000) +#define MCTL_CTL_MUTEX (0x0004) +#define MCTL_CTL_MUTEX_STATUS (0x0008) +#define MCTL_CTL_MUTEX_ITF (0x000C) +#define MCTL_CTL_MUTEX_DBUF (0x0010) +#define MCTL_CTL_MUTEX_SCF (0x0014) +#define MCTL_CTL_MUTEX_OV (0x0018) +#define MCTL_CTL_MUTEX_WCH0 (0x0020) +#define MCTL_CTL_MUTEX_WCH1 (0x0024) +#define MCTL_CTL_MUTEX_WCH2 (0x0028) +#define MCTL_CTL_MUTEX_RCH8 (0x002C) +#define MCTL_CTL_MUTEX_RCH0 (0x0030) +#define MCTL_CTL_MUTEX_RCH1 (0x0034) +#define MCTL_CTL_MUTEX_RCH2 (0x0038) +#define MCTL_CTL_MUTEX_RCH3 (0x003C) +#define MCTL_CTL_MUTEX_RCH4 (0x0040) +#define MCTL_CTL_MUTEX_RCH5 (0x0044) +#define MCTL_CTL_MUTEX_RCH6 (0x0048) +#define MCTL_CTL_MUTEX_RCH7 (0x004C) +#define MCTL_CTL_TOP (0x0050) +#define MCTL_CTL_FLUSH_STATUS (0x0054) +#define MCTL_CTL_CLEAR (0x0058) +#define MCTL_CTL_CACK_TOUT (0x0060) +#define MCTL_CTL_MUTEX_TOUT (0x0064) +#define MCTL_CTL_STATUS (0x0068) +#define MCTL_CTL_INTEN (0x006C) +#define MCTL_CTL_SW_ST (0x0070) +#define MCTL_CTL_ST_SEL (0x0074) +#define MCTL_CTL_END_SEL (0x0078) +#define MCTL_CTL_CLK_SEL (0x0080) +#define MCTL_CTL_CLK_EN (0x0084) +#define MCTL_CTL_DBG (0x00E0) + +/******************************************************************************* + ** MCTL SYS + */ + +#define MCTL_CTL_SECU_CFG (0x0000) +#define MCTL_PAY_SECU_FLUSH_EN (0x0018) +#define MCTL_CTL_SECU_GATE0 (0x0080) +#define MCTL_CTL_SECU_GATE1 (0x0084) +#define MCTL_CTL_SECU_GATE2 (0x0088) +#define MCTL_DSI0_SECU_CFG_EN (0x00A0) +#define MCTL_DSI1_SECU_CFG_EN (0x00A4) + +#define MCTL_RCH0_FLUSH_EN (0x0100) +#define MCTL_RCH1_FLUSH_EN (0x0104) +#define MCTL_RCH2_FLUSH_EN (0x0108) +#define MCTL_RCH3_FLUSH_EN (0x010C) +#define MCTL_RCH4_FLUSH_EN (0x0110) +#define MCTL_RCH5_FLUSH_EN (0x0114) +#define MCTL_RCH6_FLUSH_EN (0x0118) +#define MCTL_RCH7_FLUSH_EN (0x011C) +#define MCTL_WCH0_FLUSH_EN (0x0120) +#define MCTL_WCH1_FLUSH_EN (0x0124) +#define MCTL_OV0_FLUSH_EN (0x0128) +#define MCTL_OV1_FLUSH_EN (0x012C) +#define MCTL_OV2_FLUSH_EN (0x0130) +#define MCTL_OV3_FLUSH_EN (0x0134) +#define MCTL_RCH8_FLUSH_EN (0x0138) +#define MCTL_WCH2_FLUSH_EN (0x013C) + +#define MCTL_RCH0_OV_OEN (0x0160) +#define MCTL_RCH1_OV_OEN (0x0164) +#define MCTL_RCH2_OV_OEN (0x0168) +#define MCTL_RCH3_OV_OEN (0x016C) +#define MCTL_RCH4_OV_OEN (0x0170) +#define MCTL_RCH5_OV_OEN (0x0174) +#define MCTL_RCH6_OV_OEN (0x0178) +#define MCTL_RCH7_OV_OEN (0x017C) + +#define MCTL_RCH_OV0_SEL (0x0180) +#define MCTL_RCH_OV1_SEL (0x0184) +#define MCTL_RCH_OV2_SEL (0x0188) +#define MCTL_RCH_OV3_SEL (0x018C) + +#define MCTL_WCH0_OV_IEN (0x01A0) +#define MCTL_WCH1_OV_IEN (0x01A4) + +#define MCTL_WCH_OV2_SEL (0x01A8) +#define MCTL_WCH_OV3_SEL (0x01AC) + +#define MCTL_WB_ENC_SEL (0x01B0) +#define MCTL_DSI_MUX_SEL (0x01B4) + +#define MCTL_RCH0_STARTY (0x01C0) +#define MCTL_RCH1_STARTY (0x01C4) +#define MCTL_RCH2_STARTY (0x01C8) +#define MCTL_RCH3_STARTY (0x01CC) +#define MCTL_RCH4_STARTY (0x01D0) +#define MCTL_RCH5_STARTY (0x01D4) +#define MCTL_RCH6_STARTY (0x01D8) +#define MCTL_RCH7_STARTY (0x01DC) + +#define MCTL_MCTL_CLK_SEL (0x01F0) +#define MCTL_MCTL_CLK_EN (0x01F4) +#define MCTL_MOD_CLK_SEL (0x01F8) +#define MCTL_MOD_CLK_EN (0x01FC) + +#define MCTL_MOD0_DBG (0x0200) +#define MCTL_MOD1_DBG (0x0204) +#define MCTL_MOD2_DBG (0x0208) +#define MCTL_MOD3_DBG (0x020C) +#define MCTL_MOD4_DBG (0x0210) +#define MCTL_MOD5_DBG (0x0214) +#define MCTL_MOD6_DBG (0x0218) +#define MCTL_MOD7_DBG (0x021C) +#define MCTL_MOD8_DBG (0x0220) +#define MCTL_MOD9_DBG (0x0224) +#define MCTL_MOD10_DBG (0x0228) +#define MCTL_MOD11_DBG (0x022C) +#define MCTL_MOD12_DBG (0x0230) +#define MCTL_MOD13_DBG (0x0234) +#define MCTL_MOD14_DBG (0x0238) +#define MCTL_MOD15_DBG (0x023C) +#define MCTL_MOD16_DBG (0x0240) +#define MCTL_MOD17_DBG (0x0244) +#define MCTL_MOD18_DBG (0x0248) +#define MCTL_MOD19_DBG (0x024C) +#define MCTL_MOD20_DBG (0x0250) +#define MCTL_MOD0_STATUS (0x0280) +#define MCTL_MOD1_STATUS (0x0284) +#define MCTL_MOD2_STATUS (0x0288) +#define MCTL_MOD3_STATUS (0x028C) +#define MCTL_MOD4_STATUS (0x0290) +#define MCTL_MOD5_STATUS (0x0294) +#define MCTL_MOD6_STATUS (0x0298) +#define MCTL_MOD7_STATUS (0x029C) +#define MCTL_MOD8_STATUS (0x02A0) +#define MCTL_MOD9_STATUS (0x02A4) +#define MCTL_MOD10_STATUS (0x02A8) +#define MCTL_MOD11_STATUS (0x02AC) +#define MCTL_MOD12_STATUS (0x02B0) +#define MCTL_MOD13_STATUS (0x02B4) +#define MCTL_MOD14_STATUS (0x02B8) +#define MCTL_MOD15_STATUS (0x02BC) +#define MCTL_MOD16_STATUS (0x02C0) +#define MCTL_MOD17_STATUS (0x02C4) +#define MCTL_MOD18_STATUS (0x02C8) +#define MCTL_MOD19_STATUS (0x02CC) +#define MCTL_MOD20_STATUS (0x02D0) +#define MCTL_SW_DBG (0x0300) +#define MCTL_SW0_STATUS0 (0x0304) +#define MCTL_SW0_STATUS1 (0x0308) +#define MCTL_SW0_STATUS2 (0x030C) +#define MCTL_SW0_STATUS3 (0x0310) +#define MCTL_SW0_STATUS4 (0x0314) +#define MCTL_SW0_STATUS5 (0x0318) +#define MCTL_SW0_STATUS6 (0x031C) +#define MCTL_SW0_STATUS7 (0x0320) +#define MCTL_SW1_STATUS (0x0324) + + +#define MCTL_MOD_DBG_CH_NUM (10) +#define MCTL_MOD_DBG_OV_NUM (4) +#define MCTL_MOD_DBG_DBUF_NUM (2) +#define MCTL_MOD_DBG_SCF_NUM (1) +#define MCTL_MOD_DBG_ITF_NUM (2) +#define MCTL_MOD_DBG_ADD_CH_NUM (2) + +enum dss_mctl_idx { + DSS_MCTL0 = 0, + DSS_MCTL1, + DSS_MCTL2, + DSS_MCTL3, + DSS_MCTL4, + DSS_MCTL5, + DSS_MCTL_IDX_MAX, +}; + +typedef struct dss_mctl { + uint32_t ctl_mutex_itf; + uint32_t ctl_mutex_dbuf; + uint32_t ctl_mutex_scf; + uint32_t ctl_mutex_ov; +} dss_mctl_t; + +typedef struct dss_mctl_ch_base { + char __iomem *chn_mutex_base; + char __iomem *chn_flush_en_base; + char __iomem *chn_ov_en_base; + char __iomem *chn_starty_base; + char __iomem *chn_mod_dbg_base; +} dss_mctl_ch_base_t; + +typedef struct dss_mctl_ch { + uint32_t chn_mutex; + uint32_t chn_flush_en; + uint32_t chn_ov_oen; + uint32_t chn_starty; + uint32_t chn_mod_dbg; +} dss_mctl_ch_t; + +typedef struct dss_mctl_sys { + uint32_t ov_flush_en[DSS_OVL_IDX_MAX]; + uint32_t chn_ov_sel[DSS_OVL_IDX_MAX]; + uint32_t wchn_ov_sel[DSS_WCH_MAX]; + uint8_t ov_flush_en_used[DSS_OVL_IDX_MAX]; + uint8_t chn_ov_sel_used[DSS_OVL_IDX_MAX]; + uint8_t wch_ov_sel_used[DSS_WCH_MAX]; +} dss_mctl_sys_t; + +/******************************************************************************* + ** OVL + */ +#define OVL_SIZE (0x0000) +#define OVL_BG_COLOR (0x4) +#define OVL_DST_STARTPOS (0x8) +#define OVL_DST_ENDPOS (0xC) +#define OVL_GCFG (0x10) +#define OVL_LAYER0_POS (0x14) +#define OVL_LAYER0_SIZE (0x18) +#define OVL_LAYER0_SRCLOKEY (0x1C) +#define OVL_LAYER0_SRCHIKEY (0x20) +#define OVL_LAYER0_DSTLOKEY (0x24) +#define OVL_LAYER0_DSTHIKEY (0x28) +#define OVL_LAYER0_PATTERN (0x2C) +#define OVL_LAYER0_ALPHA (0x30) +#define OVL_LAYER0_CFG (0x34) +#define OVL_LAYER0_INFO_ALPHA (0x40) +#define OVL_LAYER0_INFO_SRCCOLOR (0x44) +#define OVL_LAYER1_POS (0x50) +#define OVL_LAYER1_SIZE (0x54) +#define OVL_LAYER1_SRCLOKEY (0x58) +#define OVL_LAYER1_SRCHIKEY (0x5C) +#define OVL_LAYER1_DSTLOKEY (0x60) +#define OVL_LAYER1_DSTHIKEY (0x64) +#define OVL_LAYER1_PATTERN (0x68) +#define OVL_LAYER1_ALPHA (0x6C) +#define OVL_LAYER1_CFG (0x70) +#define OVL_LAYER1_INFO_ALPHA (0x7C) +#define OVL_LAYER1_INFO_SRCCOLOR (0x80) +#define OVL_LAYER2_POS (0x8C) +#define OVL_LAYER2_SIZE (0x90) +#define OVL_LAYER2_SRCLOKEY (0x94) +#define OVL_LAYER2_SRCHIKEY (0x98) +#define OVL_LAYER2_DSTLOKEY (0x9C) +#define OVL_LAYER2_DSTHIKEY (0xA0) +#define OVL_LAYER2_PATTERN (0xA4) +#define OVL_LAYER2_ALPHA (0xA8) +#define OVL_LAYER2_CFG (0xAC) +#define OVL_LAYER2_INFO_ALPHA (0xB8) +#define OVL_LAYER2_INFO_SRCCOLOR (0xBC) +#define OVL_LAYER3_POS (0xC8) +#define OVL_LAYER3_SIZE (0xCC) +#define OVL_LAYER3_SRCLOKEY (0xD0) +#define OVL_LAYER3_SRCHIKEY (0xD4) +#define OVL_LAYER3_DSTLOKEY (0xD8) +#define OVL_LAYER3_DSTHIKEY (0xDC) +#define OVL_LAYER3_PATTERN (0xE0) +#define OVL_LAYER3_ALPHA (0xE4) +#define OVL_LAYER3_CFG (0xE8) +#define OVL_LAYER3_INFO_ALPHA (0xF4) +#define OVL_LAYER3_INFO_SRCCOLOR (0xF8) +#define OVL_LAYER4_POS (0x104) +#define OVL_LAYER4_SIZE (0x108) +#define OVL_LAYER4_SRCLOKEY (0x10C) +#define OVL_LAYER4_SRCHIKEY (0x110) +#define OVL_LAYER4_DSTLOKEY (0x114) +#define OVL_LAYER4_DSTHIKEY (0x118) +#define OVL_LAYER4_PATTERN (0x11C) +#define OVL_LAYER4_ALPHA (0x120) +#define OVL_LAYER4_CFG (0x124) +#define OVL_LAYER4_INFO_ALPHA (0x130) +#define OVL_LAYER4_INFO_SRCCOLOR (0x134) +#define OVL_LAYER5_POS (0x140) +#define OVL_LAYER5_SIZE (0x144) +#define OVL_LAYER5_SRCLOKEY (0x148) +#define OVL_LAYER5_SRCHIKEY (0x14C) +#define OVL_LAYER5_DSTLOKEY (0x150) +#define OVL_LAYER5_DSTHIKEY (0x154) +#define OVL_LAYER5_PATTERN (0x158) +#define OVL_LAYER5_ALPHA (0x15C) +#define OVL_LAYER5_CFG (0x160) +#define OVL_LAYER5_INFO_ALPHA (0x16C) +#define OVL_LAYER5_INFO_SRCCOLOR (0x170) +#define OVL_LAYER6_POS (0x14) +#define OVL_LAYER6_SIZE (0x18) +#define OVL_LAYER6_SRCLOKEY (0x1C) +#define OVL_LAYER6_SRCHIKEY (0x20) +#define OVL_LAYER6_DSTLOKEY (0x24) +#define OVL_LAYER6_DSTHIKEY (0x28) +#define OVL_LAYER6_PATTERN (0x2C) +#define OVL_LAYER6_ALPHA (0x30) +#define OVL_LAYER6_CFG (0x34) +#define OVL_LAYER6_INFO_ALPHA (0x40) +#define OVL_LAYER6_INFO_SRCCOLOR (0x44) +#define OVL_LAYER7_POS (0x50) +#define OVL_LAYER7_SIZE (0x54) +#define OVL_LAYER7_SRCLOKEY (0x58) +#define OVL_LAYER7_SRCHIKEY (0x5C) +#define OVL_LAYER7_DSTLOKEY (0x60) +#define OVL_LAYER7_DSTHIKEY (0x64) +#define OVL_LAYER7_PATTERN (0x68) +#define OVL_LAYER7_ALPHA (0x6C) +#define OVL_LAYER7_CFG (0x70) +#define OVL_LAYER7_INFO_ALPHA (0x7C) +#define OVL_LAYER7_INFO_SRCCOLOR (0x80) +#define OVL_LAYER0_ST_INFO (0x48) +#define OVL_LAYER1_ST_INFO (0x84) +#define OVL_LAYER2_ST_INFO (0xC0) +#define OVL_LAYER3_ST_INFO (0xFC) +#define OVL_LAYER4_ST_INFO (0x138) +#define OVL_LAYER5_ST_INFO (0x174) +#define OVL_LAYER6_ST_INFO (0x48) +#define OVL_LAYER7_ST_INFO (0x84) +#define OVL_LAYER0_IST_INFO (0x4C) +#define OVL_LAYER1_IST_INFO (0x88) +#define OVL_LAYER2_IST_INFO (0xC4) +#define OVL_LAYER3_IST_INFO (0x100) +#define OVL_LAYER4_IST_INFO (0x13C) +#define OVL_LAYER5_IST_INFO (0x178) +#define OVL_LAYER6_IST_INFO (0x4C) +#define OVL_LAYER7_IST_INFO (0x88) +#define OVL_LAYER0_PSPOS (0x38) +#define OVL_LAYER0_PEPOS (0x3C) +#define OVL_LAYER1_PSPOS (0x74) +#define OVL_LAYER1_PEPOS (0x78) +#define OVL_LAYER2_PSPOS (0xB0) +#define OVL_LAYER2_PEPOS (0xB4) +#define OVL_LAYER3_PSPOS (0xEC) +#define OVL_LAYER3_PEPOS (0xF0) +#define OVL_LAYER4_PSPOS (0x128) +#define OVL_LAYER4_PEPOS (0x12C) +#define OVL_LAYER5_PSPOS (0x164) +#define OVL_LAYER5_PEPOS (0x168) +#define OVL_LAYER6_PSPOS (0x38) +#define OVL_LAYER6_PEPOS (0x3C) +#define OVL_LAYER7_PSPOS (0x74) +#define OVL_LAYER7_PEPOS (0x78) + +#define OVL6_BASE_ST_INFO (0x17C) +#define OVL6_BASE_IST_INFO (0x180) +#define OVL6_GATE_CTRL (0x184) +#define OVL6_RD_SHADOW_SEL (0x188) +#define OVL6_OV_CLK_SEL (0x18C) +#define OVL6_OV_CLK_EN (0x190) +#define OVL6_BLOCK_SIZE (0x1A0) +#define OVL6_BLOCK_DBG (0x1A4) +#define OVL6_REG_DEFAULT (0x1A8) + +#define OVL2_BASE_ST_INFO (0x8C) +#define OVL2_BASE_IST_INFO (0x90) +#define OVL2_GATE_CTRL (0x94) +#define OVL2_OV_RD_SHADOW_SEL (0x98) +#define OVL2_OV_CLK_SEL (0x9C) +#define OVL2_OV_CLK_EN (0xA0) +#define OVL2_BLOCK_SIZE (0xB0) +#define OVL2_BLOCK_DBG (0xB4) +#define OVL2_REG_DEFAULT (0xB8) + +/* LAYER0_CFG */ +#define BIT_OVL_LAYER_SRC_CFG BIT(8) +#define BIT_OVL_LAYER_ENABLE BIT(0) + +/* LAYER0_INFO_ALPHA */ +#define BIT_OVL_LAYER_SRCALPHA_FLAG BIT(3) +#define BIT_OVL_LAYER_DSTALPHA_FLAG BIT(2) + +/* LAYER0_INFO_SRCCOLOR */ +#define BIT_OVL_LAYER_SRCCOLOR_FLAG BIT(0) + +#define OVL_6LAYER_NUM (6) +#define OVL_2LAYER_NUM (2) + +typedef struct dss_ovl_layer { + uint32_t layer_pos; + uint32_t layer_size; + uint32_t layer_pattern; + uint32_t layer_alpha; + uint32_t layer_cfg; + +} dss_ovl_layer_t; + +typedef struct dss_ovl_layer_pos { + uint32_t layer_pspos; + uint32_t layer_pepos; + +} dss_ovl_layer_pos_t; + +typedef struct dss_ovl { + uint32_t ovl_size; + uint32_t ovl_bg_color; + uint32_t ovl_dst_startpos; + uint32_t ovl_dst_endpos; + uint32_t ovl_gcfg; + uint32_t ovl_block_size; + dss_ovl_layer_t ovl_layer[OVL_6LAYER_NUM]; + dss_ovl_layer_pos_t ovl_layer_pos[OVL_6LAYER_NUM]; + uint8_t ovl_layer_used[OVL_6LAYER_NUM]; +} dss_ovl_t; + +typedef struct dss_ovl_alpha { + uint32_t src_amode; + uint32_t src_gmode; + uint32_t alpha_offsrc; + uint32_t src_lmode; + uint32_t src_pmode; + + uint32_t alpha_smode; + + uint32_t dst_amode; + uint32_t dst_gmode; + uint32_t alpha_offdst; + uint32_t dst_pmode; + + uint32_t fix_mode; +} dss_ovl_alpha_t; + +/******************************************************************************* + ** DBUF + */ +#define DBUF_FRM_SIZE (0x0000) +#define DBUF_FRM_HSIZE (0x0004) +#define DBUF_SRAM_VALID_NUM (0x0008) +#define DBUF_WBE_EN (0x000C) +#define DBUF_THD_FILL_LEV0 (0x0010) +#define DBUF_DFS_FILL_LEV1 (0x0014) +#define DBUF_THD_RQOS (0x0018) +#define DBUF_THD_WQOS (0x001C) +#define DBUF_THD_CG (0x0020) +#define DBUF_THD_OTHER (0x0024) +#define DBUF_FILL_LEV0_CNT (0x0028) +#define DBUF_FILL_LEV1_CNT (0x002C) +#define DBUF_FILL_LEV2_CNT (0x0030) +#define DBUF_FILL_LEV3_CNT (0x0034) +#define DBUF_FILL_LEV4_CNT (0x0038) +#define DBUF_ONLINE_FILL_LEVEL (0x003C) +#define DBUF_WB_FILL_LEVEL (0x0040) +#define DBUF_DFS_STATUS (0x0044) +#define DBUF_THD_FLUX_REQ_BEF (0x0048) +#define DBUF_DFS_LP_CTRL (0x004C) +#define DBUF_RD_SHADOW_SEL (0x0050) +#define DBUF_MEM_CTRL (0x0054) +#define DBUF_PM_CTRL (0x0058) +#define DBUF_CLK_SEL (0x005C) +#define DBUF_CLK_EN (0x0060) +#define DBUF_THD_FLUX_REQ_AFT (0x0064) +#define DBUF_THD_DFS_OK (0x0068) +#define DBUF_FLUX_REQ_CTRL (0x006C) +#define DBUF_REG_DEFAULT (0x00A4) + +/******************************************************************************* + ** SBL + */ + +#define SBL_REG_FRMT_MODE (0x0000) +#define SBL_REG_FRMT_DBUF_CTRL (0x0008) +#define SBL_REG_FRMT_FRAME_WIDTH_7_TO_0 (0x0010) +#define SBL_REG_FRMT_FRAME_WIDTH_15_TO_8 (0x0014) +#define SBL_REG_FRMT_FRAME_HEIGHT_7_TO_0 (0x0018) +#define SBL_REG_FRMT_FRAME_HEIGHT_15_TO_8 (0x001c) +#define SBL_REG_FRMT_ROI_HOR_START_7_TO_0 (0x0080) +#define SBL_REG_FRMT_ROI_HOR_START_15_TO_8 (0x0084) +#define SBL_REG_FRMT_ROI_HOR_END_7_TO_0 (0x0088) +#define SBL_REG_FRMT_ROI_HOR_END_15_TO_8 (0x008c) +#define SBL_REG_FRMT_ROI_VER_START_7_TO_0 (0x0090) +#define SBL_REG_FRMT_ROI_VER_START_15_TO_8 (0x0094) +#define SBL_REG_FRMT_ROI_VER_END_7_TO_0 (0x0098) +#define SBL_REG_FRMT_ROI_VER_END_15_TO_8 (0x009c) +#define SBL_REG_CALC_CONTROL_0 (0x0400) +#define SBL_REG_CALC_CONTROL_1 (0x0404) +#define SBL_REG_CALC_AMBIENT_LIGHT_7_TO_0 (0x0408) +#define SBL_REG_CALC_AMBIENT_LIGHT_15_TO_8 (0x040c) +#define SBL_REG_CALC_BACKLIGHT_7_TO_0 (0x0410) +#define SBL_REG_CALC_BACKLIGHT_15_TO_8 (0x0414) +#define SBL_REG_CALC_ASSERTIVENESS (0x0418) +#define SBL_REG_CALC_TF_CONTROL (0x041c) +#define SBL_REG_CALC_STRENGTH_MANUAL_7_TO_0 (0x0420) +#define SBL_REG_CALC_STRENGTH_MANUAL_9_TO_8 (0x0424) +#define SBL_REG_CALC_GAIN_AA_MANUAL_7_TO_0 (0x0428) +#define SBL_REG_CALC_GAIN_AA_MANUAL_11_TO_8 (0x042c) +#define SBL_REG_CALC_ROI_FACTOR_IN_7_TO_0 (0x0430) +#define SBL_REG_CALC_ROI_FACTOR_IN_15_TO_8 (0x0434) +#define SBL_REG_CALC_ROI_FACTOR_OUT_7_TO_0 (0x0438) +#define SBL_REG_CALC_ROI_FACTOR_OUT_15_TO_8 (0x043c) +#define SBL_REG_CALC_PSR_DELTA_CHANGE_7_TO_0 (0x0448) +#define SBL_REG_CALC_PSR_DELTA_CHANGE_15_TO_8 (0x044c) +#define SBL_REG_CALC_PSR_DELTA_SETTLE_7_TO_0 (0x0450) +#define SBL_REG_CALC_PSR_DELTA_SETTLE_15_TO_8 (0x0454) +#define SBL_REG_CALC_AL_SCALE_7_TO_0 (0x0458) +#define SBL_REG_CALC_AL_SCALE_15_TO_8 (0x045c) +#define SBL_REG_CALC_AL_TF_STEP_SAMPLE (0x0460) +#define SBL_REG_CALC_AL_TF_STEP_WAIT_7_TO_0 (0x0468) +#define SBL_REG_CALC_AL_TF_STEP_WAIT_11_TO_8 (0x046c) +#define SBL_REG_CALC_AL_TF_STEP_WAITUP_7_TO_0 (0x0470) +#define SBL_REG_CALC_AL_TF_STEP_WAITUP_11_TO_8 (0x0474) +#define SBL_REG_CALC_AL_TF_STEP_SIZE_7_TO_0 (0x0478) +#define SBL_REG_CALC_AL_TF_STEP_SIZE_11_TO_8 (0x047c) +#define SBL_REG_CALC_AL_TF_LIMIT_7_TO_0 (0x0480) +#define SBL_REG_CALC_AL_TF_LIMIT_15_TO_8 (0x0484) +#define SBL_REG_CALC_AL_TF_ALPHA (0x0488) +#define SBL_REG_CALC_AL_TF_ALPHA_UP (0x048c) +#define SBL_REG_CALC_AL_TF_NOISE_7_TO_0 (0x0490) +#define SBL_REG_CALC_AL_TF_NOISE_15_TO_8 (0x0494) +#define SBL_REG_CALC_AL_TF_M_INC_7_TO_0 (0x0498) +#define SBL_REG_CALC_AL_TF_M_INC_15_TO_8 (0x049c) +#define SBL_REG_CALC_AL_TF_K_INC_7_TO_0 (0x04a0) +#define SBL_REG_CALC_AL_TF_K_INC_15_TO_8 (0x04a4) +#define SBL_REG_CALC_AL_TF_M_DEC_7_TO_0 (0x04a8) +#define SBL_REG_CALC_AL_TF_M_DEC_15_TO_8 (0x04ac) +#define SBL_REG_CALC_AL_TF_K_DEC_7_TO_0 (0x04b0) +#define SBL_REG_CALC_AL_TF_K_DEC_15_TO_8 (0x04b4) +#define SBL_REG_CALC_AL_TF_AGGRESSIVENESS (0x04b8) +#define SBL_REG_CALC_AL_RTF_FILTER_A_7_TO_0 (0x04c0) +#define SBL_REG_CALC_AL_RTF_FILTER_A_15_TO_8 (0x04c4) +#define SBL_REG_CALC_AL_RTF_FILTER_B_7_TO_0 (0x04c8) +#define SBL_REG_CALC_AL_RTF_FILTER_B_15_TO_8 (0x04cc) +#define SBL_REG_CALC_AL_RTF_FILTER_C_7_TO_0 (0x04d0) +#define SBL_REG_CALC_AL_RTF_FILTER_C_15_TO_8 (0x04d4) +#define SBL_REG_CALC_AB_AL_KNEE1_7_TO_0 (0x04d8) +#define SBL_REG_CALC_AB_AL_KNEE1_15_TO_8 (0x04dc) +#define SBL_REG_CALC_AB_AL_KNEE2_7_TO_0 (0x04e0) +#define SBL_REG_CALC_AB_AL_KNEE2_15_TO_8 (0x04e4) +#define SBL_REG_CALC_AB_BL_KNEE1_7_TO_0 (0x04e8) +#define SBL_REG_CALC_AB_BL_KNEE1_15_TO_8 (0x04ec) +#define SBL_REG_CALC_AB_BL_KNEE2_7_TO_0 (0x04f0) +#define SBL_REG_CALC_AB_BL_KNEE2_15_TO_8 (0x04f4) +#define SBL_REG_CALC_BL_PANEL_MAX_7_TO_0 (0x04f8) +#define SBL_REG_CALC_BL_PANEL_MAX_15_TO_8 (0x04fc) +#define SBL_REG_CALC_BL_OFFSET_7_TO_0 (0x0500) +#define SBL_REG_CALC_BL_OFFSET_15_TO_8 (0x0504) +#define SBL_REG_CALC_BL_MIN_7_TO_0 (0x0508) +#define SBL_REG_CALC_BL_MIN_15_TO_8 (0x050c) +#define SBL_REG_CALC_BL_ATTEN_ALPHA_7_TO_0 (0x0510) +#define SBL_REG_CALC_BL_ATTEN_ALPHA_9_TO_8 (0x0514) +#define SBL_REG_CALC_SBC1_TF_DEPTH_7_TO_0 (0x0518) +#define SBL_REG_CALC_SBC1_TF_DEPTH_15_TO_8 (0x051c) +#define SBL_REG_CALC_SBC1_TF_STEP_7_TO_0 (0x0520) +#define SBL_REG_CALC_SBC1_TF_STEP_15_TO_8 (0x0524) +#define SBL_REG_CALC_SBC1_TF_ASYM (0x0528) +#define SBL_REG_CALC_SBC1_TF_DEPTH_LOG_7_TO_0 (0x0530) +#define SBL_REG_CALC_SBC1_TF_DEPTH_LOG_15_TO_8 (0x0534) +#define SBL_REG_CALC_SBC1_TF_STEP_LOG_7_TO_0 (0x0538) +#define SBL_REG_CALC_SBC1_TF_STEP_LOG_15_TO_8 (0x053c) +#define SBL_REG_CALC_SBC1_TF_ASYM_LOG (0x0540) +#define SBL_REG_CALC_SBC2_TF_DEPTH_7_TO_0 (0x0548) +#define SBL_REG_CALC_SBC2_TF_DEPTH_15_TO_8 (0x054c) +#define SBL_REG_CALC_SBC2_TF_STEP_7_TO_0 (0x0550) +#define SBL_REG_CALC_SBC2_TF_STEP_15_TO_8 (0x0554) +#define SBL_REG_CALC_SBC2_TF_ASYM (0x0558) +#define SBL_REG_CALC_SBC2_TF_DEPTH_LOG_7_TO_0 (0x0560) +#define SBL_REG_CALC_SBC2_TF_DEPTH_LOG_15_TO_8 (0x0564) +#define SBL_REG_CALC_SBC2_TF_STEP_LOG_7_TO_0 (0x0568) +#define SBL_REG_CALC_SBC2_TF_STEP_LOG_15_TO_8 (0x056c) +#define SBL_REG_CALC_SBC2_TF_ASYM_LOG (0x0570) +#define SBL_REG_CALC_CALIBRATION_A_7_TO_0 (0x05b8) +#define SBL_REG_CALC_CALIBRATION_A_15_TO_8 (0x05bc) +#define SBL_REG_CALC_CALIBRATION_B_7_TO_0 (0x05c0) +#define SBL_REG_CALC_CALIBRATION_B_15_TO_8 (0x05c4) +#define SBL_REG_CALC_CALIBRATION_C_7_TO_0 (0x05c8) +#define SBL_REG_CALC_CALIBRATION_C_15_TO_8 (0x05cc) +#define SBL_REG_CALC_CALIBRATION_D_7_TO_0 (0x05d0) +#define SBL_REG_CALC_CALIBRATION_D_15_TO_8 (0x05d4) +#define SBL_REG_CALC_CALIBRATION_E_7_TO_0 (0x05d8) +#define SBL_REG_CALC_CALIBRATION_E_15_TO_8 (0x05dc) +#define SBL_REG_CALC_BACKLIGHT_SCALE_7_TO_0 (0x05e0) +#define SBL_REG_CALC_BACKLIGHT_SCALE_15_TO_8 (0x05e4) +#define SBL_REG_CALC_GAIN_AA_TF_DEPTH_7_TO_0 (0x05e8) +#define SBL_REG_CALC_GAIN_AA_TF_DEPTH_15_TO_8 (0x05ec) +#define SBL_REG_CALC_GAIN_AA_TF_STEP_7_TO_0 (0x05f0) +#define SBL_REG_CALC_GAIN_AA_TF_STEP_11_TO_8 (0x05f4) +#define SBL_REG_CALC_GAIN_AA_TF_ASYM (0x05f8) +#define SBL_REG_CALC_STRENGTH_LIMIT_7_TO_0 (0x0600) +#define SBL_REG_CALC_STRENGTH_LIMIT_9_TO_8 (0x0604) +#define SBL_REG_CALC_ICUT_HIST_MIN (0x0608) +#define SBL_REG_CALC_ICUT_BL_MIN_7_TO_0 (0x0610) +#define SBL_REG_CALC_ICUT_BL_MIN_15_TO_8 (0x0614) +#define SBL_REG_CALC_GAIN_CA_TF_DEPTH_7_TO_0 (0x0618) +#define SBL_REG_CALC_GAIN_CA_TF_DEPTH_15_TO_8 (0x061c) +#define SBL_REG_CALC_GAIN_CA_TF_STEP_7_TO_0 (0x0620) +#define SBL_REG_CALC_GAIN_CA_TF_STEP_11_TO_8 (0x0624) +#define SBL_REG_CALC_GAIN_CA_TF_ASYM (0x0628) +#define SBL_REG_CALC_GAIN_MAX_7_TO_0 (0x0630) +#define SBL_REG_CALC_GAIN_MAX_11_TO_8 (0x0634) +#define SBL_REG_CALC_GAIN_MIDDLE_7_TO_0 (0x0638) +#define SBL_REG_CALC_GAIN_MIDDLE_11_TO_8 (0x063c) +#define SBL_REG_CALC_BRIGHTPR (0x0640) +#define SBL_REG_CALC_BPR_CORRECT (0x0648) +#define SBL_CALC_BACKLIGHT_OUT_7_TO_0 (0x0650) +#define SBL_CALC_BACKLIGHT_OUT_15_TO_8 (0x0654) +#define SBL_CALC_STRENGTH_INROI_OUT_7_TO_0 (0x0658) +#define SBL_CALC_STRENGTH_INROI_OUT_9_TO_8 (0x065c) +#define SBL_CALC_STRENGTH_OUTROI_OUT_7_TO_0 (0x0660) +#define SBL_CALC_STRENGTH_OUTROI_OUT_9_TO_8 (0x0664) +#define SBL_CALC_DARKENH_OUT_7_TO_0 (0x0668) +#define SBL_CALC_DARKENH_OUT_15_TO_8 (0x066c) +#define SBL_CALC_BRIGHTPR_OUT (0x0670) +#define SBL_CALC_STAT_OUT_7_TO_0 (0x0678) +#define SBL_CALC_STAT_OUT_15_TO_8 (0x067c) +#define SBL_REG_CALC_AL_DELTA_SETTLE_7_TO_0 (0x0680) +#define SBL_REG_CALC_AL_DELTA_SETTLE_15_TO_8 (0x0684) +#define SBL_REG_CALC_BL_DELTA_SETTLE_7_TO_0 (0x0688) +#define SBL_REG_CALC_BL_DELTA_SETTLE_15_TO_8 (0x068c) +#define SBL_CALC_AL_CALIB_LUT_ADDR_I (0x06c0) +#define SBL_CALC_AL_CALIB_LUT_DATA_W_7_TO_0 (0x06d0) +#define SBL_CALC_AL_CALIB_LUT_DATA_W_15_TO_8 (0x06d4) +#define SBL_CALC_BL_IN_LUT_ADDR_I (0x0700) +#define SBL_CALC_BL_IN_LUT_DATA_W_7_TO_0 (0x0710) +#define SBL_CALC_BL_IN_LUT_DATA_W_15_TO_8 (0x0714) +#define SBL_CALC_BL_OUT_LUT_ADDR_I (0x0740) +#define SBL_CALC_BL_OUT_LUT_DATA_W_7_TO_0 (0x0750) +#define SBL_CALC_BL_OUT_LUT_DATA_W_15_TO_8 (0x0754) +#define SBL_CALC_BL_ATTEN_LUT_ADDR_I (0x0780) +#define SBL_CALC_BL_ATTEN_LUT_DATA_W_7_TO_0 (0x0790) +#define SBL_CALC_BL_ATTEN_LUT_DATA_W_15_TO_8 (0x0794) +#define SBL_CALC_BL_AUTO_LUT_ADDR_I (0x07c0) +#define SBL_CALC_BL_AUTO_LUT_DATA_W_7_TO_0 (0x07d0) +#define SBL_CALC_BL_AUTO_LUT_DATA_W_15_TO_8 (0x07d4) +#define SBL_CALC_AL_CHANGE_LUT_ADDR_I (0x0800) +#define SBL_CALC_AL_CHANGE_LUT_DATA_W_7_TO_0 (0x0810) +#define SBL_CALC_AL_CHANGE_LUT_DATA_W_15_TO_8 (0x0814) +#define SBL_REG_CABC_INTENSITY_7_TO_0 (0x0900) +#define SBL_REG_CABC_INTENSITY_11_TO_8 (0x0904) +#define SBL_REG_CABC_ICUT_SELECT (0x0908) +#define SBL_REG_CABC_ICUT_MANUAL (0x090c) +#define SBL_CABC_ICUT_OUT (0x0910) +#define SBL_REG_CORE1_VC_CONTROL_0 (0x0c00) +#define SBL_REG_CORE1_IRDX_CONTROL_0 (0x0c40) +#define SBL_REG_CORE1_IRDX_CONTROL_1 (0x0c44) +#define SBL_REG_CORE1_IRDX_VARIANCE (0x0c4c) +#define SBL_REG_CORE1_IRDX_SLOPE_MAX (0x0c50) +#define SBL_REG_CORE1_IRDX_SLOPE_MIN (0x0c54) +#define SBL_REG_CORE1_IRDX_BLACK_LEVEL_7_TO_0 (0x0c58) +#define SBL_REG_CORE1_IRDX_BLACK_LEVEL_9_TO_8 (0x0c5c) +#define SBL_REG_CORE1_IRDX_WHITE_LEVEL_7_TO_0 (0x0c60) +#define SBL_REG_CORE1_IRDX_WHITE_LEVEL_9_TO_8 (0x0c64) +#define SBL_REG_CORE1_IRDX_LIMIT_AMPL (0x0c68) +#define SBL_REG_CORE1_IRDX_DITHER (0x0c6c) +#define SBL_REG_CORE1_IRDX_STRENGTH_INROI_7_TO_0 (0x0c70) +#define SBL_REG_CORE1_IRDX_STRENGTH_INROI_9_TO_8 (0x0c74) +#define SBL_REG_CORE1_IRDX_STRENGTH_OUTROI_7_TO_0 (0x0c78) +#define SBL_REG_CORE1_IRDX_STRENGTH_OUTROI_9_TO_8 (0x0c7c) +#define SBL_CORE1_IRDX_ASYMMETRY_LUT_ADDR_I (0x0c80) +#define SBL_CORE1_IRDX_ASYMMETRY_LUT_DATA_W_7_TO_0 (0x0c84) +#define SBL_CORE1_IRDX_ASYMMETRY_LUT_DATA_W_11_TO_8 (0x0c88) +#define SBL_CORE1_IRDX_COLOR_LUT_ADDR_I (0x0cc0) +#define SBL_CORE1_IRDX_COLOR_LUT_DATA_W_7_TO_0 (0x0cc4) +#define SBL_CORE1_IRDX_COLOR_LUT_DATA_W_11_TO_8 (0x0cc8) +#define SBL_REG_CORE1_IRDX_FILTER_CTRL (0x0d00) +#define SBL_REG_CORE1_IRDX_SVARIANCE (0x0d04) +#define SBL_REG_CORE1_IRDX_BRIGHTPR (0x0d08) +#define SBL_REG_CORE1_IRDX_CONTRAST (0x0d0c) +#define SBL_REG_CORE1_IRDX_DARKENH_7_TO_0 (0x0d10) +#define SBL_REG_CORE1_IRDX_DARKENH_15_TO_8 (0x0d14) +#define SBL_REG_CORE1_DTHR_CONTROL (0x0dc0) +#define SBL_REG_CORE1_LOGO_TOP (0x0dd0) +#define SBL_REG_CORE1_LOGO_LEFT (0x0dd4) +#define SBL_REG_CORE1_CA_D_ARTITHRESH_7_TO_0 (0x0e00) +#define SBL_REG_CORE1_CA_D_ARTITHRESH_9_TO_8 (0x0e04) +#define SBL_CORE1_CA_STR_ATTEN_7_TO_0 (0x0e10) +#define SBL_CORE1_CA_STR_ATTEN_15_TO_8 (0x0e14) +#define SBL_CORE1_CA_STR_ATTEN_16 (0x0e18) +#define SBL_REG_CORE1_FRD_D_THRESH_7_TO_0 (0x0e20) +#define SBL_REG_CORE1_FRD_D_THRESH_9_TO_8 (0x0e24) +#define SBL_REG_CORE1_REG0_7_TO_0 (0x0e28) +#define SBL_REG_CORE1_REG0_15_TO_8 (0x0e2c) +#define SBL_REG_CORE1_REG1_7_TO_0 (0x0e30) +#define SBL_REG_CORE1_REG1_15_TO_8 (0x0e34) +#define SBL_REG_CORE1_REG2_7_TO_0 (0x0e38) +#define SBL_REG_CORE1_REG2_15_TO_8 (0x0e3c) +#define SBL_REG_CORE1_REG3_7_TO_0 (0x0e40) +#define SBL_REG_CORE1_REG3_15_TO_8 (0x0e44) +#define SBL_REG_CORE1_REG4_7_TO_0 (0x0e48) +#define SBL_REG_CORE1_REG4_15_TO_8 (0x0e4c) +#define SBL_REG_CORE1_REG5_7_TO_0 (0x0e50) +#define SBL_REG_CORE1_REG5_15_TO_8 (0x0e54) +#define SBL_CORE1_REG_OUT0_7_TO_0 (0x0e58) +#define SBL_CORE1_REG_OUT0_15_TO_8 (0x0e5c) +#define SBL_CORE1_REG_OUT1_7_TO_0 (0x0e60) +#define SBL_CORE1_REG_OUT1_15_TO_8 (0x0e64) + +typedef struct dss_sbl { + int sbl_backlight_l; + int sbl_backlight_h; + int sbl_ambient_light_l; + int sbl_ambient_light_h; + int sbl_calibration_a_l; + int sbl_calibration_a_h; + int sbl_calibration_b_l; + int sbl_calibration_b_h; + int sbl_calibration_c_l; + int sbl_calibration_c_h; + int sbl_calibration_d_l; + int sbl_calibration_d_h; + int sbl_enable; +} dss_sbl_t; + +/******************************************************************************* + ** DPP + */ + +#define DPP_RD_SHADOW_SEL (0x000) +#define DPP_DEFAULT (0x004) +#define DPP_ID (0x008) +#define DPP_IMG_SIZE_BEF_SR (0x00C) +#define DPP_IMG_SIZE_AFT_SR (0x010) +#define DPP_SBL (0x014) +#define DPP_SBL_MEM_CTRL (0x018) +#define DPP_ARSR1P_MEM_CTRL (0x01C) +#define DPP_CLK_SEL (0x020) +#define DPP_CLK_EN (0x024) +#define DPP_DBG1_CNT (0x028) +#define DPP_DBG2_CNT (0x02C) +#define DPP_DBG1 (0x030) +#define DPP_DBG2 (0x034) +#define DPP_DBG3 (0x038) +#define DPP_DBG4 (0x03C) +#define DPP_INTS (0x040) +#define DPP_INT_MSK (0x044) +#define DPP_ARSR1P (0x048) +#define DPP_DBG_CNT DPP_DBG1_CNT + + +#define DPP_CLRBAR_CTRL (0x100) +#define DPP_CLRBAR_1ST_CLR (0x104) +#define DPP_CLRBAR_2ND_CLR (0x108) +#define DPP_CLRBAR_3RD_CLR (0x10C) + + +#define DPP_CLIP_TOP (0x180) +#define DPP_CLIP_BOTTOM (0x184) +#define DPP_CLIP_LEFT (0x188) +#define DPP_CLIP_RIGHT (0x18C) +#define DPP_CLIP_EN (0x190) +#define DPP_CLIP_DBG (0x194) + + +#define DITHER_PARA (0x000) +#define DITHER_CTL (0x004) +#define DITHER_MATRIX_PART1 (0x008) +#define DITHER_MATRIX_PART0 (0x00C) +#define DITHER_ERRDIFF_WEIGHT (0x010) +#define DITHER_FRC_01_PART1 (0x014) +#define DITHER_FRC_01_PART0 (0x018) +#define DITHER_FRC_10_PART1 (0x01C) +#define DITHER_FRC_10_PART0 (0x020) +#define DITHER_FRC_11_PART1 (0x024) +#define DITHER_FRC_11_PART0 (0x028) +#define DITHER_MEM_CTRL (0x02C) +#define DITHER_DBG0 (0x030) +#define DITHER_DBG1 (0x034) +#define DITHER_DBG2 (0x038) + + +#define CSC10B_IDC0 (0x000) +#define CSC10B_IDC1 (0x004) +#define CSC10B_IDC2 (0x008) +#define CSC10B_ODC0 (0x00C) +#define CSC10B_ODC1 (0x010) +#define CSC10B_ODC2 (0x014) +#define CSC10B_P00 (0x018) +#define CSC10B_P01 (0x01C) +#define CSC10B_P02 (0x020) +#define CSC10B_P10 (0x024) +#define CSC10B_P11 (0x028) +#define CSC10B_P12 (0x02C) +#define CSC10B_P20 (0x030) +#define CSC10B_P21 (0x034) +#define CSC10B_P22 (0x038) +#define CSC10B_MODULE_EN (0x03C) +#define CSC10B_MPREC (0x040) + + +#define GAMA_EN (0x000) +#define GAMA_MEM_CTRL (0x004) + + +#define ACM_EN (0x000) +#define ACM_SATA_OFFSET (0x004) +#define ACM_HUESEL (0x008) +#define ACM_CSC_IDC0 (0x00C) +#define ACM_CSC_IDC1 (0x010) +#define ACM_CSC_IDC2 (0x014) +#define ACM_CSC_P00 (0x018) +#define ACM_CSC_P01 (0x01C) +#define ACM_CSC_P02 (0x020) +#define ACM_CSC_P10 (0x024) +#define ACM_CSC_P11 (0x028) +#define ACM_CSC_P12 (0x02C) +#define ACM_CSC_P20 (0x030) +#define ACM_CSC_P21 (0x034) +#define ACM_CSC_P22 (0x038) +#define ACM_CSC_MRREC (0x03C) +#define ACM_R0_H (0x040) +#define ACM_R1_H (0x044) +#define ACM_R2_H (0x048) +#define ACM_R3_H (0x04C) +#define ACM_R4_H (0x050) +#define ACM_R5_H (0x054) +#define ACM_R6_H (0x058) +#define ACM_LUT_DIS0 (0x05C) +#define ACM_LUT_DIS1 (0x060) +#define ACM_LUT_DIS2 (0x064) +#define ACM_LUT_DIS3 (0x068) +#define ACM_LUT_DIS4 (0x06C) +#define ACM_LUT_DIS5 (0x070) +#define ACM_LUT_DIS6 (0x074) +#define ACM_LUT_DIS7 (0x078) +#define ACM_LUT_PARAM0 (0x07C) +#define ACM_LUT_PARAM1 (0x080) +#define ACM_LUT_PARAM2 (0x084) +#define ACM_LUT_PARAM3 (0x088) +#define ACM_LUT_PARAM4 (0x08C) +#define ACM_LUT_PARAM5 (0x090) +#define ACM_LUT_PARAM6 (0x094) +#define ACM_LUT_PARAM7 (0x098) +#define ACM_LUT_SEL (0x09C) +#define ACM_MEM_CTRL (0x0A0) +#define ACM_DEBUG_TOP (0x0A4) +#define ACM_DEBUG_CFG (0x0A8) +#define ACM_DEBUG_W (0x0AC) + + +#define ACE_EN (0x000) +#define ACE_SKIN_CFG (0x004) +#define ACE_LUT_SEL (0x008) +#define ACE_HIST_IND (0x00C) +#define ACE_ACTIVE (0x010) +#define ACE_DBG (0x014) +#define ACE_MEM_CTRL (0x018) +#define ACE_IN_SEL (0x01C) +#define ACE_R2Y (0x020) +#define ACE_G2Y (0x024) +#define ACE_B2Y (0x028) +#define ACE_Y_OFFSET (0x02C) +#define ACE_Y_CEN (0x030) +#define ACE_U_CEN (0x034) +#define ACE_V_CEN (0x038) +#define ACE_Y_EXT (0x03C) +#define ACE_U_EXT (0x040) +#define ACE_V_EXT (0x044) +#define ACE_Y_ATTENU (0x048) +#define ACE_U_ATTENU (0x04C) +#define ACE_V_ATTENU (0x050) +#define ACE_ROTA (0x054) +#define ACE_ROTB (0x058) +#define ACE_Y_CORE (0x05C) +#define ACE_U_CORE (0x060) +#define ACE_V_CORE (0x064) + + +#define LCP_XCC_COEF_00 (0x000) +#define LCP_XCC_COEF_01 (0x004) +#define LCP_XCC_COEF_02 (0x008) +#define LCP_XCC_COEF_03 (0x00C) +#define LCP_XCC_COEF_10 (0x010) +#define LCP_XCC_COEF_11 (0x014) +#define LCP_XCC_COEF_12 (0x018) +#define LCP_XCC_COEF_13 (0x01C) +#define LCP_XCC_COEF_20 (0x020) +#define LCP_XCC_COEF_21 (0x024) +#define LCP_XCC_COEF_22 (0x028) +#define LCP_XCC_COEF_23 (0x02C) +#define LCP_GMP_BYPASS_EN (0x030) +#define LCP_XCC_BYPASS_EN (0x034) +#define LCP_DEGAMA_EN (0x038) +#define LCP_DEGAMA_MEM_CTRL (0x03C) +#define LCP_GMP_MEM_CTRL (0x040) + + +typedef struct dss_arsr1p { + uint32_t ihleft; + uint32_t ihright; + uint32_t ihleft1; + uint32_t ihright1; + uint32_t ivtop; + uint32_t ivbottom; + uint32_t uv_offset; + uint32_t ihinc; + uint32_t ivinc; + uint32_t mode; + uint32_t format; + + uint32_t skin_thres_y; + uint32_t skin_thres_u; + uint32_t skin_thres_v; + uint32_t skin_expected; + uint32_t skin_cfg; + uint32_t shoot_cfg1; + uint32_t shoot_cfg2; + uint32_t sharp_cfg1; + uint32_t sharp_cfg2; + uint32_t sharp_cfg3; + uint32_t sharp_cfg4; + uint32_t sharp_cfg5; + uint32_t sharp_cfg6; + uint32_t sharp_cfg7; + uint32_t sharp_cfg8; + uint32_t sharp_cfg9; + uint32_t sharp_cfg10; + uint32_t sharp_cfg11; + uint32_t diff_ctrl; + uint32_t lsc_cfg1; + uint32_t lsc_cfg2; + uint32_t lsc_cfg3; + uint32_t force_clk_on_cfg; + + uint32_t dpp_img_hrz_bef_sr; + uint32_t dpp_img_vrt_bef_sr; + uint32_t dpp_img_hrz_aft_sr; + uint32_t dpp_img_vrt_aft_sr; +} dss_arsr1p_t; + +#define ARSR1P_INC_FACTOR (65536) + +#define ARSR1P_IHLEFT (0x000) +#define ARSR1P_IHRIGHT (0x004) +#define ARSR1P_IHLEFT1 (0x008) +#define ARSR1P_IHRIGHT1 (0x00C) +#define ARSR1P_IVTOP (0x010) +#define ARSR1P_IVBOTTOM (0x014) +#define ARSR1P_UV_OFFSET (0x018) +#define ARSR1P_IHINC (0x01C) +#define ARSR1P_IVINC (0x020) +#define ARSR1P_MODE (0x024) +#define ARSR1P_FORMAT (0x028) +#define ARSR1P_SKIN_THRES_Y (0x02C) +#define ARSR1P_SKIN_THRES_U (0x030) +#define ARSR1P_SKIN_THRES_V (0x034) +#define ARSR1P_SKIN_EXPECTED (0x038) +#define ARSR1P_SKIN_CFG (0x03C) +#define ARSR1P_SHOOT_CFG1 (0x040) +#define ARSR1P_SHOOT_CFG2 (0x044) +#define ARSR1P_SHARP_CFG1 (0x048) +#define ARSR1P_SHARP_CFG2 (0x04C) +#define ARSR1P_SHARP_CFG3 (0x050) +#define ARSR1P_SHARP_CFG4 (0x054) +#define ARSR1P_SHARP_CFG5 (0x058) +#define ARSR1P_SHARP_CFG6 (0x05C) +#define ARSR1P_SHARP_CFG7 (0x060) +#define ARSR1P_SHARP_CFG8 (0x064) +#define ARSR1P_SHARP_CFG9 (0x068) +#define ARSR1P_SHARP_CFG10 (0x06C) +#define ARSR1P_SHARP_CFG11 (0x070) +#define ARSR1P_DIFF_CTRL (0x074) +#define ARSR1P_LSC_CFG1 (0x078) +#define ARSR1P_LSC_CFG2 (0x07C) +#define ARSR1P_LSC_CFG3 (0x080) +#define ARSR1P_FORCE_CLK_ON_CFG (0x084) + +/******************************************************************************* + ** BIT EXT + */ +#define BIT_EXT0_CTL (0x000) + + +#define U_GAMA_R_COEF (0x000) +#define U_GAMA_G_COEF (0x400) +#define U_GAMA_B_COEF (0x800) +#define U_GAMA_R_LAST_COEF (0x200) +#define U_GAMA_G_LAST_COEF (0x600) +#define U_GAMA_B_LAST_COEF (0xA00) + + +#define ACM_U_H_COEF (0x000) +#define ACM_U_SATA_COEF (0x200) +#define ACM_U_SATR0_COEF (0x300) +#define ACM_U_SATR1_COEF (0x340) +#define ACM_U_SATR2_COEF (0x380) +#define ACM_U_SATR3_COEF (0x3C0) +#define ACM_U_SATR4_COEF (0x400) +#define ACM_U_SATR5_COEF (0x440) +#define ACM_U_SATR6_COEF (0x480) +#define ACM_U_SATR7_COEF (0x4C0) + + +#define LCP_U_GMP_COEF (0x0000) +#define LCP_U_DEGAMA_R_COEF (0x5000) +#define LCP_U_DEGAMA_G_COEF (0x5400) +#define LCP_U_DEGAMA_B_COEF (0x5800) +#define LCP_U_DEGAMA_R_LAST_COEF (0x5200) +#define LCP_U_DEGAMA_G_LAST_COEF (0x5600) +#define LCP_U_DEGAMA_B_LAST_COEF (0x5A00) + + +#define ACE_HIST0 (0x000) +#define ACE_HIST1 (0x400) +#define ACE_LUT0 (0x800) +#define ACE_LUT1 (0xA00) + + +#define ARSR1P_LSC_GAIN (0x084) +#define ARSR1P_COEFF_H_Y0 (0x0F0) +#define ARSR1P_COEFF_H_Y1 (0x114) +#define ARSR1P_COEFF_V_Y0 (0x138) +#define ARSR1P_COEFF_V_Y1 (0x15C) +#define ARSR1P_COEFF_H_UV0 (0x180) +#define ARSR1P_COEFF_H_UV1 (0x1A4) +#define ARSR1P_COEFF_V_UV0 (0x1C8) +#define ARSR1P_COEFF_V_UV1 (0x1EC) + + +#define HIACE_INT_STAT (0x0000) +#define HIACE_INT_UNMASK (0x0004) +#define HIACE_BYPASS_ACE (0x0008) +#define HIACE_BYPASS_ACE_STAT (0x000c) +#define HIACE_UPDATE_LOCAL (0x0010) +#define HIACE_LOCAL_VALID (0x0014) +#define HIACE_GAMMA_AB_SHADOW (0x0018) +#define HIACE_GAMMA_AB_WORK (0x001c) +#define HIACE_GLOBAL_HIST_AB_SHADOW (0x0020) +#define HIACE_GLOBAL_HIST_AB_WORK (0x0024) +#define HIACE_IMAGE_INFO (0x0030) +#define HIACE_HALF_BLOCK_H_W (0x0034) +#define HIACE_XYWEIGHT (0x0038) +#define HIACE_LHIST_SFT (0x003c) +#define HIACE_HUE (0x0050) +#define HIACE_SATURATION (0x0054) +#define HIACE_VALUE (0x0058) +#define HIACE_SKIN_GAIN (0x005c) +#define HIACE_UP_LOW_TH (0x0060) +#define HIACE_UP_CNT (0x0070) +#define HIACE_LOW_CNT (0x0074) +#define HIACE_GLOBAL_HIST_LUT_ADDR (0x0080) +#define HIACE_LHIST_EN (0x0100) +#define HIACE_LOCAL_HIST_VxHy_2z_2z1 (0x0104) +#define HIACE_GAMMA_EN (0x0108) +#define HIACE_GAMMA_VxHy_3z2_3z1_3z_W (0x010c) +#define HIACE_GAMMA_EN_HV_R (0x0110) +#define HIACE_GAMMA_VxHy_3z2_3z1_3z_R (0x0114) +#define HIACE_INIT_GAMMA (0x0120) +#define HIACE_MANUAL_RELOAD (0x0124) +#define HIACE_RAMCLK_FUNC (0x0128) +#define HIACE_CLK_GATE (0x012c) +#define HIACE_GAMMA_RAM_A_CFG_MEM_CTRL (0x0130) +#define HIACE_GAMMA_RAM_B_CFG_MEM_CTRL (0x0134) +#define HIACE_LHIST_RAM_CFG_MEM_CTRL (0x0138) +#define HIACE_GAMMA_RAM_A_CFG_PM_CTRL (0x0140) +#define HIACE_GAMMA_RAM_B_CFG_PM_CTRL (0x0144) +#define HIACE_LHIST_RAM_CFG_PM_CTRL (0x0148) + +/******************************************************************************* + ** IFBC + */ +#define IFBC_SIZE (0x0000) +#define IFBC_CTRL (0x0004) +#define IFBC_HIMAX_CTRL0 (0x0008) +#define IFBC_HIMAX_CTRL1 (0x000C) +#define IFBC_HIMAX_CTRL2 (0x0010) +#define IFBC_HIMAX_CTRL3 (0x0014) +#define IFBC_EN (0x0018) +#define IFBC_MEM_CTRL (0x001C) +#define IFBC_INSERT (0x0020) +#define IFBC_HIMAX_TEST_MODE (0x0024) +#define IFBC_CORE_GT (0x0028) +#define IFBC_PM_CTRL (0x002C) +#define IFBC_RD_SHADOW (0x0030) +#define IFBC_ORISE_CTL (0x0034) +#define IFBC_ORSISE_DEBUG0 (0x0038) +#define IFBC_ORSISE_DEBUG1 (0x003C) +#define IFBC_RSP_COMP_TEST (0x0040) +#define IFBC_CLK_SEL (0x044) +#define IFBC_CLK_EN (0x048) +#define IFBC_PAD (0x004C) +#define IFBC_REG_DEFAULT (0x0050) + +/******************************************************************************* + ** DSC + */ +#define DSC_VERSION (0x0000) +#define DSC_PPS_IDENTIFIER (0x0004) +#define DSC_EN (0x0008) +#define DSC_CTRL (0x000C) +#define DSC_PIC_SIZE (0x0010) +#define DSC_SLICE_SIZE (0x0014) +#define DSC_CHUNK_SIZE (0x0018) +#define DSC_INITIAL_DELAY (0x001C) +#define DSC_RC_PARAM0 (0x0020) +#define DSC_RC_PARAM1 (0x0024) +#define DSC_RC_PARAM2 (0x0028) +#define DSC_RC_PARAM3 (0x002C) +#define DSC_FLATNESS_QP_TH (0x0030) +#define DSC_RC_PARAM4 (0x0034) +#define DSC_RC_PARAM5 (0x0038) +#define DSC_RC_BUF_THRESH0 (0x003C) +#define DSC_RC_BUF_THRESH1 (0x0040) +#define DSC_RC_BUF_THRESH2 (0x0044) +#define DSC_RC_BUF_THRESH3 (0x0048) +#define DSC_RC_RANGE_PARAM0 (0x004C) +#define DSC_RC_RANGE_PARAM1 (0x0050) +#define DSC_RC_RANGE_PARAM2 (0x0054) +#define DSC_RC_RANGE_PARAM3 (0x0058) +#define DSC_RC_RANGE_PARAM4 (0x005C) +#define DSC_RC_RANGE_PARAM5 (0x0060) +#define DSC_RC_RANGE_PARAM6 (0x0064) +#define DSC_RC_RANGE_PARAM7 (0x0068) +#define DSC_ADJUSTMENT_BITS (0x006C) +#define DSC_BITS_PER_GRP (0x0070) +#define DSC_MULTI_SLICE_CTL (0x0074) +#define DSC_OUT_CTRL (0x0078) +#define DSC_CLK_SEL (0x007C) +#define DSC_CLK_EN (0x0080) +#define DSC_MEM_CTRL (0x0084) +#define DSC_ST_DATAIN (0x0088) +#define DSC_ST_DATAOUT (0x008C) +#define DSC0_ST_SLC_POS (0x0090) +#define DSC1_ST_SLC_POS (0x0094) +#define DSC0_ST_PIC_POS (0x0098) +#define DSC1_ST_PIC_POS (0x009C) +#define DSC0_ST_FIFO (0x00A0) +#define DSC1_ST_FIFO (0x00A4) +#define DSC0_ST_LINEBUF (0x00A8) +#define DSC1_ST_LINEBUF (0x00AC) +#define DSC_ST_ITFC (0x00B0) +#define DSC_RD_SHADOW_SEL (0x00B4) +#define DSC_REG_DEFAULT (0x00B8) + +/******************************************************************************* + ** LDI + */ +#define LDI_DPI0_HRZ_CTRL0 (0x0000) +#define LDI_DPI0_HRZ_CTRL1 (0x0004) +#define LDI_DPI0_HRZ_CTRL2 (0x0008) +#define LDI_VRT_CTRL0 (0x000C) +#define LDI_VRT_CTRL1 (0x0010) +#define LDI_VRT_CTRL2 (0x0014) +#define LDI_PLR_CTRL (0x0018) +#define LDI_SH_MASK_INT (0x001C) +#define LDI_3D_CTRL (0x0020) +#define LDI_CTRL (0x0024) +#define LDI_WORK_MODE (0x0028) +#define LDI_DE_SPACE_LOW (0x002C) +#define LDI_DSI_CMD_MOD_CTRL (0x0030) +#define LDI_DSI_TE_CTRL (0x0034) +#define LDI_DSI_TE_HS_NUM (0x0038) +#define LDI_DSI_TE_HS_WD (0x003C) +#define LDI_DSI_TE_VS_WD (0x0040) +#define LDI_FRM_MSK (0x0044) +#define LDI_FRM_MSK_UP (0x0048) +#define LDI_VINACT_MSK_LEN (0x0050) +#define LDI_VSTATE (0x0054) +#define LDI_DPI0_HSTATE (0x0058) +#define LDI_DPI1_HSTATE (0x005C) +#define LDI_CMD_EVENT_SEL (0x0060) +#define LDI_SRAM_LP_CTRL (0x0064) +#define LDI_ITF_RD_SHADOW (0x006C) +#define LDI_DPI1_HRZ_CTRL0 (0x00F0) +#define LDI_DPI1_HRZ_CTRL1 (0x00F4) +#define LDI_DPI1_HRZ_CTRL2 (0x00F8) +#define LDI_OVERLAP_SIZE (0x00FC) +#define LDI_MEM_CTRL (0x0100) +#define LDI_PM_CTRL (0x0104) +#define LDI_CLK_SEL (0x0108) +#define LDI_CLK_EN (0x010C) +#define LDI_IF_BYPASS (0x0110) +#define LDI_FRM_VALID_DBG (0x0118) +/* LDI GLB*/ +#define LDI_PXL0_DIV2_GT_EN (0x0210) +#define LDI_PXL0_DIV4_GT_EN (0x0214) +#define LDI_PXL0_GT_EN (0x0218) +#define LDI_PXL0_DSI_GT_EN (0x021C) +#define LDI_PXL0_DIVXCFG (0x0220) +#define LDI_DSI1_CLK_SEL (0x0224) +#define LDI_VESA_CLK_SEL (0x0228) +/* DSI1 RST*/ +#define LDI_DSI1_RST_SEL (0x0238) +/* LDI INTERRUPT*/ +#define LDI_MCU_ITF_INTS (0x0240) +#define LDI_MCU_ITF_INT_MSK (0x0244) +#define LDI_CPU_ITF_INTS (0x0248) +#define LDI_CPU_ITF_INT_MSK (0x024C) +/* LDI MODULE CLOCK GATING*/ +#define LDI_MODULE_CLK_SEL (0x0258) +#define LDI_MODULE_CLK_EN (0x025C) + +/******************************************************************************* + ** MIPI DSI + */ +#define MIPIDSI_VERSION_OFFSET (0x0000) +#define MIPIDSI_PWR_UP_OFFSET (0x0004) +#define MIPIDSI_CLKMGR_CFG_OFFSET (0x0008) +#define MIPIDSI_DPI_VCID_OFFSET (0x000c) +#define MIPIDSI_DPI_COLOR_CODING_OFFSET (0x0010) +#define MIPIDSI_DPI_CFG_POL_OFFSET (0x0014) +#define MIPIDSI_DPI_LP_CMD_TIM_OFFSET (0x0018) +#define MIPIDSI_PCKHDL_CFG_OFFSET (0x002c) +#define MIPIDSI_GEN_VCID_OFFSET (0x0030) +#define MIPIDSI_MODE_CFG_OFFSET (0x0034) +#define MIPIDSI_VID_MODE_CFG_OFFSET (0x0038) +#define MIPIDSI_VID_PKT_SIZE_OFFSET (0x003c) +#define MIPIDSI_VID_NUM_CHUNKS_OFFSET (0x0040) +#define MIPIDSI_VID_NULL_SIZE_OFFSET (0x0044) +#define MIPIDSI_VID_HSA_TIME_OFFSET (0x0048) +#define MIPIDSI_VID_HBP_TIME_OFFSET (0x004c) +#define MIPIDSI_VID_HLINE_TIME_OFFSET (0x0050) +#define MIPIDSI_VID_VSA_LINES_OFFSET (0x0054) +#define MIPIDSI_VID_VBP_LINES_OFFSET (0x0058) +#define MIPIDSI_VID_VFP_LINES_OFFSET (0x005c) +#define MIPIDSI_VID_VACTIVE_LINES_OFFSET (0x0060) +#define MIPIDSI_EDPI_CMD_SIZE_OFFSET (0x0064) +#define MIPIDSI_CMD_MODE_CFG_OFFSET (0x0068) +#define MIPIDSI_GEN_HDR_OFFSET (0x006c) +#define MIPIDSI_GEN_PLD_DATA_OFFSET (0x0070) +#define MIPIDSI_CMD_PKT_STATUS_OFFSET (0x0074) +#define MIPIDSI_TO_CNT_CFG_OFFSET (0x0078) +#define MIPIDSI_HS_RD_TO_CNT_OFFSET (0x007C) +#define MIPIDSI_LP_RD_TO_CNT_OFFSET (0x0080) +#define MIPIDSI_HS_WR_TO_CNT_OFFSET (0x0084) +#define MIPIDSI_LP_WR_TO_CNT_OFFSET (0x0088) +#define MIPIDSI_BTA_TO_CNT_OFFSET (0x008C) +#define MIPIDSI_SDF_3D_OFFSET (0x0090) +#define MIPIDSI_LPCLK_CTRL_OFFSET (0x0094) +#define MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET (0x0098) +#define MIPIDSI_PHY_TMR_CFG_OFFSET (0x009c) +#define MIPIDSI_PHY_RSTZ_OFFSET (0x00a0) +#define MIPIDSI_PHY_IF_CFG_OFFSET (0x00a4) +#define MIPIDSI_PHY_ULPS_CTRL_OFFSET (0x00a8) +#define MIPIDSI_PHY_TX_TRIGGERS_OFFSET (0x00ac) +#define MIPIDSI_PHY_STATUS_OFFSET (0x00b0) +#define MIPIDSI_PHY_TST_CTRL0_OFFSET (0x00b4) +#define MIPIDSI_PHY_TST_CTRL1_OFFSET (0x00b8) +#define MIPIDSI_INT_ST0_OFFSET (0x00bc) +#define MIPIDSI_INT_ST1_OFFSET (0x00c0) +#define MIPIDSI_INT_MSK0_OFFSET (0x00c4) +#define MIPIDSI_INT_MSK1_OFFSET (0x00c8) +#define INT_FORCE0 (0x00D8) +#define INT_FORCE1 (0x00DC) +#define MIPIDSI_DSC_PARAMETER_OFFSET (0x00f0) +#define MIPIDSI_PHY_TMR_RD_CFG_OFFSET (0x00f4) +#define VID_SHADOW_CTRL (0x0100) +#define DPI_VCID_ACT (0x010C) +#define DPI_COLOR_CODING_ACT (0x0110) +#define DPI_LP_CMD_TIM_ACT (0x0118) +#define VID_MODE_CFG_ACT (0x0138) +#define VID_PKT_SIZE_ACT (0x013C) +#define VID_NUM_CHUNKS_ACT (0x0140) +#define VID_NULL_SIZE_ACT (0x0144) +#define VID_HSA_TIME_ACT (0x0148) +#define VID_HBP_TIME_ACT (0x014C) +#define VID_HLINE_TIME_ACT (0x0150) +#define VID_VSA_LINES_ACT (0x0154) +#define VID_VBP_LINES_ACT (0x0158) +#define VID_VFP_LINES_ACT (0x015C) +#define VID_VACTIVE_LINES_ACT (0x0160) +#define SDF_3D_ACT (0x0190) + +/******************************************************************************* + ** MMBUF + */ +#define SMC_LOCK (0x0000) +#define SMC_MEM_LP (0x0004) +#define SMC_GCLK_CS (0x000C) +#define SMC_QOS_BACKDOOR (0x0010) +#define SMC_DFX_WCMD_CNT_1ST (0x0014) +#define SMC_DFX_WCMD_CNT_2ND (0x0018) +#define SMC_DFX_WCMD_CNT_3RD (0x001C) +#define SMC_DFX_WCMD_CNT_4TH (0x0020) +#define SMC_DFX_RCMD_CNT_1ST (0x0024) +#define SMC_DFX_RCMD_CNT_2ND (0x0028) +#define SMC_DFX_RCMD_CNT_3RD (0x002C) +#define SMC_DFX_RCMD_CNT_4TH (0x0030) +#define SMC_CS_IDLE (0x0034) +#define SMC_DFX_BFIFO_CNT0 (0x0038) +#define SMC_DFX_RDFIFO_CNT1 (0x003C) +#define SMC_SP_SRAM_STATE0 (0x0040) +#define SMC_SP_SRAM_STATE1 (0x0044) + +/******************************************************************************* + ** dirty_region_updt + */ +typedef struct dirty_region_updt { + uint32_t dbuf_frm_size; + uint32_t dbuf_frm_hsize; + uint32_t dpp_img_hrz_bef_sr; + uint32_t dpp_img_vrt_bef_sr; + uint32_t dpp_img_hrz_aft_sr; + uint32_t dpp_img_vrt_aft_sr; + uint32_t ldi_dpi0_hrz_ctrl0; + uint32_t ldi_dpi0_hrz_ctrl1; + uint32_t ldi_dpi0_hrz_ctrl2; + uint32_t ldi_dpi1_hrz_ctrl0; + uint32_t ldi_dpi1_hrz_ctrl1; + uint32_t ldi_dpi1_hrz_ctrl2; + uint32_t ldi_vrt_ctrl0; + uint32_t ldi_vrt_ctrl1; + uint32_t ldi_vrt_ctrl2; + uint32_t ldi_ctrl; + uint32_t ifbc_size; + uint32_t edpi_cmd_size; + dss_arsr1p_t s_arsr1p; +} dirty_region_updt_t; + +/******************************************************************************* + ** dss module reg + */ +typedef struct dss_module_reg { + char __iomem *mif_ch_base[DSS_CHN_MAX_DEFINE]; + char __iomem *aif_ch_base[DSS_CHN_MAX_DEFINE]; + char __iomem *aif1_ch_base[DSS_CHN_MAX_DEFINE]; + dss_mctl_ch_base_t mctl_ch_base[DSS_CHN_MAX_DEFINE]; + char __iomem *dma_base[DSS_CHN_MAX_DEFINE]; + char __iomem *dfc_base[DSS_CHN_MAX_DEFINE]; + char __iomem *scl_base[DSS_CHN_MAX_DEFINE]; + char __iomem *scl_lut_base[DSS_CHN_MAX_DEFINE]; + char __iomem *arsr2p_base[DSS_CHN_MAX_DEFINE]; + char __iomem *arsr2p_lut_base[DSS_CHN_MAX_DEFINE]; + char __iomem *post_clip_base[DSS_CHN_MAX_DEFINE]; + char __iomem *pcsc_base[DSS_CHN_MAX_DEFINE]; + char __iomem *csc_base[DSS_CHN_MAX_DEFINE]; + + char __iomem *ov_base[DSS_OVL_IDX_MAX]; + char __iomem *mctl_base[DSS_MCTL_IDX_MAX]; + char __iomem *mctl_sys_base; + char __iomem *smmu_base; + char __iomem *post_scf_base; + + dss_mif_t mif[DSS_CHN_MAX_DEFINE]; + dss_aif_t aif[DSS_CHN_MAX_DEFINE]; + dss_aif_t aif1[DSS_CHN_MAX_DEFINE]; + dss_aif_bw_t aif_bw[DSS_CHN_MAX_DEFINE]; + dss_aif_bw_t aif1_bw[DSS_CHN_MAX_DEFINE]; + dss_rdma_t rdma[DSS_CHN_MAX_DEFINE]; + dss_wdma_t wdma[DSS_CHN_MAX_DEFINE]; + dss_dfc_t dfc[DSS_CHN_MAX_DEFINE]; + dss_scl_t scl[DSS_CHN_MAX_DEFINE]; + dss_arsr2p_t arsr2p[DSS_CHN_MAX_DEFINE]; + dss_post_clip_t post_clip[DSS_CHN_MAX_DEFINE]; + dss_csc_t pcsc[DSS_CHN_MAX_DEFINE]; + dss_csc_t csc[DSS_CHN_MAX_DEFINE]; + dss_ovl_t ov[DSS_OVL_IDX_MAX]; + dss_mctl_t mctl[DSS_MCTL_IDX_MAX]; + dss_mctl_ch_t mctl_ch[DSS_CHN_MAX_DEFINE]; + dss_mctl_sys_t mctl_sys; + dss_smmu_t smmu; + dirty_region_updt_t dirty_region_updt; + dss_arsr1p_t post_scf; + + uint8_t mif_used[DSS_CHN_MAX_DEFINE]; + uint8_t aif_ch_used[DSS_CHN_MAX_DEFINE]; + uint8_t aif1_ch_used[DSS_CHN_MAX_DEFINE]; + uint8_t dma_used[DSS_CHN_MAX_DEFINE]; + uint8_t dfc_used[DSS_CHN_MAX_DEFINE]; + uint8_t scl_used[DSS_CHN_MAX_DEFINE]; + uint8_t arsr2p_used[DSS_CHN_MAX_DEFINE]; + uint8_t arsr2p_effect_used[DSS_CHN_MAX_DEFINE]; + uint8_t post_cilp_used[DSS_CHN_MAX_DEFINE]; + uint8_t pcsc_used[DSS_CHN_MAX_DEFINE]; + uint8_t csc_used[DSS_CHN_MAX_DEFINE]; + uint8_t ov_used[DSS_OVL_IDX_MAX]; + uint8_t ch_reg_default_used[DSS_CHN_MAX_DEFINE]; + uint8_t mctl_used[DSS_MCTL_IDX_MAX]; + uint8_t mctl_ch_used[DSS_CHN_MAX_DEFINE]; + uint8_t mctl_sys_used; + uint8_t smmu_used; + uint8_t dirty_region_updt_used; + uint8_t post_scf_used; +} dss_module_reg_t; + +typedef struct dss_mmbuf_info { + uint32_t mm_base[DSS_CHN_MAX_DEFINE]; + uint32_t mm_size[DSS_CHN_MAX_DEFINE]; + + uint8_t mm_used[DSS_CHN_MAX_DEFINE]; +} dss_mmbuf_info_t; + +#endif /* HISI_DSS_REGS_H */ -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 5/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_fb_bl.c | 323 +++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c | 507 ++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_def.h | 125 ++++ drivers/video/fbdev/hisi/dss/hisi_fb_isr.c | 327 +++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_panel.c | 835 +++++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_panel.h | 839 ++++++++++++++++++++++++ 6 files changed, 2956 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_bl.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_def.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_isr.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_panel.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_panel.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c b/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c new file mode 100755 index 000000000000..ee4b8c7f4abb --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include <linux/leds.h> +#define K3_DSS_SBL_WORKQUEUE "k3_dss_sbl_workqueue" + +static int lcd_backlight_registered; +static unsigned int is_recovery_mode; +static int is_no_fastboot_bl_enable; + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY +unsigned long backlight_duration = (3 * HZ / 60); +#endif + +void hisifb_set_backlight(struct hisi_fb_data_type *hisifd, uint32_t bkl_lvl) +{ + struct hisi_fb_panel_data *pdata = NULL; + uint32_t temp = bkl_lvl; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + if (!hisifd->panel_power_on || !hisifd->backlight.bl_updated) { + hisifd->bl_level = bkl_lvl; + return; + } + + if (pdata->set_backlight) { + if (hisifd->backlight.bl_level_old == temp) { + hisifd->bl_level = bkl_lvl; + return; + } + if (hisifd->backlight.bl_level_old == 0) { + HISI_FB_INFO("backlight level = %d", bkl_lvl); + } + hisifd->bl_level = bkl_lvl; + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) { + hisifb_set_vsync_activate_state(hisifd, true); + hisifb_activate_vsync(hisifd); + } + pdata->set_backlight(hisifd->pdev, bkl_lvl); + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) { + hisifb_set_vsync_activate_state(hisifd, false); + hisifb_deactivate_vsync(hisifd); + } + hisifd->backlight.bl_level_old = temp; + } +} + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY +static void hisifb_bl_workqueue_handler(struct work_struct *work) +#else +static void hisifb_bl_workqueue_handler(struct hisi_fb_data_type *hisifd) +#endif +{ + struct hisi_fb_panel_data *pdata = NULL; +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + struct hisifb_backlight *pbacklight = NULL; + struct hisi_fb_data_type *hisifd = NULL; + + pbacklight = + container_of(to_delayed_work(work), struct hisifb_backlight, + bl_worker); + BUG_ON(pbacklight == NULL); + + hisifd = container_of(pbacklight, struct hisi_fb_data_type, backlight); +#endif + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + if (!hisifd->backlight.bl_updated) { + down(&hisifd->blank_sem); + + if (hisifd->backlight.frame_updated == 0) { + up(&hisifd->blank_sem); + return; + } + + hisifd->backlight.frame_updated = 0; + hisifd->backlight.bl_updated = 1; + if (is_recovery_mode) { + hisifd->bl_level = hisifd->panel_info.bl_default; + } else { + if (!is_no_fastboot_bl_enable) { + is_no_fastboot_bl_enable = 1; + hisifd->bl_level = + hisifd->panel_info.bl_default; + } + } + + hisifb_set_backlight(hisifd, hisifd->bl_level); + up(&hisifd->blank_sem); + } +} + +void hisifb_backlight_update(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + if (!hisifd->backlight.bl_updated) { + hisifd->backlight.frame_updated = 1; +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + schedule_delayed_work(&hisifd->backlight.bl_worker, + backlight_duration); +#else + hisifb_bl_workqueue_handler(hisifd); +#endif + } +} + +void hisifb_backlight_cancel(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + cancel_delayed_work(&hisifd->backlight.bl_worker); +#endif + hisifd->backlight.bl_updated = 0; + hisifd->backlight.bl_level_old = 0; + hisifd->backlight.frame_updated = 0; + + if (pdata->set_backlight) { + hisifd->bl_level = 0; + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) + hisifb_activate_vsync(hisifd); + pdata->set_backlight(hisifd->pdev, hisifd->bl_level); + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) + hisifb_deactivate_vsync(hisifd); + } +} + +#ifdef CONFIG_FB_BACKLIGHT +static int hisi_fb_bl_get_brightness(struct backlight_device *pbd) +{ + if (NULL == pbd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + return pbd->props.brightness; +} + +static int hisi_fb_bl_update_status(struct backlight_device *pbd) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t bl_lvl = 0; + + if (NULL == pbd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + + hisifd = bl_get_data(pbd); + if (NULL == hisifd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + + bl_lvl = pbd->props.brightness; + bl_lvl = hisifd->fbi->bl_curve[bl_lvl]; + + down(&hisifd->blank_sem); + hisifb_set_backlight(hisifd, bl_lvl); + up(&hisifd->blank_sem); + + return 0; +} + +static struct backlight_ops hisi_fb_bl_ops = { + .get_brightness = hisi_fb_bl_get_brightness, + .update_status = hisi_fb_bl_update_status, +}; +#else +static void hisi_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct hisi_fb_data_type *hisifd = NULL; + int bl_lvl = 0; + + if (NULL == led_cdev) { + HISI_FB_ERR("NULL pointer!\n"); + return; + } + + hisifd = dev_get_drvdata(led_cdev->dev->parent); + if (NULL == hisifd) { + HISI_FB_ERR("NULL pointer!\n"); + return; + } + + if (value < 0) + value = 0; + + if (value > hisifd->panel_info.bl_max) + value = hisifd->panel_info.bl_max; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl = + (2 * value * hisifd->panel_info.bl_max + hisifd->panel_info.bl_max) + / (2 * hisifd->panel_info.bl_max); + if (!bl_lvl && value) + bl_lvl = 1; + hisifb_set_backlight(hisifd, bl_lvl); +} + +static struct led_classdev backlight_led = { + .name = DEV_NAME_LCD_BKL, + .brightness_set = hisi_fb_set_bl_brightness, +}; +#endif + +void hisifb_backlight_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; +#ifdef CONFIG_FB_BACKLIGHT + struct backlight_device *pbd = NULL; + struct fb_info *fbi = NULL; + char name[16] = { 0 }; + struct backlight_properties props; +#endif + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + hisifd->backlight.bl_updated = 0; + hisifd->backlight.frame_updated = 0; + hisifd->backlight.bl_level_old = 0; + sema_init(&hisifd->backlight.bl_sem, 1); +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + INIT_DELAYED_WORK(&hisifd->backlight.bl_worker, + hisifb_bl_workqueue_handler); +#endif + + if (lcd_backlight_registered) return; + +#ifdef CONFIG_FB_BACKLIGHT + fbi = hisifd->fbi; + + snprintf(name, sizeof(name), "hisifb%d_bl", hisifd->index); + props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + props.brightness = FB_BACKLIGHT_LEVELS - 1; + pbd = backlight_device_register(name, fbi->dev, hisifd, + &hisi_fb_bl_ops, &props); + if (IS_ERR(pbd)) { + fbi->bl_dev = NULL; + HISI_FB_ERR("backlight_device_register failed!\n"); + } + + fbi->bl_dev = pbd; + fb_bl_default_curve(fbi, 0, + hisifd->panel_info.bl_min, + hisifd->panel_info.bl_max); +#else + backlight_led.brightness = hisifd->panel_info.bl_default; + backlight_led.max_brightness = hisifd->panel_info.bl_max; + /* android supports only one lcd-backlight/lcd for now */ +#ifdef CONFIG_LEDS_CLASS + if (led_classdev_register(&pdev->dev, &backlight_led)) { + HISI_FB_ERR("led_classdev_register failed!\n"); + return; + } +#endif +#endif + + if (HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_SBL)) { + hisifd->backlight.sbl_queue = + create_singlethread_workqueue(K3_DSS_SBL_WORKQUEUE); + if (!hisifd->backlight.sbl_queue) { + HISI_FB_ERR("failed to create sbl_queue!\n"); + return; + } + } + + lcd_backlight_registered = 1; +} + +void hisifb_backlight_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(hisifd->fbi->bl_dev); +#else +#ifdef CONFIG_LEDS_CLASS + led_classdev_unregister(&backlight_led); +#endif +#endif + if (hisifd->backlight.sbl_queue) { + destroy_workqueue(hisifd->backlight.sbl_queue); + hisifd->backlight.sbl_queue = NULL; + } + } +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c b/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c new file mode 100755 index 000000000000..e36a39ad4d31 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c @@ -0,0 +1,507 @@ +/* Copyright (c) 2008-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" + +#define HISI_DSS_LAYERBUF_FREE "hisi-dss-layerbuf-free" + +int hisifb_layerbuf_lock(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, struct list_head *plock_list) +{ + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + struct hisifb_layerbuf *node = NULL; + struct ion_handle *ionhnd = NULL; + struct iommu_map_format iommu_format; + bool add_tail = false; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(plock_list == NULL); + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + add_tail = false; + ionhnd = NULL; + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) + continue; + + if (layer->img.shared_fd < 0) + continue; + + if ((layer->img.phy_addr == 0) && + (layer->img.vir_addr == 0) && + (layer->img.afbc_payload_addr == 0)) { + HISI_FB_ERR + ("fb%d, layer_idx%d, chn_idx%d, no buffer!\n", + hisifd->index, layer->layer_idx, + layer->chn_idx); + continue; + } + + if (layer->img.shared_fd >= 0) { + ionhnd = + ion_import_dma_buf(hisifd->ion_client, + layer->img.shared_fd); + if (IS_ERR(ionhnd)) { + ionhnd = NULL; + HISI_FB_ERR + ("fb%d, layer_idx%d, failed to ion_import_dma_buf, " + "ionclient %p, share_fd %d!\n", + hisifd->index, i, + hisifd->ion_client, + layer->img.shared_fd); + } else { + if (layer->img.mmu_enable == 1) { + memset(&iommu_format, 0, + sizeof(struct iommu_map_format)); + ion_map_iommu(hisifd->ion_client,ionhnd, + &iommu_format); + } + add_tail = true; + } + } + + if (add_tail) { + node = + kzalloc(sizeof(struct hisifb_layerbuf), + GFP_KERNEL); + if (node == NULL) { + HISI_FB_ERR + ("fb%d, layer_idx%d, failed to kzalloc!\n", + hisifd->index, layer->layer_idx); + + if (ionhnd) { + ion_free(hisifd->ion_client, + ionhnd); + ionhnd = NULL; + } + continue; + } + + node->shared_fd = layer->img.shared_fd; + node->frame_no = pov_req->frame_no; + node->ion_handle = ionhnd; + node->has_map_iommu = (ionhnd + && (layer->img.mmu_enable == 1)) ? true : false; + node->timeline = 0; + + node->mmbuf.addr = layer->img.mmbuf_base; + node->mmbuf.size = layer->img.mmbuf_size; + + node->vir_addr = layer->img.vir_addr; + node->chn_idx = layer->chn_idx; + + list_add_tail(&node->list_node, plock_list); + if (g_debug_layerbuf_sync) { + HISI_FB_INFO + ("fb%d, frame_no=%d, layer_idx(%d), " + "shared_fd=%d, ion_handle=%p, " + "has_map_iommu=%d, timeline=%d, mmbuf(0x%x, %d).\n", + hisifd->index, node->frame_no, i, + node->shared_fd, node->ion_handle, + node->has_map_iommu, + node->timeline, node->mmbuf.addr, + node->mmbuf.size); + } + } + } + } + + return 0; +} + +void hisifb_layerbuf_flush(struct hisi_fb_data_type *hisifd, + struct list_head *plock_list) +{ + struct hisifb_layerbuf *node, *_node_; + unsigned long flags = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(hisifd->ion_client == NULL); + BUG_ON(plock_list == NULL); + + spin_lock_irqsave(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + hisifd->buf_sync_ctrl.layerbuf_flushed = true; + list_for_each_entry_safe(node, _node_, plock_list, list_node) { + list_del(&node->list_node); + list_add_tail(&node->list_node, + &(hisifd->buf_sync_ctrl.layerbuf_list)); + } + spin_unlock_irqrestore(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), + flags); +} + +void hisifb_layerbuf_unlock(struct hisi_fb_data_type *hisifd, + struct list_head *pfree_list) +{ + struct hisifb_layerbuf *node, *_node_; + + BUG_ON(hisifd == NULL); + BUG_ON(hisifd->ion_client == NULL); + BUG_ON(hisifd->mmbuf_gen_pool == NULL); + BUG_ON(pfree_list == NULL); + + list_for_each_entry_safe(node, _node_, pfree_list, list_node) { + list_del(&node->list_node); + + if (g_debug_layerbuf_sync) { + HISI_FB_INFO + ("fb%d, frame_no=%d, share_fd=%d, " + "ion_handle=%p, has_map_iommu=%d, " + "timeline=%d, mmbuf(0x%x, %d). " + "vir_addr = 0x%llx, chn_idx = %d\n", + hisifd->index, node->frame_no, node->shared_fd, + node->ion_handle, node->has_map_iommu, + node->timeline, node->mmbuf.addr, node->mmbuf.size, + node->vir_addr, node->chn_idx); + } + + node->timeline = 0; + if (node->ion_handle) { + if (node->has_map_iommu) { + ion_unmap_iommu(hisifd->ion_client, + node->ion_handle); + } + ion_free(hisifd->ion_client, node->ion_handle); + } + kfree(node); + } +} + +void hisifb_layerbuf_lock_exception(struct hisi_fb_data_type *hisifd, + struct list_head *plock_list) +{ + unsigned long flags = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(plock_list == NULL); + + spin_lock_irqsave(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock_irqrestore(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + + hisifb_layerbuf_unlock(hisifd, plock_list); +} + +static void hisifb_layerbuf_unlock_work(struct work_struct *work) +{ + struct hisifb_buf_sync *pbuf_sync = NULL; + struct hisi_fb_data_type *hisifd = NULL; + unsigned long flags; + struct hisifb_layerbuf *node, *_node_; + struct list_head free_list; + + pbuf_sync = + container_of(work, struct hisifb_buf_sync, free_layerbuf_work); + BUG_ON(pbuf_sync == NULL); + hisifd = + container_of(pbuf_sync, struct hisi_fb_data_type, buf_sync_ctrl); + BUG_ON(hisifd == NULL); + BUG_ON(hisifd->ion_client == NULL); + + INIT_LIST_HEAD(&free_list); + spin_lock_irqsave(&pbuf_sync->layerbuf_spinlock, flags); + list_for_each_entry_safe(node, _node_, &pbuf_sync->layerbuf_list, + list_node) { + if (node->timeline >= 2) { + list_del(&node->list_node); + list_add_tail(&node->list_node, &free_list); + } + } + spin_unlock_irqrestore(&pbuf_sync->layerbuf_spinlock, flags); + + hisifb_layerbuf_unlock(hisifd, &free_list); +} + +#ifdef CONFIG_BUF_SYNC_USED +#define BUF_SYNC_TIMEOUT_MSEC (10 * MSEC_PER_SEC) +#define BUF_SYNC_FENCE_NAME "hisi-dss-fence" +#define BUF_SYNC_TIMELINE_NAME "hisi-dss-timeline" +int hisifb_buf_sync_create_fence(struct hisi_fb_data_type *hisifd, + unsigned value) +{ + int fd = -1; + struct sync_fence *fence = NULL; + struct sync_pt *pt = NULL; + + BUG_ON(hisifd == NULL); + fd = get_unused_fd_flags(0); + if (fd < 0) { + HISI_FB_ERR("get_unused_fd failed!\n"); + return fd; + } + + pt = sw_sync_pt_create(hisifd->buf_sync_ctrl.timeline, value); + if (pt == NULL) { + return -ENOMEM; + } + + fence = sync_fence_create(BUF_SYNC_FENCE_NAME, pt); + if (fence == NULL) { + sync_pt_free(pt); + return -ENOMEM; + } + + sync_fence_install(fence, fd); + + return fd; +} + +int hisifb_buf_sync_wait(int fence_fd) +{ + int ret = 0; + struct sync_fence *fence = NULL; + + fence = sync_fence_fdget(fence_fd); + if (fence == NULL) { + HISI_FB_ERR("fence_fd=%d, sync_fence_fdget failed!\n", + fence_fd); + return -EINVAL; + } + + ret = sync_fence_wait(fence, BUF_SYNC_TIMEOUT_MSEC); + if (ret < 0) { + HISI_FB_ERR("Waiting on fence failed, fence_fd: %d, ret: %d.\n", + fence_fd, ret); + } + sync_fence_put(fence); + + return ret; +} + +int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) + continue; + + if (layer->acquire_fence >= 0) { + hisifb_buf_sync_wait(layer->acquire_fence); + } + } + } + + return 0; +} + +void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_layerbuf *node = NULL; + struct hisifb_layerbuf *_node_ = NULL; + + BUG_ON(hisifd == NULL); + + spin_lock(&hisifd->buf_sync_ctrl.refresh_lock); + if (hisifd->buf_sync_ctrl.refresh) { + sw_sync_timeline_inc(hisifd->buf_sync_ctrl.timeline, + hisifd->buf_sync_ctrl.refresh); + hisifd->buf_sync_ctrl.refresh = 0; + } + spin_unlock(&hisifd->buf_sync_ctrl.refresh_lock); + + spin_lock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + list_for_each_entry_safe(node, _node_, + &(hisifd->buf_sync_ctrl.layerbuf_list), + list_node) { + if (hisifd->buf_sync_ctrl.layerbuf_flushed) { + node->timeline++; + } + } + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + + queue_work(hisifd->buf_sync_ctrl.free_layerbuf_queue, + &(hisifd->buf_sync_ctrl.free_layerbuf_work)); +} + +void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd) +{ + unsigned long flags; + + spin_lock_irqsave(&hisifd->buf_sync_ctrl.refresh_lock, flags); + sw_sync_timeline_inc(hisifd->buf_sync_ctrl.timeline, + hisifd->buf_sync_ctrl.refresh + 1); + hisifd->buf_sync_ctrl.refresh = 0; + hisifd->buf_sync_ctrl.timeline_max++; + spin_unlock_irqrestore(&hisifd->buf_sync_ctrl.refresh_lock, flags); +} + +void hisifb_buf_sync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + spin_lock_init(&hisifd->buf_sync_ctrl.refresh_lock); + hisifd->buf_sync_ctrl.refresh = 0; + hisifd->buf_sync_ctrl.timeline_max = 1; + hisifd->buf_sync_ctrl.timeline = + sw_sync_timeline_create(BUF_SYNC_TIMELINE_NAME); + if (hisifd->buf_sync_ctrl.timeline == NULL) { + HISI_FB_ERR("cannot create time line!"); + return; /* -ENOMEM */ + } + + spin_lock_init(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + INIT_LIST_HEAD(&(hisifd->buf_sync_ctrl.layerbuf_list)); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + + INIT_WORK(&(hisifd->buf_sync_ctrl.free_layerbuf_work), + hisifb_layerbuf_unlock_work); + hisifd->buf_sync_ctrl.free_layerbuf_queue = + create_singlethread_workqueue(HISI_DSS_LAYERBUF_FREE); + if (!hisifd->buf_sync_ctrl.free_layerbuf_queue) { + HISI_FB_ERR("failed to create free_layerbuf_queue!\n"); + return; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} + +void hisifb_buf_sync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->buf_sync_ctrl.timeline) { + sync_timeline_destroy((struct sync_timeline *) + hisifd->buf_sync_ctrl.timeline); + hisifd->buf_sync_ctrl.timeline = NULL; + } + + if (hisifd->buf_sync_ctrl.free_layerbuf_queue) { + destroy_workqueue(hisifd->buf_sync_ctrl.free_layerbuf_queue); + hisifd->buf_sync_ctrl.free_layerbuf_queue = NULL; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} +#else +int hisifb_buf_sync_wait(int fence_fd) +{ + return 0; +} + +int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + return 0; +} + +void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_layerbuf *node = NULL; + struct hisifb_layerbuf *_node_ = NULL; + + BUG_ON(hisifd == NULL); + + + + spin_lock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + list_for_each_entry_safe(node, _node_, + &(hisifd->buf_sync_ctrl.layerbuf_list), + list_node) { + if (hisifd->buf_sync_ctrl.layerbuf_flushed) { + node->timeline++; + } + } + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + + queue_work(hisifd->buf_sync_ctrl.free_layerbuf_queue, + &(hisifd->buf_sync_ctrl.free_layerbuf_work)); +} + +void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd) +{ +} + +void hisifb_buf_sync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + spin_lock_init(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + INIT_LIST_HEAD(&(hisifd->buf_sync_ctrl.layerbuf_list)); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + + INIT_WORK(&(hisifd->buf_sync_ctrl.free_layerbuf_work), + hisifb_layerbuf_unlock_work); + hisifd->buf_sync_ctrl.free_layerbuf_queue = + create_singlethread_workqueue(HISI_DSS_LAYERBUF_FREE); + if (!hisifd->buf_sync_ctrl.free_layerbuf_queue) { + HISI_FB_ERR("failed to create free_layerbuf_queue!\n"); + return; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} + +void hisifb_buf_sync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->buf_sync_ctrl.free_layerbuf_queue) { + destroy_workqueue(hisifd->buf_sync_ctrl.free_layerbuf_queue); + hisifd->buf_sync_ctrl.free_layerbuf_queue = NULL; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_def.h b/drivers/video/fbdev/hisi/dss/hisi_fb_def.h new file mode 100755 index 000000000000..3496be2e1838 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_def.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_FB_DEF_H +#define HISI_FB_DEF_H + +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <asm/bug.h> + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* align */ +#ifndef ALIGN_DOWN +#define ALIGN_DOWN(val, al) ((val) & ~((al)-1)) +#endif +#ifndef ALIGN_UP +#define ALIGN_UP(val, al) (((val) + ((al)-1)) & ~((al)-1)) +#endif + +#ifndef BIT +#define BIT(x) (1<<(x)) +#endif + +#ifndef IS_EVEN +#define IS_EVEN(x) ((x) % 2 == 0) +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define KHZ (1000) +#define MHZ (1000 * 1000) + +enum { + WAIT_TYPE_US = 0, + WAIT_TYPE_MS, +}; + +/*--------------------------------------------------------------------------*/ +extern uint32_t hisi_fb_msg_level; + +/* + * Message printing priorities: + * LEVEL 0 KERN_EMERG (highest priority) + * LEVEL 1 KERN_ALERT + * LEVEL 2 KERN_CRIT + * LEVEL 3 KERN_ERR + * LEVEL 4 KERN_WARNING + * LEVEL 5 KERN_NOTICE + * LEVEL 6 KERN_INFO + * LEVEL 7 KERN_DEBUG (Lowest priority) + */ +#define HISI_FB_EMERG(msg, ...) \ + do { if (hisi_fb_msg_level > 0) \ + printk(KERN_EMERG "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_ALERT(msg, ...) \ + do { if (hisi_fb_msg_level > 1) \ + printk(KERN_ALERT "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_CRIT(msg, ...) \ + do { if (hisi_fb_msg_level > 2) \ + printk(KERN_CRIT "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_ERR(msg, ...) \ + do { if (hisi_fb_msg_level > 3) \ + printk(KERN_ERR "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_WARNING(msg, ...) \ + do { if (hisi_fb_msg_level > 4) \ + printk(KERN_WARNING "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_NOTICE(msg, ...) \ + do { if (hisi_fb_msg_level > 5) \ + printk(KERN_NOTICE "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_INFO(msg, ...) \ + do { if (hisi_fb_msg_level > 6) \ + printk(KERN_INFO "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_DEBUG(msg, ...) \ + do { if (hisi_fb_msg_level > 7) \ + printk(KERN_INFO "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) + +#define assert(expr) \ + if(!(expr)) { \ + printk(KERN_ERR "[hisifb]: assertion failed! %s,%s,%s,line=%d\n",\ + #expr, __FILE__, __func__, __LINE__); \ + } + +#define HISI_FB_ASSERT(x) assert(x) + +#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) + +#define inpw(port) readw(port) +#define outpw(port, val) writew(val, port) +#define inpdw(port) readl(port) +#define outpdw(port, val) writel(val, port) + +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c b/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c new file mode 100755 index 000000000000..ca361f8028b9 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c @@ -0,0 +1,327 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_overlay_utils.h" + +/******************************************************************************* + ** handle isr + */ +irqreturn_t dss_pdp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_dpp = 0; + uint32_t isr_s2_smmu = 0; + uint32_t mask = 0; + uint32_t isr_te_vsync = 0; + uint32_t i = 0; + uint32_t temp = 0; + struct timeval tv; + dss_module_reg_t *dss_module = NULL; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd == NULL); + dss_module = &(hisifd->dss_module); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS); + isr_s2_dpp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INTS); + isr_s2_smmu = + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INTS, isr_s2_dpp); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_PDP_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_PDP_INT_MSK)); + isr_s2 &= + ~(inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK)); + isr_s2_dpp &= ~(inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK)); + + if (is_mipi_cmd_panel(hisifd)) { + isr_te_vsync = BIT_LCD_TE0_PIN; + } else { + isr_te_vsync = BIT_VSYNC; + } + + if (isr_s2 & BIT_VACTIVE0_END) { + hisifd->vactive0_end_flag = 1; + if (g_err_status & DSS_PDP_LDI_UNDERFLOW) { + temp = + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("fb%d, BIT_VACTIVE0_END: frame_no=%d, dpp_dbg =0x%x\n", + hisifd->index, hisifd->ov_req.frame_no, temp); + g_err_status &= ~DSS_PDP_LDI_UNDERFLOW; + } + } + + if (isr_s2 & BIT_VACTIVE0_START) { + if (hisifd->ov_vactive0_start_isr_handler) { + hisifd->ov_vactive0_start_isr_handler(hisifd); + } + + if (g_err_status & DSS_PDP_LDI_UNDERFLOW) { + temp = + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("fb%d, BIT_VACTIVE0_START: frame_no=%d, dpp_dbg=0x%x\n", + hisifd->index, hisifd->ov_req.frame_no, temp); + } + } + + if (isr_s2 & isr_te_vsync) { + if (hisifd->vsync_isr_handler) { + hisifd->vsync_isr_handler(hisifd); + } + + if (hisifd->buf_sync_signal) { + hisifd->buf_sync_signal(hisifd); + } + + if (g_err_status & + (DSS_PDP_LDI_UNDERFLOW | DSS_PDP_SMMU_ERR | + DSS_SDP_SMMU_ERR)) { + temp = + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("isr_te_vsync:frame_no = %d,dpp_dbg = 0x%x\n", + hisifd->ov_req.frame_no, temp); + } + + if (g_debug_ldi_underflow) { + hisifb_get_timestamp(&tv); + HISI_FB_INFO + ("isr_te_vsync:frame_no = %d,isr_s2 = 0x%x\n", + hisifd->ov_req.frame_no, isr_s2); + } + } + + if (isr_s2 & BIT_LDI_UNFLOW) { + mask = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + mask |= BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, mask); + + if (g_debug_ldi_underflow_clear) { + if (is_mipi_cmd_panel(hisifd)) { + if (g_ldi_data_gate_en == 0) { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } else { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } + + if (g_debug_ldi_underflow) { + if (g_debug_ovl_online_composer) { + if (hisifd->dss_debug_wq) + queue_work(hisifd->dss_debug_wq, + &hisifd->dss_debug_work); + } + } + g_err_status |= DSS_PDP_LDI_UNDERFLOW; + + if (hisifd->ldi_data_gate_en == 0) { + temp = + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("ldi underflow! frame_no = %d,dpp_dbg = 0x%x!\n", + hisifd->ov_req.frame_no, temp); + + for (i = 0; i < DSS_WCHN_W0; i++) { + if ((i != DSS_RCHN_V0) && (i != DSS_RCHN_G0)) { + HISI_FB_INFO + ("RCH[%d], DMA_BUF_DBG0 = 0x%x,DMA_BUF_DBG1 = 0x%x!!\n", + i, inp32(dss_module->dma_base[i] + + DMA_BUF_DBG0), + inp32(dss_module->dma_base[i] + + DMA_BUF_DBG1)); + } + } + for (i = 0; i < 18; i++) { + HISI_FB_INFO("MCTL_MOD%d_STATUS = 0x%x\n", + i, inp32(dss_module->mctl_sys_base + + MCTL_MOD0_STATUS + i * 0x4)); + } + } + } + + return IRQ_HANDLED; +} + +irqreturn_t dss_sdp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_smmu = 0; + uint32_t mask = 0; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd == NULL); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_SDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INTS); + isr_s2_smmu = + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_SDP_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_SDP_INT_MSK)); + isr_s2 &= + ~(inp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK)); + + if (isr_s2 & BIT_VACTIVE0_END) { + hisifd->vactive0_end_flag = 1; + } + + if (isr_s2 & BIT_VACTIVE0_START) { + if (hisifd->ov_vactive0_start_isr_handler) + hisifd->ov_vactive0_start_isr_handler(hisifd); + } + + if (isr_s2 & BIT_VSYNC) { + if (hisifd->vsync_isr_handler) { + hisifd->vsync_isr_handler(hisifd); + } + + if (hisifd->buf_sync_signal) { + hisifd->buf_sync_signal(hisifd); + } + } + + if (isr_s2 & BIT_LDI_UNFLOW) { + mask = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + mask |= BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, + mask); + if (g_debug_ldi_underflow_clear) { + if (is_mipi_cmd_panel(hisifd)) { + if (g_ldi_data_gate_en == 0) { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } else { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } + if (g_debug_ldi_underflow) { + if (g_debug_ovl_online_composer) { + if (hisifd->dss_debug_wq) + queue_work(hisifd->dss_debug_wq, + &hisifd->dss_debug_work); + } + } + g_err_status |= DSS_SDP_LDI_UNDERFLOW; + if (hisifd->ldi_data_gate_en == 0) + HISI_FB_ERR("ldi underflow!\n"); + } + return IRQ_HANDLED; +} + +irqreturn_t dss_adp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2_smmu = 0; + uint32_t isr_s3_copybit = 0; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd == NULL); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_OFF_INTS); + isr_s2_smmu = + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + GLB_CPU_OFF_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_OFF_INT_MSK)); + isr_s3_copybit = inp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INTS); + outp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INTS, isr_s3_copybit); + isr_s3_copybit &= ~(inp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INT_MSK)); + + if (isr_s1 & BIT_OFF_WCH0_INTS) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH0] == 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH0] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH0])); + } + } + if (isr_s1 & BIT_OFF_WCH1_INTS) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH1] == 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH1] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH1])); + } + } + if (isr_s1 & BIT_OFF_WCH0_WCH1_FRM_END_INT) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH0_WCH1] == + 1) { + hisifd->cmdlist_info-> + cmdlist_wb_done[WB_TYPE_WCH0_WCH1] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH0_WCH1])); + } + } + + if (isr_s3_copybit & BIT_OFF_CAM_WCH2_FRMEND_INTS) { + if (hisifd->copybit_info->copybit_flag == 1) { + hisifd->copybit_info->copybit_done = 1; + wake_up_interruptible_all(& + (hisifd->copybit_info->copybit_wq)); + } + + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH2] == 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH2] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH2])); + } + } + + return IRQ_HANDLED; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c new file mode 100755 index 000000000000..a26035e8beba --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c @@ -0,0 +1,835 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_fb_panel.h" + +DEFINE_SEMAPHORE(hisi_fb_dts_resource_sem); +mipi_ifbc_division_t g_mipi_ifbc_division[MIPI_DPHY_NUM][IFBC_TYPE_MAX] = { + + { + {XRES_DIV_1, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_0, PXL0_DSI_GT_EN_1} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_1, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_2, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_3, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_4, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + } + , + + { + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_1, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_2, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_3, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_2, IFBC_COMP_MODE_4, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, 3} + } +}; + +int gpio_cmds_tx(struct gpio_desc *cmds, int cnt) +{ + int ret = 0; + struct gpio_desc *cm = NULL; + int i = 0; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if ((cm == NULL) || (cm->label == NULL)) { + HISI_FB_ERR("cm or cm->label is null! index=%d\n", i); + ret = -1; + goto error; + } + + if (!gpio_is_valid(*(cm->gpio))) { + HISI_FB_ERR + ("gpio invalid, dtype=%d, lable=%s, gpio=%d!\n", + cm->dtype, cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + + if (cm->dtype == DTYPE_GPIO_INPUT) { + if (gpio_direction_input(*(cm->gpio)) != 0) { + HISI_FB_ERR + ("failed to gpio_direction_input, lable=%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype == DTYPE_GPIO_OUTPUT) { + if (gpio_direction_output(*(cm->gpio), cm->value) != 0) { + HISI_FB_ERR + ("failed to gpio_direction_output, label%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype == DTYPE_GPIO_REQUEST) { + if (gpio_request(*(cm->gpio), cm->label) != 0) { + HISI_FB_ERR + ("failed to gpio_request, lable=%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype == DTYPE_GPIO_FREE) { + gpio_free(*(cm->gpio)); + } else { + HISI_FB_ERR("dtype=%x NOT supported\n", cm->dtype); + ret = -1; + goto error; + } + + if (cm->wait) { + if (cm->waittype == WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype == WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + + cm++; + } + + return 0; + + error: + return ret; +} + +int resource_cmds_tx(struct platform_device *pdev, + struct resource_desc *cmds, int cnt) +{ + int ret = 0; + struct resource *res = NULL; + struct resource_desc *cm = NULL; + int i = 0; + + BUG_ON(pdev == NULL); + cm = cmds; + + for (i = 0; i < cnt; i++) { + if ((cm == NULL) || (cm->name == NULL)) { + HISI_FB_ERR("cm or cm->name is null! index=%d\n", i); + ret = -1; + goto error; + } + + res = platform_get_resource_byname(pdev, cm->flag, cm->name); + if (!res) { + HISI_FB_ERR("failed to get %s resource!\n", cm->name); + ret = -1; + goto error; + } + *(cm->value) = res->start; + cm++; + } + + error: + return ret; +} + +int vcc_cmds_tx(struct platform_device *pdev, struct vcc_desc *cmds, int cnt) +{ + int ret = 0; + struct vcc_desc *cm = NULL; + int i = 0; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if ((cm == NULL) || (cm->id == NULL)) { + HISI_FB_ERR("cm or cm->id is null! index=%d\n", i); + ret = -1; + goto error; + } + + if (cm->dtype == DTYPE_VCC_GET) { + BUG_ON(pdev == NULL); + *(cm->regulator) = + devm_regulator_get(&pdev->dev, cm->id); + if (IS_ERR(*(cm->regulator))) { + HISI_FB_ERR("failed to get %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } else if (cm->dtype == DTYPE_VCC_PUT) { + if (!IS_ERR(*(cm->regulator))) { + devm_regulator_put(*(cm->regulator)); + } + } else if (cm->dtype == DTYPE_VCC_ENABLE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_enable(*(cm->regulator)) != 0) { + HISI_FB_ERR + ("failed to enable %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } + } else if (cm->dtype == DTYPE_VCC_DISABLE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_disable(*(cm->regulator)) != 0) { + HISI_FB_ERR + ("failed to disable %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } + } else if (cm->dtype == DTYPE_VCC_SET_VOLTAGE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_set_voltage + (*(cm->regulator), cm->min_uV, + cm->max_uV) != 0) { + HISI_FB_ERR + ("failed to set %s regulator voltage!\n", + cm->id); + ret = -1; + goto error; + } + } + } else { + HISI_FB_ERR("dtype=%x NOT supported\n", cm->dtype); + ret = -1; + goto error; + } + + if (cm->wait) { + if (cm->waittype == WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype == WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + + cm++; + } + + return 0; + + error: + return ret; +} + +int pinctrl_cmds_tx(struct platform_device *pdev, struct pinctrl_cmd_desc *cmds, + int cnt) +{ + int ret = 0; + + int i = 0; + struct pinctrl_cmd_desc *cm = NULL; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if (cm == NULL) { + HISI_FB_ERR("cm is null! index=%d\n", i); + continue; + } + if (cm->dtype == DTYPE_PINCTRL_GET) { + BUG_ON(pdev == NULL); + cm->pctrl_data->p = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(cm->pctrl_data->p)) { + ret = -1; + HISI_FB_ERR("failed to get p, index=%d!\n", i); + goto err; + } + } else if (cm->dtype == DTYPE_PINCTRL_STATE_GET) { + if (cm->mode == DTYPE_PINCTRL_STATE_DEFAULT) { + cm->pctrl_data->pinctrl_def = + pinctrl_lookup_state(cm->pctrl_data->p, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(cm->pctrl_data->pinctrl_def)) { + ret = -1; + HISI_FB_ERR + ("failed to get pinctrl_def, index=%d!\n", + i); + goto err; + } + } else if (cm->mode == DTYPE_PINCTRL_STATE_IDLE) { + cm->pctrl_data->pinctrl_idle = + pinctrl_lookup_state(cm->pctrl_data->p, + PINCTRL_STATE_IDLE); + if (IS_ERR(cm->pctrl_data->pinctrl_idle)) { + ret = -1; + HISI_FB_ERR + ("failed to get pinctrl_idle, index=%d!\n", + i); + goto err; + } + } else { + ret = -1; + HISI_FB_ERR("unknown pinctrl type to get!\n"); + goto err; + } + } else if (cm->dtype == DTYPE_PINCTRL_SET) { + if (cm->mode == DTYPE_PINCTRL_STATE_DEFAULT) { + if (cm->pctrl_data->p + && cm->pctrl_data->pinctrl_def) { + ret = + pinctrl_select_state(cm->pctrl_data->p, + cm->pctrl_data->pinctrl_def); + if (ret) { + HISI_FB_ERR + ("could not set this pin to default state!\n"); + ret = -1; + goto err; + } + } + } else if (cm->mode == DTYPE_PINCTRL_STATE_IDLE) { + if (cm->pctrl_data->p + && cm->pctrl_data->pinctrl_idle) { + ret = + pinctrl_select_state(cm->pctrl_data->p, + cm->pctrl_data->pinctrl_idle); + if (ret) { + HISI_FB_ERR + ("could not set this pin to idle state!\n"); + ret = -1; + goto err; + } + } + } else { + ret = -1; + HISI_FB_ERR("unknown pinctrl type to set!\n"); + goto err; + } + } else if (cm->dtype == DTYPE_PINCTRL_PUT) { + if (cm->pctrl_data->p) + pinctrl_put(cm->pctrl_data->p); + } else { + HISI_FB_ERR("not supported command type!\n"); + ret = -1; + goto err; + } + + cm++; + } + + return 0; + + err: + return ret; +} + +int panel_next_on(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->on(next_pdev); + } + + return ret; +} + +int panel_next_off(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->off)) + ret = next_pdata->off(next_pdev); + } + + return ret; +} + +int panel_next_remove(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->remove)) + ret = next_pdata->remove(next_pdev); + } + + return ret; +} + +int panel_next_set_backlight(struct platform_device *pdev, uint32_t bl_level) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->set_backlight)) + ret = next_pdata->set_backlight(next_pdev, bl_level); + } + + return ret; +} + +int panel_next_vsync_ctrl(struct platform_device *pdev, int enable) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev == NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata == NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->vsync_ctrl)) + ret = next_pdata->vsync_ctrl(next_pdev, enable); + } + + return ret; +} + +bool is_ldi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + if (hisifd->panel_info.type & PANEL_LCDC) + return true; + + return false; +} + +bool is_mipi_cmd_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info.type & (PANEL_MIPI_CMD | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_mipi_cmd_panel_ext(struct hisi_panel_info *pinfo) +{ + BUG_ON(pinfo == NULL); + + if (pinfo->type & (PANEL_MIPI_CMD | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_mipi_video_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info. + type & (PANEL_MIPI_VIDEO | PANEL_DUAL_MIPI_VIDEO | PANEL_RGB2MIPI)) + return true; + + return false; +} + +bool is_mipi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info.type & (PANEL_MIPI_VIDEO | PANEL_MIPI_CMD | + PANEL_DUAL_MIPI_VIDEO | + PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_dual_mipi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info. + type & (PANEL_DUAL_MIPI_VIDEO | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_dual_mipi_panel_ext(struct hisi_panel_info *pinfo) +{ + BUG_ON(pinfo == NULL); + + if (pinfo->type & (PANEL_DUAL_MIPI_VIDEO | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_hisi_writeback_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info.type & PANEL_WRITEBACK) + return true; + + return false; +} + +bool is_ifbc_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->panel_info.ifbc_type != IFBC_TYPE_NONE) + return true; + + return false; +} + +bool is_ifbc_vesa_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if ((hisifd->panel_info.ifbc_type == IFBC_TYPE_VESA2X_SINGLE) || + (hisifd->panel_info.ifbc_type == IFBC_TYPE_VESA3X_SINGLE) || + (hisifd->panel_info.ifbc_type == IFBC_TYPE_VESA2X_DUAL) || + (hisifd->panel_info.ifbc_type == IFBC_TYPE_VESA3X_DUAL)) + return true; + + return false; +} + +bool mipi_panel_check_reg(struct hisi_fb_data_type *hisifd, + uint32_t *read_value) +{ + int ret = 0; + char lcd_reg_05[] = { 0x05 }; + char lcd_reg_0a[] = { 0x0a }; + char lcd_reg_0e[] = { 0x0e }; + char lcd_reg_0f[] = { 0x0f }; + + struct dsi_cmd_desc lcd_check_reg[] = { + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_05), lcd_reg_05} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0a), lcd_reg_0a} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0e), lcd_reg_0e} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0f), lcd_reg_0f} + , + }; + + ret = mipi_dsi_cmds_rx(read_value, lcd_check_reg, + ARRAY_SIZE(lcd_check_reg), + hisifd->mipi_dsi0_base); + if (ret) { + HISI_FB_ERR("Read error number: %d\n", ret); + return false; + } + + return true; +} + +int mipi_ifbc_get_rect(struct hisi_fb_data_type *hisifd, struct dss_rect *rect) +{ + uint32_t ifbc_type = 0; + uint32_t mipi_idx = 0; + uint32_t xres_div = 1; + uint32_t yres_div = 1; + + BUG_ON(hisifd == NULL); + BUG_ON(rect == NULL); + + ifbc_type = hisifd->panel_info.ifbc_type; + BUG_ON((ifbc_type < IFBC_TYPE_NONE) || (ifbc_type >= IFBC_TYPE_MAX)); + + mipi_idx = is_dual_mipi_panel(hisifd) ? 1 : 0; + + xres_div = g_mipi_ifbc_division[mipi_idx][ifbc_type].xres_div; + yres_div = g_mipi_ifbc_division[mipi_idx][ifbc_type].yres_div; + + if ((rect->w % xres_div) > 0) { + HISI_FB_ERR + ("fb%d, xres(%d) is not division_h(%d) pixel aligned!\n", + hisifd->index, rect->w, xres_div); + } + + if ((rect->h % yres_div) > 0) { + HISI_FB_ERR + ("fb%d, yres(%d) is not division_v(%d) pixel aligned!\n", + hisifd->index, rect->h, yres_div); + } + + if ((mipi_idx == 0) && (ifbc_type == IFBC_TYPE_RSP3X) + && (hisifd->panel_info.type == PANEL_MIPI_CMD)) { + rect->w *= 2; + rect->h /= 2; + } + + rect->w /= xres_div; + rect->h /= yres_div; + + return 0; +} + +bool hisi_fb_device_probe_defer(uint32_t panel_type, uint32_t bl_type) +{ + bool flag = true; + + down(&hisi_fb_dts_resource_sem); + + switch (panel_type) { + case PANEL_NO: + if (g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) { + flag = false; + } + break; + case PANEL_LCDC: + case PANEL_MIPI2RGB: + case PANEL_RGB2MIPI: + if ((g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) && + (g_dts_resouce_ready & DTS_SPI_READY)) { + if (bl_type & (BL_SET_BY_PWM | BL_SET_BY_BLPWM)) { + if (g_dts_resouce_ready & DTS_PWM_READY) + flag = false; + } else { + flag = false; + } + } + break; + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + case PANEL_EDP: + if (g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) { + if (bl_type & (BL_SET_BY_PWM | BL_SET_BY_BLPWM)) { + if (g_dts_resouce_ready & DTS_PWM_READY) + flag = false; + } else { + flag = false; + } + } + break; + case PANEL_HDMI: + if (g_dts_resouce_ready & DTS_PANEL_PRIMARY_READY) + flag = false; + break; + case PANEL_WRITEBACK: + if (g_dts_resouce_ready & DTS_PANEL_OFFLINECOMPOSER_READY) + flag = false; + break; + default: + HISI_FB_ERR("not support this panel type(%d).\n", panel_type); + break; + } + + up(&hisi_fb_dts_resource_sem); + + return flag; +} + +void hisi_fb_device_set_status0(uint32_t status) +{ + down(&hisi_fb_dts_resource_sem); + g_dts_resouce_ready |= status; + up(&hisi_fb_dts_resource_sem); +} + +int hisi_fb_device_set_status1(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + down(&hisi_fb_dts_resource_sem); + + switch (hisifd->panel_info.type) { + case PANEL_LCDC: + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + case PANEL_EDP: + case PANEL_MIPI2RGB: + case PANEL_RGB2MIPI: + case PANEL_HDMI: + if (hisifd->index == PRIMARY_PANEL_IDX) { + g_dts_resouce_ready |= DTS_PANEL_PRIMARY_READY; + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + g_dts_resouce_ready |= DTS_PANEL_EXTERNAL_READY; + } else { + HISI_FB_ERR("not support fb(%d).\n", hisifd->index); + } + break; + case PANEL_WRITEBACK: + g_dts_resouce_ready |= DTS_PANEL_WRITEBACK_READY; + break; + default: + HISI_FB_ERR("not support this panel type(%d).\n", + hisifd->panel_info.type); + ret = -1; + break; + } + + up(&hisi_fb_dts_resource_sem); + + return ret; +} + +struct platform_device *hisi_fb_device_alloc(struct hisi_fb_panel_data *pdata, + uint32_t type, uint32_t id) +{ + struct platform_device *this_dev = NULL; + char dev_name[32] = { 0 }; + + BUG_ON(pdata == NULL); + + switch (type) { + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_MIPIDSI); + break; + case PANEL_EDP: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_EDP); + break; + case PANEL_NO: + case PANEL_LCDC: + case PANEL_HDMI: + case PANEL_WRITEBACK: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_DSS_DPE); + break; + case PANEL_RGB2MIPI: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_RGB2MIPI); + break; + default: + HISI_FB_ERR("invalid panel type = %d!\n", type); + return NULL; + } + + if (pdata != NULL) + pdata->next = NULL; + else + return NULL; + + this_dev = + platform_device_alloc(dev_name, + (((uint32_t) type << 16) | (uint32_t) id)); + if (this_dev) { + if (platform_device_add_data + (this_dev, pdata, sizeof(struct hisi_fb_panel_data))) { + HISI_FB_ERR("failed to platform_device_add_data!\n"); + platform_device_put(this_dev); + return NULL; + } + } + + return this_dev; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h new file mode 100755 index 000000000000..8afb1f42a8c5 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h @@ -0,0 +1,839 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_FB_PANEL_H +#define HISI_FB_PANEL_H + +#include "hisi_fb_def.h" +#include "hisi_mipi_dsi.h" +#include "hisi_dss.h" + +/* panel type list */ +#define PANEL_NO BIT(0) /* No Panel */ +#define PANEL_LCDC BIT(1) /* internal LCDC type */ +#define PANEL_HDMI BIT(2) /* HDMI TV */ +#define PANEL_MIPI_VIDEO BIT(3) /* MIPI */ +#define PANEL_MIPI_CMD BIT(4) /* MIPI */ +#define PANEL_DUAL_MIPI_VIDEO BIT(5) /* DUAL MIPI */ +#define PANEL_DUAL_MIPI_CMD BIT(6) /* DUAL MIPI */ +#define PANEL_EDP BIT(7) /* LVDS */ +#define PANEL_MIPI2RGB BIT(8) /* MIPI to RGB */ +#define PANEL_RGB2MIPI BIT(9) /* RGB to MIPI */ +#define PANEL_WRITEBACK BIT(11) /* Wifi display */ + +/* dts initial */ +#define DTS_FB_RESOURCE_INIT_READY BIT(0) +#define DTS_PWM_READY BIT(1) + +#define DTS_SPI_READY BIT(3) +#define DTS_PANEL_PRIMARY_READY BIT(4) +#define DTS_PANEL_EXTERNAL_READY BIT(5) +#define DTS_PANEL_OFFLINECOMPOSER_READY BIT(6) +#define DTS_PANEL_WRITEBACK_READY BIT(7) + +/* device name */ +#define DEV_NAME_DSS_DPE "dss_dpe" +#define DEV_NAME_SPI "spi_dev0" +#define DEV_NAME_HDMI "hdmi" +#define DEV_NAME_EDP "edp" +#define DEV_NAME_MIPI2RGB "mipi2rgb" +#define DEV_NAME_RGB2MIPI "rgb2mipi" +#define DEV_NAME_MIPIDSI "mipi_dsi" +#define DEV_NAME_FB "hisi_fb" +#define DEV_NAME_PWM "hisi_pwm" +#define DEV_NAME_BLPWM "hisi_blpwm" +#define DEV_NAME_LCD_BKL "lcd_backlight0" + +/* vcc name */ +#define REGULATOR_PDP_NAME "regulator_dsssubsys" +#define REGULATOR_MMBUF "regulator_mmbuf" + +/* irq name */ +#define IRQ_PDP_NAME "irq_pdp" +#define IRQ_SDP_NAME "irq_sdp" +#define IRQ_ADP_NAME "irq_adp" +#define IRQ_DSI0_NAME "irq_dsi0" +#define IRQ_DSI1_NAME "irq_dsi1" + +/* dts compatible */ +#define DTS_COMP_FB_NAME "hisilicon,hisifb" +#define DTS_COMP_PWM_NAME "hisilicon,hisipwm" +#define DTS_COMP_BLPWM_NAME "hisilicon,hisiblpwm" +#define DTS_PATH_LOGO_BUFFER "/reserved-memory/logo-buffer" + +/* lcd resource name */ +#define LCD_BL_TYPE_NAME "lcd-bl-type" +#define FPGA_FLAG_NAME "fpga_flag" +#define LCD_DISPLAY_TYPE_NAME "lcd-display-type" +#define LCD_IFBC_TYPE_NAME "lcd-ifbc-type" + +/* backlight type */ +#define BL_SET_BY_NONE BIT(0) +#define BL_SET_BY_PWM BIT(1) +#define BL_SET_BY_BLPWM BIT(2) +#define BL_SET_BY_MIPI BIT(3) +#define BL_SET_BY_SH_BLPWM BIT(4) + +/* supported display effect type */ +#define COMFORM_MODE BIT(0) +#define ACM_COLOR_ENHANCE_MODE BIT(1) +#define IC_COLOR_ENHANCE_MODE BIT(2) +#define CINEMA_MODE BIT(3) +#define VR_MODE BIT(4) +#define LED_RG_COLOR_TEMP_MODE BIT(16) +#define GAMMA_MAP BIT(19) + +#define LCD_BL_IC_NAME_MAX (50) +#define DEV_DSS_VOLTAGE_ID (20) + +enum BLPWM_PRECISION_TYPE { + BLPWM_PRECISION_DEFAULT_TYPE = 0, + BLPWM_PRECISION_10000_TYPE = 1, + BLPWM_PRECISION_2048_TYPE = 2, +}; + +enum LCD_INIT_STEP { + LCD_INIT_NONE = 0, + LCD_INIT_POWER_ON, + LCD_INIT_LDI_SEND_SEQUENCE, + LCD_INIT_MIPI_LP_SEND_SEQUENCE, + LCD_INIT_MIPI_HS_SEND_SEQUENCE, +}; + +enum LCD_UNINIT_STEP { + LCD_UNINIT_NONE = 0, + LCD_UNINIT_POWER_OFF, + LCD_UNINIT_LDI_SEND_SEQUENCE, + LCD_UNINIT_MIPI_LP_SEND_SEQUENCE, + LCD_UNINIT_MIPI_HS_SEND_SEQUENCE, +}; + +enum LCD_ESD_RECOVER_STEP { + LCD_ESD_RECOVER_NONE = 0, + LCD_ESD_RECOVER_POWER_OFF, + LCD_ESD_RECOVER_POWER_ON, +}; + +enum LCD_REFRESH_DIRECTION { + LCD_REFRESH_LEFT_TOP = 0, + LCD_REFRESH_RIGHT_TOP, + LCD_REFRESH_LEFT_BOTTOM, + LCD_REFRESH_RIGHT_BOTTOM, +}; + +enum IFBC_TYPE { + IFBC_TYPE_NONE = 0, + IFBC_TYPE_ORISE2X, + IFBC_TYPE_ORISE3X, + IFBC_TYPE_HIMAX2X, + IFBC_TYPE_RSP2X, + IFBC_TYPE_RSP3X, + IFBC_TYPE_VESA2X_SINGLE, + IFBC_TYPE_VESA3X_SINGLE, + IFBC_TYPE_VESA2X_DUAL, + IFBC_TYPE_VESA3X_DUAL, + + IFBC_TYPE_MAX +}; + +enum IFBC_COMP_MODE { + IFBC_COMP_MODE_0 = 0, + IFBC_COMP_MODE_1, + IFBC_COMP_MODE_2, + IFBC_COMP_MODE_3, + IFBC_COMP_MODE_4, + IFBC_COMP_MODE_5, + IFBC_COMP_MODE_6, +}; + +enum XRES_DIV { + XRES_DIV_1 = 1, + XRES_DIV_2, + XRES_DIV_3, + XRES_DIV_4, + XRES_DIV_5, + XRES_DIV_6, +}; + +enum YRES_DIV { + YRES_DIV_1 = 1, + YRES_DIV_2, + YRES_DIV_3, + YRES_DIV_4, + YRES_DIV_5, + YRES_DIV_6, +}; + +enum PXL0_DIVCFG { + PXL0_DIVCFG_0 = 0, + PXL0_DIVCFG_1, + PXL0_DIVCFG_2, + PXL0_DIVCFG_3, + PXL0_DIVCFG_4, + PXL0_DIVCFG_5, + PXL0_DIVCFG_6, + PXL0_DIVCFG_7, +}; + +enum PXL0_DIV2_GT_EN { + PXL0_DIV2_GT_EN_CLOSE = 0, + PXL0_DIV2_GT_EN_OPEN, +}; + +enum PXL0_DIV4_GT_EN { + PXL0_DIV4_GT_EN_CLOSE = 0, + PXL0_DIV4_GT_EN_OPEN, +}; + +enum PXL0_DSI_GT_EN { + PXL0_DSI_GT_EN_0 = 0, + PXL0_DSI_GT_EN_1, + PXL0_DSI_GT_EN_2, + PXL0_DSI_GT_EN_3, +}; + +enum VSYNC_CTRL_TYPE { + VSYNC_CTRL_NONE = 0x0, + VSYNC_CTRL_ISR_OFF = BIT(0), + VSYNC_CTRL_MIPI_ULPS = BIT(1), + VSYNC_CTRL_CLK_OFF = BIT(2), + VSYNC_CTRL_VCC_OFF = BIT(3), +}; + +enum PERI_VOLTAGE_VALUE { + PERI_VOLTAGE_07V = 0x0, + PERI_VOLTAGE_08V = 0x2, +}; + +#define MIPI_DSI_BIT_CLK_STR1 "00001" +#define MIPI_DSI_BIT_CLK_STR2 "00010" +#define MIPI_DSI_BIT_CLK_STR3 "00100" +#define MIPI_DSI_BIT_CLK_STR4 "01000" +#define MIPI_DSI_BIT_CLK_STR5 "10000" + +/* resource desc */ +struct resource_desc { + uint32_t flag; + char *name; + uint32_t *value; +}; + +/* dtype for vcc */ +enum { + DTYPE_VCC_GET, + DTYPE_VCC_PUT, + DTYPE_VCC_ENABLE, + DTYPE_VCC_DISABLE, + DTYPE_VCC_SET_VOLTAGE, +}; + +/* vcc desc */ +struct vcc_desc { + int dtype; + char *id; + struct regulator **regulator; + int min_uV; + int max_uV; + int waittype; + int wait; +}; + +/* pinctrl operation */ +enum { + DTYPE_PINCTRL_GET, + DTYPE_PINCTRL_STATE_GET, + DTYPE_PINCTRL_SET, + DTYPE_PINCTRL_PUT, +}; + +/* pinctrl state */ +enum { + DTYPE_PINCTRL_STATE_DEFAULT, + DTYPE_PINCTRL_STATE_IDLE, +}; + +/* pinctrl data */ +struct pinctrl_data { + struct pinctrl *p; + struct pinctrl_state *pinctrl_def; + struct pinctrl_state *pinctrl_idle; +}; +struct pinctrl_cmd_desc { + int dtype; + struct pinctrl_data *pctrl_data; + int mode; +}; + +/* dtype for gpio */ +enum { + DTYPE_GPIO_REQUEST, + DTYPE_GPIO_FREE, + DTYPE_GPIO_INPUT, + DTYPE_GPIO_OUTPUT, +}; + +/* gpio desc */ +struct gpio_desc { + int dtype; + int waittype; + int wait; + char *label; + uint32_t *gpio; + int value; +}; + +struct spi_cmd_desc { + int reg_len; + char *reg; + int val_len; + char *val; + int waittype; + int wait; +}; + +enum { + IFBC_ORISE_CTL_8LINE = 0, + IFBC_ORISE_CTL_16LINE, + IFBC_ORISE_CTL_32LINE, + IFBC_ORISE_CTL_FRAME, +}; + +typedef struct mipi_ifbc_division { + uint32_t xres_div; + uint32_t yres_div; + uint32_t comp_mode; + uint32_t pxl0_div2_gt_en; + uint32_t pxl0_div4_gt_en; + uint32_t pxl0_divxcfg; + uint32_t pxl0_dsi_gt_en; +} mipi_ifbc_division_t; + +struct ldi_panel_info { + uint32_t h_back_porch; + uint32_t h_front_porch; + uint32_t h_pulse_width; + + /* + ** note: vbp > 8 if used overlay compose, + ** also lcd vbp > 8 in lcd power on sequence + */ + uint32_t v_back_porch; + uint32_t v_front_porch; + uint32_t v_pulse_width; + + uint8_t hsync_plr; + uint8_t vsync_plr; + uint8_t pixelclk_plr; + uint8_t data_en_plr; + + /* for cabc */ + uint8_t dpi0_overlap_size; + uint8_t dpi1_overlap_size; +}; + +/* DSI PHY configuration */ +struct mipi_dsi_phy_ctrl { + uint64_t lane_byte_clk; + uint32_t clk_division; + + uint32_t clk_lane_lp2hs_time; + uint32_t clk_lane_hs2lp_time; + uint32_t data_lane_lp2hs_time; + uint32_t data_lane_hs2lp_time; + uint32_t clk2data_delay; + uint32_t data2clk_delay; + + uint32_t clk_pre_delay; + uint32_t clk_post_delay; + uint32_t clk_t_lpx; + uint32_t clk_t_hs_prepare; + uint32_t clk_t_hs_zero; + uint32_t clk_t_hs_trial; + uint32_t clk_t_wakeup; + uint32_t data_pre_delay; + uint32_t data_post_delay; + uint32_t data_t_lpx; + uint32_t data_t_hs_prepare; + uint32_t data_t_hs_zero; + uint32_t data_t_hs_trial; + uint32_t data_t_ta_go; + uint32_t data_t_ta_get; + uint32_t data_t_wakeup; + + uint32_t phy_stop_wait_time; + + uint32_t rg_vrefsel_vcm; + uint32_t rg_hstx_ckg_sel; + uint32_t rg_pll_fbd_div5f; + uint32_t rg_pll_fbd_div1f; + uint32_t rg_pll_fbd_2p; + uint32_t rg_pll_enbwt; + uint32_t rg_pll_fbd_p; + uint32_t rg_pll_fbd_s; + uint32_t rg_pll_pre_div1p; + uint32_t rg_pll_pre_p; + uint32_t rg_pll_vco_750m; + uint32_t rg_pll_lpf_rs; + uint32_t rg_pll_lpf_cs; + uint32_t rg_pll_enswc; + uint32_t rg_pll_chp; + + + uint32_t pll_register_override; + uint32_t pll_power_down; + uint32_t rg_band_sel; + uint32_t rg_phase_gen_en; + uint32_t reload_sel; + uint32_t rg_pll_cp_p; + uint32_t rg_pll_refsel; + uint32_t rg_pll_cp; + uint32_t load_command; +}; + +struct mipi_panel_info { + uint8_t dsi_version; + uint8_t vc; + uint8_t lane_nums; + uint8_t lane_nums_select_support; + uint8_t color_mode; + uint32_t dsi_bit_clk; /* clock lane(p/n) */ + uint32_t burst_mode; + uint32_t max_tx_esc_clk; + uint8_t non_continue_en; + + uint32_t dsi_bit_clk_val1; + uint32_t dsi_bit_clk_val2; + uint32_t dsi_bit_clk_val3; + uint32_t dsi_bit_clk_val4; + uint32_t dsi_bit_clk_val5; + uint32_t dsi_bit_clk_upt; + /*uint32_t dsi_pclk_rate; */ + + uint32_t hs_wr_to_time; + + uint32_t clk_post_adjust; + uint32_t clk_pre_adjust; + uint32_t clk_pre_delay_adjust; + uint32_t clk_t_hs_exit_adjust; + uint32_t clk_t_hs_trial_adjust; + uint32_t clk_t_hs_prepare_adjust; + int clk_t_lpx_adjust; + uint32_t clk_t_hs_zero_adjust; + uint32_t data_post_delay_adjust; + int data_t_lpx_adjust; + uint32_t data_t_hs_prepare_adjust; + uint32_t data_t_hs_zero_adjust; + uint32_t data_t_hs_trial_adjust; + uint32_t rg_vrefsel_vcm_adjust; + + uint32_t rg_vrefsel_vcm_clk_adjust; + uint32_t rg_vrefsel_vcm_data_adjust; +}; + +struct sbl_panel_info { + uint32_t strength_limit; + uint32_t calibration_a; + uint32_t calibration_b; + uint32_t calibration_c; + uint32_t calibration_d; + uint32_t t_filter_control; + uint32_t backlight_min; + uint32_t backlight_max; + uint32_t backlight_scale; + uint32_t ambient_light_min; + uint32_t filter_a; + uint32_t filter_b; + uint32_t logo_left; + uint32_t logo_top; + uint32_t variance_intensity_space; + uint32_t slope_max; + uint32_t slope_min; +}; + +typedef struct dss_sharpness_bit { + uint32_t sharp_en; + uint32_t sharp_mode; + + uint32_t flt0_c0; + uint32_t flt0_c1; + uint32_t flt0_c2; + + uint32_t flt1_c0; + uint32_t flt1_c1; + uint32_t flt1_c2; + + uint32_t flt2_c0; + uint32_t flt2_c1; + uint32_t flt2_c2; + + uint32_t ungain; + uint32_t ovgain; + + uint32_t lineamt1; + uint32_t linedeten; + uint32_t linethd2; + uint32_t linethd1; + + uint32_t sharpthd1; + uint32_t sharpthd1mul; + uint32_t sharpamt1; + + uint32_t edgethd1; + uint32_t edgethd1mul; + uint32_t edgeamt1; +} sharp2d_t; + +struct dsc_panel_info { + + uint32_t bits_per_pixel; + uint32_t block_pred_enable; + uint32_t linebuf_depth; + uint32_t bits_per_component; + uint32_t slice_width; + uint32_t slice_height; + uint32_t initial_xmit_delay; + uint32_t first_line_bpg_offset; + uint32_t mux_word_size; + uint32_t initial_offset; + uint32_t flatness_max_qp; + uint32_t flatness_min_qp; + uint32_t rc_edge_factor; + uint32_t rc_model_size; + uint32_t rc_tgt_offset_lo; + uint32_t rc_tgt_offset_hi; + uint32_t rc_quant_incr_limit1; + uint32_t rc_quant_incr_limit0; + uint32_t rc_buf_thresh0; + uint32_t rc_buf_thresh1; + uint32_t rc_buf_thresh2; + uint32_t rc_buf_thresh3; + uint32_t rc_buf_thresh4; + uint32_t rc_buf_thresh5; + uint32_t rc_buf_thresh6; + uint32_t rc_buf_thresh7; + uint32_t rc_buf_thresh8; + uint32_t rc_buf_thresh9; + uint32_t rc_buf_thresh10; + uint32_t rc_buf_thresh11; + uint32_t rc_buf_thresh12; + uint32_t rc_buf_thresh13; + uint32_t range_min_qp0; + uint32_t range_max_qp0; + uint32_t range_bpg_offset0; + uint32_t range_min_qp1; + uint32_t range_max_qp1; + uint32_t range_bpg_offset1; + uint32_t range_min_qp2; + uint32_t range_max_qp2; + uint32_t range_bpg_offset2; + uint32_t range_min_qp3; + uint32_t range_max_qp3; + uint32_t range_bpg_offset3; + uint32_t range_min_qp4; + uint32_t range_max_qp4; + uint32_t range_bpg_offset4; + uint32_t range_min_qp5; + uint32_t range_max_qp5; + uint32_t range_bpg_offset5; + uint32_t range_min_qp6; + uint32_t range_max_qp6; + uint32_t range_bpg_offset6; + uint32_t range_min_qp7; + uint32_t range_max_qp7; + uint32_t range_bpg_offset7; + uint32_t range_min_qp8; + uint32_t range_max_qp8; + uint32_t range_bpg_offset8; + uint32_t range_min_qp9; + uint32_t range_max_qp9; + uint32_t range_bpg_offset9; + uint32_t range_min_qp10; + uint32_t range_max_qp10; + uint32_t range_bpg_offset10; + uint32_t range_min_qp11; + uint32_t range_max_qp11; + uint32_t range_bpg_offset11; + uint32_t range_min_qp12; + uint32_t range_max_qp12; + uint32_t range_bpg_offset12; + uint32_t range_min_qp13; + uint32_t range_max_qp13; + uint32_t range_bpg_offset13; + uint32_t range_min_qp14; + uint32_t range_max_qp14; + uint32_t range_bpg_offset14; +}; + +struct hisi_panel_info { + uint32_t type; + uint32_t xres; + uint32_t yres; + uint32_t width; + uint32_t height; + uint32_t bpp; + uint32_t fps; + uint32_t fps_updt; + uint32_t orientation; + uint32_t bgr_fmt; + uint32_t bl_set_type; + uint32_t bl_min; + uint32_t bl_max; + uint32_t bl_default; + uint32_t blpwm_precision_type; + uint32_t blpwm_out_div_value; + uint32_t blpwm_input_ena; + uint32_t blpwm_in_num; + uint32_t blpwm_input_precision; + uint32_t bl_ic_ctrl_mode; + uint64_t pxl_clk_rate; + uint64_t pxl_clk_rate_adjust; + uint32_t pxl_clk_rate_div; + uint32_t vsync_ctrl_type; + uint8_t fake_hdmi; + uint8_t reserved[3]; + + uint32_t ifbc_type; + uint32_t ifbc_cmp_dat_rev0; + uint32_t ifbc_cmp_dat_rev1; + uint32_t ifbc_auto_sel; + uint32_t ifbc_orise_ctl; + uint32_t ifbc_orise_ctr; + + uint8_t lcd_init_step; + uint8_t lcd_uninit_step; + uint8_t lcd_uninit_step_support; + uint8_t lcd_refresh_direction_ctrl; + uint8_t lcd_adjust_support; + + uint8_t sbl_support; + uint8_t color_temperature_support; + uint8_t color_temp_rectify_support; + uint32_t color_temp_rectify_R; + uint32_t color_temp_rectify_G; + uint32_t color_temp_rectify_B; + uint8_t comform_mode_support; + uint8_t cinema_mode_support; + uint8_t frc_enable; + uint8_t esd_enable; + uint8_t esd_skip_mipi_check; + uint8_t esd_recover_step; + uint8_t dirty_region_updt_support; + uint8_t dsi_bit_clk_upt_support; + uint8_t fps_updt_support; + uint8_t panel_effect_support; + + uint8_t prefix_ce_support; + uint8_t prefix_sharpness1D_support; + uint8_t prefix_sharpness2D_support; + sharp2d_t *sharp2d_table; + + uint8_t gmp_support; + uint8_t gamma_support; + uint8_t gamma_type; + uint8_t xcc_support; + uint8_t acm_support; + uint8_t acm_ce_support; + uint8_t hiace_support; + uint8_t dither_support; + uint8_t arsr1p_sharpness_support; + uint8_t post_scf_support; + uint8_t default_gmp_off; + + uint32_t acm_valid_num; + uint32_t r0_hh; + uint32_t r0_lh; + uint32_t r1_hh; + uint32_t r1_lh; + uint32_t r2_hh; + uint32_t r2_lh; + uint32_t r3_hh; + uint32_t r3_lh; + uint32_t r4_hh; + uint32_t r4_lh; + uint32_t r5_hh; + uint32_t r5_lh; + uint32_t r6_hh; + uint32_t r6_lh; + + uint32_t cinema_acm_valid_num; + uint32_t cinema_r0_hh; + uint32_t cinema_r0_lh; + uint32_t cinema_r1_hh; + uint32_t cinema_r1_lh; + uint32_t cinema_r2_hh; + uint32_t cinema_r2_lh; + uint32_t cinema_r3_hh; + uint32_t cinema_r3_lh; + uint32_t cinema_r4_hh; + uint32_t cinema_r4_lh; + uint32_t cinema_r5_hh; + uint32_t cinema_r5_lh; + uint32_t cinema_r6_hh; + uint32_t cinema_r6_lh; + + uint32_t *acm_lut_hue_table; + uint32_t acm_lut_hue_table_len; + uint32_t *acm_lut_value_table; + uint32_t acm_lut_value_table_len; + uint32_t *acm_lut_sata_table; + uint32_t acm_lut_sata_table_len; + uint32_t *acm_lut_satr_table; + uint32_t acm_lut_satr_table_len; + + uint32_t *cinema_acm_lut_hue_table; + uint32_t cinema_acm_lut_hue_table_len; + uint32_t *cinema_acm_lut_value_table; + uint32_t cinema_acm_lut_value_table_len; + uint32_t *cinema_acm_lut_sata_table; + uint32_t cinema_acm_lut_sata_table_len; + uint32_t *cinema_acm_lut_satr_table; + uint32_t cinema_acm_lut_satr_table_len; + + uint32_t *acm_lut_satr0_table; + uint32_t acm_lut_satr0_table_len; + uint32_t *acm_lut_satr1_table; + uint32_t acm_lut_satr1_table_len; + uint32_t *acm_lut_satr2_table; + uint32_t acm_lut_satr2_table_len; + uint32_t *acm_lut_satr3_table; + uint32_t acm_lut_satr3_table_len; + uint32_t *acm_lut_satr4_table; + uint32_t acm_lut_satr4_table_len; + uint32_t *acm_lut_satr5_table; + uint32_t acm_lut_satr5_table_len; + uint32_t *acm_lut_satr6_table; + uint32_t acm_lut_satr6_table_len; + uint32_t *acm_lut_satr7_table; + uint32_t acm_lut_satr7_table_len; + + uint32_t *cinema_acm_lut_satr0_table; + uint32_t *cinema_acm_lut_satr1_table; + uint32_t *cinema_acm_lut_satr2_table; + uint32_t *cinema_acm_lut_satr3_table; + uint32_t *cinema_acm_lut_satr4_table; + uint32_t *cinema_acm_lut_satr5_table; + uint32_t *cinema_acm_lut_satr6_table; + uint32_t *cinema_acm_lut_satr7_table; + + uint32_t *gamma_lut_table_R; + uint32_t *gamma_lut_table_G; + uint32_t *gamma_lut_table_B; + uint32_t gamma_lut_table_len; + uint32_t *cinema_gamma_lut_table_R; + uint32_t *cinema_gamma_lut_table_G; + uint32_t *cinema_gamma_lut_table_B; + uint32_t cinema_gamma_lut_table_len; + uint32_t *igm_lut_table_R; + uint32_t *igm_lut_table_G; + uint32_t *igm_lut_table_B; + uint32_t igm_lut_table_len; + uint32_t *gmp_lut_table_low32bit; + uint32_t *gmp_lut_table_high4bit; + uint32_t gmp_lut_table_len; + uint32_t *xcc_table; + uint32_t xcc_table_len; + + uint32_t *pgainlsc0; + uint32_t *pgainlsc1; + uint32_t pgainlsc_len; + uint32_t *hcoeff0y; + uint32_t *hcoeff1y; + uint32_t *hcoeff2y; + uint32_t *hcoeff3y; + uint32_t *hcoeff4y; + uint32_t *hcoeff5y; + uint32_t hcoeffy_len; + uint32_t *vcoeff0y; + uint32_t *vcoeff1y; + uint32_t *vcoeff2y; + uint32_t *vcoeff3y; + uint32_t *vcoeff4y; + uint32_t *vcoeff5y; + uint32_t vcoeffy_len; + uint32_t *hcoeff0uv; + uint32_t *hcoeff1uv; + uint32_t *hcoeff2uv; + uint32_t *hcoeff3uv; + uint32_t hcoeffuv_len; + uint32_t *vcoeff0uv; + uint32_t *vcoeff1uv; + uint32_t *vcoeff2uv; + uint32_t *vcoeff3uv; + uint32_t vcoeffuv_len; + + struct spi_device *spi_dev; + struct ldi_panel_info ldi; + struct ldi_panel_info ldi_updt; + struct ldi_panel_info ldi_lfps; + struct mipi_panel_info mipi; + struct sbl_panel_info smart_bl; + struct dsc_panel_info vesa_dsc; + struct lcd_dirty_region_info dirty_region_info; + + struct mipi_dsi_phy_ctrl dsi_phy_ctrl; + + struct hiace_alg_parameter hiace_param; + struct ce_algorithm_parameter ce_alg_param; +}; + +struct hisi_fb_data_type; +struct hisi_fb_panel_data { + struct hisi_panel_info *panel_info; + + /* function entry chain */ + int (*on) (struct platform_device *pdev); + int (*off) (struct platform_device *pdev); + int (*remove) (struct platform_device *pdev); + int (*set_backlight) (struct platform_device *pdev, uint32_t bl_level); + int (*vsync_ctrl) (struct platform_device *pdev, int enable); + + struct platform_device *next; +}; + +/******************************************************************************* + ** FUNCTIONS PROTOTYPES + */ +#define MIPI_DPHY_NUM (2) + +extern uint32_t g_dts_resouce_ready; +extern mipi_ifbc_division_t g_mipi_ifbc_division[MIPI_DPHY_NUM][IFBC_TYPE_MAX]; +int resource_cmds_tx(struct platform_device *pdev, + struct resource_desc *cmds, int cnt); +int vcc_cmds_tx(struct platform_device *pdev, struct vcc_desc *cmds, int cnt); +int pinctrl_cmds_tx(struct platform_device *pdev, struct pinctrl_cmd_desc *cmds, + int cnt); +int gpio_cmds_tx(struct gpio_desc *cmds, int cnt); +extern struct spi_device *g_spi_dev; + +int panel_next_on(struct platform_device *pdev); +int panel_next_off(struct platform_device *pdev); +int panel_next_remove(struct platform_device *pdev); +int panel_next_set_backlight(struct platform_device *pdev, uint32_t bl_level); +int panel_next_vsync_ctrl(struct platform_device *pdev, int enable); + +bool is_ldi_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_cmd_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_cmd_panel_ext(struct hisi_panel_info *pinfo); +bool is_mipi_video_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_panel(struct hisi_fb_data_type *hisifd); +bool is_dual_mipi_panel(struct hisi_fb_data_type *hisifd); +bool is_dual_mipi_panel_ext(struct hisi_panel_info *pinfo); +bool is_ifbc_panel(struct hisi_fb_data_type *hisifd); +bool is_ifbc_vesa_panel(struct hisi_fb_data_type *hisifd); +bool mipi_panel_check_reg(struct hisi_fb_data_type *hisifd, + uint32_t *read_value); +int mipi_ifbc_get_rect(struct hisi_fb_data_type *hisifd, struct dss_rect *rect); +bool is_hisi_writeback_panel(struct hisi_fb_data_type *hisifd); +void hisi_fb_device_set_status0(uint32_t status); +int hisi_fb_device_set_status1(struct hisi_fb_data_type *hisifd); +bool hisi_fb_device_probe_defer(uint32_t panel_type, uint32_t bl_type); +#endif /* HISI_FB_PANEL_H */ -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 5/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_fb_bl.c | 323 +++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c | 507 ++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_def.h | 125 ++++ drivers/video/fbdev/hisi/dss/hisi_fb_isr.c | 327 +++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_panel.c | 835 +++++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_fb_panel.h | 839 ++++++++++++++++++++++++ 6 files changed, 2956 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_bl.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_def.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_isr.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_panel.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_panel.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c b/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c new file mode 100755 index 000000000000..ee4b8c7f4abb --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_bl.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include <linux/leds.h> +#define K3_DSS_SBL_WORKQUEUE "k3_dss_sbl_workqueue" + +static int lcd_backlight_registered; +static unsigned int is_recovery_mode; +static int is_no_fastboot_bl_enable; + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY +unsigned long backlight_duration = (3 * HZ / 60); +#endif + +void hisifb_set_backlight(struct hisi_fb_data_type *hisifd, uint32_t bkl_lvl) +{ + struct hisi_fb_panel_data *pdata = NULL; + uint32_t temp = bkl_lvl; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + if (!hisifd->panel_power_on || !hisifd->backlight.bl_updated) { + hisifd->bl_level = bkl_lvl; + return; + } + + if (pdata->set_backlight) { + if (hisifd->backlight.bl_level_old = temp) { + hisifd->bl_level = bkl_lvl; + return; + } + if (hisifd->backlight.bl_level_old = 0) { + HISI_FB_INFO("backlight level = %d", bkl_lvl); + } + hisifd->bl_level = bkl_lvl; + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) { + hisifb_set_vsync_activate_state(hisifd, true); + hisifb_activate_vsync(hisifd); + } + pdata->set_backlight(hisifd->pdev, bkl_lvl); + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) { + hisifb_set_vsync_activate_state(hisifd, false); + hisifb_deactivate_vsync(hisifd); + } + hisifd->backlight.bl_level_old = temp; + } +} + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY +static void hisifb_bl_workqueue_handler(struct work_struct *work) +#else +static void hisifb_bl_workqueue_handler(struct hisi_fb_data_type *hisifd) +#endif +{ + struct hisi_fb_panel_data *pdata = NULL; +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + struct hisifb_backlight *pbacklight = NULL; + struct hisi_fb_data_type *hisifd = NULL; + + pbacklight + container_of(to_delayed_work(work), struct hisifb_backlight, + bl_worker); + BUG_ON(pbacklight = NULL); + + hisifd = container_of(pbacklight, struct hisi_fb_data_type, backlight); +#endif + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + if (!hisifd->backlight.bl_updated) { + down(&hisifd->blank_sem); + + if (hisifd->backlight.frame_updated = 0) { + up(&hisifd->blank_sem); + return; + } + + hisifd->backlight.frame_updated = 0; + hisifd->backlight.bl_updated = 1; + if (is_recovery_mode) { + hisifd->bl_level = hisifd->panel_info.bl_default; + } else { + if (!is_no_fastboot_bl_enable) { + is_no_fastboot_bl_enable = 1; + hisifd->bl_level + hisifd->panel_info.bl_default; + } + } + + hisifb_set_backlight(hisifd, hisifd->bl_level); + up(&hisifd->blank_sem); + } +} + +void hisifb_backlight_update(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + if (!hisifd->backlight.bl_updated) { + hisifd->backlight.frame_updated = 1; +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + schedule_delayed_work(&hisifd->backlight.bl_worker, + backlight_duration); +#else + hisifb_bl_workqueue_handler(hisifd); +#endif + } +} + +void hisifb_backlight_cancel(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + cancel_delayed_work(&hisifd->backlight.bl_worker); +#endif + hisifd->backlight.bl_updated = 0; + hisifd->backlight.bl_level_old = 0; + hisifd->backlight.frame_updated = 0; + + if (pdata->set_backlight) { + hisifd->bl_level = 0; + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) + hisifb_activate_vsync(hisifd); + pdata->set_backlight(hisifd->pdev, hisifd->bl_level); + if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) + hisifb_deactivate_vsync(hisifd); + } +} + +#ifdef CONFIG_FB_BACKLIGHT +static int hisi_fb_bl_get_brightness(struct backlight_device *pbd) +{ + if (NULL = pbd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + return pbd->props.brightness; +} + +static int hisi_fb_bl_update_status(struct backlight_device *pbd) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t bl_lvl = 0; + + if (NULL = pbd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + + hisifd = bl_get_data(pbd); + if (NULL = hisifd) { + HISI_FB_ERR("NULL pointer!\n"); + return 0; + } + + bl_lvl = pbd->props.brightness; + bl_lvl = hisifd->fbi->bl_curve[bl_lvl]; + + down(&hisifd->blank_sem); + hisifb_set_backlight(hisifd, bl_lvl); + up(&hisifd->blank_sem); + + return 0; +} + +static struct backlight_ops hisi_fb_bl_ops = { + .get_brightness = hisi_fb_bl_get_brightness, + .update_status = hisi_fb_bl_update_status, +}; +#else +static void hisi_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct hisi_fb_data_type *hisifd = NULL; + int bl_lvl = 0; + + if (NULL = led_cdev) { + HISI_FB_ERR("NULL pointer!\n"); + return; + } + + hisifd = dev_get_drvdata(led_cdev->dev->parent); + if (NULL = hisifd) { + HISI_FB_ERR("NULL pointer!\n"); + return; + } + + if (value < 0) + value = 0; + + if (value > hisifd->panel_info.bl_max) + value = hisifd->panel_info.bl_max; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl + (2 * value * hisifd->panel_info.bl_max + hisifd->panel_info.bl_max) + / (2 * hisifd->panel_info.bl_max); + if (!bl_lvl && value) + bl_lvl = 1; + hisifb_set_backlight(hisifd, bl_lvl); +} + +static struct led_classdev backlight_led = { + .name = DEV_NAME_LCD_BKL, + .brightness_set = hisi_fb_set_bl_brightness, +}; +#endif + +void hisifb_backlight_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; +#ifdef CONFIG_FB_BACKLIGHT + struct backlight_device *pbd = NULL; + struct fb_info *fbi = NULL; + char name[16] = { 0 }; + struct backlight_properties props; +#endif + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + hisifd->backlight.bl_updated = 0; + hisifd->backlight.frame_updated = 0; + hisifd->backlight.bl_level_old = 0; + sema_init(&hisifd->backlight.bl_sem, 1); +#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY + INIT_DELAYED_WORK(&hisifd->backlight.bl_worker, + hisifb_bl_workqueue_handler); +#endif + + if (lcd_backlight_registered) return; + +#ifdef CONFIG_FB_BACKLIGHT + fbi = hisifd->fbi; + + snprintf(name, sizeof(name), "hisifb%d_bl", hisifd->index); + props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + props.brightness = FB_BACKLIGHT_LEVELS - 1; + pbd = backlight_device_register(name, fbi->dev, hisifd, + &hisi_fb_bl_ops, &props); + if (IS_ERR(pbd)) { + fbi->bl_dev = NULL; + HISI_FB_ERR("backlight_device_register failed!\n"); + } + + fbi->bl_dev = pbd; + fb_bl_default_curve(fbi, 0, + hisifd->panel_info.bl_min, + hisifd->panel_info.bl_max); +#else + backlight_led.brightness = hisifd->panel_info.bl_default; + backlight_led.max_brightness = hisifd->panel_info.bl_max; + /* android supports only one lcd-backlight/lcd for now */ +#ifdef CONFIG_LEDS_CLASS + if (led_classdev_register(&pdev->dev, &backlight_led)) { + HISI_FB_ERR("led_classdev_register failed!\n"); + return; + } +#endif +#endif + + if (HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_SBL)) { + hisifd->backlight.sbl_queue + create_singlethread_workqueue(K3_DSS_SBL_WORKQUEUE); + if (!hisifd->backlight.sbl_queue) { + HISI_FB_ERR("failed to create sbl_queue!\n"); + return; + } + } + + lcd_backlight_registered = 1; +} + +void hisifb_backlight_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(hisifd->fbi->bl_dev); +#else +#ifdef CONFIG_LEDS_CLASS + led_classdev_unregister(&backlight_led); +#endif +#endif + if (hisifd->backlight.sbl_queue) { + destroy_workqueue(hisifd->backlight.sbl_queue); + hisifd->backlight.sbl_queue = NULL; + } + } +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c b/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c new file mode 100755 index 000000000000..e36a39ad4d31 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_buf_sync.c @@ -0,0 +1,507 @@ +/* Copyright (c) 2008-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" + +#define HISI_DSS_LAYERBUF_FREE "hisi-dss-layerbuf-free" + +int hisifb_layerbuf_lock(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, struct list_head *plock_list) +{ + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + struct hisifb_layerbuf *node = NULL; + struct ion_handle *ionhnd = NULL; + struct iommu_map_format iommu_format; + bool add_tail = false; + + BUG_ON(hisifd = NULL); + BUG_ON(pov_req = NULL); + BUG_ON(plock_list = NULL); + + pov_h_block_infos + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + add_tail = false; + ionhnd = NULL; + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) + continue; + + if (layer->img.shared_fd < 0) + continue; + + if ((layer->img.phy_addr = 0) && + (layer->img.vir_addr = 0) && + (layer->img.afbc_payload_addr = 0)) { + HISI_FB_ERR + ("fb%d, layer_idx%d, chn_idx%d, no buffer!\n", + hisifd->index, layer->layer_idx, + layer->chn_idx); + continue; + } + + if (layer->img.shared_fd >= 0) { + ionhnd + ion_import_dma_buf(hisifd->ion_client, + layer->img.shared_fd); + if (IS_ERR(ionhnd)) { + ionhnd = NULL; + HISI_FB_ERR + ("fb%d, layer_idx%d, failed to ion_import_dma_buf, " + "ionclient %p, share_fd %d!\n", + hisifd->index, i, + hisifd->ion_client, + layer->img.shared_fd); + } else { + if (layer->img.mmu_enable = 1) { + memset(&iommu_format, 0, + sizeof(struct iommu_map_format)); + ion_map_iommu(hisifd->ion_client,ionhnd, + &iommu_format); + } + add_tail = true; + } + } + + if (add_tail) { + node + kzalloc(sizeof(struct hisifb_layerbuf), + GFP_KERNEL); + if (node = NULL) { + HISI_FB_ERR + ("fb%d, layer_idx%d, failed to kzalloc!\n", + hisifd->index, layer->layer_idx); + + if (ionhnd) { + ion_free(hisifd->ion_client, + ionhnd); + ionhnd = NULL; + } + continue; + } + + node->shared_fd = layer->img.shared_fd; + node->frame_no = pov_req->frame_no; + node->ion_handle = ionhnd; + node->has_map_iommu = (ionhnd + && (layer->img.mmu_enable = 1)) ? true : false; + node->timeline = 0; + + node->mmbuf.addr = layer->img.mmbuf_base; + node->mmbuf.size = layer->img.mmbuf_size; + + node->vir_addr = layer->img.vir_addr; + node->chn_idx = layer->chn_idx; + + list_add_tail(&node->list_node, plock_list); + if (g_debug_layerbuf_sync) { + HISI_FB_INFO + ("fb%d, frame_no=%d, layer_idx(%d), " + "shared_fd=%d, ion_handle=%p, " + "has_map_iommu=%d, timeline=%d, mmbuf(0x%x, %d).\n", + hisifd->index, node->frame_no, i, + node->shared_fd, node->ion_handle, + node->has_map_iommu, + node->timeline, node->mmbuf.addr, + node->mmbuf.size); + } + } + } + } + + return 0; +} + +void hisifb_layerbuf_flush(struct hisi_fb_data_type *hisifd, + struct list_head *plock_list) +{ + struct hisifb_layerbuf *node, *_node_; + unsigned long flags = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(hisifd->ion_client = NULL); + BUG_ON(plock_list = NULL); + + spin_lock_irqsave(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + hisifd->buf_sync_ctrl.layerbuf_flushed = true; + list_for_each_entry_safe(node, _node_, plock_list, list_node) { + list_del(&node->list_node); + list_add_tail(&node->list_node, + &(hisifd->buf_sync_ctrl.layerbuf_list)); + } + spin_unlock_irqrestore(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), + flags); +} + +void hisifb_layerbuf_unlock(struct hisi_fb_data_type *hisifd, + struct list_head *pfree_list) +{ + struct hisifb_layerbuf *node, *_node_; + + BUG_ON(hisifd = NULL); + BUG_ON(hisifd->ion_client = NULL); + BUG_ON(hisifd->mmbuf_gen_pool = NULL); + BUG_ON(pfree_list = NULL); + + list_for_each_entry_safe(node, _node_, pfree_list, list_node) { + list_del(&node->list_node); + + if (g_debug_layerbuf_sync) { + HISI_FB_INFO + ("fb%d, frame_no=%d, share_fd=%d, " + "ion_handle=%p, has_map_iommu=%d, " + "timeline=%d, mmbuf(0x%x, %d). " + "vir_addr = 0x%llx, chn_idx = %d\n", + hisifd->index, node->frame_no, node->shared_fd, + node->ion_handle, node->has_map_iommu, + node->timeline, node->mmbuf.addr, node->mmbuf.size, + node->vir_addr, node->chn_idx); + } + + node->timeline = 0; + if (node->ion_handle) { + if (node->has_map_iommu) { + ion_unmap_iommu(hisifd->ion_client, + node->ion_handle); + } + ion_free(hisifd->ion_client, node->ion_handle); + } + kfree(node); + } +} + +void hisifb_layerbuf_lock_exception(struct hisi_fb_data_type *hisifd, + struct list_head *plock_list) +{ + unsigned long flags = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(plock_list = NULL); + + spin_lock_irqsave(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock_irqrestore(&(hisifd->buf_sync_ctrl.layerbuf_spinlock), flags); + + hisifb_layerbuf_unlock(hisifd, plock_list); +} + +static void hisifb_layerbuf_unlock_work(struct work_struct *work) +{ + struct hisifb_buf_sync *pbuf_sync = NULL; + struct hisi_fb_data_type *hisifd = NULL; + unsigned long flags; + struct hisifb_layerbuf *node, *_node_; + struct list_head free_list; + + pbuf_sync + container_of(work, struct hisifb_buf_sync, free_layerbuf_work); + BUG_ON(pbuf_sync = NULL); + hisifd + container_of(pbuf_sync, struct hisi_fb_data_type, buf_sync_ctrl); + BUG_ON(hisifd = NULL); + BUG_ON(hisifd->ion_client = NULL); + + INIT_LIST_HEAD(&free_list); + spin_lock_irqsave(&pbuf_sync->layerbuf_spinlock, flags); + list_for_each_entry_safe(node, _node_, &pbuf_sync->layerbuf_list, + list_node) { + if (node->timeline >= 2) { + list_del(&node->list_node); + list_add_tail(&node->list_node, &free_list); + } + } + spin_unlock_irqrestore(&pbuf_sync->layerbuf_spinlock, flags); + + hisifb_layerbuf_unlock(hisifd, &free_list); +} + +#ifdef CONFIG_BUF_SYNC_USED +#define BUF_SYNC_TIMEOUT_MSEC (10 * MSEC_PER_SEC) +#define BUF_SYNC_FENCE_NAME "hisi-dss-fence" +#define BUF_SYNC_TIMELINE_NAME "hisi-dss-timeline" +int hisifb_buf_sync_create_fence(struct hisi_fb_data_type *hisifd, + unsigned value) +{ + int fd = -1; + struct sync_fence *fence = NULL; + struct sync_pt *pt = NULL; + + BUG_ON(hisifd = NULL); + fd = get_unused_fd_flags(0); + if (fd < 0) { + HISI_FB_ERR("get_unused_fd failed!\n"); + return fd; + } + + pt = sw_sync_pt_create(hisifd->buf_sync_ctrl.timeline, value); + if (pt = NULL) { + return -ENOMEM; + } + + fence = sync_fence_create(BUF_SYNC_FENCE_NAME, pt); + if (fence = NULL) { + sync_pt_free(pt); + return -ENOMEM; + } + + sync_fence_install(fence, fd); + + return fd; +} + +int hisifb_buf_sync_wait(int fence_fd) +{ + int ret = 0; + struct sync_fence *fence = NULL; + + fence = sync_fence_fdget(fence_fd); + if (fence = NULL) { + HISI_FB_ERR("fence_fd=%d, sync_fence_fdget failed!\n", + fence_fd); + return -EINVAL; + } + + ret = sync_fence_wait(fence, BUF_SYNC_TIMEOUT_MSEC); + if (ret < 0) { + HISI_FB_ERR("Waiting on fence failed, fence_fd: %d, ret: %d.\n", + fence_fd, ret); + } + sync_fence_put(fence); + + return ret; +} + +int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(pov_req = NULL); + + pov_h_block_infos + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) + continue; + + if (layer->acquire_fence >= 0) { + hisifb_buf_sync_wait(layer->acquire_fence); + } + } + } + + return 0; +} + +void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_layerbuf *node = NULL; + struct hisifb_layerbuf *_node_ = NULL; + + BUG_ON(hisifd = NULL); + + spin_lock(&hisifd->buf_sync_ctrl.refresh_lock); + if (hisifd->buf_sync_ctrl.refresh) { + sw_sync_timeline_inc(hisifd->buf_sync_ctrl.timeline, + hisifd->buf_sync_ctrl.refresh); + hisifd->buf_sync_ctrl.refresh = 0; + } + spin_unlock(&hisifd->buf_sync_ctrl.refresh_lock); + + spin_lock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + list_for_each_entry_safe(node, _node_, + &(hisifd->buf_sync_ctrl.layerbuf_list), + list_node) { + if (hisifd->buf_sync_ctrl.layerbuf_flushed) { + node->timeline++; + } + } + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + + queue_work(hisifd->buf_sync_ctrl.free_layerbuf_queue, + &(hisifd->buf_sync_ctrl.free_layerbuf_work)); +} + +void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd) +{ + unsigned long flags; + + spin_lock_irqsave(&hisifd->buf_sync_ctrl.refresh_lock, flags); + sw_sync_timeline_inc(hisifd->buf_sync_ctrl.timeline, + hisifd->buf_sync_ctrl.refresh + 1); + hisifd->buf_sync_ctrl.refresh = 0; + hisifd->buf_sync_ctrl.timeline_max++; + spin_unlock_irqrestore(&hisifd->buf_sync_ctrl.refresh_lock, flags); +} + +void hisifb_buf_sync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + spin_lock_init(&hisifd->buf_sync_ctrl.refresh_lock); + hisifd->buf_sync_ctrl.refresh = 0; + hisifd->buf_sync_ctrl.timeline_max = 1; + hisifd->buf_sync_ctrl.timeline + sw_sync_timeline_create(BUF_SYNC_TIMELINE_NAME); + if (hisifd->buf_sync_ctrl.timeline = NULL) { + HISI_FB_ERR("cannot create time line!"); + return; /* -ENOMEM */ + } + + spin_lock_init(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + INIT_LIST_HEAD(&(hisifd->buf_sync_ctrl.layerbuf_list)); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + + INIT_WORK(&(hisifd->buf_sync_ctrl.free_layerbuf_work), + hisifb_layerbuf_unlock_work); + hisifd->buf_sync_ctrl.free_layerbuf_queue + create_singlethread_workqueue(HISI_DSS_LAYERBUF_FREE); + if (!hisifd->buf_sync_ctrl.free_layerbuf_queue) { + HISI_FB_ERR("failed to create free_layerbuf_queue!\n"); + return; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} + +void hisifb_buf_sync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->buf_sync_ctrl.timeline) { + sync_timeline_destroy((struct sync_timeline *) + hisifd->buf_sync_ctrl.timeline); + hisifd->buf_sync_ctrl.timeline = NULL; + } + + if (hisifd->buf_sync_ctrl.free_layerbuf_queue) { + destroy_workqueue(hisifd->buf_sync_ctrl.free_layerbuf_queue); + hisifd->buf_sync_ctrl.free_layerbuf_queue = NULL; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} +#else +int hisifb_buf_sync_wait(int fence_fd) +{ + return 0; +} + +int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + return 0; +} + +void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_layerbuf *node = NULL; + struct hisifb_layerbuf *_node_ = NULL; + + BUG_ON(hisifd = NULL); + + + + spin_lock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + list_for_each_entry_safe(node, _node_, + &(hisifd->buf_sync_ctrl.layerbuf_list), + list_node) { + if (hisifd->buf_sync_ctrl.layerbuf_flushed) { + node->timeline++; + } + } + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + spin_unlock(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + + queue_work(hisifd->buf_sync_ctrl.free_layerbuf_queue, + &(hisifd->buf_sync_ctrl.free_layerbuf_work)); +} + +void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd) +{ +} + +void hisifb_buf_sync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + spin_lock_init(&(hisifd->buf_sync_ctrl.layerbuf_spinlock)); + INIT_LIST_HEAD(&(hisifd->buf_sync_ctrl.layerbuf_list)); + hisifd->buf_sync_ctrl.layerbuf_flushed = false; + + INIT_WORK(&(hisifd->buf_sync_ctrl.free_layerbuf_work), + hisifb_layerbuf_unlock_work); + hisifd->buf_sync_ctrl.free_layerbuf_queue + create_singlethread_workqueue(HISI_DSS_LAYERBUF_FREE); + if (!hisifd->buf_sync_ctrl.free_layerbuf_queue) { + HISI_FB_ERR("failed to create free_layerbuf_queue!\n"); + return; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} + +void hisifb_buf_sync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->buf_sync_ctrl.free_layerbuf_queue) { + destroy_workqueue(hisifd->buf_sync_ctrl.free_layerbuf_queue); + hisifd->buf_sync_ctrl.free_layerbuf_queue = NULL; + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_def.h b/drivers/video/fbdev/hisi/dss/hisi_fb_def.h new file mode 100755 index 000000000000..3496be2e1838 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_def.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_FB_DEF_H +#define HISI_FB_DEF_H + +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <asm/bug.h> + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* align */ +#ifndef ALIGN_DOWN +#define ALIGN_DOWN(val, al) ((val) & ~((al)-1)) +#endif +#ifndef ALIGN_UP +#define ALIGN_UP(val, al) (((val) + ((al)-1)) & ~((al)-1)) +#endif + +#ifndef BIT +#define BIT(x) (1<<(x)) +#endif + +#ifndef IS_EVEN +#define IS_EVEN(x) ((x) % 2 = 0) +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define KHZ (1000) +#define MHZ (1000 * 1000) + +enum { + WAIT_TYPE_US = 0, + WAIT_TYPE_MS, +}; + +/*--------------------------------------------------------------------------*/ +extern uint32_t hisi_fb_msg_level; + +/* + * Message printing priorities: + * LEVEL 0 KERN_EMERG (highest priority) + * LEVEL 1 KERN_ALERT + * LEVEL 2 KERN_CRIT + * LEVEL 3 KERN_ERR + * LEVEL 4 KERN_WARNING + * LEVEL 5 KERN_NOTICE + * LEVEL 6 KERN_INFO + * LEVEL 7 KERN_DEBUG (Lowest priority) + */ +#define HISI_FB_EMERG(msg, ...) \ + do { if (hisi_fb_msg_level > 0) \ + printk(KERN_EMERG "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_ALERT(msg, ...) \ + do { if (hisi_fb_msg_level > 1) \ + printk(KERN_ALERT "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_CRIT(msg, ...) \ + do { if (hisi_fb_msg_level > 2) \ + printk(KERN_CRIT "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_ERR(msg, ...) \ + do { if (hisi_fb_msg_level > 3) \ + printk(KERN_ERR "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_WARNING(msg, ...) \ + do { if (hisi_fb_msg_level > 4) \ + printk(KERN_WARNING "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_NOTICE(msg, ...) \ + do { if (hisi_fb_msg_level > 5) \ + printk(KERN_NOTICE "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_INFO(msg, ...) \ + do { if (hisi_fb_msg_level > 6) \ + printk(KERN_INFO "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) +#define HISI_FB_DEBUG(msg, ...) \ + do { if (hisi_fb_msg_level > 7) \ + printk(KERN_INFO "[hisifb]%s: "msg, __func__, ## __VA_ARGS__); } while (0) + +#define assert(expr) \ + if(!(expr)) { \ + printk(KERN_ERR "[hisifb]: assertion failed! %s,%s,%s,line=%d\n",\ + #expr, __FILE__, __func__, __LINE__); \ + } + +#define HISI_FB_ASSERT(x) assert(x) + +#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) + +#define inpw(port) readw(port) +#define outpw(port, val) writew(val, port) +#define inpdw(port) readl(port) +#define outpdw(port, val) writel(val, port) + +#endif diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c b/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c new file mode 100755 index 000000000000..ca361f8028b9 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_isr.c @@ -0,0 +1,327 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_overlay_utils.h" + +/******************************************************************************* + ** handle isr + */ +irqreturn_t dss_pdp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_dpp = 0; + uint32_t isr_s2_smmu = 0; + uint32_t mask = 0; + uint32_t isr_te_vsync = 0; + uint32_t i = 0; + uint32_t temp = 0; + struct timeval tv; + dss_module_reg_t *dss_module = NULL; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd = NULL); + dss_module = &(hisifd->dss_module); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS); + isr_s2_dpp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INTS); + isr_s2_smmu + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INTS, isr_s2_dpp); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_PDP_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_PDP_INT_MSK)); + isr_s2 &+ ~(inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK)); + isr_s2_dpp &= ~(inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK)); + + if (is_mipi_cmd_panel(hisifd)) { + isr_te_vsync = BIT_LCD_TE0_PIN; + } else { + isr_te_vsync = BIT_VSYNC; + } + + if (isr_s2 & BIT_VACTIVE0_END) { + hisifd->vactive0_end_flag = 1; + if (g_err_status & DSS_PDP_LDI_UNDERFLOW) { + temp + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("fb%d, BIT_VACTIVE0_END: frame_no=%d, dpp_dbg =0x%x\n", + hisifd->index, hisifd->ov_req.frame_no, temp); + g_err_status &= ~DSS_PDP_LDI_UNDERFLOW; + } + } + + if (isr_s2 & BIT_VACTIVE0_START) { + if (hisifd->ov_vactive0_start_isr_handler) { + hisifd->ov_vactive0_start_isr_handler(hisifd); + } + + if (g_err_status & DSS_PDP_LDI_UNDERFLOW) { + temp + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("fb%d, BIT_VACTIVE0_START: frame_no=%d, dpp_dbg=0x%x\n", + hisifd->index, hisifd->ov_req.frame_no, temp); + } + } + + if (isr_s2 & isr_te_vsync) { + if (hisifd->vsync_isr_handler) { + hisifd->vsync_isr_handler(hisifd); + } + + if (hisifd->buf_sync_signal) { + hisifd->buf_sync_signal(hisifd); + } + + if (g_err_status & + (DSS_PDP_LDI_UNDERFLOW | DSS_PDP_SMMU_ERR | + DSS_SDP_SMMU_ERR)) { + temp + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("isr_te_vsync:frame_no = %d,dpp_dbg = 0x%x\n", + hisifd->ov_req.frame_no, temp); + } + + if (g_debug_ldi_underflow) { + hisifb_get_timestamp(&tv); + HISI_FB_INFO + ("isr_te_vsync:frame_no = %d,isr_s2 = 0x%x\n", + hisifd->ov_req.frame_no, isr_s2); + } + } + + if (isr_s2 & BIT_LDI_UNFLOW) { + mask = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + mask |= BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, mask); + + if (g_debug_ldi_underflow_clear) { + if (is_mipi_cmd_panel(hisifd)) { + if (g_ldi_data_gate_en = 0) { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } else { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } + + if (g_debug_ldi_underflow) { + if (g_debug_ovl_online_composer) { + if (hisifd->dss_debug_wq) + queue_work(hisifd->dss_debug_wq, + &hisifd->dss_debug_work); + } + } + g_err_status |= DSS_PDP_LDI_UNDERFLOW; + + if (hisifd->ldi_data_gate_en = 0) { + temp + inp32(hisifd->dss_base + DSS_DPP_OFFSET + + DPP_DBG_CNT); + HISI_FB_INFO + ("ldi underflow! frame_no = %d,dpp_dbg = 0x%x!\n", + hisifd->ov_req.frame_no, temp); + + for (i = 0; i < DSS_WCHN_W0; i++) { + if ((i != DSS_RCHN_V0) && (i != DSS_RCHN_G0)) { + HISI_FB_INFO + ("RCH[%d], DMA_BUF_DBG0 = 0x%x,DMA_BUF_DBG1 = 0x%x!!\n", + i, inp32(dss_module->dma_base[i] + + DMA_BUF_DBG0), + inp32(dss_module->dma_base[i] + + DMA_BUF_DBG1)); + } + } + for (i = 0; i < 18; i++) { + HISI_FB_INFO("MCTL_MOD%d_STATUS = 0x%x\n", + i, inp32(dss_module->mctl_sys_base + + MCTL_MOD0_STATUS + i * 0x4)); + } + } + } + + return IRQ_HANDLED; +} + +irqreturn_t dss_sdp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_smmu = 0; + uint32_t mask = 0; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd = NULL); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_SDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INTS); + isr_s2_smmu + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_SDP_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_SDP_INT_MSK)); + isr_s2 &+ ~(inp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK)); + + if (isr_s2 & BIT_VACTIVE0_END) { + hisifd->vactive0_end_flag = 1; + } + + if (isr_s2 & BIT_VACTIVE0_START) { + if (hisifd->ov_vactive0_start_isr_handler) + hisifd->ov_vactive0_start_isr_handler(hisifd); + } + + if (isr_s2 & BIT_VSYNC) { + if (hisifd->vsync_isr_handler) { + hisifd->vsync_isr_handler(hisifd); + } + + if (hisifd->buf_sync_signal) { + hisifd->buf_sync_signal(hisifd); + } + } + + if (isr_s2 & BIT_LDI_UNFLOW) { + mask + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + mask |= BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, + mask); + if (g_debug_ldi_underflow_clear) { + if (is_mipi_cmd_panel(hisifd)) { + if (g_ldi_data_gate_en = 0) { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } else { + if (hisifd->ldi_underflow_wq) { + disable_ldi(hisifd); + queue_work(hisifd->ldi_underflow_wq, + &hisifd->ldi_underflow_work); + } + } + } + if (g_debug_ldi_underflow) { + if (g_debug_ovl_online_composer) { + if (hisifd->dss_debug_wq) + queue_work(hisifd->dss_debug_wq, + &hisifd->dss_debug_work); + } + } + g_err_status |= DSS_SDP_LDI_UNDERFLOW; + if (hisifd->ldi_data_gate_en = 0) + HISI_FB_ERR("ldi underflow!\n"); + } + return IRQ_HANDLED; +} + +irqreturn_t dss_adp_isr(int irq, void *ptr) +{ + struct hisi_fb_data_type *hisifd = NULL; + uint32_t isr_s1 = 0; + uint32_t isr_s2_smmu = 0; + uint32_t isr_s3_copybit = 0; + + hisifd = (struct hisi_fb_data_type *)ptr; + BUG_ON(hisifd = NULL); + + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_OFF_INTS); + isr_s2_smmu + inp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTSTAT_NS); + + outp32(hisifd->dss_base + DSS_SMMU_OFFSET + SMMU_INTCLR_NS, + isr_s2_smmu); + outp32(hisifd->dss_base + GLB_CPU_OFF_INTS, isr_s1); + + isr_s1 &= ~(inp32(hisifd->dss_base + GLB_CPU_OFF_INT_MSK)); + isr_s3_copybit = inp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INTS); + outp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INTS, isr_s3_copybit); + isr_s3_copybit &= ~(inp32(hisifd->dss_base + GLB_CPU_OFF_CAM_INT_MSK)); + + if (isr_s1 & BIT_OFF_WCH0_INTS) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH0] = 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH0] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH0])); + } + } + if (isr_s1 & BIT_OFF_WCH1_INTS) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH1] = 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH1] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH1])); + } + } + if (isr_s1 & BIT_OFF_WCH0_WCH1_FRM_END_INT) { + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH0_WCH1] = + 1) { + hisifd->cmdlist_info-> + cmdlist_wb_done[WB_TYPE_WCH0_WCH1] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH0_WCH1])); + } + } + + if (isr_s3_copybit & BIT_OFF_CAM_WCH2_FRMEND_INTS) { + if (hisifd->copybit_info->copybit_flag = 1) { + hisifd->copybit_info->copybit_done = 1; + wake_up_interruptible_all(& + (hisifd->copybit_info->copybit_wq)); + } + + if (hisifd->cmdlist_info->cmdlist_wb_flag[WB_TYPE_WCH2] = 1) { + hisifd->cmdlist_info->cmdlist_wb_done[WB_TYPE_WCH2] = 1; + wake_up_interruptible_all(& + (hisifd->cmdlist_info->cmdlist_wb_wq + [WB_TYPE_WCH2])); + } + } + + return IRQ_HANDLED; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c new file mode 100755 index 000000000000..a26035e8beba --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.c @@ -0,0 +1,835 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_fb_panel.h" + +DEFINE_SEMAPHORE(hisi_fb_dts_resource_sem); +mipi_ifbc_division_t g_mipi_ifbc_division[MIPI_DPHY_NUM][IFBC_TYPE_MAX] = { + + { + {XRES_DIV_1, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_0, PXL0_DSI_GT_EN_1} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_1, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_2, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_3, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_4, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_2, PXL0_DSI_GT_EN_3} + } + , + + { + {XRES_DIV_2, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_1, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_0, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_1, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_2, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_3, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_3, YRES_DIV_2, IFBC_COMP_MODE_4, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_OPEN, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_5, PXL0_DIV2_GT_EN_CLOSE, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_4, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_3, PXL0_DSI_GT_EN_3} + , + + {XRES_DIV_6, YRES_DIV_1, IFBC_COMP_MODE_6, PXL0_DIV2_GT_EN_OPEN, + PXL0_DIV4_GT_EN_CLOSE, PXL0_DIVCFG_5, 3} + } +}; + +int gpio_cmds_tx(struct gpio_desc *cmds, int cnt) +{ + int ret = 0; + struct gpio_desc *cm = NULL; + int i = 0; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if ((cm = NULL) || (cm->label = NULL)) { + HISI_FB_ERR("cm or cm->label is null! index=%d\n", i); + ret = -1; + goto error; + } + + if (!gpio_is_valid(*(cm->gpio))) { + HISI_FB_ERR + ("gpio invalid, dtype=%d, lable=%s, gpio=%d!\n", + cm->dtype, cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + + if (cm->dtype = DTYPE_GPIO_INPUT) { + if (gpio_direction_input(*(cm->gpio)) != 0) { + HISI_FB_ERR + ("failed to gpio_direction_input, lable=%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype = DTYPE_GPIO_OUTPUT) { + if (gpio_direction_output(*(cm->gpio), cm->value) != 0) { + HISI_FB_ERR + ("failed to gpio_direction_output, label%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype = DTYPE_GPIO_REQUEST) { + if (gpio_request(*(cm->gpio), cm->label) != 0) { + HISI_FB_ERR + ("failed to gpio_request, lable=%s, gpio=%d!\n", + cm->label, *(cm->gpio)); + ret = -1; + goto error; + } + } else if (cm->dtype = DTYPE_GPIO_FREE) { + gpio_free(*(cm->gpio)); + } else { + HISI_FB_ERR("dtype=%x NOT supported\n", cm->dtype); + ret = -1; + goto error; + } + + if (cm->wait) { + if (cm->waittype = WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype = WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + + cm++; + } + + return 0; + + error: + return ret; +} + +int resource_cmds_tx(struct platform_device *pdev, + struct resource_desc *cmds, int cnt) +{ + int ret = 0; + struct resource *res = NULL; + struct resource_desc *cm = NULL; + int i = 0; + + BUG_ON(pdev = NULL); + cm = cmds; + + for (i = 0; i < cnt; i++) { + if ((cm = NULL) || (cm->name = NULL)) { + HISI_FB_ERR("cm or cm->name is null! index=%d\n", i); + ret = -1; + goto error; + } + + res = platform_get_resource_byname(pdev, cm->flag, cm->name); + if (!res) { + HISI_FB_ERR("failed to get %s resource!\n", cm->name); + ret = -1; + goto error; + } + *(cm->value) = res->start; + cm++; + } + + error: + return ret; +} + +int vcc_cmds_tx(struct platform_device *pdev, struct vcc_desc *cmds, int cnt) +{ + int ret = 0; + struct vcc_desc *cm = NULL; + int i = 0; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if ((cm = NULL) || (cm->id = NULL)) { + HISI_FB_ERR("cm or cm->id is null! index=%d\n", i); + ret = -1; + goto error; + } + + if (cm->dtype = DTYPE_VCC_GET) { + BUG_ON(pdev = NULL); + *(cm->regulator) + devm_regulator_get(&pdev->dev, cm->id); + if (IS_ERR(*(cm->regulator))) { + HISI_FB_ERR("failed to get %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } else if (cm->dtype = DTYPE_VCC_PUT) { + if (!IS_ERR(*(cm->regulator))) { + devm_regulator_put(*(cm->regulator)); + } + } else if (cm->dtype = DTYPE_VCC_ENABLE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_enable(*(cm->regulator)) != 0) { + HISI_FB_ERR + ("failed to enable %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } + } else if (cm->dtype = DTYPE_VCC_DISABLE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_disable(*(cm->regulator)) != 0) { + HISI_FB_ERR + ("failed to disable %s regulator!\n", + cm->id); + ret = -1; + goto error; + } + } + } else if (cm->dtype = DTYPE_VCC_SET_VOLTAGE) { + if (!IS_ERR(*(cm->regulator))) { + if (regulator_set_voltage + (*(cm->regulator), cm->min_uV, + cm->max_uV) != 0) { + HISI_FB_ERR + ("failed to set %s regulator voltage!\n", + cm->id); + ret = -1; + goto error; + } + } + } else { + HISI_FB_ERR("dtype=%x NOT supported\n", cm->dtype); + ret = -1; + goto error; + } + + if (cm->wait) { + if (cm->waittype = WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype = WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + + cm++; + } + + return 0; + + error: + return ret; +} + +int pinctrl_cmds_tx(struct platform_device *pdev, struct pinctrl_cmd_desc *cmds, + int cnt) +{ + int ret = 0; + + int i = 0; + struct pinctrl_cmd_desc *cm = NULL; + + cm = cmds; + for (i = 0; i < cnt; i++) { + if (cm = NULL) { + HISI_FB_ERR("cm is null! index=%d\n", i); + continue; + } + if (cm->dtype = DTYPE_PINCTRL_GET) { + BUG_ON(pdev = NULL); + cm->pctrl_data->p = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(cm->pctrl_data->p)) { + ret = -1; + HISI_FB_ERR("failed to get p, index=%d!\n", i); + goto err; + } + } else if (cm->dtype = DTYPE_PINCTRL_STATE_GET) { + if (cm->mode = DTYPE_PINCTRL_STATE_DEFAULT) { + cm->pctrl_data->pinctrl_def + pinctrl_lookup_state(cm->pctrl_data->p, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(cm->pctrl_data->pinctrl_def)) { + ret = -1; + HISI_FB_ERR + ("failed to get pinctrl_def, index=%d!\n", + i); + goto err; + } + } else if (cm->mode = DTYPE_PINCTRL_STATE_IDLE) { + cm->pctrl_data->pinctrl_idle + pinctrl_lookup_state(cm->pctrl_data->p, + PINCTRL_STATE_IDLE); + if (IS_ERR(cm->pctrl_data->pinctrl_idle)) { + ret = -1; + HISI_FB_ERR + ("failed to get pinctrl_idle, index=%d!\n", + i); + goto err; + } + } else { + ret = -1; + HISI_FB_ERR("unknown pinctrl type to get!\n"); + goto err; + } + } else if (cm->dtype = DTYPE_PINCTRL_SET) { + if (cm->mode = DTYPE_PINCTRL_STATE_DEFAULT) { + if (cm->pctrl_data->p + && cm->pctrl_data->pinctrl_def) { + ret + pinctrl_select_state(cm->pctrl_data->p, + cm->pctrl_data->pinctrl_def); + if (ret) { + HISI_FB_ERR + ("could not set this pin to default state!\n"); + ret = -1; + goto err; + } + } + } else if (cm->mode = DTYPE_PINCTRL_STATE_IDLE) { + if (cm->pctrl_data->p + && cm->pctrl_data->pinctrl_idle) { + ret + pinctrl_select_state(cm->pctrl_data->p, + cm->pctrl_data->pinctrl_idle); + if (ret) { + HISI_FB_ERR + ("could not set this pin to idle state!\n"); + ret = -1; + goto err; + } + } + } else { + ret = -1; + HISI_FB_ERR("unknown pinctrl type to set!\n"); + goto err; + } + } else if (cm->dtype = DTYPE_PINCTRL_PUT) { + if (cm->pctrl_data->p) + pinctrl_put(cm->pctrl_data->p); + } else { + HISI_FB_ERR("not supported command type!\n"); + ret = -1; + goto err; + } + + cm++; + } + + return 0; + + err: + return ret; +} + +int panel_next_on(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->on(next_pdev); + } + + return ret; +} + +int panel_next_off(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->off)) + ret = next_pdata->off(next_pdev); + } + + return ret; +} + +int panel_next_remove(struct platform_device *pdev) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->remove)) + ret = next_pdata->remove(next_pdev); + } + + return ret; +} + +int panel_next_set_backlight(struct platform_device *pdev, uint32_t bl_level) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->set_backlight)) + ret = next_pdata->set_backlight(next_pdev, bl_level); + } + + return ret; +} + +int panel_next_vsync_ctrl(struct platform_device *pdev, int enable) +{ + int ret = 0; + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_fb_panel_data *next_pdata = NULL; + struct platform_device *next_pdev = NULL; + + BUG_ON(pdev = NULL); + pdata = dev_get_platdata(&pdev->dev); + BUG_ON(pdata = NULL); + + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = dev_get_platdata(&next_pdev->dev); + if ((next_pdata) && (next_pdata->vsync_ctrl)) + ret = next_pdata->vsync_ctrl(next_pdev, enable); + } + + return ret; +} + +bool is_ldi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + if (hisifd->panel_info.type & PANEL_LCDC) + return true; + + return false; +} + +bool is_mipi_cmd_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info.type & (PANEL_MIPI_CMD | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_mipi_cmd_panel_ext(struct hisi_panel_info *pinfo) +{ + BUG_ON(pinfo = NULL); + + if (pinfo->type & (PANEL_MIPI_CMD | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_mipi_video_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info. + type & (PANEL_MIPI_VIDEO | PANEL_DUAL_MIPI_VIDEO | PANEL_RGB2MIPI)) + return true; + + return false; +} + +bool is_mipi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info.type & (PANEL_MIPI_VIDEO | PANEL_MIPI_CMD | + PANEL_DUAL_MIPI_VIDEO | + PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_dual_mipi_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info. + type & (PANEL_DUAL_MIPI_VIDEO | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_dual_mipi_panel_ext(struct hisi_panel_info *pinfo) +{ + BUG_ON(pinfo = NULL); + + if (pinfo->type & (PANEL_DUAL_MIPI_VIDEO | PANEL_DUAL_MIPI_CMD)) + return true; + + return false; +} + +bool is_hisi_writeback_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info.type & PANEL_WRITEBACK) + return true; + + return false; +} + +bool is_ifbc_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->panel_info.ifbc_type != IFBC_TYPE_NONE) + return true; + + return false; +} + +bool is_ifbc_vesa_panel(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if ((hisifd->panel_info.ifbc_type = IFBC_TYPE_VESA2X_SINGLE) || + (hisifd->panel_info.ifbc_type = IFBC_TYPE_VESA3X_SINGLE) || + (hisifd->panel_info.ifbc_type = IFBC_TYPE_VESA2X_DUAL) || + (hisifd->panel_info.ifbc_type = IFBC_TYPE_VESA3X_DUAL)) + return true; + + return false; +} + +bool mipi_panel_check_reg(struct hisi_fb_data_type *hisifd, + uint32_t *read_value) +{ + int ret = 0; + char lcd_reg_05[] = { 0x05 }; + char lcd_reg_0a[] = { 0x0a }; + char lcd_reg_0e[] = { 0x0e }; + char lcd_reg_0f[] = { 0x0f }; + + struct dsi_cmd_desc lcd_check_reg[] = { + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_05), lcd_reg_05} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0a), lcd_reg_0a} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0e), lcd_reg_0e} + , + {DTYPE_GEN_WRITE1, 0, 10, WAIT_TYPE_US, + sizeof(lcd_reg_0f), lcd_reg_0f} + , + }; + + ret = mipi_dsi_cmds_rx(read_value, lcd_check_reg, + ARRAY_SIZE(lcd_check_reg), + hisifd->mipi_dsi0_base); + if (ret) { + HISI_FB_ERR("Read error number: %d\n", ret); + return false; + } + + return true; +} + +int mipi_ifbc_get_rect(struct hisi_fb_data_type *hisifd, struct dss_rect *rect) +{ + uint32_t ifbc_type = 0; + uint32_t mipi_idx = 0; + uint32_t xres_div = 1; + uint32_t yres_div = 1; + + BUG_ON(hisifd = NULL); + BUG_ON(rect = NULL); + + ifbc_type = hisifd->panel_info.ifbc_type; + BUG_ON((ifbc_type < IFBC_TYPE_NONE) || (ifbc_type >= IFBC_TYPE_MAX)); + + mipi_idx = is_dual_mipi_panel(hisifd) ? 1 : 0; + + xres_div = g_mipi_ifbc_division[mipi_idx][ifbc_type].xres_div; + yres_div = g_mipi_ifbc_division[mipi_idx][ifbc_type].yres_div; + + if ((rect->w % xres_div) > 0) { + HISI_FB_ERR + ("fb%d, xres(%d) is not division_h(%d) pixel aligned!\n", + hisifd->index, rect->w, xres_div); + } + + if ((rect->h % yres_div) > 0) { + HISI_FB_ERR + ("fb%d, yres(%d) is not division_v(%d) pixel aligned!\n", + hisifd->index, rect->h, yres_div); + } + + if ((mipi_idx = 0) && (ifbc_type = IFBC_TYPE_RSP3X) + && (hisifd->panel_info.type = PANEL_MIPI_CMD)) { + rect->w *= 2; + rect->h /= 2; + } + + rect->w /= xres_div; + rect->h /= yres_div; + + return 0; +} + +bool hisi_fb_device_probe_defer(uint32_t panel_type, uint32_t bl_type) +{ + bool flag = true; + + down(&hisi_fb_dts_resource_sem); + + switch (panel_type) { + case PANEL_NO: + if (g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) { + flag = false; + } + break; + case PANEL_LCDC: + case PANEL_MIPI2RGB: + case PANEL_RGB2MIPI: + if ((g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) && + (g_dts_resouce_ready & DTS_SPI_READY)) { + if (bl_type & (BL_SET_BY_PWM | BL_SET_BY_BLPWM)) { + if (g_dts_resouce_ready & DTS_PWM_READY) + flag = false; + } else { + flag = false; + } + } + break; + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + case PANEL_EDP: + if (g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) { + if (bl_type & (BL_SET_BY_PWM | BL_SET_BY_BLPWM)) { + if (g_dts_resouce_ready & DTS_PWM_READY) + flag = false; + } else { + flag = false; + } + } + break; + case PANEL_HDMI: + if (g_dts_resouce_ready & DTS_PANEL_PRIMARY_READY) + flag = false; + break; + case PANEL_WRITEBACK: + if (g_dts_resouce_ready & DTS_PANEL_OFFLINECOMPOSER_READY) + flag = false; + break; + default: + HISI_FB_ERR("not support this panel type(%d).\n", panel_type); + break; + } + + up(&hisi_fb_dts_resource_sem); + + return flag; +} + +void hisi_fb_device_set_status0(uint32_t status) +{ + down(&hisi_fb_dts_resource_sem); + g_dts_resouce_ready |= status; + up(&hisi_fb_dts_resource_sem); +} + +int hisi_fb_device_set_status1(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + + BUG_ON(hisifd = NULL); + + down(&hisi_fb_dts_resource_sem); + + switch (hisifd->panel_info.type) { + case PANEL_LCDC: + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + case PANEL_EDP: + case PANEL_MIPI2RGB: + case PANEL_RGB2MIPI: + case PANEL_HDMI: + if (hisifd->index = PRIMARY_PANEL_IDX) { + g_dts_resouce_ready |= DTS_PANEL_PRIMARY_READY; + } else if (hisifd->index = EXTERNAL_PANEL_IDX) { + g_dts_resouce_ready |= DTS_PANEL_EXTERNAL_READY; + } else { + HISI_FB_ERR("not support fb(%d).\n", hisifd->index); + } + break; + case PANEL_WRITEBACK: + g_dts_resouce_ready |= DTS_PANEL_WRITEBACK_READY; + break; + default: + HISI_FB_ERR("not support this panel type(%d).\n", + hisifd->panel_info.type); + ret = -1; + break; + } + + up(&hisi_fb_dts_resource_sem); + + return ret; +} + +struct platform_device *hisi_fb_device_alloc(struct hisi_fb_panel_data *pdata, + uint32_t type, uint32_t id) +{ + struct platform_device *this_dev = NULL; + char dev_name[32] = { 0 }; + + BUG_ON(pdata = NULL); + + switch (type) { + case PANEL_MIPI_VIDEO: + case PANEL_MIPI_CMD: + case PANEL_DUAL_MIPI_VIDEO: + case PANEL_DUAL_MIPI_CMD: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_MIPIDSI); + break; + case PANEL_EDP: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_EDP); + break; + case PANEL_NO: + case PANEL_LCDC: + case PANEL_HDMI: + case PANEL_WRITEBACK: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_DSS_DPE); + break; + case PANEL_RGB2MIPI: + snprintf(dev_name, sizeof(dev_name), DEV_NAME_RGB2MIPI); + break; + default: + HISI_FB_ERR("invalid panel type = %d!\n", type); + return NULL; + } + + if (pdata != NULL) + pdata->next = NULL; + else + return NULL; + + this_dev + platform_device_alloc(dev_name, + (((uint32_t) type << 16) | (uint32_t) id)); + if (this_dev) { + if (platform_device_add_data + (this_dev, pdata, sizeof(struct hisi_fb_panel_data))) { + HISI_FB_ERR("failed to platform_device_add_data!\n"); + platform_device_put(this_dev); + return NULL; + } + } + + return this_dev; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h new file mode 100755 index 000000000000..8afb1f42a8c5 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_panel.h @@ -0,0 +1,839 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_FB_PANEL_H +#define HISI_FB_PANEL_H + +#include "hisi_fb_def.h" +#include "hisi_mipi_dsi.h" +#include "hisi_dss.h" + +/* panel type list */ +#define PANEL_NO BIT(0) /* No Panel */ +#define PANEL_LCDC BIT(1) /* internal LCDC type */ +#define PANEL_HDMI BIT(2) /* HDMI TV */ +#define PANEL_MIPI_VIDEO BIT(3) /* MIPI */ +#define PANEL_MIPI_CMD BIT(4) /* MIPI */ +#define PANEL_DUAL_MIPI_VIDEO BIT(5) /* DUAL MIPI */ +#define PANEL_DUAL_MIPI_CMD BIT(6) /* DUAL MIPI */ +#define PANEL_EDP BIT(7) /* LVDS */ +#define PANEL_MIPI2RGB BIT(8) /* MIPI to RGB */ +#define PANEL_RGB2MIPI BIT(9) /* RGB to MIPI */ +#define PANEL_WRITEBACK BIT(11) /* Wifi display */ + +/* dts initial */ +#define DTS_FB_RESOURCE_INIT_READY BIT(0) +#define DTS_PWM_READY BIT(1) + +#define DTS_SPI_READY BIT(3) +#define DTS_PANEL_PRIMARY_READY BIT(4) +#define DTS_PANEL_EXTERNAL_READY BIT(5) +#define DTS_PANEL_OFFLINECOMPOSER_READY BIT(6) +#define DTS_PANEL_WRITEBACK_READY BIT(7) + +/* device name */ +#define DEV_NAME_DSS_DPE "dss_dpe" +#define DEV_NAME_SPI "spi_dev0" +#define DEV_NAME_HDMI "hdmi" +#define DEV_NAME_EDP "edp" +#define DEV_NAME_MIPI2RGB "mipi2rgb" +#define DEV_NAME_RGB2MIPI "rgb2mipi" +#define DEV_NAME_MIPIDSI "mipi_dsi" +#define DEV_NAME_FB "hisi_fb" +#define DEV_NAME_PWM "hisi_pwm" +#define DEV_NAME_BLPWM "hisi_blpwm" +#define DEV_NAME_LCD_BKL "lcd_backlight0" + +/* vcc name */ +#define REGULATOR_PDP_NAME "regulator_dsssubsys" +#define REGULATOR_MMBUF "regulator_mmbuf" + +/* irq name */ +#define IRQ_PDP_NAME "irq_pdp" +#define IRQ_SDP_NAME "irq_sdp" +#define IRQ_ADP_NAME "irq_adp" +#define IRQ_DSI0_NAME "irq_dsi0" +#define IRQ_DSI1_NAME "irq_dsi1" + +/* dts compatible */ +#define DTS_COMP_FB_NAME "hisilicon,hisifb" +#define DTS_COMP_PWM_NAME "hisilicon,hisipwm" +#define DTS_COMP_BLPWM_NAME "hisilicon,hisiblpwm" +#define DTS_PATH_LOGO_BUFFER "/reserved-memory/logo-buffer" + +/* lcd resource name */ +#define LCD_BL_TYPE_NAME "lcd-bl-type" +#define FPGA_FLAG_NAME "fpga_flag" +#define LCD_DISPLAY_TYPE_NAME "lcd-display-type" +#define LCD_IFBC_TYPE_NAME "lcd-ifbc-type" + +/* backlight type */ +#define BL_SET_BY_NONE BIT(0) +#define BL_SET_BY_PWM BIT(1) +#define BL_SET_BY_BLPWM BIT(2) +#define BL_SET_BY_MIPI BIT(3) +#define BL_SET_BY_SH_BLPWM BIT(4) + +/* supported display effect type */ +#define COMFORM_MODE BIT(0) +#define ACM_COLOR_ENHANCE_MODE BIT(1) +#define IC_COLOR_ENHANCE_MODE BIT(2) +#define CINEMA_MODE BIT(3) +#define VR_MODE BIT(4) +#define LED_RG_COLOR_TEMP_MODE BIT(16) +#define GAMMA_MAP BIT(19) + +#define LCD_BL_IC_NAME_MAX (50) +#define DEV_DSS_VOLTAGE_ID (20) + +enum BLPWM_PRECISION_TYPE { + BLPWM_PRECISION_DEFAULT_TYPE = 0, + BLPWM_PRECISION_10000_TYPE = 1, + BLPWM_PRECISION_2048_TYPE = 2, +}; + +enum LCD_INIT_STEP { + LCD_INIT_NONE = 0, + LCD_INIT_POWER_ON, + LCD_INIT_LDI_SEND_SEQUENCE, + LCD_INIT_MIPI_LP_SEND_SEQUENCE, + LCD_INIT_MIPI_HS_SEND_SEQUENCE, +}; + +enum LCD_UNINIT_STEP { + LCD_UNINIT_NONE = 0, + LCD_UNINIT_POWER_OFF, + LCD_UNINIT_LDI_SEND_SEQUENCE, + LCD_UNINIT_MIPI_LP_SEND_SEQUENCE, + LCD_UNINIT_MIPI_HS_SEND_SEQUENCE, +}; + +enum LCD_ESD_RECOVER_STEP { + LCD_ESD_RECOVER_NONE = 0, + LCD_ESD_RECOVER_POWER_OFF, + LCD_ESD_RECOVER_POWER_ON, +}; + +enum LCD_REFRESH_DIRECTION { + LCD_REFRESH_LEFT_TOP = 0, + LCD_REFRESH_RIGHT_TOP, + LCD_REFRESH_LEFT_BOTTOM, + LCD_REFRESH_RIGHT_BOTTOM, +}; + +enum IFBC_TYPE { + IFBC_TYPE_NONE = 0, + IFBC_TYPE_ORISE2X, + IFBC_TYPE_ORISE3X, + IFBC_TYPE_HIMAX2X, + IFBC_TYPE_RSP2X, + IFBC_TYPE_RSP3X, + IFBC_TYPE_VESA2X_SINGLE, + IFBC_TYPE_VESA3X_SINGLE, + IFBC_TYPE_VESA2X_DUAL, + IFBC_TYPE_VESA3X_DUAL, + + IFBC_TYPE_MAX +}; + +enum IFBC_COMP_MODE { + IFBC_COMP_MODE_0 = 0, + IFBC_COMP_MODE_1, + IFBC_COMP_MODE_2, + IFBC_COMP_MODE_3, + IFBC_COMP_MODE_4, + IFBC_COMP_MODE_5, + IFBC_COMP_MODE_6, +}; + +enum XRES_DIV { + XRES_DIV_1 = 1, + XRES_DIV_2, + XRES_DIV_3, + XRES_DIV_4, + XRES_DIV_5, + XRES_DIV_6, +}; + +enum YRES_DIV { + YRES_DIV_1 = 1, + YRES_DIV_2, + YRES_DIV_3, + YRES_DIV_4, + YRES_DIV_5, + YRES_DIV_6, +}; + +enum PXL0_DIVCFG { + PXL0_DIVCFG_0 = 0, + PXL0_DIVCFG_1, + PXL0_DIVCFG_2, + PXL0_DIVCFG_3, + PXL0_DIVCFG_4, + PXL0_DIVCFG_5, + PXL0_DIVCFG_6, + PXL0_DIVCFG_7, +}; + +enum PXL0_DIV2_GT_EN { + PXL0_DIV2_GT_EN_CLOSE = 0, + PXL0_DIV2_GT_EN_OPEN, +}; + +enum PXL0_DIV4_GT_EN { + PXL0_DIV4_GT_EN_CLOSE = 0, + PXL0_DIV4_GT_EN_OPEN, +}; + +enum PXL0_DSI_GT_EN { + PXL0_DSI_GT_EN_0 = 0, + PXL0_DSI_GT_EN_1, + PXL0_DSI_GT_EN_2, + PXL0_DSI_GT_EN_3, +}; + +enum VSYNC_CTRL_TYPE { + VSYNC_CTRL_NONE = 0x0, + VSYNC_CTRL_ISR_OFF = BIT(0), + VSYNC_CTRL_MIPI_ULPS = BIT(1), + VSYNC_CTRL_CLK_OFF = BIT(2), + VSYNC_CTRL_VCC_OFF = BIT(3), +}; + +enum PERI_VOLTAGE_VALUE { + PERI_VOLTAGE_07V = 0x0, + PERI_VOLTAGE_08V = 0x2, +}; + +#define MIPI_DSI_BIT_CLK_STR1 "00001" +#define MIPI_DSI_BIT_CLK_STR2 "00010" +#define MIPI_DSI_BIT_CLK_STR3 "00100" +#define MIPI_DSI_BIT_CLK_STR4 "01000" +#define MIPI_DSI_BIT_CLK_STR5 "10000" + +/* resource desc */ +struct resource_desc { + uint32_t flag; + char *name; + uint32_t *value; +}; + +/* dtype for vcc */ +enum { + DTYPE_VCC_GET, + DTYPE_VCC_PUT, + DTYPE_VCC_ENABLE, + DTYPE_VCC_DISABLE, + DTYPE_VCC_SET_VOLTAGE, +}; + +/* vcc desc */ +struct vcc_desc { + int dtype; + char *id; + struct regulator **regulator; + int min_uV; + int max_uV; + int waittype; + int wait; +}; + +/* pinctrl operation */ +enum { + DTYPE_PINCTRL_GET, + DTYPE_PINCTRL_STATE_GET, + DTYPE_PINCTRL_SET, + DTYPE_PINCTRL_PUT, +}; + +/* pinctrl state */ +enum { + DTYPE_PINCTRL_STATE_DEFAULT, + DTYPE_PINCTRL_STATE_IDLE, +}; + +/* pinctrl data */ +struct pinctrl_data { + struct pinctrl *p; + struct pinctrl_state *pinctrl_def; + struct pinctrl_state *pinctrl_idle; +}; +struct pinctrl_cmd_desc { + int dtype; + struct pinctrl_data *pctrl_data; + int mode; +}; + +/* dtype for gpio */ +enum { + DTYPE_GPIO_REQUEST, + DTYPE_GPIO_FREE, + DTYPE_GPIO_INPUT, + DTYPE_GPIO_OUTPUT, +}; + +/* gpio desc */ +struct gpio_desc { + int dtype; + int waittype; + int wait; + char *label; + uint32_t *gpio; + int value; +}; + +struct spi_cmd_desc { + int reg_len; + char *reg; + int val_len; + char *val; + int waittype; + int wait; +}; + +enum { + IFBC_ORISE_CTL_8LINE = 0, + IFBC_ORISE_CTL_16LINE, + IFBC_ORISE_CTL_32LINE, + IFBC_ORISE_CTL_FRAME, +}; + +typedef struct mipi_ifbc_division { + uint32_t xres_div; + uint32_t yres_div; + uint32_t comp_mode; + uint32_t pxl0_div2_gt_en; + uint32_t pxl0_div4_gt_en; + uint32_t pxl0_divxcfg; + uint32_t pxl0_dsi_gt_en; +} mipi_ifbc_division_t; + +struct ldi_panel_info { + uint32_t h_back_porch; + uint32_t h_front_porch; + uint32_t h_pulse_width; + + /* + ** note: vbp > 8 if used overlay compose, + ** also lcd vbp > 8 in lcd power on sequence + */ + uint32_t v_back_porch; + uint32_t v_front_porch; + uint32_t v_pulse_width; + + uint8_t hsync_plr; + uint8_t vsync_plr; + uint8_t pixelclk_plr; + uint8_t data_en_plr; + + /* for cabc */ + uint8_t dpi0_overlap_size; + uint8_t dpi1_overlap_size; +}; + +/* DSI PHY configuration */ +struct mipi_dsi_phy_ctrl { + uint64_t lane_byte_clk; + uint32_t clk_division; + + uint32_t clk_lane_lp2hs_time; + uint32_t clk_lane_hs2lp_time; + uint32_t data_lane_lp2hs_time; + uint32_t data_lane_hs2lp_time; + uint32_t clk2data_delay; + uint32_t data2clk_delay; + + uint32_t clk_pre_delay; + uint32_t clk_post_delay; + uint32_t clk_t_lpx; + uint32_t clk_t_hs_prepare; + uint32_t clk_t_hs_zero; + uint32_t clk_t_hs_trial; + uint32_t clk_t_wakeup; + uint32_t data_pre_delay; + uint32_t data_post_delay; + uint32_t data_t_lpx; + uint32_t data_t_hs_prepare; + uint32_t data_t_hs_zero; + uint32_t data_t_hs_trial; + uint32_t data_t_ta_go; + uint32_t data_t_ta_get; + uint32_t data_t_wakeup; + + uint32_t phy_stop_wait_time; + + uint32_t rg_vrefsel_vcm; + uint32_t rg_hstx_ckg_sel; + uint32_t rg_pll_fbd_div5f; + uint32_t rg_pll_fbd_div1f; + uint32_t rg_pll_fbd_2p; + uint32_t rg_pll_enbwt; + uint32_t rg_pll_fbd_p; + uint32_t rg_pll_fbd_s; + uint32_t rg_pll_pre_div1p; + uint32_t rg_pll_pre_p; + uint32_t rg_pll_vco_750m; + uint32_t rg_pll_lpf_rs; + uint32_t rg_pll_lpf_cs; + uint32_t rg_pll_enswc; + uint32_t rg_pll_chp; + + + uint32_t pll_register_override; + uint32_t pll_power_down; + uint32_t rg_band_sel; + uint32_t rg_phase_gen_en; + uint32_t reload_sel; + uint32_t rg_pll_cp_p; + uint32_t rg_pll_refsel; + uint32_t rg_pll_cp; + uint32_t load_command; +}; + +struct mipi_panel_info { + uint8_t dsi_version; + uint8_t vc; + uint8_t lane_nums; + uint8_t lane_nums_select_support; + uint8_t color_mode; + uint32_t dsi_bit_clk; /* clock lane(p/n) */ + uint32_t burst_mode; + uint32_t max_tx_esc_clk; + uint8_t non_continue_en; + + uint32_t dsi_bit_clk_val1; + uint32_t dsi_bit_clk_val2; + uint32_t dsi_bit_clk_val3; + uint32_t dsi_bit_clk_val4; + uint32_t dsi_bit_clk_val5; + uint32_t dsi_bit_clk_upt; + /*uint32_t dsi_pclk_rate; */ + + uint32_t hs_wr_to_time; + + uint32_t clk_post_adjust; + uint32_t clk_pre_adjust; + uint32_t clk_pre_delay_adjust; + uint32_t clk_t_hs_exit_adjust; + uint32_t clk_t_hs_trial_adjust; + uint32_t clk_t_hs_prepare_adjust; + int clk_t_lpx_adjust; + uint32_t clk_t_hs_zero_adjust; + uint32_t data_post_delay_adjust; + int data_t_lpx_adjust; + uint32_t data_t_hs_prepare_adjust; + uint32_t data_t_hs_zero_adjust; + uint32_t data_t_hs_trial_adjust; + uint32_t rg_vrefsel_vcm_adjust; + + uint32_t rg_vrefsel_vcm_clk_adjust; + uint32_t rg_vrefsel_vcm_data_adjust; +}; + +struct sbl_panel_info { + uint32_t strength_limit; + uint32_t calibration_a; + uint32_t calibration_b; + uint32_t calibration_c; + uint32_t calibration_d; + uint32_t t_filter_control; + uint32_t backlight_min; + uint32_t backlight_max; + uint32_t backlight_scale; + uint32_t ambient_light_min; + uint32_t filter_a; + uint32_t filter_b; + uint32_t logo_left; + uint32_t logo_top; + uint32_t variance_intensity_space; + uint32_t slope_max; + uint32_t slope_min; +}; + +typedef struct dss_sharpness_bit { + uint32_t sharp_en; + uint32_t sharp_mode; + + uint32_t flt0_c0; + uint32_t flt0_c1; + uint32_t flt0_c2; + + uint32_t flt1_c0; + uint32_t flt1_c1; + uint32_t flt1_c2; + + uint32_t flt2_c0; + uint32_t flt2_c1; + uint32_t flt2_c2; + + uint32_t ungain; + uint32_t ovgain; + + uint32_t lineamt1; + uint32_t linedeten; + uint32_t linethd2; + uint32_t linethd1; + + uint32_t sharpthd1; + uint32_t sharpthd1mul; + uint32_t sharpamt1; + + uint32_t edgethd1; + uint32_t edgethd1mul; + uint32_t edgeamt1; +} sharp2d_t; + +struct dsc_panel_info { + + uint32_t bits_per_pixel; + uint32_t block_pred_enable; + uint32_t linebuf_depth; + uint32_t bits_per_component; + uint32_t slice_width; + uint32_t slice_height; + uint32_t initial_xmit_delay; + uint32_t first_line_bpg_offset; + uint32_t mux_word_size; + uint32_t initial_offset; + uint32_t flatness_max_qp; + uint32_t flatness_min_qp; + uint32_t rc_edge_factor; + uint32_t rc_model_size; + uint32_t rc_tgt_offset_lo; + uint32_t rc_tgt_offset_hi; + uint32_t rc_quant_incr_limit1; + uint32_t rc_quant_incr_limit0; + uint32_t rc_buf_thresh0; + uint32_t rc_buf_thresh1; + uint32_t rc_buf_thresh2; + uint32_t rc_buf_thresh3; + uint32_t rc_buf_thresh4; + uint32_t rc_buf_thresh5; + uint32_t rc_buf_thresh6; + uint32_t rc_buf_thresh7; + uint32_t rc_buf_thresh8; + uint32_t rc_buf_thresh9; + uint32_t rc_buf_thresh10; + uint32_t rc_buf_thresh11; + uint32_t rc_buf_thresh12; + uint32_t rc_buf_thresh13; + uint32_t range_min_qp0; + uint32_t range_max_qp0; + uint32_t range_bpg_offset0; + uint32_t range_min_qp1; + uint32_t range_max_qp1; + uint32_t range_bpg_offset1; + uint32_t range_min_qp2; + uint32_t range_max_qp2; + uint32_t range_bpg_offset2; + uint32_t range_min_qp3; + uint32_t range_max_qp3; + uint32_t range_bpg_offset3; + uint32_t range_min_qp4; + uint32_t range_max_qp4; + uint32_t range_bpg_offset4; + uint32_t range_min_qp5; + uint32_t range_max_qp5; + uint32_t range_bpg_offset5; + uint32_t range_min_qp6; + uint32_t range_max_qp6; + uint32_t range_bpg_offset6; + uint32_t range_min_qp7; + uint32_t range_max_qp7; + uint32_t range_bpg_offset7; + uint32_t range_min_qp8; + uint32_t range_max_qp8; + uint32_t range_bpg_offset8; + uint32_t range_min_qp9; + uint32_t range_max_qp9; + uint32_t range_bpg_offset9; + uint32_t range_min_qp10; + uint32_t range_max_qp10; + uint32_t range_bpg_offset10; + uint32_t range_min_qp11; + uint32_t range_max_qp11; + uint32_t range_bpg_offset11; + uint32_t range_min_qp12; + uint32_t range_max_qp12; + uint32_t range_bpg_offset12; + uint32_t range_min_qp13; + uint32_t range_max_qp13; + uint32_t range_bpg_offset13; + uint32_t range_min_qp14; + uint32_t range_max_qp14; + uint32_t range_bpg_offset14; +}; + +struct hisi_panel_info { + uint32_t type; + uint32_t xres; + uint32_t yres; + uint32_t width; + uint32_t height; + uint32_t bpp; + uint32_t fps; + uint32_t fps_updt; + uint32_t orientation; + uint32_t bgr_fmt; + uint32_t bl_set_type; + uint32_t bl_min; + uint32_t bl_max; + uint32_t bl_default; + uint32_t blpwm_precision_type; + uint32_t blpwm_out_div_value; + uint32_t blpwm_input_ena; + uint32_t blpwm_in_num; + uint32_t blpwm_input_precision; + uint32_t bl_ic_ctrl_mode; + uint64_t pxl_clk_rate; + uint64_t pxl_clk_rate_adjust; + uint32_t pxl_clk_rate_div; + uint32_t vsync_ctrl_type; + uint8_t fake_hdmi; + uint8_t reserved[3]; + + uint32_t ifbc_type; + uint32_t ifbc_cmp_dat_rev0; + uint32_t ifbc_cmp_dat_rev1; + uint32_t ifbc_auto_sel; + uint32_t ifbc_orise_ctl; + uint32_t ifbc_orise_ctr; + + uint8_t lcd_init_step; + uint8_t lcd_uninit_step; + uint8_t lcd_uninit_step_support; + uint8_t lcd_refresh_direction_ctrl; + uint8_t lcd_adjust_support; + + uint8_t sbl_support; + uint8_t color_temperature_support; + uint8_t color_temp_rectify_support; + uint32_t color_temp_rectify_R; + uint32_t color_temp_rectify_G; + uint32_t color_temp_rectify_B; + uint8_t comform_mode_support; + uint8_t cinema_mode_support; + uint8_t frc_enable; + uint8_t esd_enable; + uint8_t esd_skip_mipi_check; + uint8_t esd_recover_step; + uint8_t dirty_region_updt_support; + uint8_t dsi_bit_clk_upt_support; + uint8_t fps_updt_support; + uint8_t panel_effect_support; + + uint8_t prefix_ce_support; + uint8_t prefix_sharpness1D_support; + uint8_t prefix_sharpness2D_support; + sharp2d_t *sharp2d_table; + + uint8_t gmp_support; + uint8_t gamma_support; + uint8_t gamma_type; + uint8_t xcc_support; + uint8_t acm_support; + uint8_t acm_ce_support; + uint8_t hiace_support; + uint8_t dither_support; + uint8_t arsr1p_sharpness_support; + uint8_t post_scf_support; + uint8_t default_gmp_off; + + uint32_t acm_valid_num; + uint32_t r0_hh; + uint32_t r0_lh; + uint32_t r1_hh; + uint32_t r1_lh; + uint32_t r2_hh; + uint32_t r2_lh; + uint32_t r3_hh; + uint32_t r3_lh; + uint32_t r4_hh; + uint32_t r4_lh; + uint32_t r5_hh; + uint32_t r5_lh; + uint32_t r6_hh; + uint32_t r6_lh; + + uint32_t cinema_acm_valid_num; + uint32_t cinema_r0_hh; + uint32_t cinema_r0_lh; + uint32_t cinema_r1_hh; + uint32_t cinema_r1_lh; + uint32_t cinema_r2_hh; + uint32_t cinema_r2_lh; + uint32_t cinema_r3_hh; + uint32_t cinema_r3_lh; + uint32_t cinema_r4_hh; + uint32_t cinema_r4_lh; + uint32_t cinema_r5_hh; + uint32_t cinema_r5_lh; + uint32_t cinema_r6_hh; + uint32_t cinema_r6_lh; + + uint32_t *acm_lut_hue_table; + uint32_t acm_lut_hue_table_len; + uint32_t *acm_lut_value_table; + uint32_t acm_lut_value_table_len; + uint32_t *acm_lut_sata_table; + uint32_t acm_lut_sata_table_len; + uint32_t *acm_lut_satr_table; + uint32_t acm_lut_satr_table_len; + + uint32_t *cinema_acm_lut_hue_table; + uint32_t cinema_acm_lut_hue_table_len; + uint32_t *cinema_acm_lut_value_table; + uint32_t cinema_acm_lut_value_table_len; + uint32_t *cinema_acm_lut_sata_table; + uint32_t cinema_acm_lut_sata_table_len; + uint32_t *cinema_acm_lut_satr_table; + uint32_t cinema_acm_lut_satr_table_len; + + uint32_t *acm_lut_satr0_table; + uint32_t acm_lut_satr0_table_len; + uint32_t *acm_lut_satr1_table; + uint32_t acm_lut_satr1_table_len; + uint32_t *acm_lut_satr2_table; + uint32_t acm_lut_satr2_table_len; + uint32_t *acm_lut_satr3_table; + uint32_t acm_lut_satr3_table_len; + uint32_t *acm_lut_satr4_table; + uint32_t acm_lut_satr4_table_len; + uint32_t *acm_lut_satr5_table; + uint32_t acm_lut_satr5_table_len; + uint32_t *acm_lut_satr6_table; + uint32_t acm_lut_satr6_table_len; + uint32_t *acm_lut_satr7_table; + uint32_t acm_lut_satr7_table_len; + + uint32_t *cinema_acm_lut_satr0_table; + uint32_t *cinema_acm_lut_satr1_table; + uint32_t *cinema_acm_lut_satr2_table; + uint32_t *cinema_acm_lut_satr3_table; + uint32_t *cinema_acm_lut_satr4_table; + uint32_t *cinema_acm_lut_satr5_table; + uint32_t *cinema_acm_lut_satr6_table; + uint32_t *cinema_acm_lut_satr7_table; + + uint32_t *gamma_lut_table_R; + uint32_t *gamma_lut_table_G; + uint32_t *gamma_lut_table_B; + uint32_t gamma_lut_table_len; + uint32_t *cinema_gamma_lut_table_R; + uint32_t *cinema_gamma_lut_table_G; + uint32_t *cinema_gamma_lut_table_B; + uint32_t cinema_gamma_lut_table_len; + uint32_t *igm_lut_table_R; + uint32_t *igm_lut_table_G; + uint32_t *igm_lut_table_B; + uint32_t igm_lut_table_len; + uint32_t *gmp_lut_table_low32bit; + uint32_t *gmp_lut_table_high4bit; + uint32_t gmp_lut_table_len; + uint32_t *xcc_table; + uint32_t xcc_table_len; + + uint32_t *pgainlsc0; + uint32_t *pgainlsc1; + uint32_t pgainlsc_len; + uint32_t *hcoeff0y; + uint32_t *hcoeff1y; + uint32_t *hcoeff2y; + uint32_t *hcoeff3y; + uint32_t *hcoeff4y; + uint32_t *hcoeff5y; + uint32_t hcoeffy_len; + uint32_t *vcoeff0y; + uint32_t *vcoeff1y; + uint32_t *vcoeff2y; + uint32_t *vcoeff3y; + uint32_t *vcoeff4y; + uint32_t *vcoeff5y; + uint32_t vcoeffy_len; + uint32_t *hcoeff0uv; + uint32_t *hcoeff1uv; + uint32_t *hcoeff2uv; + uint32_t *hcoeff3uv; + uint32_t hcoeffuv_len; + uint32_t *vcoeff0uv; + uint32_t *vcoeff1uv; + uint32_t *vcoeff2uv; + uint32_t *vcoeff3uv; + uint32_t vcoeffuv_len; + + struct spi_device *spi_dev; + struct ldi_panel_info ldi; + struct ldi_panel_info ldi_updt; + struct ldi_panel_info ldi_lfps; + struct mipi_panel_info mipi; + struct sbl_panel_info smart_bl; + struct dsc_panel_info vesa_dsc; + struct lcd_dirty_region_info dirty_region_info; + + struct mipi_dsi_phy_ctrl dsi_phy_ctrl; + + struct hiace_alg_parameter hiace_param; + struct ce_algorithm_parameter ce_alg_param; +}; + +struct hisi_fb_data_type; +struct hisi_fb_panel_data { + struct hisi_panel_info *panel_info; + + /* function entry chain */ + int (*on) (struct platform_device *pdev); + int (*off) (struct platform_device *pdev); + int (*remove) (struct platform_device *pdev); + int (*set_backlight) (struct platform_device *pdev, uint32_t bl_level); + int (*vsync_ctrl) (struct platform_device *pdev, int enable); + + struct platform_device *next; +}; + +/******************************************************************************* + ** FUNCTIONS PROTOTYPES + */ +#define MIPI_DPHY_NUM (2) + +extern uint32_t g_dts_resouce_ready; +extern mipi_ifbc_division_t g_mipi_ifbc_division[MIPI_DPHY_NUM][IFBC_TYPE_MAX]; +int resource_cmds_tx(struct platform_device *pdev, + struct resource_desc *cmds, int cnt); +int vcc_cmds_tx(struct platform_device *pdev, struct vcc_desc *cmds, int cnt); +int pinctrl_cmds_tx(struct platform_device *pdev, struct pinctrl_cmd_desc *cmds, + int cnt); +int gpio_cmds_tx(struct gpio_desc *cmds, int cnt); +extern struct spi_device *g_spi_dev; + +int panel_next_on(struct platform_device *pdev); +int panel_next_off(struct platform_device *pdev); +int panel_next_remove(struct platform_device *pdev); +int panel_next_set_backlight(struct platform_device *pdev, uint32_t bl_level); +int panel_next_vsync_ctrl(struct platform_device *pdev, int enable); + +bool is_ldi_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_cmd_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_cmd_panel_ext(struct hisi_panel_info *pinfo); +bool is_mipi_video_panel(struct hisi_fb_data_type *hisifd); +bool is_mipi_panel(struct hisi_fb_data_type *hisifd); +bool is_dual_mipi_panel(struct hisi_fb_data_type *hisifd); +bool is_dual_mipi_panel_ext(struct hisi_panel_info *pinfo); +bool is_ifbc_panel(struct hisi_fb_data_type *hisifd); +bool is_ifbc_vesa_panel(struct hisi_fb_data_type *hisifd); +bool mipi_panel_check_reg(struct hisi_fb_data_type *hisifd, + uint32_t *read_value); +int mipi_ifbc_get_rect(struct hisi_fb_data_type *hisifd, struct dss_rect *rect); +bool is_hisi_writeback_panel(struct hisi_fb_data_type *hisifd); +void hisi_fb_device_set_status0(uint32_t status); +int hisi_fb_device_set_status1(struct hisi_fb_data_type *hisifd); +bool hisi_fb_device_probe_defer(uint32_t panel_type, uint32_t bl_type); +#endif /* HISI_FB_PANEL_H */ -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 6/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_fb_utils.c | 249 ++++ drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c | 680 +++++++++ drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c | 401 ++++++ .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c | 1450 ++++++++++++++++++++ .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h | 249 ++++ 5 files changed, 3029 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c new file mode 100755 index 000000000000..3c7965716890 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_overlay_utils.h" +#if defined (CONFIG_HISI_PERIDVFS) +#include "peri_volt_poll.h" +#endif + +#define MAX_BUF 60 +void set_reg(char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1UL << bw) - 1UL; + uint32_t tmp = 0; + + tmp = inp32(addr); + tmp &= ~(mask << bs); + + outp32(addr, tmp | ((val & mask) << bs)); + + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%x\n", addr, + tmp | ((val & mask) << bs)); + } +} + +uint32_t set_bits32(uint32_t old_val, uint32_t val, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1UL << bw) - 1UL; + uint32_t tmp = 0; + + tmp = old_val; + tmp &= ~(mask << bs); + + return (tmp | ((val & mask) << bs)); +} + +void hisifb_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs) +{ + set_reg(addr, val, bw, bs); +} + +bool is_dss_idle_enable(void) +{ + return ((g_enable_dss_idle == 1) ? true : false); +} + +uint32_t get_panel_xres(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + return ((hisifd->resolution_rect.w > + 0) ? hisifd->resolution_rect.w : hisifd->panel_info.xres); +} + +uint32_t get_panel_yres(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + return ((hisifd->resolution_rect.h > + 0) ? hisifd->resolution_rect.h : hisifd->panel_info.yres); +} + +uint32_t hisifb_line_length(int index, uint32_t xres, int bpp) +{ + return ALIGN_UP(xres * bpp, DMA_STRIDE_ALIGN); +} + +void hisifb_get_timestamp(struct timeval *tv) +{ + struct timespec ts; + + ktime_get_ts(&ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; +} + +uint32_t hisifb_timestamp_diff(struct timeval *lasttime, + struct timeval *curtime) +{ + uint32_t ret; + ret = (curtime->tv_usec >= lasttime->tv_usec) ? + curtime->tv_usec - lasttime->tv_usec : + 1000000 - (lasttime->tv_usec - curtime->tv_usec); + + return ret; +} + +void hisifb_save_file(char *filename, char *buf, uint32_t buf_len) +{ + ssize_t write_len = 0; + struct file *fd = NULL; + mm_segment_t old_fs; + loff_t pos = 0; + + BUG_ON(filename == NULL); + BUG_ON(buf == NULL); + + fd = filp_open(filename, O_CREAT | O_RDWR, 0644); + if (IS_ERR(fd)) { + HISI_FB_ERR("filp_open returned:filename %s, error %ld\n", + filename, PTR_ERR(fd)); + return; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + write_len = vfs_write(fd, (char __user *)buf, buf_len, &pos); + + pos = 0; + set_fs(old_fs); + filp_close(fd, NULL); +} + +int hisifb_ctrl_on(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + if (pdata->on) { + ret = pdata->on(hisifd->pdev); + } + + hisifb_vsync_resume(hisifd); + hisi_overlay_on(hisifd, false); + + if (hisifd->panel_info.esd_enable) { + hrtimer_start(&hisifd->esd_ctrl.esd_hrtimer, + ktime_set(ESD_CHECK_TIME_PERIOD / 1000, + (ESD_CHECK_TIME_PERIOD % 1000) * + 1000000), HRTIMER_MODE_REL); + } + + return ret; +} + +int hisifb_ctrl_off(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + if (hisifd->panel_info.esd_enable) { + hrtimer_cancel(&hisifd->esd_ctrl.esd_hrtimer); + } + + hisifb_vsync_suspend(hisifd); + hisi_overlay_off(hisifd); + + if (pdata->off) { + ret = pdata->off(hisifd->pdev); + } + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + + hisifb_layerbuf_unlock(hisifd, + &(hisifd->buf_sync_ctrl.layerbuf_list)); + } + + return ret; +} + +int hisifb_ctrl_dss_clk_rate_set(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + dss_clk_rate_t dss_clk_rate; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->core_clk_upt_support == 0) { + HISI_FB_DEBUG("no support core_clk_upt\n"); + return ret; + } + + ret = copy_from_user(&dss_clk_rate, argp, sizeof(dss_clk_rate_t)); + if (ret) { + HISI_FB_ERR("copy_from_user failed!ret=%d.", ret); + return ret; + } + + down(&hisifd->blank_sem); + + if (!hisifd->panel_power_on) { + HISI_FB_DEBUG("fb%d, panel power off!\n", hisifd->index); + ret = -EPERM; + goto err_out; + } + + ret = set_dss_clk_rate(hisifd, dss_clk_rate); + + err_out: + up(&hisifd->blank_sem); + + return ret; +} + +/*lint +e665, +e514, +e84, +e886, +e846, +e778*/ +void hisifb_sysfs_attrs_add(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->sysfs_attrs_append_fnc) { + /* hisifd->sysfs_attrs_append_fnc(hisifd, &dev_attr_lcd_model.attr); */ + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c new file mode 100755 index 000000000000..3778ac0b4b2c --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c @@ -0,0 +1,680 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#include "hisi_fb.h" + +/* + ** /sys/class/graphics/fb0/vsync_event + */ +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) +#define VSYNC_TIMEOUT_MSEC (100) +#endif +#define VSYNC_CTRL_EXPIRE_COUNT (4) + +#ifdef CONFIG_REPORT_VSYNC +extern void mali_kbase_pm_report_vsync(int); +#endif +extern int mipi_dsi_ulps_cfg(struct hisi_fb_data_type *hisifd, int enable); +extern bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd); + +void hisifb_frame_updated(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->vsync_ctrl.vsync_report_fnc) { + atomic_inc(&(hisifd->vsync_ctrl.buffer_updated)); + } +} + +void hisifb_vsync_isr_handler(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + struct hisi_fb_panel_data *pdata = NULL; + int buffer_updated = 0; + ktime_t pre_vsync_timestamp; + + BUG_ON(hisifd == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + pre_vsync_timestamp = vsync_ctrl->vsync_timestamp; + vsync_ctrl->vsync_timestamp = ktime_get(); + wake_up_interruptible_all(&(vsync_ctrl->vsync_wait)); + + if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) { + spin_lock(&vsync_ctrl->spin_lock); + if (vsync_ctrl->vsync_ctrl_expire_count) { + vsync_ctrl->vsync_ctrl_expire_count--; + if (vsync_ctrl->vsync_ctrl_expire_count == 0) + schedule_work(&vsync_ctrl->vsync_ctrl_work); + } + spin_unlock(&vsync_ctrl->spin_lock); + } + + if (vsync_ctrl->vsync_report_fnc) { + if (hisifd->vsync_ctrl.vsync_enabled) { + buffer_updated = + atomic_dec_return(&(vsync_ctrl->buffer_updated)); + } else { + buffer_updated = 1; + } + + if (buffer_updated < 0) { + atomic_cmpxchg(&(vsync_ctrl->buffer_updated), + buffer_updated, 1); + } else { + vsync_ctrl->vsync_report_fnc(buffer_updated); + } + } + + if (g_debug_online_vsync) { + HISI_FB_INFO("fb%d, VSYNC=%llu, time_diff=%llu.\n", + hisifd->index, + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp), + (ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp) - + ktime_to_ns(pre_vsync_timestamp))); + } +} + +static int vsync_timestamp_changed(struct hisi_fb_data_type *hisifd, + ktime_t prev_timestamp) +{ + BUG_ON(hisifd == NULL); + return !ktime_equal(prev_timestamp, hisifd->vsync_ctrl.vsync_timestamp); +} + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) +static int wait_for_vsync_thread(void *data) +{ + struct hisi_fb_data_type *hisifd = (struct hisi_fb_data_type *)data; + ktime_t prev_timestamp; + int ret = 0; + + while (!kthread_should_stop()) { + prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp; + ret = + wait_event_interruptible_timeout(hisifd->vsync_ctrl. + vsync_wait, + vsync_timestamp_changed + (hisifd, prev_timestamp) + && hisifd->vsync_ctrl. + vsync_enabled, + msecs_to_jiffies + (VSYNC_TIMEOUT_MSEC)); + + /*if (ret == 0) { + HISI_FB_ERR("wait vsync timeout!"); + return -ETIMEDOUT; + } + */ + + if (ret > 0) { + char *envp[2]; + char buf[64]; + /* fb%d_VSYNC=%llu */ + snprintf(buf, sizeof(buf), "VSYNC=%llu", + ktime_to_ns(hisifd->vsync_ctrl. + vsync_timestamp)); + envp[0] = buf; + envp[1] = NULL; + kobject_uevent_env(&hisifd->pdev->dev.kobj, KOBJ_CHANGE, + envp); + } + } + + return 0; +} +#else +static ssize_t vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = -1; + int vsync_flag = 0; + struct fb_info *fbi = NULL; + struct hisi_fb_data_type *hisifd = NULL; + ktime_t prev_timestamp; + + if (NULL == dev) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + fbi = dev_get_drvdata(dev); + if (NULL == fbi) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + hisifd = (struct hisi_fb_data_type *)fbi->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + if (NULL == buf) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp; + + /*lint -e666 */ + ret = wait_event_interruptible(hisifd->vsync_ctrl.vsync_wait, + (vsync_timestamp_changed + (hisifd, prev_timestamp) + && hisifd->vsync_ctrl.vsync_enabled)); + /*lint +e666 */ + vsync_flag = (vsync_timestamp_changed(hisifd, prev_timestamp) && + hisifd->vsync_ctrl.vsync_enabled); + + if (vsync_flag) { + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu, xxxxxxEvent=x \n", + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp)); + buf[strlen(buf) + 1] = '\0'; + + } else { + return -1; + } + + return ret; +} + +static ssize_t vsync_timestamp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = -1; + struct fb_info *fbi = NULL; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL == dev) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + fbi = dev_get_drvdata(dev); + if (NULL == fbi) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + hisifd = (struct hisi_fb_data_type *)fbi->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + if (NULL == buf) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + ret = snprintf(buf, PAGE_SIZE, "%llu \n", + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp)); + buf[strlen(buf) + 1] = '\0'; + + return ret; +} + +static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); +static DEVICE_ATTR(vsync_timestamp, S_IRUGO, vsync_timestamp_show, NULL); +#endif + +#ifdef CONFIG_FAKE_VSYNC_USED +enum hrtimer_restart hisifb_fake_vsync(struct hrtimer *timer) +{ + struct hisi_fb_data_type *hisifd = NULL; + int fps = 60; + + hisifd = + container_of(timer, struct hisi_fb_data_type, fake_vsync_hrtimer); + BUG_ON(hisifd == NULL); + + if (!hisifd->panel_power_on) + goto error; + + if (hisifd->fake_vsync_used && hisifd->vsync_ctrl.vsync_enabled) { + hisifd->vsync_ctrl.vsync_timestamp = ktime_get(); + wake_up_interruptible_all(&hisifd->vsync_ctrl.vsync_wait); + } + + error: + hrtimer_start(&hisifd->fake_vsync_hrtimer, + ktime_set(0, NSEC_PER_SEC / fps), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +#endif + +static void hisifb_vsync_ctrl_workqueue_handler(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + struct hisi_fb_panel_data *pdata = NULL; + unsigned long flags = 0; + + vsync_ctrl = container_of(work, typeof(*vsync_ctrl), vsync_ctrl_work); + BUG_ON(vsync_ctrl == NULL); + hisifd = vsync_ctrl->hisifd; + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + + down(&(hisifd->blank_sem)); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&(hisifd->blank_sem)); + return; + } + + mutex_lock(&(vsync_ctrl->vsync_lock)); + if (vsync_ctrl->vsync_ctrl_disabled_set && + (vsync_ctrl->vsync_ctrl_expire_count == 0) && + vsync_ctrl->vsync_ctrl_enabled && + !vsync_ctrl->vsync_enabled + && !vsync_ctrl->vsync_ctrl_offline_enabled) { + HISI_FB_DEBUG("fb%d, dss clk off!\n", hisifd->index); + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + if (pdata->vsync_ctrl) { + pdata->vsync_ctrl(hisifd->pdev, 0); + } else { + HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", + hisifd->index); + } + vsync_ctrl->vsync_ctrl_enabled = 0; + vsync_ctrl->vsync_ctrl_disabled_set = 0; + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 0); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + if (hisifd->lp_fnc) + hisifd->lp_fnc(hisifd, true); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + dpe_inner_clk_disable(hisifd); + dpe_common_clk_disable(hisifd); + mipi_dsi_clk_disable(hisifd); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + /* dpe_regulator_disable(hisifd); */ + } + } + mutex_unlock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_report_fnc) { + vsync_ctrl->vsync_report_fnc(1); + } + + up(&(hisifd->blank_sem)); +} + +void hisifb_vsync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + char name[64] = { 0 }; +#endif + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + if (vsync_ctrl->vsync_created) + return; + + vsync_ctrl->hisifd = hisifd; + vsync_ctrl->vsync_infinite = 0; + vsync_ctrl->vsync_enabled = 0; + vsync_ctrl->vsync_ctrl_offline_enabled = 0; + vsync_ctrl->vsync_timestamp = ktime_get(); + init_waitqueue_head(&(vsync_ctrl->vsync_wait)); + spin_lock_init(&(vsync_ctrl->spin_lock)); + INIT_WORK(&vsync_ctrl->vsync_ctrl_work, + hisifb_vsync_ctrl_workqueue_handler); + + mutex_init(&(vsync_ctrl->vsync_lock)); + + atomic_set(&(vsync_ctrl->buffer_updated), 1); +#ifdef CONFIG_REPORT_VSYNC + vsync_ctrl->vsync_report_fnc = mali_kbase_pm_report_vsync; +#else + vsync_ctrl->vsync_report_fnc = NULL; +#endif + +#ifdef CONFIG_FAKE_VSYNC_USED + /* hrtimer for fake vsync timing */ + hisifd->fake_vsync_used = false; + hrtimer_init(&hisifd->fake_vsync_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hisifd->fake_vsync_hrtimer.function = hisifb_fake_vsync; + hrtimer_start(&hisifd->fake_vsync_hrtimer, + ktime_set(0, NSEC_PER_SEC / 60), HRTIMER_MODE_REL); +#endif + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + snprintf(name, sizeof(name), "hisifb%d_vsync", hisifd->index); + vsync_ctrl->vsync_thread = + kthread_run(wait_for_vsync_thread, hisifd, name); + if (IS_ERR(vsync_ctrl->vsync_thread)) { + vsync_ctrl->vsync_thread = NULL; + HISI_FB_ERR("failed to run vsync thread!\n"); + return; + } +#else + if (hisifd->sysfs_attrs_append_fnc) { + hisifd->sysfs_attrs_append_fnc(hisifd, + &dev_attr_vsync_event.attr); + hisifd->sysfs_attrs_append_fnc(hisifd, + &dev_attr_vsync_timestamp.attr); + } +#endif + + vsync_ctrl->vsync_created = 1; +} + +void hisifb_vsync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(pdev == NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + if (!vsync_ctrl->vsync_created) + return; + +#ifdef CONFIG_FAKE_VSYNC_USED + hisifd->fake_vsync_used = false; + hrtimer_cancel(&hisifd->fake_vsync_hrtimer); +#endif + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + if (vsync_ctrl->vsync_thread) + kthread_stop(vsync_ctrl->vsync_thread); +#endif + + vsync_ctrl->vsync_created = 0; +} + +void hisifb_set_vsync_activate_state(struct hisi_fb_data_type *hisifd, + bool infinite) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(hisifd == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (infinite) { + vsync_ctrl->vsync_infinite_count += 1; + } else { + vsync_ctrl->vsync_infinite_count -= 1; + } + + if (vsync_ctrl->vsync_infinite_count >= 1) { + vsync_ctrl->vsync_infinite = 1; + } + + if (vsync_ctrl->vsync_infinite_count == 0) { + vsync_ctrl->vsync_infinite = 0; + } + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + unsigned long flags = 0; + int clk_enabled = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_ctrl_enabled == 0) { + HISI_FB_DEBUG("fb%d, dss clk on!\n", hisifd->index); + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + /* dpe_regulator_enable(hisifd); */ + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + mipi_dsi_clk_enable(hisifd); + dpe_common_clk_enable(hisifd); + dpe_inner_clk_enable(hisifd); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + if (hisifd->lp_fnc) + hisifd->lp_fnc(hisifd, false); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 1); + } + + vsync_ctrl->vsync_ctrl_enabled = 1; + clk_enabled = 1; + } else if (vsync_ctrl->vsync_ctrl_isr_enabled) { + clk_enabled = 1; + vsync_ctrl->vsync_ctrl_isr_enabled = 0; + } else { + ; + } + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + vsync_ctrl->vsync_ctrl_disabled_set = 0; + vsync_ctrl->vsync_ctrl_expire_count = 0; + if (clk_enabled) { + if (pdata->vsync_ctrl) { + pdata->vsync_ctrl(hisifd->pdev, 1); + } else { + HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", + hisifd->index); + } + } + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +void hisifb_deactivate_vsync(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + unsigned long flags = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + if (vsync_ctrl->vsync_infinite == 0) + vsync_ctrl->vsync_ctrl_disabled_set = 1; + + if (vsync_ctrl->vsync_ctrl_enabled) + vsync_ctrl->vsync_ctrl_expire_count = VSYNC_CTRL_EXPIRE_COUNT; + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + int enable = 0; + + if (NULL == info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + return -EINVAL; + } + + pdata = dev_get_platdata(&hisifd->pdev->dev); + if (NULL == pdata) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + vsync_ctrl = &(hisifd->vsync_ctrl); + if (NULL == vsync_ctrl) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + HISI_FB_ERR("hisifb_vsync_ctrl ioctl failed!\n"); + return ret; + } + + enable = (enable) ? 1 : 0; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_enabled == enable) { + mutex_unlock(&(vsync_ctrl->vsync_lock)); + return 0; + } + + if (g_debug_online_vsync) + HISI_FB_INFO("fb%d, enable=%d!\n", hisifd->index, enable); + + vsync_ctrl->vsync_enabled = enable; + + mutex_unlock(&(vsync_ctrl->vsync_lock)); + + down(&hisifd->blank_sem); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&hisifd->blank_sem); + return 0; + } + + if (enable) { + hisifb_activate_vsync(hisifd); + } else { + hisifb_deactivate_vsync(hisifd); + } + + up(&hisifd->blank_sem); + + return 0; +} + +int hisifb_vsync_resume(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(hisifd == NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl == NULL); + + vsync_ctrl->vsync_enabled = 0; + vsync_ctrl->vsync_ctrl_expire_count = 0; + vsync_ctrl->vsync_ctrl_disabled_set = 0; + vsync_ctrl->vsync_ctrl_enabled = 1; + vsync_ctrl->vsync_ctrl_isr_enabled = 1; + + atomic_set(&(vsync_ctrl->buffer_updated), 1); + +#if 0 + if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) { + if ((hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) + || (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) + || (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_VCC_OFF)) { + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 0); + } + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + dpe_inner_clk_disable(hisifd); + dpe_common_clk_disable(hisifd); + mipi_dsi_clk_disable(hisifd); + } + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + dpe_regulator_disable(hisifd); + } + } + } +#endif + + return 0; +} + +int hisifb_vsync_suspend(struct hisi_fb_data_type *hisifd) +{ + return 0; +} + +#pragma GCC diagnostic pop diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c new file mode 100755 index 000000000000..0d00d3fd9c60 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c @@ -0,0 +1,401 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_mipi_dsi.h" + +/* + * mipi dsi short write with 0, 1 2 parameters + * Write to GEN_HDR 24 bit register the value: + * 1. 00h, MCS_command[15:8] ,VC[7:6],13h + * 2. Data1[23:16], MCS_command[15:8] ,VC[7:6],23h + */ +int mipi_dsi_swrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + uint32_t hdr = 0; + int len = 0; + + if (cm->dlen && cm->payload == 0) { + HISI_FB_ERR("NO payload error!\n"); + return 0; + } + + BUG_ON(cm->dlen > 2); + len = cm->dlen; + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + if (len == 1) { + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(0); + } else if (len == 2) { + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(cm->payload[1]); + } else { + hdr |= DSI_HDR_DATA1(0); + hdr |= DSI_HDR_DATA2(0); + } + + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); + + return len; /* 4 bytes */ +} + +/* + * mipi dsi long write + * Write to GEN_PLD_DATA 32 bit register the value: + * Data3[31:24], Data2[23:16], Data1[15:8], MCS_command[7:0] + * If need write again to GEN_PLD_DATA 32 bit register the value: + * Data7[31:24], Data6[23:16], Data5[15:8], Data4[7:0] + * + * Write to GEN_HDR 24 bit register the value: WC[23:8] ,VC[7:6],29h + */ +int mipi_dsi_lwrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + uint32_t hdr = 0; + int i = 0; + + if (cm->dlen && cm->payload == 0) { + HISI_FB_ERR("NO payload error!\n"); + return 0; + } + + /* fill up payload */ + for (i = 0; i < cm->dlen; i += 4) { + set_reg(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET, + *((uint32_t *) (cm->payload + i)), 32, 0); + } + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_WC(cm->dlen); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); + + return cm->dlen; +} + +void mipi_dsi_max_return_packet_size(struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + uint32_t hdr = 0; + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_WC(cm->dlen); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); +} + +uint32_t mipi_dsi_read(uint32_t *out, char __iomem *dsi_base) +{ + uint32_t pkg_status; + uint32_t try_times = 700; + + do { + pkg_status = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if (!(pkg_status & 0x10)) + break; + udelay(50); + } while (--try_times); + + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); + if (!try_times) + HISI_FB_ERR("mipi_dsi_read timeout\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x \n" + "MIPIDSI_PHY_STATUS = 0x%x \n", + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET)); + + return try_times; +} + +void mipi_dsi_sread(uint32_t *out, char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t tmp = 0; + + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if ((tmp & 0x00000040) == 0x00000040) { + break; + } + } while (time_after(dw_jiffies, jiffies)); + + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if ((tmp & 0x00000040) != 0x00000040) { + break; + } + } while (time_after(dw_jiffies, jiffies)); + + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); +} + +void mipi_dsi_lread(uint32_t *out, char __iomem *dsi_base) +{ + /* do something here */ +} + +/* + * prepare cmd buffer to be txed + */ +int mipi_dsi_cmd_add(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + int len = 0; + + BUG_ON(cm == NULL); + BUG_ON(dsi_base == NULL); + + switch (cm->dtype) { + case DTYPE_GEN_WRITE: + case DTYPE_GEN_WRITE1: + case DTYPE_GEN_WRITE2: + + case DTYPE_DCS_WRITE: + case DTYPE_DCS_WRITE1: + len = mipi_dsi_swrite(cm, dsi_base); + break; + case DTYPE_GEN_LWRITE: + case DTYPE_DCS_LWRITE: + case DTYPE_DSC_LWRITE: + + len = mipi_dsi_lwrite(cm, dsi_base); + break; + default: + HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype); + break; + } + + return len; +} + +int mipi_dsi_cmds_tx(struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base) +{ + struct dsi_cmd_desc *cm = NULL; + int i = 0; + + BUG_ON(cmds == NULL); + BUG_ON(dsi_base == NULL); + + cm = cmds; + + for (i = 0; i < cnt; i++) { + mipi_dsi_cmd_add(cm, dsi_base); + + if (cm->wait) { + if (cm->waittype == WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype == WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + cm++; + } + + return cnt; +} + +void mipi_dsi_check_0lane_is_ready(char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t tmp = 0; + + dw_jiffies = jiffies + HZ / 10; + do { + tmp = inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((tmp & 0x10) == 0x10) { + HISI_FB_INFO("0 lane is stopping state"); + return; + } + } while (time_after(dw_jiffies, jiffies)); + + HISI_FB_ERR("0 lane is not stopping state:tmp=0x%x", tmp); +} + +static void mipi_dsi_sread_request(struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + uint32_t hdr = 0; + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(0); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); +} + +static int mipi_dsi_read_add(uint32_t *out, struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t pkg_status = 0; + uint32_t phy_status = 0; + int is_timeout = 1; + int ret = 0; + + BUG_ON(cm == NULL); + BUG_ON(dsi_base == NULL); + + if (cm->dtype == DTYPE_DCS_READ) { + mipi_dsi_sread_request(cm, dsi_base); + + if (!mipi_dsi_read(out, dsi_base)) { + HISI_FB_ERR("Read register 0x%X timeout\n", + cm->payload[0]); + return -1; + } + } else if (cm->dtype == DTYPE_GEN_READ1) { + + /*read status register */ + dw_jiffies = jiffies + HZ; + do { + pkg_status = + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + phy_status = + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((pkg_status & 0x1) == 0x1 && !(phy_status & 0x2)) { + is_timeout = 0; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (is_timeout) { + HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x\n" + "MIPIDSI_PHY_STATUS = 0x%x \n" + "MIPIDSI_INT_ST1_OFFSET = 0x%x \n", + cm->payload[0], + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET)); + return -1; + } + /*send read cmd to fifo */ + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, + ((cm->payload[0] << 8) | cm->dtype), 24, 0); + + is_timeout = 1; + /*wait dsi read data */ + dw_jiffies = jiffies + HZ; + do { + pkg_status = + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if (!(pkg_status & 0x10)) { + is_timeout = 0; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (is_timeout) { + HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x\n" + "MIPIDSI_PHY_STATUS = 0x%x \n" + "MIPIDSI_INT_ST1_OFFSET = 0x%x \n", + cm->payload[0], + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET)); + return -1; + } + /*get read data */ + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); + } else { + ret = -1; + HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype); + } + + return ret; +} + +int mipi_dsi_cmds_rx(uint32_t *out, struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base) +{ + struct dsi_cmd_desc *cm = NULL; + int i = 0; + int err_num = 0; + + BUG_ON(cmds == NULL); + BUG_ON(dsi_base == NULL); + + cm = cmds; + + for (i = 0; i < cnt; i++) { + if (mipi_dsi_read_add(&(out[i]), cm, dsi_base)) { + err_num++; + } + + if (cm->wait) { + if (cm->waittype == WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype == WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + cm++; + } + + return err_num; +} + +int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data, + char __iomem *dsi_base) +{ + uint32_t *read_value = NULL; + uint32_t *expected_value = NULL; + uint32_t *read_mask = NULL; + char **reg_name = NULL; + int log_on = 0; + struct dsi_cmd_desc *cmds = NULL; + + int cnt = 0; + int cnt_not_match = 0; + int ret = 0; + int i; + + BUG_ON(data == NULL); + BUG_ON(dsi_base == NULL); + + read_value = data->read_value; + expected_value = data->expected_value; + read_mask = data->read_mask; + reg_name = data->reg_name; + log_on = data->log_on; + + cmds = data->cmds; + cnt = data->cnt; + + ret = mipi_dsi_cmds_rx(read_value, cmds, cnt, dsi_base); + if (ret) { + HISI_FB_ERR("Read error number: %d\n", ret); + return cnt; + } + + for (i = 0; i < cnt; i++) { + if (log_on) { + HISI_FB_INFO("Read reg %s: 0x%x, value = 0x%x\n", + reg_name[i], cmds[i].payload[0], + read_value[i]); + } + + if (expected_value[i] != (read_value[i] & read_mask[i])) { + cnt_not_match++; + } + } + + return cnt_not_match; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c new file mode 100755 index 000000000000..6b1832f49e3c --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c @@ -0,0 +1,1450 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" + +#define MAX_ITEM_OFFSET (0x3F) +#define CMDLIST_ADDR_OFFSET (0x3FFFF) + +#define CMDLIST_HEADER_LEN (SZ_1K) +#define CMDLIST_ITEM_LEN (SZ_8K) +#define MAX_ITEM_INDEX (SZ_1K) + +dss_cmdlist_data_t *g_cmdlist_data = NULL; +uint32_t g_online_cmdlist_idxs = 0; +uint32_t g_offline_cmdlist_idxs = 0; + +/* get cmdlist indexs */ +int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req, + uint32_t *cmdlist_pre_idxs, + uint32_t *cmdlist_idxs) +{ + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int k = 0; + int m = 0; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + bool no_ovl_idx = false; + + BUG_ON(pov_req == NULL); + + pov_h_block_infos = (dss_overlay_block_t *) pov_req->ov_block_infos_ptr; + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + continue; + + if (layer->chn_idx == DSS_RCHN_V2) { + cmdlist_idxs_temp |= (1 << DSS_CMDLIST_V2); + } else { + cmdlist_idxs_temp |= (1 << layer->chn_idx); + } + } + } + + if (pov_req->wb_enable == 1) { + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + + if (wb_layer->chn_idx == DSS_WCHN_W2) { + no_ovl_idx = true; + cmdlist_idxs_temp |= (1 << DSS_CMDLIST_W2); + } else { + cmdlist_idxs_temp |= (1 << wb_layer->chn_idx); + } + } + } + + if (no_ovl_idx == false) { + cmdlist_idxs_temp |= + (1 << (DSS_CMDLIST_OV0 + pov_req->ovl_idx)); + } + + if (cmdlist_idxs_temp & (~HISI_DSS_CMDLIST_IDXS_MAX)) { + HISI_FB_ERR("cmdlist_idxs_temp(0x%x) is invalid!\n", + cmdlist_idxs_temp); + return -EINVAL; + } + + if (cmdlist_idxs && cmdlist_pre_idxs) { + *cmdlist_idxs = cmdlist_idxs_temp; + *cmdlist_pre_idxs &= (~(*cmdlist_idxs)); + } else if (cmdlist_idxs) { + *cmdlist_idxs = cmdlist_idxs_temp; + } else if (cmdlist_pre_idxs) { + *cmdlist_pre_idxs = cmdlist_idxs_temp; + } else { + HISI_FB_ERR("cmdlist_idxs && cmdlist_pre_idxs is NULL!\n"); + return -EINVAL; + } + + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO("cmdlist_pre_idxs(0x%x), cmdlist_idxs(0x%x).\n", + (cmdlist_pre_idxs ? *cmdlist_pre_idxs : 0), + (cmdlist_idxs ? *cmdlist_idxs : 0)); + } + + return 0; +} + +uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs) +{ + uint32_t cmdlist_idxs_temp = 0; + + BUG_ON(hisifd == NULL); + + cmdlist_idxs_temp = g_offline_cmdlist_idxs; + g_offline_cmdlist_idxs |= cmdlist_idxs; + cmdlist_idxs_temp = (g_offline_cmdlist_idxs & (~cmdlist_idxs_temp)); + + cmdlist_idxs_temp |= (cmdlist_idxs & g_online_cmdlist_idxs); + g_online_cmdlist_idxs &= (~cmdlist_idxs_temp); + + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO + ("g_online_cmdlist_idxs=0x%x, cmdlist_idxs_need_start=0x%x\n", + g_online_cmdlist_idxs, cmdlist_idxs_temp); + } + + return cmdlist_idxs_temp; +} + +/* + ** data0: addr0[17:0] + ** data1: addr0[17:0] + addr1[5:0] + ** data2: addr0[17:0] + addr2[5:0] + ** + ** cnt[1:0]: + ** 2'b00: reg0 + ** 2'b01: reg0, reg1 + ** 2'b10: reg0, reg1, reg2 + ** 2'b11: ((inp32(addr0) & data1) | data2) -> addr0 + */ +void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd, char __iomem *addr, + uint32_t value, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1 << bw) - 1; + dss_cmdlist_node_t *node = NULL; + int cmdlist_idx = -1; + int index = 0; + uint32_t new_addr = 0; + uint32_t old_addr = 0; + int condition = 0; + + BUG_ON(addr == NULL); + BUG_ON(hisifd == NULL); + + cmdlist_idx = hisifd->cmdlist_idx; + BUG_ON((cmdlist_idx < 0) || (cmdlist_idx >= HISI_DSS_CMDLIST_MAX)); + + node = + list_entry(hisifd->cmdlist_data->cmdlist_head_temp[cmdlist_idx].prev, + dss_cmdlist_node_t, list_node); + BUG_ON(node == NULL); + + if (node->node_type == CMDLIST_NODE_NOP) { + HISI_FB_ERR("can't set register value to NOP node!"); + return; + } + + index = node->item_index; + new_addr = (uint32_t) (addr - hisifd->dss_base + hisifd->dss_base_phy); + new_addr = (new_addr >> 2) & CMDLIST_ADDR_OFFSET; + old_addr = node->list_item[index].reg_addr.ul32 & CMDLIST_ADDR_OFFSET; + condition = (((new_addr - old_addr) < MAX_ITEM_OFFSET) + && (new_addr >= old_addr)); + + if (bw != 32) { + if (node->item_flag != 0) + index++; + + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].data1 = ~(mask << bs); + node->list_item[index].data2 = (mask & value) << bs; + node->list_item[index].reg_addr.bits.cnt = 3; + node->item_flag = 3; + } else { + if (node->item_flag == 0) { + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].reg_addr.bits.cnt = 0; + node->item_flag = 1; + } else if (node->item_flag == 1 && condition) { + node->list_item[index].reg_addr.bits.add1 = + new_addr - old_addr; + node->list_item[index].data1 = value; + node->list_item[index].reg_addr.bits.cnt = 1; + node->item_flag = 2; + } else if (node->item_flag == 2 && condition) { + node->list_item[index].reg_addr.bits.add2 = + new_addr - old_addr; + node->list_item[index].data2 = value; + node->list_item[index].reg_addr.bits.cnt = 2; + node->item_flag = 3; + } else { + index++; + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].reg_addr.bits.cnt = 0; + node->item_flag = 1; + } + } + + BUG_ON(index >= MAX_ITEM_INDEX); + + node->item_index = index; + node->list_header->total_items.bits.count = node->item_index + 1; +} + +/* + ** flush cache for cmdlist, make sure that + ** cmdlist has writen through to memory before config register + */ +void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd, + struct ion_client *ion_client, + uint32_t cmdlist_idxs) +{ + uint32_t i = 0; + uint32_t cmdlist_idxs_temp = 0; + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + struct sg_table *table = NULL; + struct list_head *cmdlist_heads = NULL; + + BUG_ON(hisifd == NULL); + + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + cmdlist_heads = + &(hisifd->cmdlist_data->cmdlist_head_temp[i]); + if (!cmdlist_heads) { + HISI_FB_ERR("cmdlist_data is NULL!\n"); + continue; + } + + list_for_each_entry_safe_reverse(node, _node_, + cmdlist_heads, + list_node) { + + if (!node->header_ion_handle) { + HISI_FB_ERR + ("header_ion_handle is NULL!\n"); + } else { + table = ion_sg_table(ion_client, + node->header_ion_handle); + BUG_ON(table == NULL); + dma_sync_sg_for_device(NULL, table->sgl, + table->nents, + DMA_TO_DEVICE); + } + + if (!node->item_ion_handle) { + HISI_FB_ERR("item_ion_handle is NULL!\n"); + } else { + table = ion_sg_table(ion_client, + node->item_ion_handle); + BUG_ON(table == NULL); + dma_sync_sg_for_device(NULL, table->sgl, + table->nents, + DMA_TO_DEVICE); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } +} + +dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client) +{ + int ret = 0; + dss_cmdlist_node_t *node = NULL; + size_t header_len = CMDLIST_HEADER_LEN; + size_t item_len = CMDLIST_ITEM_LEN; + + BUG_ON(ion_client == NULL); + + node = + (dss_cmdlist_node_t *) kzalloc(sizeof(dss_cmdlist_node_t), + GFP_KERNEL); + if (IS_ERR(node)) { + HISI_FB_ERR("failed to alloc dss_cmdlist_node_t!"); + goto err_alloc_cmdlist_node; + } + + memset(node, 0, sizeof(dss_cmdlist_node_t)); + + /*alloc buffer for header */ + node->header_ion_handle = + ion_alloc(ion_client, header_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0); + if (IS_ERR(node->header_ion_handle)) { + HISI_FB_ERR("failed to ion_alloc node->header_ion_handle!"); + goto err_header_ion_handle; + } + + node->list_header = + (cmd_header_t *) ion_map_kernel(ion_client, + node->header_ion_handle); + if (!node->list_header) { + HISI_FB_ERR("failed to ion_map_kernel node->list_header!"); + goto err_header_ion_map; + } + memset(node->list_header, 0, header_len); + + ret = + ion_phys(ion_client, node->header_ion_handle, &node->header_phys, + &header_len); + if (ret < 0) { + HISI_FB_ERR("failed to ion_phys node->header_phys!"); + goto err_header_ion_phys; + } + + /*alloc buffer for items */ + node->item_ion_handle = + ion_alloc(ion_client, item_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0); + if (!node->item_ion_handle) { + HISI_FB_ERR("failed to ion_alloc node->item_ion_handle!"); + goto err_item_ion_handle; + } + + node->list_item = + (cmd_item_t *) ion_map_kernel(ion_client, node->item_ion_handle); + if (!node->list_item) { + HISI_FB_ERR("failed to ion_map_kernel node->list_item!"); + goto err_item_ion_map; + } + + memset(node->list_item, 0, item_len); + ret = + ion_phys(ion_client, node->item_ion_handle, &node->item_phys, + &item_len); + if (ret < 0) { + HISI_FB_ERR("failed to ion_phys node->item_phys!"); + goto err_item_ion_phys; + } + + /* fill node info */ + node->item_flag = 0; + node->item_index = 0; + + node->is_used = 0; + node->node_type = CMDLIST_NODE_NONE; + return node; + + err_item_ion_phys: + if (node->item_ion_handle) + ion_unmap_kernel(ion_client, node->item_ion_handle); + err_item_ion_map: + if (node->item_ion_handle) + ion_free(ion_client, node->item_ion_handle); + err_item_ion_handle: + err_header_ion_phys: + if (node->header_ion_handle) + ion_unmap_kernel(ion_client, node->header_ion_handle); + err_header_ion_map: + if (node->header_ion_handle) + ion_free(ion_client, node->header_ion_handle); + err_header_ion_handle: + if (node) + kfree(node); + err_alloc_cmdlist_node: + return NULL; +} + +void hisi_cmdlist_node_free(struct ion_client *ion_client, + dss_cmdlist_node_t *node) +{ + BUG_ON(ion_client == NULL); + BUG_ON(node == NULL); + + if (node->header_ion_handle) { + ion_unmap_kernel(ion_client, node->header_ion_handle); + ion_free(ion_client, node->header_ion_handle); + } + + if (node->item_ion_handle) { + ion_unmap_kernel(ion_client, node->item_ion_handle); + ion_free(ion_client, node->item_ion_handle); + } + + kfree(node); + node = NULL; +} + +static dss_cmdlist_node_t *hisi_cmdlist_get_free_node(dss_cmdlist_node_t * + node[], int *id) +{ + int i = 0; + + for (i = 0; i < HISI_DSS_CMDLIST_NODE_MAX; i++) { + if (node[i] && (node[i]->is_used == 0)) { + node[i]->is_used = 1; + *id = i + 1; + return node[i]; + } + } + + return NULL; +} + +int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int reserved) +{ + dss_cmdlist_node_t *node = NULL; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int id = 0; + + BUG_ON(hisifd == NULL); + + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + node = + hisi_cmdlist_get_free_node(hisifd->cmdlist_data-> + cmdlist_nodes_temp[i], + &id); + if (!node) { + HISI_FB_ERR + ("failed to hisi_get_free_cmdlist_node!\n"); + return -EINVAL; + } + + node->list_header->flag.bits.id = id; + node->list_header->flag.bits.nop = 0x1; + node->list_header->flag.bits.pending = + pending ? 0x1 : 0x0; + node->list_header->flag.bits.valid_flag = + CMDLIST_NODE_VALID; + node->list_header->next_list = node->header_phys; + + node->is_used = 1; + node->node_type = CMDLIST_NODE_NOP; + node->reserved = reserved ? 0x1 : 0x0; + + /*add this nop to list */ + list_add_tail(&(node->list_node), + &(hisifd->cmdlist_data->cmdlist_head_temp[i])); + + if (node->list_node.prev != + &(hisifd->cmdlist_data->cmdlist_head_temp[i])) { + dss_cmdlist_node_t *pre_node = NULL; + pre_node = + list_entry(node->list_node.prev, + dss_cmdlist_node_t, list_node); + pre_node->list_header->next_list = + node->header_phys; + if (node->list_header->flag.bits.pending == 0x1) { + pre_node->reserved = 0x0; + } + + pre_node->list_header->flag.bits.task_end = 0x1; + + if (g_debug_ovl_cmdlist) { + HISI_FB_DEBUG + ("i = %d, next_list = 0x%x\n", i, + (uint32_t) (node->header_phys)); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int task_end, + int remove, int last, uint32_t wb_type) +{ + char __iomem *cmdlist_base = NULL; + dss_cmdlist_node_t *node = NULL; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int id = 0; + + BUG_ON(hisifd == NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + node = + hisi_cmdlist_get_free_node(hisifd->cmdlist_data-> + cmdlist_nodes_temp[i], + &id); + if (!node) { + HISI_FB_ERR + ("failed to hisi_get_free_cmdnode!\n"); + return -EINVAL; + } + + /*fill the header and item info */ + node->list_header->flag.bits.id = id; + node->list_header->flag.bits.pending = + pending ? 0x1 : 0x0; + + if (i < DSS_CMDLIST_W0) { + node->list_header->flag.bits.event_list = + remove ? 0x8 : (0xE + i); + } else if (i < DSS_CMDLIST_OV0) { + node->list_header->flag.bits.event_list = + remove ? 0x8 : (0x16 + i); + } else if (i == DSS_CMDLIST_V2) { + node->list_header->flag.bits.event_list = + remove ? 0x8 : 0x16; + } else if (i == DSS_CMDLIST_W2) { + node->list_header->flag.bits.event_list = + remove ? 0x8 : 0x20; + } else { + node->list_header->flag.bits.event_list = + remove ? 0x8 : (0xE + i); + } + + node->list_header->flag.bits.task_end = + task_end ? 0x1 : 0x0; + node->list_header->flag.bits.last = last ? 0x1 : 0x0; + + node->list_header->flag.bits.valid_flag = + CMDLIST_NODE_VALID; + node->list_header->flag.bits.exec = 0x1; + node->list_header->list_addr = node->item_phys; + node->list_header->next_list = node->item_phys; + + node->is_used = 1; + node->node_type = CMDLIST_NODE_FRAME; + node->item_flag = 0; + node->reserved = 0; + + /* add this nop to list */ + list_add_tail(&(node->list_node), + &(hisifd->cmdlist_data->cmdlist_head_temp[i])); + + if (node->list_node.prev != + &(hisifd->cmdlist_data->cmdlist_head_temp[i])) { + dss_cmdlist_node_t *pre_node = NULL; + pre_node = + list_entry(node->list_node.prev, + dss_cmdlist_node_t, list_node); + pre_node->list_header->next_list = + node->header_phys; + pre_node->reserved = 0x0; + if (g_debug_ovl_cmdlist) { + HISI_FB_DEBUG + ("i = %d, next_list = 0x%x\n", i, + (uint32_t) node->header_phys); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + + BUG_ON(cmdlist_heads == NULL); + + list_for_each_entry_safe(node, _node_, cmdlist_heads, list_node) { + if (node->reserved != 0x1) { + list_del(&node->list_node); + + memset(node->list_header, 0, CMDLIST_HEADER_LEN); + memset(node->list_item, 0, CMDLIST_ITEM_LEN); + + node->item_index = 0; + node->item_flag = 0; + node->node_type = CMDLIST_NODE_NONE; + node->is_used = 0; + } + } + + return 0; +} + +int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs) +{ + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int delay_count = 0; + bool is_timeout = true; + int ret = 0; + + BUG_ON(hisifd == NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + while (1) { + tmp = + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + if (((tmp & 0xF) == 0x0) || delay_count > 5000) { + is_timeout = + (delay_count > 5000) ? true : false; + delay_count = 0; + break; + } else { + udelay(1); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("cmdlist_ch%d not in idle state,ints=0x%x !\n", + i, tmp); + ret = -1; + } + } + + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + + return ret; +} + +/* + ** stop the pending state for one new frame + ** if the current cmdlist status is e_status_wait. + */ +int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs) +{ + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int delay_count = 0; + bool is_timeout = true; + + BUG_ON(hisifd == NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + while (1) { + tmp = + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + if (((tmp & 0xF) == 0x0) || delay_count > 500) { + is_timeout = + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(1); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("cmdlist_ch%d not in idle state,ints=0x%x !\n", + i, tmp); + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + } + } + + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + return 0; +} + +/* + **start cmdlist. + **it will set cmdlist into pending state. + */ +extern uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX]; +int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs, uint32_t wb_compose_type) +{ + char __iomem *mctl_base = NULL; + char __iomem *cmdlist_base = NULL; + dss_cmdlist_node_t *cmdlist_node = NULL; + uint32_t offset = 0; + uint32_t list_addr = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int temp = 0; + int status_temp = 0; + int ints_temp = 0; + + BUG_ON(hisifd == NULL); + + mctl_base = + hisifd->dss_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + status_temp = + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + ints_temp = + inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset); + + if (mctl_idx >= DSS_MCTL2) { + cmdlist_node = + list_first_entry(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i]), + dss_cmdlist_node_t, + list_node); + } else { + cmdlist_node = + list_first_entry(&(hisifd->cmdlist_data-> + cmdlist_head_temp[i]), + dss_cmdlist_node_t, + list_node); + } + + list_addr = cmdlist_node->header_phys; + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO + ("list_addr:0x%x, i=%d, ints_temp=0x%x\n", + list_addr, i, ints_temp); + } + + temp |= (1 << i); + outp32(cmdlist_base + CMDLIST_ADDR_MASK_EN, BIT(i)); + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%lx\n", + cmdlist_base + + CMDLIST_ADDR_MASK_EN, BIT(i)); + } + + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, + mctl_idx, 3, 2); + if (mctl_idx <= DSS_MCTL1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 6); + } else { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x0, 1, 6); + } + + set_reg(cmdlist_base + CMDLIST_CH0_STAAD + i*offset, + list_addr, 32, 0); + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 0); + if ((mctl_idx <= DSS_MCTL1) + && ((ints_temp & 0x2) == 0x2)) { + set_reg(cmdlist_base + CMDLIST_SWRST, 0x1, 1, i); + } + + if (mctl_idx >= DSS_MCTL2) { + if (((status_temp & 0xF) == 0x0) + || ((ints_temp & 0x2) == 0x2)) { + set_reg(cmdlist_base + CMDLIST_SWRST, + 0x1, 1, i); + } else { + HISI_FB_INFO + ("i=%d, status_temp=0x%x, ints_temp=0x%x\n", + i, status_temp, ints_temp); + } + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + outp32(cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp); + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%x\n", + cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp); + } + + if (mctl_idx >= DSS_MCTL2) { + set_reg(mctl_base + MCTL_CTL_ST_SEL, 0x1, 1, 0); + set_reg(mctl_base + MCTL_CTL_SW_ST, 0x1, 1, 0); + } + + return 0; +} + +void hisi_cmdlist_config_mif_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_idxs, int mctl_idx) +{ + char __iomem *dss_base = NULL; + char __iomem *tmp_base = NULL; + + uint32_t cmdlist_idxs_temp = 0; + int delay_count = 0; + bool is_timeout = true; + int i = 0; + int j = 0; + int mif_sub_ch_nums = 4; + int tmp = 0; + int mif_nums_max = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + dss_base = hisifd->dss_base; + + if (mctl_idx <= DSS_MCTL1) { + mif_nums_max = DSS_WCHN_W0; + } else { + mif_nums_max = DSS_CHN_MAX; + } + + if (mctl_idx == DSS_MCTL5) { + for (i = DSS_RCHN_V2; i < DSS_CHN_MAX_DEFINE; i++) { + is_timeout = false; + + while (1) { + for (j = 1; j <= mif_sub_ch_nums; j++) { + tmp |= + inp32(dss_base + DSS_MIF_OFFSET + + MIF_STAT1 + + 0x10 * (i * mif_sub_ch_nums +j)); + } + + if (((tmp & 0x1f) == 0x0) || delay_count > 500) { + is_timeout = + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(10); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR("mif_ch%d MIF_STAT1=0x%x !\n", i, + tmp); + } + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0); + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0); + } + } else { + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + is_timeout = false; + + while (1) { + for (j = 1; j <= mif_sub_ch_nums; j++) { + tmp |= + inp32(dss_base + DSS_MIF_OFFSET + MIF_STAT1 + + 0x10 * (i * mif_sub_ch_nums + j)); + } + if (((tmp & 0x1f) == 0x0) + || delay_count > 500) { + is_timeout = + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(10); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("mif_ch%d MIF_STAT1=0x%x !\n", i, tmp); + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + tmp_base = hisifd->dss_module.mif_ch_base[i]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, + 0); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } + mdelay(5); + + if (mctl_idx == DSS_MCTL5) { + tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0); + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0); + } + } else { + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + tmp_base = hisifd->dss_module.mif_ch_base[i]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, + 0); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } +} + +void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + char __iomem *dss_base = NULL; + char __iomem *cmdlist_base = NULL; + char __iomem *tmp_base = NULL; + struct hisi_panel_info *pinfo = NULL; + + uint32_t offset = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int ovl_idx = 0; + int mctl_idx = 0; + int ints_temp = 0; + int start_sel = 0; + uint32_t start_sel_temp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + dss_base = hisifd->dss_base; + cmdlist_base = dss_base + DSS_CMDLIST_OFFSET; + ovl_idx = pov_req->ovl_idx; + pinfo = &(hisifd->panel_info); + + if (cmdlist_idxs == 0) return; + + mctl_idx = ovl_idx; + if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) { + mctl_idx = DSS_MCTL5; + } + + offset = 0x40; + cmdlist_idxs_temp = HISI_DSS_CMDLIST_IDXS_MAX; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + ints_temp = + inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset); + start_sel = + inp32(cmdlist_base + CMDLIST_CH0_CTRL + i * offset); + + if (((ints_temp & 0x2) == 0x2) + && ((start_sel & 0x1c) == 0)) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2); + start_sel_temp |= (1 << i); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + tmp_base = hisifd->dss_module.mctl_base[mctl_idx]; + if (tmp_base) { + set_reg(tmp_base + MCTL_CTL_CLEAR, 0x1, 1, 0); + } + + hisi_cmdlist_config_mif_reset(hisifd, pov_req, cmdlist_idxs, mctl_idx); + cmdlist_idxs_temp = start_sel_temp; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, mctl_idx, 3, 2); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + if (mctl_idx >= DSS_MCTL2) { + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + + i * offset, 0x6, 3, 2); + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + + i * offset, 0x0, 1, 0); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + return; +} + +int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_pre_idxs) +{ + dss_overlay_t *pov_req = NULL; + char __iomem *cmdlist_base = NULL; + int i = 0; + uint32_t tmp = 0; + uint32_t offset = 0; + int ret = 0; + + BUG_ON(hisifd == NULL); + pov_req = &(hisifd->ov_req); + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + + ret = + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, 0, 1, 1, 1, 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + + for (i = 0; i < DSS_WCHN_W0; i++) { + tmp = (0x1 << i); + hisifd->cmdlist_idx = i; + + if ((cmdlist_pre_idxs & tmp) == tmp) { + hisifd->set_reg(hisifd, + hisifd->dss_module.mctl_base[pov_req-> + ovl_idx] + + MCTL_CTL_MUTEX_RCH0 + i * 0x4, 0, 32, + 0); + hisifd->set_reg(hisifd, cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2); + } + } + + return 0; + + err_return: + return ret; +} + +void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *cmdlist_base = NULL; + + BUG_ON(hisifd == NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + set_reg(cmdlist_base + CMDLIST_CTRL, 0x3, 2, 4); +} + +void hisi_dump_cmdlist_node_items(cmd_item_t *item, uint32_t count) +{ + uint32_t index = 0; + uint32_t addr = 0; + + for (index = 0; index < count; index++) { + addr = item[index].reg_addr.bits.add0; + addr = addr & CMDLIST_ADDR_OFFSET; + addr = addr << 2; + HISI_FB_INFO + ("set addr:0x%x value:0x%x add1:0x%x value:0x%x " + "add2:0x%x value:0x%x \n", + addr, item[index].data0, + item[index].reg_addr.bits.add1 << 2, item[index].data1, + item[index].reg_addr.bits.add2 << 2, item[index].data2); + } +} + +static void hisi_dump_cmdlist_content(struct list_head *cmdlist_head, + char *filename, uint32_t addr) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + + BUG_ON(cmdlist_head == NULL); + BUG_ON(filename == NULL); + + if (g_dump_cmdlist_content == 0) + return; + + HISI_FB_INFO("%s\n", filename); + + list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) { + if (node->header_phys == addr) { + hisifb_save_file(filename, (char *)(node->list_header), + CMDLIST_HEADER_LEN); + } + + if (node->item_phys == addr) { + hisifb_save_file(filename, (char *)(node->list_item), + CMDLIST_ITEM_LEN); + } + } +} + +static void hisi_dump_cmdlist_one_node(struct list_head *cmdlist_head, + uint32_t cmdlist_idx) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + uint32_t count = 0; + int i = 0; + char filename[256] = { 0 }; + + BUG_ON(cmdlist_head == NULL); + + list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) { + if (node->node_type == CMDLIST_NODE_NOP) { + HISI_FB_INFO("node type = NOP node\n"); + } else if (node->node_type == CMDLIST_NODE_FRAME) { + HISI_FB_INFO("node type = Frame node\n"); + } + + HISI_FB_INFO + ("\t qos | flag | pending | tast_end | last | event_list | list_addr | next_list | count | id | is_used | reserved | cmdlist_idx\n"); + HISI_FB_INFO + ("\t ------+---------+------------+------------+------------+------------\n"); + HISI_FB_INFO + ("\t 0x%2x | 0x%2x |0x%6x | 0x%5x | 0x%3x | 0x%8x | 0x%8x | 0x%8x | 0x%3x | 0x%2x | 0x%2x | 0x%2x | 0x%2x\n", + node->list_header->flag.bits.qos, + node->list_header->flag.bits.valid_flag, + node->list_header->flag.bits.pending, + node->list_header->flag.bits.task_end, + node->list_header->flag.bits.last, + node->list_header->flag.bits.event_list, + node->list_header->list_addr, node->list_header->next_list, + node->list_header->total_items.bits.count, + node->list_header->flag.bits.id, node->is_used, + node->reserved, cmdlist_idx); + + if (i == 0) { + snprintf(filename, 256, + "/data/dssdump/list_start_0x%x.txt", + (uint32_t) node->header_phys); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->header_phys); + } +#if 0 + if ((node->list_header->next_list != 0x0) && + (node->list_header->next_list != 0xFFFFFFFF)) { + snprintf(filename, 256, + "/data/dssdump/next_list_0x%x.txt", + node->list_header->next_list); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->list_header->next_list); + } + + if ((node->list_header->list_addr != 0x0) && + (node->list_header->list_addr != 0xFFFFFFFF)) { + snprintf(filename, 256, + "/data/dssdump/list_addr_0x%x.txt", + node->list_header->list_addr); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->list_header->list_addr); + } +#endif + count = node->list_header->total_items.bits.count; + hisi_dump_cmdlist_node_items(node->list_item, count); + + i++; + } +} + +int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + int i = 0; + uint32_t cmdlist_idxs_temp = 0; + uint32_t wb_compose_type = 0; + + BUG_ON(hisifd == NULL); + + if (pov_req) { + if (pov_req->wb_enable) + wb_compose_type = pov_req->wb_compose_type; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if (0x1 == (cmdlist_idxs_temp & 0x1)) { + if (pov_req && pov_req->wb_enable) { + hisi_dump_cmdlist_one_node(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i]), i); + } else { + hisi_dump_cmdlist_one_node(& + (hisifd->cmdlist_data->cmdlist_head_temp[i]), i); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + int i = 0; + uint32_t cmdlist_idxs_temp = 0; + uint32_t wb_compose_type = 0; + + BUG_ON(hisifd == NULL); + + if (pov_req) { + if (pov_req->wb_enable) + wb_compose_type = pov_req->wb_compose_type; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + if (pov_req && pov_req->wb_enable) { + hisi_cmdlist_del_all_node(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i])); + } else { + hisi_cmdlist_del_all_node(& + (hisifd->cmdlist_data->cmdlist_head_temp[i])); + } + } + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + + return 0; +} + +static dss_cmdlist_data_t *hisi_cmdlist_data_alloc(struct hisi_fb_data_type + *hisifd) +{ + int i = 0; + int j = 0; + dss_cmdlist_data_t *cmdlist_data = NULL; + + BUG_ON(hisifd == NULL); + + cmdlist_data = + (dss_cmdlist_data_t *) kmalloc(sizeof(dss_cmdlist_data_t), + GFP_ATOMIC); + if (cmdlist_data) { + memset(cmdlist_data, 0, sizeof(dss_cmdlist_data_t)); + } else { + HISI_FB_ERR("failed to kmalloc cmdlist_data!\n"); + return NULL; + } + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + INIT_LIST_HEAD(&(cmdlist_data->cmdlist_head_temp[i])); + + for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) { + cmdlist_data->cmdlist_nodes_temp[i][j] = + hisi_cmdlist_node_alloc(hisifd->ion_client); + if (cmdlist_data->cmdlist_nodes_temp[i][j] == NULL) { + HISI_FB_ERR + ("failed to hisi_cmdlist_node_alloc!\n"); + kfree(cmdlist_data); + return NULL; + } + } + } + + return cmdlist_data; +} + +static void hisi_cmdlist_data_free(struct hisi_fb_data_type *hisifd, + dss_cmdlist_data_t *cmdlist_data) +{ + int i = 0; + int j = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(cmdlist_data == NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) { + hisi_cmdlist_node_free(hisifd->ion_client, + hisifd->cmdlist_data->cmdlist_nodes_temp[i][j]); + } + } +} + +static dss_cmdlist_info_t *hisi_cmdlist_info_alloc(struct hisi_fb_data_type + *hisifd) +{ + int i = 0; + dss_cmdlist_info_t *cmdlist_info = NULL; + + BUG_ON(hisifd == NULL); + + cmdlist_info = + (dss_cmdlist_info_t *) kmalloc(sizeof(dss_cmdlist_info_t), GFP_ATOMIC); + if (cmdlist_info) { + memset(cmdlist_info, 0, sizeof(dss_cmdlist_info_t)); + } else { + HISI_FB_ERR("failed to kmalloc cmdlist_info!\n"); + return NULL; + } + + sema_init(&(cmdlist_info->cmdlist_wb_common_sem), 1); + + for (i = 0; i < WB_TYPE_MAX; i++) { + sema_init(&(cmdlist_info->cmdlist_wb_sem[i]), 1); + init_waitqueue_head(&(cmdlist_info->cmdlist_wb_wq[i])); + cmdlist_info->cmdlist_wb_done[i] = 0; + cmdlist_info->cmdlist_wb_flag[i] = 0; + } + + return cmdlist_info; +} + +static dss_copybit_info_t *hisi_copybit_info_alloc(struct hisi_fb_data_type + *hisifd) +{ + dss_copybit_info_t *copybit_info = NULL; + + BUG_ON(hisifd == NULL); + + copybit_info = + (dss_copybit_info_t *) kmalloc(sizeof(dss_copybit_info_t), + GFP_ATOMIC); + if (copybit_info) { + memset(copybit_info, 0, sizeof(dss_copybit_info_t)); + } else { + HISI_FB_ERR("failed to kmalloc copybit_info!\n"); + return NULL; + } + + sema_init(&(copybit_info->copybit_sem), 1); + + init_waitqueue_head(&(copybit_info->copybit_wq)); + copybit_info->copybit_done = 0; + + return copybit_info; +} + +void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd) +{ + int tmp = 0; + + BUG_ON(hisifd == NULL); + + tmp = (hisifd->frame_count + 1) % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp]; + hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX); + + tmp = hisifd->frame_count % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp]; + hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX); +} + +int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + int i = 0; + + BUG_ON(hisifd == NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) { + hisifd->ov_block_rects[i] = + (dss_rect_t *) kmalloc(sizeof(dss_rect_t), GFP_ATOMIC); + if (!hisifd->ov_block_rects[i]) { + HISI_FB_ERR("ov_block_rects[%d] failed to alloc!", i); + return -EINVAL; + } + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifd->cmdlist_data_tmp[0] = hisi_cmdlist_data_alloc(hisifd); + hisifd->cmdlist_data_tmp[1] = hisi_cmdlist_data_alloc(hisifd); + hisifd->cmdlist_info = hisi_cmdlist_info_alloc(hisifd); + hisifd->copybit_info = hisi_copybit_info_alloc(hisifd); + } else { + if (hisifd->index == PRIMARY_PANEL_IDX + || (hisifd->index == EXTERNAL_PANEL_IDX + && !hisifd->panel_info.fake_hdmi)) { + for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) { + hisifd->cmdlist_data_tmp[i] = + hisi_cmdlist_data_alloc(hisifd); + } + } + } + + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[0]; + hisifd->cmdlist_idx = -1; + + return ret; +} + +int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd) +{ + int i = 0; + + BUG_ON(hisifd == NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) { + if (hisifd->ov_block_rects[i]) { + kfree(hisifd->ov_block_rects[i]); + hisifd->ov_block_rects[i] = NULL; + } + } + + for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) { + if (hisifd->cmdlist_data_tmp[i]) { + hisi_cmdlist_data_free(hisifd, + hisifd->cmdlist_data_tmp[i]); + kfree(hisifd->cmdlist_data_tmp[i]); + hisifd->cmdlist_data_tmp[i] = NULL; + } + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + if (hisifd->cmdlist_info) { + kfree(hisifd->cmdlist_info); + hisifd->cmdlist_info = NULL; + } + + if (hisifd->copybit_info) { + kfree(hisifd->copybit_info); + hisifd->copybit_info = NULL; + } + } + + return 0; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h new file mode 100755 index 000000000000..5f5d8c0fd506 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h @@ -0,0 +1,249 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef _CMD_LIST_UTILS_H_ +#define _CMD_LIST_UTILS_H_ +#include "hisi_overlay_utils_hi3660.h" + +#define HISI_DSS_CMDLIST_DATA_MAX (3) +#define HISI_DSS_CMDLIST_NODE_MAX (32) +#define HISI_DSS_CMDLIST_BLOCK_MAX (32) + +#define HISI_DSS_SUPPORT_DPP_MODULE_BIT(module) \ + (BIT(module) & HISI_DSS_DPP_MAX_SUPPORT_BIT) + +enum dpp_module_idx { + DPP_MODULE_POST_SCF = 0, + DPP_MODULE_DBUF, + DPP_MODULE_SBL, + DPP_MODULE_ACM, + DPP_MODULE_ACE, + DPP_MODULE_LCP_IGM, + DPP_MODULE_LCP_GMP, + DPP_MODULE_LCP_XCC, + DPP_MODULE_GAMA, + DPP_MODULE_DITHER, + DPP_MODULE_IFBC, + DPP_MODULE_MAX +}; + +enum wb_type { + WB_TYPE_WCH0, + WB_TYPE_WCH1, + WB_TYPE_WCH2, + WB_TYPE_WCH0_WCH1, + + WB_TYPE_MAX, +}; + +enum dss_cmdlist_idx { + DSS_CMDLIST_NONE = -1, + DSS_CMDLIST_D2 = 0, + DSS_CMDLIST_D3, + DSS_CMDLIST_V0, + DSS_CMDLIST_G0, + DSS_CMDLIST_V1, + DSS_CMDLIST_G1, + DSS_CMDLIST_D0, + DSS_CMDLIST_D1, + + DSS_CMDLIST_W0, + DSS_CMDLIST_W1, + + DSS_CMDLIST_OV0, + DSS_CMDLIST_OV1, + DSS_CMDLIST_OV2, + DSS_CMDLIST_OV3, + + DSS_CMDLIST_V2, + DSS_CMDLIST_W2, + DSS_CMDLIST_MAX, +}; + +typedef union { + struct { + uint32_t exec:1; + uint32_t last:1; + uint32_t nop:1; + uint32_t interrupt:1; + uint32_t pending:1; + uint32_t id:10; + uint32_t event_list:6; + uint32_t qos:1; + uint32_t task_end:1; + uint32_t reserved:1; + uint32_t valid_flag:8; + } bits; + uint32_t ul32; +} cmd_flag_t; + +typedef union { + struct { + uint32_t count:14; + uint32_t reserved:18; + } bits; + uint32_t ul32; +} total_items_t; + +typedef union { + struct { + uint32_t add0:18; + uint32_t add1:6; + uint32_t add2:6; + uint32_t cnt:2; + } bits; + uint32_t ul32; +} reg_addr_t; + +typedef struct cmd_item { + reg_addr_t reg_addr; + uint32_t data0; + uint32_t data1; + uint32_t data2; +} cmd_item_t; + +typedef struct cmd_header { + cmd_flag_t flag; + uint32_t next_list; + total_items_t total_items; + uint32_t list_addr; +} cmd_header_t; + +enum dss_cmdlist_node_valid { + CMDLIST_NODE_INVALID = 0x0, + CMDLIST_NODE_VALID = 0xA5, +}; + +enum dss_cmdlist_node_type { + CMDLIST_NODE_NONE = 0x0, + CMDLIST_NODE_NOP = 0x1, + CMDLIST_NODE_FRAME = 0x2, +}; + +enum dss_cmdlist_status { + e_status_idle = 0x0, + e_status_wait = 0x1, + e_status_other, +}; + +/* + ** for normal node,all variable should be filled. + ** for NOP node, just the list_header,header_ion_handle, list_node, node_flag should be filled. + ** node_type must be CMDLIST_NODE_NOP when it is NOP node. + ** And item_ion_handle in NOP node should be NULL. + */ +typedef struct dss_cmdlist_node { + struct list_head list_node; + + struct ion_handle *header_ion_handle; + ion_phys_addr_t header_phys; + cmd_header_t *list_header; + + struct ion_handle *item_ion_handle; + ion_phys_addr_t item_phys; + cmd_item_t *list_item; + + uint32_t item_index; + int item_flag; + uint32_t node_type; + int is_used; + int reserved; +} dss_cmdlist_node_t; + +typedef struct dss_cmdlist_heads { + struct list_head cmdlist_head; + + dss_cmdlist_node_t *cmdlist_nodes[HISI_DSS_CMDLIST_NODE_MAX]; +} dss_cmdlist_heads_t; + +typedef struct dss_cmdlist_data { + dss_cmdlist_heads_t *cmdlist_heads[HISI_DSS_CMDLIST_MAX]; + struct list_head cmdlist_head_temp[HISI_DSS_CMDLIST_MAX]; + dss_cmdlist_node_t + *cmdlist_nodes_temp[HISI_DSS_CMDLIST_MAX] + [HISI_DSS_CMDLIST_NODE_MAX]; +} dss_cmdlist_data_t; + +typedef struct dss_cmdlist_info { + struct semaphore cmdlist_wb_common_sem; + struct semaphore cmdlist_wb_sem[WB_TYPE_MAX]; + wait_queue_head_t cmdlist_wb_wq[WB_TYPE_MAX]; + uint32_t cmdlist_wb_done[WB_TYPE_MAX]; + uint32_t cmdlist_wb_flag[WB_TYPE_MAX]; +} dss_cmdlist_info_t; + +typedef struct dss_copybit_info { + struct semaphore copybit_sem; + wait_queue_head_t copybit_wq; + uint32_t copybit_flag; + uint32_t copybit_done; +} dss_copybit_info_t; + +typedef struct dss_wb_info { + uint32_t to_be_continued; + uint32_t cmdlist_idxs; + uint32_t wb_compose_type; + uint32_t mctl_idx; +} dss_wb_info_t; + +extern dss_cmdlist_data_t *g_cmdlist_data; + +/****************************************************************************** + ** FUNCTIONS PROTOTYPES + */ +void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *addr, uint32_t value, uint8_t bw, + uint8_t bs); +void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd, + struct ion_client *ion_client, + uint32_t cmdlist_idxs); + +dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client); +void hisi_cmdlist_node_free(struct ion_client *ion_client, + dss_cmdlist_node_t *node); + +uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); + +int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req, + uint32_t *cmdlist_pre_idxs, + uint32_t *cmdlist_idxs); +void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd); + +int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int reserved); +int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int task_end, + int remove, int last, uint32_t wb_type); +int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads); + +int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs, uint32_t wb_compose_type); +int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); +void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); + +int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); +int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); + +int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs); +void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd); +int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); + +int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd); +int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd); + +#endif -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 6/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_fb_utils.c | 249 ++++ drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c | 680 +++++++++ drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c | 401 ++++++ .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c | 1450 ++++++++++++++++++++ .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h | 249 ++++ 5 files changed, 3029 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c new file mode 100755 index 000000000000..3c7965716890 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" +#include "hisi_overlay_utils.h" +#if defined (CONFIG_HISI_PERIDVFS) +#include "peri_volt_poll.h" +#endif + +#define MAX_BUF 60 +void set_reg(char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1UL << bw) - 1UL; + uint32_t tmp = 0; + + tmp = inp32(addr); + tmp &= ~(mask << bs); + + outp32(addr, tmp | ((val & mask) << bs)); + + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%x\n", addr, + tmp | ((val & mask) << bs)); + } +} + +uint32_t set_bits32(uint32_t old_val, uint32_t val, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1UL << bw) - 1UL; + uint32_t tmp = 0; + + tmp = old_val; + tmp &= ~(mask << bs); + + return (tmp | ((val & mask) << bs)); +} + +void hisifb_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs) +{ + set_reg(addr, val, bw, bs); +} + +bool is_dss_idle_enable(void) +{ + return ((g_enable_dss_idle = 1) ? true : false); +} + +uint32_t get_panel_xres(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + return ((hisifd->resolution_rect.w > + 0) ? hisifd->resolution_rect.w : hisifd->panel_info.xres); +} + +uint32_t get_panel_yres(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + return ((hisifd->resolution_rect.h > + 0) ? hisifd->resolution_rect.h : hisifd->panel_info.yres); +} + +uint32_t hisifb_line_length(int index, uint32_t xres, int bpp) +{ + return ALIGN_UP(xres * bpp, DMA_STRIDE_ALIGN); +} + +void hisifb_get_timestamp(struct timeval *tv) +{ + struct timespec ts; + + ktime_get_ts(&ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; +} + +uint32_t hisifb_timestamp_diff(struct timeval *lasttime, + struct timeval *curtime) +{ + uint32_t ret; + ret = (curtime->tv_usec >= lasttime->tv_usec) ? + curtime->tv_usec - lasttime->tv_usec : + 1000000 - (lasttime->tv_usec - curtime->tv_usec); + + return ret; +} + +void hisifb_save_file(char *filename, char *buf, uint32_t buf_len) +{ + ssize_t write_len = 0; + struct file *fd = NULL; + mm_segment_t old_fs; + loff_t pos = 0; + + BUG_ON(filename = NULL); + BUG_ON(buf = NULL); + + fd = filp_open(filename, O_CREAT | O_RDWR, 0644); + if (IS_ERR(fd)) { + HISI_FB_ERR("filp_open returned:filename %s, error %ld\n", + filename, PTR_ERR(fd)); + return; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + write_len = vfs_write(fd, (char __user *)buf, buf_len, &pos); + + pos = 0; + set_fs(old_fs); + filp_close(fd, NULL); +} + +int hisifb_ctrl_on(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + int ret = 0; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + if (pdata->on) { + ret = pdata->on(hisifd->pdev); + } + + hisifb_vsync_resume(hisifd); + hisi_overlay_on(hisifd, false); + + if (hisifd->panel_info.esd_enable) { + hrtimer_start(&hisifd->esd_ctrl.esd_hrtimer, + ktime_set(ESD_CHECK_TIME_PERIOD / 1000, + (ESD_CHECK_TIME_PERIOD % 1000) * + 1000000), HRTIMER_MODE_REL); + } + + return ret; +} + +int hisifb_ctrl_off(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + int ret = 0; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + if (hisifd->panel_info.esd_enable) { + hrtimer_cancel(&hisifd->esd_ctrl.esd_hrtimer); + } + + hisifb_vsync_suspend(hisifd); + hisi_overlay_off(hisifd); + + if (pdata->off) { + ret = pdata->off(hisifd->pdev); + } + + if ((hisifd->index = PRIMARY_PANEL_IDX) || + (hisifd->index = EXTERNAL_PANEL_IDX)) { + + hisifb_layerbuf_unlock(hisifd, + &(hisifd->buf_sync_ctrl.layerbuf_list)); + } + + return ret; +} + +int hisifb_ctrl_dss_clk_rate_set(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + dss_clk_rate_t dss_clk_rate; + + if (NULL = info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL = hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + return -EINVAL; + } + + if (NULL = argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->core_clk_upt_support = 0) { + HISI_FB_DEBUG("no support core_clk_upt\n"); + return ret; + } + + ret = copy_from_user(&dss_clk_rate, argp, sizeof(dss_clk_rate_t)); + if (ret) { + HISI_FB_ERR("copy_from_user failed!ret=%d.", ret); + return ret; + } + + down(&hisifd->blank_sem); + + if (!hisifd->panel_power_on) { + HISI_FB_DEBUG("fb%d, panel power off!\n", hisifd->index); + ret = -EPERM; + goto err_out; + } + + ret = set_dss_clk_rate(hisifd, dss_clk_rate); + + err_out: + up(&hisifd->blank_sem); + + return ret; +} + +/*lint +e665, +e514, +e84, +e886, +e846, +e778*/ +void hisifb_sysfs_attrs_add(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + if (hisifd->sysfs_attrs_append_fnc) { + /* hisifd->sysfs_attrs_append_fnc(hisifd, &dev_attr_lcd_model.attr); */ + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c new file mode 100755 index 000000000000..3778ac0b4b2c --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c @@ -0,0 +1,680 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#include "hisi_fb.h" + +/* + ** /sys/class/graphics/fb0/vsync_event + */ +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) +#define VSYNC_TIMEOUT_MSEC (100) +#endif +#define VSYNC_CTRL_EXPIRE_COUNT (4) + +#ifdef CONFIG_REPORT_VSYNC +extern void mali_kbase_pm_report_vsync(int); +#endif +extern int mipi_dsi_ulps_cfg(struct hisi_fb_data_type *hisifd, int enable); +extern bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd); + +void hisifb_frame_updated(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd = NULL); + + if (hisifd->vsync_ctrl.vsync_report_fnc) { + atomic_inc(&(hisifd->vsync_ctrl.buffer_updated)); + } +} + +void hisifb_vsync_isr_handler(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + struct hisi_fb_panel_data *pdata = NULL; + int buffer_updated = 0; + ktime_t pre_vsync_timestamp; + + BUG_ON(hisifd = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + pre_vsync_timestamp = vsync_ctrl->vsync_timestamp; + vsync_ctrl->vsync_timestamp = ktime_get(); + wake_up_interruptible_all(&(vsync_ctrl->vsync_wait)); + + if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) { + spin_lock(&vsync_ctrl->spin_lock); + if (vsync_ctrl->vsync_ctrl_expire_count) { + vsync_ctrl->vsync_ctrl_expire_count--; + if (vsync_ctrl->vsync_ctrl_expire_count = 0) + schedule_work(&vsync_ctrl->vsync_ctrl_work); + } + spin_unlock(&vsync_ctrl->spin_lock); + } + + if (vsync_ctrl->vsync_report_fnc) { + if (hisifd->vsync_ctrl.vsync_enabled) { + buffer_updated + atomic_dec_return(&(vsync_ctrl->buffer_updated)); + } else { + buffer_updated = 1; + } + + if (buffer_updated < 0) { + atomic_cmpxchg(&(vsync_ctrl->buffer_updated), + buffer_updated, 1); + } else { + vsync_ctrl->vsync_report_fnc(buffer_updated); + } + } + + if (g_debug_online_vsync) { + HISI_FB_INFO("fb%d, VSYNC=%llu, time_diff=%llu.\n", + hisifd->index, + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp), + (ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp) - + ktime_to_ns(pre_vsync_timestamp))); + } +} + +static int vsync_timestamp_changed(struct hisi_fb_data_type *hisifd, + ktime_t prev_timestamp) +{ + BUG_ON(hisifd = NULL); + return !ktime_equal(prev_timestamp, hisifd->vsync_ctrl.vsync_timestamp); +} + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) +static int wait_for_vsync_thread(void *data) +{ + struct hisi_fb_data_type *hisifd = (struct hisi_fb_data_type *)data; + ktime_t prev_timestamp; + int ret = 0; + + while (!kthread_should_stop()) { + prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp; + ret + wait_event_interruptible_timeout(hisifd->vsync_ctrl. + vsync_wait, + vsync_timestamp_changed + (hisifd, prev_timestamp) + && hisifd->vsync_ctrl. + vsync_enabled, + msecs_to_jiffies + (VSYNC_TIMEOUT_MSEC)); + + /*if (ret = 0) { + HISI_FB_ERR("wait vsync timeout!"); + return -ETIMEDOUT; + } + */ + + if (ret > 0) { + char *envp[2]; + char buf[64]; + /* fb%d_VSYNC=%llu */ + snprintf(buf, sizeof(buf), "VSYNC=%llu", + ktime_to_ns(hisifd->vsync_ctrl. + vsync_timestamp)); + envp[0] = buf; + envp[1] = NULL; + kobject_uevent_env(&hisifd->pdev->dev.kobj, KOBJ_CHANGE, + envp); + } + } + + return 0; +} +#else +static ssize_t vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = -1; + int vsync_flag = 0; + struct fb_info *fbi = NULL; + struct hisi_fb_data_type *hisifd = NULL; + ktime_t prev_timestamp; + + if (NULL = dev) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + fbi = dev_get_drvdata(dev); + if (NULL = fbi) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + hisifd = (struct hisi_fb_data_type *)fbi->par; + if (NULL = hisifd) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + if (NULL = buf) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp; + + /*lint -e666 */ + ret = wait_event_interruptible(hisifd->vsync_ctrl.vsync_wait, + (vsync_timestamp_changed + (hisifd, prev_timestamp) + && hisifd->vsync_ctrl.vsync_enabled)); + /*lint +e666 */ + vsync_flag = (vsync_timestamp_changed(hisifd, prev_timestamp) && + hisifd->vsync_ctrl.vsync_enabled); + + if (vsync_flag) { + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu, xxxxxxEvent=x \n", + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp)); + buf[strlen(buf) + 1] = '\0'; + + } else { + return -1; + } + + return ret; +} + +static ssize_t vsync_timestamp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = -1; + struct fb_info *fbi = NULL; + struct hisi_fb_data_type *hisifd = NULL; + + if (NULL = dev) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + fbi = dev_get_drvdata(dev); + if (NULL = fbi) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + hisifd = (struct hisi_fb_data_type *)fbi->par; + if (NULL = hisifd) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + if (NULL = buf) { + HISI_FB_ERR("NULL Pointer.\n"); + return -1; + } + + ret = snprintf(buf, PAGE_SIZE, "%llu \n", + ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp)); + buf[strlen(buf) + 1] = '\0'; + + return ret; +} + +static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); +static DEVICE_ATTR(vsync_timestamp, S_IRUGO, vsync_timestamp_show, NULL); +#endif + +#ifdef CONFIG_FAKE_VSYNC_USED +enum hrtimer_restart hisifb_fake_vsync(struct hrtimer *timer) +{ + struct hisi_fb_data_type *hisifd = NULL; + int fps = 60; + + hisifd + container_of(timer, struct hisi_fb_data_type, fake_vsync_hrtimer); + BUG_ON(hisifd = NULL); + + if (!hisifd->panel_power_on) + goto error; + + if (hisifd->fake_vsync_used && hisifd->vsync_ctrl.vsync_enabled) { + hisifd->vsync_ctrl.vsync_timestamp = ktime_get(); + wake_up_interruptible_all(&hisifd->vsync_ctrl.vsync_wait); + } + + error: + hrtimer_start(&hisifd->fake_vsync_hrtimer, + ktime_set(0, NSEC_PER_SEC / fps), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +#endif + +static void hisifb_vsync_ctrl_workqueue_handler(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + struct hisi_fb_panel_data *pdata = NULL; + unsigned long flags = 0; + + vsync_ctrl = container_of(work, typeof(*vsync_ctrl), vsync_ctrl_work); + BUG_ON(vsync_ctrl = NULL); + hisifd = vsync_ctrl->hisifd; + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + + down(&(hisifd->blank_sem)); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&(hisifd->blank_sem)); + return; + } + + mutex_lock(&(vsync_ctrl->vsync_lock)); + if (vsync_ctrl->vsync_ctrl_disabled_set && + (vsync_ctrl->vsync_ctrl_expire_count = 0) && + vsync_ctrl->vsync_ctrl_enabled && + !vsync_ctrl->vsync_enabled + && !vsync_ctrl->vsync_ctrl_offline_enabled) { + HISI_FB_DEBUG("fb%d, dss clk off!\n", hisifd->index); + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + if (pdata->vsync_ctrl) { + pdata->vsync_ctrl(hisifd->pdev, 0); + } else { + HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", + hisifd->index); + } + vsync_ctrl->vsync_ctrl_enabled = 0; + vsync_ctrl->vsync_ctrl_disabled_set = 0; + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 0); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + if (hisifd->lp_fnc) + hisifd->lp_fnc(hisifd, true); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + dpe_inner_clk_disable(hisifd); + dpe_common_clk_disable(hisifd); + mipi_dsi_clk_disable(hisifd); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + /* dpe_regulator_disable(hisifd); */ + } + } + mutex_unlock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_report_fnc) { + vsync_ctrl->vsync_report_fnc(1); + } + + up(&(hisifd->blank_sem)); +} + +void hisifb_vsync_register(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + char name[64] = { 0 }; +#endif + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + if (vsync_ctrl->vsync_created) + return; + + vsync_ctrl->hisifd = hisifd; + vsync_ctrl->vsync_infinite = 0; + vsync_ctrl->vsync_enabled = 0; + vsync_ctrl->vsync_ctrl_offline_enabled = 0; + vsync_ctrl->vsync_timestamp = ktime_get(); + init_waitqueue_head(&(vsync_ctrl->vsync_wait)); + spin_lock_init(&(vsync_ctrl->spin_lock)); + INIT_WORK(&vsync_ctrl->vsync_ctrl_work, + hisifb_vsync_ctrl_workqueue_handler); + + mutex_init(&(vsync_ctrl->vsync_lock)); + + atomic_set(&(vsync_ctrl->buffer_updated), 1); +#ifdef CONFIG_REPORT_VSYNC + vsync_ctrl->vsync_report_fnc = mali_kbase_pm_report_vsync; +#else + vsync_ctrl->vsync_report_fnc = NULL; +#endif + +#ifdef CONFIG_FAKE_VSYNC_USED + /* hrtimer for fake vsync timing */ + hisifd->fake_vsync_used = false; + hrtimer_init(&hisifd->fake_vsync_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hisifd->fake_vsync_hrtimer.function = hisifb_fake_vsync; + hrtimer_start(&hisifd->fake_vsync_hrtimer, + ktime_set(0, NSEC_PER_SEC / 60), HRTIMER_MODE_REL); +#endif + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + snprintf(name, sizeof(name), "hisifb%d_vsync", hisifd->index); + vsync_ctrl->vsync_thread + kthread_run(wait_for_vsync_thread, hisifd, name); + if (IS_ERR(vsync_ctrl->vsync_thread)) { + vsync_ctrl->vsync_thread = NULL; + HISI_FB_ERR("failed to run vsync thread!\n"); + return; + } +#else + if (hisifd->sysfs_attrs_append_fnc) { + hisifd->sysfs_attrs_append_fnc(hisifd, + &dev_attr_vsync_event.attr); + hisifd->sysfs_attrs_append_fnc(hisifd, + &dev_attr_vsync_timestamp.attr); + } +#endif + + vsync_ctrl->vsync_created = 1; +} + +void hisifb_vsync_unregister(struct platform_device *pdev) +{ + struct hisi_fb_data_type *hisifd = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(pdev = NULL); + hisifd = platform_get_drvdata(pdev); + BUG_ON(hisifd = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + if (!vsync_ctrl->vsync_created) + return; + +#ifdef CONFIG_FAKE_VSYNC_USED + hisifd->fake_vsync_used = false; + hrtimer_cancel(&hisifd->fake_vsync_hrtimer); +#endif + +#if defined(CONFIG_HISI_FB_VSYNC_THREAD) + if (vsync_ctrl->vsync_thread) + kthread_stop(vsync_ctrl->vsync_thread); +#endif + + vsync_ctrl->vsync_created = 0; +} + +void hisifb_set_vsync_activate_state(struct hisi_fb_data_type *hisifd, + bool infinite) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(hisifd = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + if (hisifd->panel_info.vsync_ctrl_type = VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (infinite) { + vsync_ctrl->vsync_infinite_count += 1; + } else { + vsync_ctrl->vsync_infinite_count -= 1; + } + + if (vsync_ctrl->vsync_infinite_count >= 1) { + vsync_ctrl->vsync_infinite = 1; + } + + if (vsync_ctrl->vsync_infinite_count = 0) { + vsync_ctrl->vsync_infinite = 0; + } + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + unsigned long flags = 0; + int clk_enabled = 0; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + if (hisifd->panel_info.vsync_ctrl_type = VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_ctrl_enabled = 0) { + HISI_FB_DEBUG("fb%d, dss clk on!\n", hisifd->index); + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + /* dpe_regulator_enable(hisifd); */ + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + mipi_dsi_clk_enable(hisifd); + dpe_common_clk_enable(hisifd); + dpe_inner_clk_enable(hisifd); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + if (hisifd->lp_fnc) + hisifd->lp_fnc(hisifd, false); + } + + if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 1); + } + + vsync_ctrl->vsync_ctrl_enabled = 1; + clk_enabled = 1; + } else if (vsync_ctrl->vsync_ctrl_isr_enabled) { + clk_enabled = 1; + vsync_ctrl->vsync_ctrl_isr_enabled = 0; + } else { + ; + } + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + vsync_ctrl->vsync_ctrl_disabled_set = 0; + vsync_ctrl->vsync_ctrl_expire_count = 0; + if (clk_enabled) { + if (pdata->vsync_ctrl) { + pdata->vsync_ctrl(hisifd->pdev, 1); + } else { + HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", + hisifd->index); + } + } + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +void hisifb_deactivate_vsync(struct hisi_fb_data_type *hisifd) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + unsigned long flags = 0; + + BUG_ON(hisifd = NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + if (hisifd->panel_info.vsync_ctrl_type = VSYNC_CTRL_NONE) + return; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags); + if (vsync_ctrl->vsync_infinite = 0) + vsync_ctrl->vsync_ctrl_disabled_set = 1; + + if (vsync_ctrl->vsync_ctrl_enabled) + vsync_ctrl->vsync_ctrl_expire_count = VSYNC_CTRL_EXPIRE_COUNT; + spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags); + + mutex_unlock(&(vsync_ctrl->vsync_lock)); +} + +int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp) +{ + int ret = 0; + struct hisi_fb_data_type *hisifd = NULL; + struct hisi_fb_panel_data *pdata = NULL; + struct hisifb_vsync *vsync_ctrl = NULL; + int enable = 0; + + if (NULL = info) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + hisifd = (struct hisi_fb_data_type *)info->par; + if (NULL = hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (hisifd->index != PRIMARY_PANEL_IDX) { + HISI_FB_ERR("fb%d, not supported!\n", hisifd->index); + return -EINVAL; + } + + pdata = dev_get_platdata(&hisifd->pdev->dev); + if (NULL = pdata) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + vsync_ctrl = &(hisifd->vsync_ctrl); + if (NULL = vsync_ctrl) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL = argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + HISI_FB_ERR("hisifb_vsync_ctrl ioctl failed!\n"); + return ret; + } + + enable = (enable) ? 1 : 0; + + mutex_lock(&(vsync_ctrl->vsync_lock)); + + if (vsync_ctrl->vsync_enabled = enable) { + mutex_unlock(&(vsync_ctrl->vsync_lock)); + return 0; + } + + if (g_debug_online_vsync) + HISI_FB_INFO("fb%d, enable=%d!\n", hisifd->index, enable); + + vsync_ctrl->vsync_enabled = enable; + + mutex_unlock(&(vsync_ctrl->vsync_lock)); + + down(&hisifd->blank_sem); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&hisifd->blank_sem); + return 0; + } + + if (enable) { + hisifb_activate_vsync(hisifd); + } else { + hisifb_deactivate_vsync(hisifd); + } + + up(&hisifd->blank_sem); + + return 0; +} + +int hisifb_vsync_resume(struct hisi_fb_data_type *hisifd) +{ + struct hisifb_vsync *vsync_ctrl = NULL; + + BUG_ON(hisifd = NULL); + vsync_ctrl = &(hisifd->vsync_ctrl); + BUG_ON(vsync_ctrl = NULL); + + vsync_ctrl->vsync_enabled = 0; + vsync_ctrl->vsync_ctrl_expire_count = 0; + vsync_ctrl->vsync_ctrl_disabled_set = 0; + vsync_ctrl->vsync_ctrl_enabled = 1; + vsync_ctrl->vsync_ctrl_isr_enabled = 1; + + atomic_set(&(vsync_ctrl->buffer_updated), 1); + +#if 0 + if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) { + if ((hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) + || (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) + || (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_VCC_OFF)) { + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) { + mipi_dsi_ulps_cfg(hisifd, 0); + } + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) { + dpe_inner_clk_disable(hisifd); + dpe_common_clk_disable(hisifd); + mipi_dsi_clk_disable(hisifd); + } + + if (hisifd->panel_info. + vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) { + dpe_regulator_disable(hisifd); + } + } + } +#endif + + return 0; +} + +int hisifb_vsync_suspend(struct hisi_fb_data_type *hisifd) +{ + return 0; +} + +#pragma GCC diagnostic pop diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c new file mode 100755 index 000000000000..0d00d3fd9c60 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c @@ -0,0 +1,401 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_mipi_dsi.h" + +/* + * mipi dsi short write with 0, 1 2 parameters + * Write to GEN_HDR 24 bit register the value: + * 1. 00h, MCS_command[15:8] ,VC[7:6],13h + * 2. Data1[23:16], MCS_command[15:8] ,VC[7:6],23h + */ +int mipi_dsi_swrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + uint32_t hdr = 0; + int len = 0; + + if (cm->dlen && cm->payload = 0) { + HISI_FB_ERR("NO payload error!\n"); + return 0; + } + + BUG_ON(cm->dlen > 2); + len = cm->dlen; + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + if (len = 1) { + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(0); + } else if (len = 2) { + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(cm->payload[1]); + } else { + hdr |= DSI_HDR_DATA1(0); + hdr |= DSI_HDR_DATA2(0); + } + + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); + + return len; /* 4 bytes */ +} + +/* + * mipi dsi long write + * Write to GEN_PLD_DATA 32 bit register the value: + * Data3[31:24], Data2[23:16], Data1[15:8], MCS_command[7:0] + * If need write again to GEN_PLD_DATA 32 bit register the value: + * Data7[31:24], Data6[23:16], Data5[15:8], Data4[7:0] + * + * Write to GEN_HDR 24 bit register the value: WC[23:8] ,VC[7:6],29h + */ +int mipi_dsi_lwrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + uint32_t hdr = 0; + int i = 0; + + if (cm->dlen && cm->payload = 0) { + HISI_FB_ERR("NO payload error!\n"); + return 0; + } + + /* fill up payload */ + for (i = 0; i < cm->dlen; i += 4) { + set_reg(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET, + *((uint32_t *) (cm->payload + i)), 32, 0); + } + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_WC(cm->dlen); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); + + return cm->dlen; +} + +void mipi_dsi_max_return_packet_size(struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + uint32_t hdr = 0; + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_WC(cm->dlen); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); +} + +uint32_t mipi_dsi_read(uint32_t *out, char __iomem *dsi_base) +{ + uint32_t pkg_status; + uint32_t try_times = 700; + + do { + pkg_status = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if (!(pkg_status & 0x10)) + break; + udelay(50); + } while (--try_times); + + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); + if (!try_times) + HISI_FB_ERR("mipi_dsi_read timeout\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x \n" + "MIPIDSI_PHY_STATUS = 0x%x \n", + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET)); + + return try_times; +} + +void mipi_dsi_sread(uint32_t *out, char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t tmp = 0; + + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if ((tmp & 0x00000040) = 0x00000040) { + break; + } + } while (time_after(dw_jiffies, jiffies)); + + dw_jiffies = jiffies + HZ / 2; + do { + tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if ((tmp & 0x00000040) != 0x00000040) { + break; + } + } while (time_after(dw_jiffies, jiffies)); + + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); +} + +void mipi_dsi_lread(uint32_t *out, char __iomem *dsi_base) +{ + /* do something here */ +} + +/* + * prepare cmd buffer to be txed + */ +int mipi_dsi_cmd_add(struct dsi_cmd_desc *cm, char __iomem *dsi_base) +{ + int len = 0; + + BUG_ON(cm = NULL); + BUG_ON(dsi_base = NULL); + + switch (cm->dtype) { + case DTYPE_GEN_WRITE: + case DTYPE_GEN_WRITE1: + case DTYPE_GEN_WRITE2: + + case DTYPE_DCS_WRITE: + case DTYPE_DCS_WRITE1: + len = mipi_dsi_swrite(cm, dsi_base); + break; + case DTYPE_GEN_LWRITE: + case DTYPE_DCS_LWRITE: + case DTYPE_DSC_LWRITE: + + len = mipi_dsi_lwrite(cm, dsi_base); + break; + default: + HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype); + break; + } + + return len; +} + +int mipi_dsi_cmds_tx(struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base) +{ + struct dsi_cmd_desc *cm = NULL; + int i = 0; + + BUG_ON(cmds = NULL); + BUG_ON(dsi_base = NULL); + + cm = cmds; + + for (i = 0; i < cnt; i++) { + mipi_dsi_cmd_add(cm, dsi_base); + + if (cm->wait) { + if (cm->waittype = WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype = WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + cm++; + } + + return cnt; +} + +void mipi_dsi_check_0lane_is_ready(char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t tmp = 0; + + dw_jiffies = jiffies + HZ / 10; + do { + tmp = inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((tmp & 0x10) = 0x10) { + HISI_FB_INFO("0 lane is stopping state"); + return; + } + } while (time_after(dw_jiffies, jiffies)); + + HISI_FB_ERR("0 lane is not stopping state:tmp=0x%x", tmp); +} + +static void mipi_dsi_sread_request(struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + uint32_t hdr = 0; + + /* fill up header */ + hdr |= DSI_HDR_DTYPE(cm->dtype); + hdr |= DSI_HDR_VC(cm->vc); + hdr |= DSI_HDR_DATA1(cm->payload[0]); + hdr |= DSI_HDR_DATA2(0); + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0); +} + +static int mipi_dsi_read_add(uint32_t *out, struct dsi_cmd_desc *cm, + char __iomem *dsi_base) +{ + unsigned long dw_jiffies = 0; + uint32_t pkg_status = 0; + uint32_t phy_status = 0; + int is_timeout = 1; + int ret = 0; + + BUG_ON(cm = NULL); + BUG_ON(dsi_base = NULL); + + if (cm->dtype = DTYPE_DCS_READ) { + mipi_dsi_sread_request(cm, dsi_base); + + if (!mipi_dsi_read(out, dsi_base)) { + HISI_FB_ERR("Read register 0x%X timeout\n", + cm->payload[0]); + return -1; + } + } else if (cm->dtype = DTYPE_GEN_READ1) { + + /*read status register */ + dw_jiffies = jiffies + HZ; + do { + pkg_status + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + phy_status + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET); + if ((pkg_status & 0x1) = 0x1 && !(phy_status & 0x2)) { + is_timeout = 0; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (is_timeout) { + HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x\n" + "MIPIDSI_PHY_STATUS = 0x%x \n" + "MIPIDSI_INT_ST1_OFFSET = 0x%x \n", + cm->payload[0], + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET)); + return -1; + } + /*send read cmd to fifo */ + set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, + ((cm->payload[0] << 8) | cm->dtype), 24, 0); + + is_timeout = 1; + /*wait dsi read data */ + dw_jiffies = jiffies + HZ; + do { + pkg_status + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET); + if (!(pkg_status & 0x10)) { + is_timeout = 0; + break; + } + } while (time_after(dw_jiffies, jiffies)); + + if (is_timeout) { + HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n" + "MIPIDSI_CMD_PKT_STATUS = 0x%x\n" + "MIPIDSI_PHY_STATUS = 0x%x \n" + "MIPIDSI_INT_ST1_OFFSET = 0x%x \n", + cm->payload[0], + inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET), + inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET)); + return -1; + } + /*get read data */ + *out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET); + } else { + ret = -1; + HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype); + } + + return ret; +} + +int mipi_dsi_cmds_rx(uint32_t *out, struct dsi_cmd_desc *cmds, int cnt, + char __iomem *dsi_base) +{ + struct dsi_cmd_desc *cm = NULL; + int i = 0; + int err_num = 0; + + BUG_ON(cmds = NULL); + BUG_ON(dsi_base = NULL); + + cm = cmds; + + for (i = 0; i < cnt; i++) { + if (mipi_dsi_read_add(&(out[i]), cm, dsi_base)) { + err_num++; + } + + if (cm->wait) { + if (cm->waittype = WAIT_TYPE_US) + udelay(cm->wait); + else if (cm->waittype = WAIT_TYPE_MS) + mdelay(cm->wait); + else + mdelay(cm->wait * 1000); + } + cm++; + } + + return err_num; +} + +int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data, + char __iomem *dsi_base) +{ + uint32_t *read_value = NULL; + uint32_t *expected_value = NULL; + uint32_t *read_mask = NULL; + char **reg_name = NULL; + int log_on = 0; + struct dsi_cmd_desc *cmds = NULL; + + int cnt = 0; + int cnt_not_match = 0; + int ret = 0; + int i; + + BUG_ON(data = NULL); + BUG_ON(dsi_base = NULL); + + read_value = data->read_value; + expected_value = data->expected_value; + read_mask = data->read_mask; + reg_name = data->reg_name; + log_on = data->log_on; + + cmds = data->cmds; + cnt = data->cnt; + + ret = mipi_dsi_cmds_rx(read_value, cmds, cnt, dsi_base); + if (ret) { + HISI_FB_ERR("Read error number: %d\n", ret); + return cnt; + } + + for (i = 0; i < cnt; i++) { + if (log_on) { + HISI_FB_INFO("Read reg %s: 0x%x, value = 0x%x\n", + reg_name[i], cmds[i].payload[0], + read_value[i]); + } + + if (expected_value[i] != (read_value[i] & read_mask[i])) { + cnt_not_match++; + } + } + + return cnt_not_match; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c new file mode 100755 index 000000000000..6b1832f49e3c --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c @@ -0,0 +1,1450 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h" + +#define MAX_ITEM_OFFSET (0x3F) +#define CMDLIST_ADDR_OFFSET (0x3FFFF) + +#define CMDLIST_HEADER_LEN (SZ_1K) +#define CMDLIST_ITEM_LEN (SZ_8K) +#define MAX_ITEM_INDEX (SZ_1K) + +dss_cmdlist_data_t *g_cmdlist_data = NULL; +uint32_t g_online_cmdlist_idxs = 0; +uint32_t g_offline_cmdlist_idxs = 0; + +/* get cmdlist indexs */ +int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req, + uint32_t *cmdlist_pre_idxs, + uint32_t *cmdlist_idxs) +{ + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int k = 0; + int m = 0; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + bool no_ovl_idx = false; + + BUG_ON(pov_req = NULL); + + pov_h_block_infos = (dss_overlay_block_t *) pov_req->ov_block_infos_ptr; + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + continue; + + if (layer->chn_idx = DSS_RCHN_V2) { + cmdlist_idxs_temp |= (1 << DSS_CMDLIST_V2); + } else { + cmdlist_idxs_temp |= (1 << layer->chn_idx); + } + } + } + + if (pov_req->wb_enable = 1) { + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + + if (wb_layer->chn_idx = DSS_WCHN_W2) { + no_ovl_idx = true; + cmdlist_idxs_temp |= (1 << DSS_CMDLIST_W2); + } else { + cmdlist_idxs_temp |= (1 << wb_layer->chn_idx); + } + } + } + + if (no_ovl_idx = false) { + cmdlist_idxs_temp |+ (1 << (DSS_CMDLIST_OV0 + pov_req->ovl_idx)); + } + + if (cmdlist_idxs_temp & (~HISI_DSS_CMDLIST_IDXS_MAX)) { + HISI_FB_ERR("cmdlist_idxs_temp(0x%x) is invalid!\n", + cmdlist_idxs_temp); + return -EINVAL; + } + + if (cmdlist_idxs && cmdlist_pre_idxs) { + *cmdlist_idxs = cmdlist_idxs_temp; + *cmdlist_pre_idxs &= (~(*cmdlist_idxs)); + } else if (cmdlist_idxs) { + *cmdlist_idxs = cmdlist_idxs_temp; + } else if (cmdlist_pre_idxs) { + *cmdlist_pre_idxs = cmdlist_idxs_temp; + } else { + HISI_FB_ERR("cmdlist_idxs && cmdlist_pre_idxs is NULL!\n"); + return -EINVAL; + } + + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO("cmdlist_pre_idxs(0x%x), cmdlist_idxs(0x%x).\n", + (cmdlist_pre_idxs ? *cmdlist_pre_idxs : 0), + (cmdlist_idxs ? *cmdlist_idxs : 0)); + } + + return 0; +} + +uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs) +{ + uint32_t cmdlist_idxs_temp = 0; + + BUG_ON(hisifd = NULL); + + cmdlist_idxs_temp = g_offline_cmdlist_idxs; + g_offline_cmdlist_idxs |= cmdlist_idxs; + cmdlist_idxs_temp = (g_offline_cmdlist_idxs & (~cmdlist_idxs_temp)); + + cmdlist_idxs_temp |= (cmdlist_idxs & g_online_cmdlist_idxs); + g_online_cmdlist_idxs &= (~cmdlist_idxs_temp); + + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO + ("g_online_cmdlist_idxs=0x%x, cmdlist_idxs_need_start=0x%x\n", + g_online_cmdlist_idxs, cmdlist_idxs_temp); + } + + return cmdlist_idxs_temp; +} + +/* + ** data0: addr0[17:0] + ** data1: addr0[17:0] + addr1[5:0] + ** data2: addr0[17:0] + addr2[5:0] + ** + ** cnt[1:0]: + ** 2'b00: reg0 + ** 2'b01: reg0, reg1 + ** 2'b10: reg0, reg1, reg2 + ** 2'b11: ((inp32(addr0) & data1) | data2) -> addr0 + */ +void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd, char __iomem *addr, + uint32_t value, uint8_t bw, uint8_t bs) +{ + uint32_t mask = (1 << bw) - 1; + dss_cmdlist_node_t *node = NULL; + int cmdlist_idx = -1; + int index = 0; + uint32_t new_addr = 0; + uint32_t old_addr = 0; + int condition = 0; + + BUG_ON(addr = NULL); + BUG_ON(hisifd = NULL); + + cmdlist_idx = hisifd->cmdlist_idx; + BUG_ON((cmdlist_idx < 0) || (cmdlist_idx >= HISI_DSS_CMDLIST_MAX)); + + node + list_entry(hisifd->cmdlist_data->cmdlist_head_temp[cmdlist_idx].prev, + dss_cmdlist_node_t, list_node); + BUG_ON(node = NULL); + + if (node->node_type = CMDLIST_NODE_NOP) { + HISI_FB_ERR("can't set register value to NOP node!"); + return; + } + + index = node->item_index; + new_addr = (uint32_t) (addr - hisifd->dss_base + hisifd->dss_base_phy); + new_addr = (new_addr >> 2) & CMDLIST_ADDR_OFFSET; + old_addr = node->list_item[index].reg_addr.ul32 & CMDLIST_ADDR_OFFSET; + condition = (((new_addr - old_addr) < MAX_ITEM_OFFSET) + && (new_addr >= old_addr)); + + if (bw != 32) { + if (node->item_flag != 0) + index++; + + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].data1 = ~(mask << bs); + node->list_item[index].data2 = (mask & value) << bs; + node->list_item[index].reg_addr.bits.cnt = 3; + node->item_flag = 3; + } else { + if (node->item_flag = 0) { + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].reg_addr.bits.cnt = 0; + node->item_flag = 1; + } else if (node->item_flag = 1 && condition) { + node->list_item[index].reg_addr.bits.add1 + new_addr - old_addr; + node->list_item[index].data1 = value; + node->list_item[index].reg_addr.bits.cnt = 1; + node->item_flag = 2; + } else if (node->item_flag = 2 && condition) { + node->list_item[index].reg_addr.bits.add2 + new_addr - old_addr; + node->list_item[index].data2 = value; + node->list_item[index].reg_addr.bits.cnt = 2; + node->item_flag = 3; + } else { + index++; + node->list_item[index].reg_addr.bits.add0 = new_addr; + node->list_item[index].data0 = value; + node->list_item[index].reg_addr.bits.cnt = 0; + node->item_flag = 1; + } + } + + BUG_ON(index >= MAX_ITEM_INDEX); + + node->item_index = index; + node->list_header->total_items.bits.count = node->item_index + 1; +} + +/* + ** flush cache for cmdlist, make sure that + ** cmdlist has writen through to memory before config register + */ +void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd, + struct ion_client *ion_client, + uint32_t cmdlist_idxs) +{ + uint32_t i = 0; + uint32_t cmdlist_idxs_temp = 0; + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + struct sg_table *table = NULL; + struct list_head *cmdlist_heads = NULL; + + BUG_ON(hisifd = NULL); + + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + cmdlist_heads + &(hisifd->cmdlist_data->cmdlist_head_temp[i]); + if (!cmdlist_heads) { + HISI_FB_ERR("cmdlist_data is NULL!\n"); + continue; + } + + list_for_each_entry_safe_reverse(node, _node_, + cmdlist_heads, + list_node) { + + if (!node->header_ion_handle) { + HISI_FB_ERR + ("header_ion_handle is NULL!\n"); + } else { + table = ion_sg_table(ion_client, + node->header_ion_handle); + BUG_ON(table = NULL); + dma_sync_sg_for_device(NULL, table->sgl, + table->nents, + DMA_TO_DEVICE); + } + + if (!node->item_ion_handle) { + HISI_FB_ERR("item_ion_handle is NULL!\n"); + } else { + table = ion_sg_table(ion_client, + node->item_ion_handle); + BUG_ON(table = NULL); + dma_sync_sg_for_device(NULL, table->sgl, + table->nents, + DMA_TO_DEVICE); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } +} + +dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client) +{ + int ret = 0; + dss_cmdlist_node_t *node = NULL; + size_t header_len = CMDLIST_HEADER_LEN; + size_t item_len = CMDLIST_ITEM_LEN; + + BUG_ON(ion_client = NULL); + + node + (dss_cmdlist_node_t *) kzalloc(sizeof(dss_cmdlist_node_t), + GFP_KERNEL); + if (IS_ERR(node)) { + HISI_FB_ERR("failed to alloc dss_cmdlist_node_t!"); + goto err_alloc_cmdlist_node; + } + + memset(node, 0, sizeof(dss_cmdlist_node_t)); + + /*alloc buffer for header */ + node->header_ion_handle + ion_alloc(ion_client, header_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0); + if (IS_ERR(node->header_ion_handle)) { + HISI_FB_ERR("failed to ion_alloc node->header_ion_handle!"); + goto err_header_ion_handle; + } + + node->list_header + (cmd_header_t *) ion_map_kernel(ion_client, + node->header_ion_handle); + if (!node->list_header) { + HISI_FB_ERR("failed to ion_map_kernel node->list_header!"); + goto err_header_ion_map; + } + memset(node->list_header, 0, header_len); + + ret + ion_phys(ion_client, node->header_ion_handle, &node->header_phys, + &header_len); + if (ret < 0) { + HISI_FB_ERR("failed to ion_phys node->header_phys!"); + goto err_header_ion_phys; + } + + /*alloc buffer for items */ + node->item_ion_handle + ion_alloc(ion_client, item_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0); + if (!node->item_ion_handle) { + HISI_FB_ERR("failed to ion_alloc node->item_ion_handle!"); + goto err_item_ion_handle; + } + + node->list_item + (cmd_item_t *) ion_map_kernel(ion_client, node->item_ion_handle); + if (!node->list_item) { + HISI_FB_ERR("failed to ion_map_kernel node->list_item!"); + goto err_item_ion_map; + } + + memset(node->list_item, 0, item_len); + ret + ion_phys(ion_client, node->item_ion_handle, &node->item_phys, + &item_len); + if (ret < 0) { + HISI_FB_ERR("failed to ion_phys node->item_phys!"); + goto err_item_ion_phys; + } + + /* fill node info */ + node->item_flag = 0; + node->item_index = 0; + + node->is_used = 0; + node->node_type = CMDLIST_NODE_NONE; + return node; + + err_item_ion_phys: + if (node->item_ion_handle) + ion_unmap_kernel(ion_client, node->item_ion_handle); + err_item_ion_map: + if (node->item_ion_handle) + ion_free(ion_client, node->item_ion_handle); + err_item_ion_handle: + err_header_ion_phys: + if (node->header_ion_handle) + ion_unmap_kernel(ion_client, node->header_ion_handle); + err_header_ion_map: + if (node->header_ion_handle) + ion_free(ion_client, node->header_ion_handle); + err_header_ion_handle: + if (node) + kfree(node); + err_alloc_cmdlist_node: + return NULL; +} + +void hisi_cmdlist_node_free(struct ion_client *ion_client, + dss_cmdlist_node_t *node) +{ + BUG_ON(ion_client = NULL); + BUG_ON(node = NULL); + + if (node->header_ion_handle) { + ion_unmap_kernel(ion_client, node->header_ion_handle); + ion_free(ion_client, node->header_ion_handle); + } + + if (node->item_ion_handle) { + ion_unmap_kernel(ion_client, node->item_ion_handle); + ion_free(ion_client, node->item_ion_handle); + } + + kfree(node); + node = NULL; +} + +static dss_cmdlist_node_t *hisi_cmdlist_get_free_node(dss_cmdlist_node_t * + node[], int *id) +{ + int i = 0; + + for (i = 0; i < HISI_DSS_CMDLIST_NODE_MAX; i++) { + if (node[i] && (node[i]->is_used = 0)) { + node[i]->is_used = 1; + *id = i + 1; + return node[i]; + } + } + + return NULL; +} + +int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int reserved) +{ + dss_cmdlist_node_t *node = NULL; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int id = 0; + + BUG_ON(hisifd = NULL); + + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + node + hisi_cmdlist_get_free_node(hisifd->cmdlist_data-> + cmdlist_nodes_temp[i], + &id); + if (!node) { + HISI_FB_ERR + ("failed to hisi_get_free_cmdlist_node!\n"); + return -EINVAL; + } + + node->list_header->flag.bits.id = id; + node->list_header->flag.bits.nop = 0x1; + node->list_header->flag.bits.pending + pending ? 0x1 : 0x0; + node->list_header->flag.bits.valid_flag + CMDLIST_NODE_VALID; + node->list_header->next_list = node->header_phys; + + node->is_used = 1; + node->node_type = CMDLIST_NODE_NOP; + node->reserved = reserved ? 0x1 : 0x0; + + /*add this nop to list */ + list_add_tail(&(node->list_node), + &(hisifd->cmdlist_data->cmdlist_head_temp[i])); + + if (node->list_node.prev !+ &(hisifd->cmdlist_data->cmdlist_head_temp[i])) { + dss_cmdlist_node_t *pre_node = NULL; + pre_node + list_entry(node->list_node.prev, + dss_cmdlist_node_t, list_node); + pre_node->list_header->next_list + node->header_phys; + if (node->list_header->flag.bits.pending = 0x1) { + pre_node->reserved = 0x0; + } + + pre_node->list_header->flag.bits.task_end = 0x1; + + if (g_debug_ovl_cmdlist) { + HISI_FB_DEBUG + ("i = %d, next_list = 0x%x\n", i, + (uint32_t) (node->header_phys)); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int task_end, + int remove, int last, uint32_t wb_type) +{ + char __iomem *cmdlist_base = NULL; + dss_cmdlist_node_t *node = NULL; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int id = 0; + + BUG_ON(hisifd = NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + node + hisi_cmdlist_get_free_node(hisifd->cmdlist_data-> + cmdlist_nodes_temp[i], + &id); + if (!node) { + HISI_FB_ERR + ("failed to hisi_get_free_cmdnode!\n"); + return -EINVAL; + } + + /*fill the header and item info */ + node->list_header->flag.bits.id = id; + node->list_header->flag.bits.pending + pending ? 0x1 : 0x0; + + if (i < DSS_CMDLIST_W0) { + node->list_header->flag.bits.event_list + remove ? 0x8 : (0xE + i); + } else if (i < DSS_CMDLIST_OV0) { + node->list_header->flag.bits.event_list + remove ? 0x8 : (0x16 + i); + } else if (i = DSS_CMDLIST_V2) { + node->list_header->flag.bits.event_list + remove ? 0x8 : 0x16; + } else if (i = DSS_CMDLIST_W2) { + node->list_header->flag.bits.event_list + remove ? 0x8 : 0x20; + } else { + node->list_header->flag.bits.event_list + remove ? 0x8 : (0xE + i); + } + + node->list_header->flag.bits.task_end + task_end ? 0x1 : 0x0; + node->list_header->flag.bits.last = last ? 0x1 : 0x0; + + node->list_header->flag.bits.valid_flag + CMDLIST_NODE_VALID; + node->list_header->flag.bits.exec = 0x1; + node->list_header->list_addr = node->item_phys; + node->list_header->next_list = node->item_phys; + + node->is_used = 1; + node->node_type = CMDLIST_NODE_FRAME; + node->item_flag = 0; + node->reserved = 0; + + /* add this nop to list */ + list_add_tail(&(node->list_node), + &(hisifd->cmdlist_data->cmdlist_head_temp[i])); + + if (node->list_node.prev !+ &(hisifd->cmdlist_data->cmdlist_head_temp[i])) { + dss_cmdlist_node_t *pre_node = NULL; + pre_node + list_entry(node->list_node.prev, + dss_cmdlist_node_t, list_node); + pre_node->list_header->next_list + node->header_phys; + pre_node->reserved = 0x0; + if (g_debug_ovl_cmdlist) { + HISI_FB_DEBUG + ("i = %d, next_list = 0x%x\n", i, + (uint32_t) node->header_phys); + } + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + + BUG_ON(cmdlist_heads = NULL); + + list_for_each_entry_safe(node, _node_, cmdlist_heads, list_node) { + if (node->reserved != 0x1) { + list_del(&node->list_node); + + memset(node->list_header, 0, CMDLIST_HEADER_LEN); + memset(node->list_item, 0, CMDLIST_ITEM_LEN); + + node->item_index = 0; + node->item_flag = 0; + node->node_type = CMDLIST_NODE_NONE; + node->is_used = 0; + } + } + + return 0; +} + +int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs) +{ + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int delay_count = 0; + bool is_timeout = true; + int ret = 0; + + BUG_ON(hisifd = NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + while (1) { + tmp + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + if (((tmp & 0xF) = 0x0) || delay_count > 5000) { + is_timeout + (delay_count > 5000) ? true : false; + delay_count = 0; + break; + } else { + udelay(1); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("cmdlist_ch%d not in idle state,ints=0x%x !\n", + i, tmp); + ret = -1; + } + } + + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + + return ret; +} + +/* + ** stop the pending state for one new frame + ** if the current cmdlist status is e_status_wait. + */ +int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs) +{ + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int delay_count = 0; + bool is_timeout = true; + + BUG_ON(hisifd = NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + while (1) { + tmp + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + if (((tmp & 0xF) = 0x0) || delay_count > 500) { + is_timeout + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(1); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("cmdlist_ch%d not in idle state,ints=0x%x !\n", + i, tmp); + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + } + } + + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + return 0; +} + +/* + **start cmdlist. + **it will set cmdlist into pending state. + */ +extern uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX]; +int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs, uint32_t wb_compose_type) +{ + char __iomem *mctl_base = NULL; + char __iomem *cmdlist_base = NULL; + dss_cmdlist_node_t *cmdlist_node = NULL; + uint32_t offset = 0; + uint32_t list_addr = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int temp = 0; + int status_temp = 0; + int ints_temp = 0; + + BUG_ON(hisifd = NULL); + + mctl_base + hisifd->dss_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + status_temp + inp32(cmdlist_base + CMDLIST_CH0_STATUS + + i * offset); + ints_temp + inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset); + + if (mctl_idx >= DSS_MCTL2) { + cmdlist_node + list_first_entry(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i]), + dss_cmdlist_node_t, + list_node); + } else { + cmdlist_node + list_first_entry(&(hisifd->cmdlist_data-> + cmdlist_head_temp[i]), + dss_cmdlist_node_t, + list_node); + } + + list_addr = cmdlist_node->header_phys; + if (g_debug_ovl_cmdlist) { + HISI_FB_INFO + ("list_addr:0x%x, i=%d, ints_temp=0x%x\n", + list_addr, i, ints_temp); + } + + temp |= (1 << i); + outp32(cmdlist_base + CMDLIST_ADDR_MASK_EN, BIT(i)); + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%lx\n", + cmdlist_base + + CMDLIST_ADDR_MASK_EN, BIT(i)); + } + + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, + mctl_idx, 3, 2); + if (mctl_idx <= DSS_MCTL1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 6); + } else { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x0, 1, 6); + } + + set_reg(cmdlist_base + CMDLIST_CH0_STAAD + i*offset, + list_addr, 32, 0); + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 0); + if ((mctl_idx <= DSS_MCTL1) + && ((ints_temp & 0x2) = 0x2)) { + set_reg(cmdlist_base + CMDLIST_SWRST, 0x1, 1, i); + } + + if (mctl_idx >= DSS_MCTL2) { + if (((status_temp & 0xF) = 0x0) + || ((ints_temp & 0x2) = 0x2)) { + set_reg(cmdlist_base + CMDLIST_SWRST, + 0x1, 1, i); + } else { + HISI_FB_INFO + ("i=%d, status_temp=0x%x, ints_temp=0x%x\n", + i, status_temp, ints_temp); + } + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + outp32(cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp); + if (g_debug_set_reg_val) { + HISI_FB_INFO("writel: [%p] = 0x%x\n", + cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp); + } + + if (mctl_idx >= DSS_MCTL2) { + set_reg(mctl_base + MCTL_CTL_ST_SEL, 0x1, 1, 0); + set_reg(mctl_base + MCTL_CTL_SW_ST, 0x1, 1, 0); + } + + return 0; +} + +void hisi_cmdlist_config_mif_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_idxs, int mctl_idx) +{ + char __iomem *dss_base = NULL; + char __iomem *tmp_base = NULL; + + uint32_t cmdlist_idxs_temp = 0; + int delay_count = 0; + bool is_timeout = true; + int i = 0; + int j = 0; + int mif_sub_ch_nums = 4; + int tmp = 0; + int mif_nums_max = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(pov_req = NULL); + + dss_base = hisifd->dss_base; + + if (mctl_idx <= DSS_MCTL1) { + mif_nums_max = DSS_WCHN_W0; + } else { + mif_nums_max = DSS_CHN_MAX; + } + + if (mctl_idx = DSS_MCTL5) { + for (i = DSS_RCHN_V2; i < DSS_CHN_MAX_DEFINE; i++) { + is_timeout = false; + + while (1) { + for (j = 1; j <= mif_sub_ch_nums; j++) { + tmp |+ inp32(dss_base + DSS_MIF_OFFSET + + MIF_STAT1 + + 0x10 * (i * mif_sub_ch_nums +j)); + } + + if (((tmp & 0x1f) = 0x0) || delay_count > 500) { + is_timeout + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(10); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR("mif_ch%d MIF_STAT1=0x%x !\n", i, + tmp); + } + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0); + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0); + } + } else { + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + is_timeout = false; + + while (1) { + for (j = 1; j <= mif_sub_ch_nums; j++) { + tmp |+ inp32(dss_base + DSS_MIF_OFFSET + MIF_STAT1 + + 0x10 * (i * mif_sub_ch_nums + j)); + } + if (((tmp & 0x1f) = 0x0) + || delay_count > 500) { + is_timeout + (delay_count > 500) ? true : false; + delay_count = 0; + break; + } else { + udelay(10); + ++delay_count; + } + } + + if (is_timeout) { + HISI_FB_ERR + ("mif_ch%d MIF_STAT1=0x%x !\n", i, tmp); + } + } + + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + tmp_base = hisifd->dss_module.mif_ch_base[i]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x0, 1, + 0); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } + mdelay(5); + + if (mctl_idx = DSS_MCTL5) { + tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0); + } + + tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0); + } + } else { + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < mif_nums_max; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + tmp_base = hisifd->dss_module.mif_ch_base[i]; + if (tmp_base) { + set_reg(tmp_base + MIF_CTRL0, 0x1, 1, + 0); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } +} + +void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + char __iomem *dss_base = NULL; + char __iomem *cmdlist_base = NULL; + char __iomem *tmp_base = NULL; + struct hisi_panel_info *pinfo = NULL; + + uint32_t offset = 0; + uint32_t cmdlist_idxs_temp = 0; + int i = 0; + int ovl_idx = 0; + int mctl_idx = 0; + int ints_temp = 0; + int start_sel = 0; + uint32_t start_sel_temp = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(pov_req = NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + dss_base = hisifd->dss_base; + cmdlist_base = dss_base + DSS_CMDLIST_OFFSET; + ovl_idx = pov_req->ovl_idx; + pinfo = &(hisifd->panel_info); + + if (cmdlist_idxs = 0) return; + + mctl_idx = ovl_idx; + if (pov_req->wb_compose_type = DSS_WB_COMPOSE_COPYBIT) { + mctl_idx = DSS_MCTL5; + } + + offset = 0x40; + cmdlist_idxs_temp = HISI_DSS_CMDLIST_IDXS_MAX; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + ints_temp + inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset); + start_sel + inp32(cmdlist_base + CMDLIST_CH0_CTRL + i * offset); + + if (((ints_temp & 0x2) = 0x2) + && ((start_sel & 0x1c) = 0)) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2); + start_sel_temp |= (1 << i); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + tmp_base = hisifd->dss_module.mctl_base[mctl_idx]; + if (tmp_base) { + set_reg(tmp_base + MCTL_CTL_CLEAR, 0x1, 1, 0); + } + + hisi_cmdlist_config_mif_reset(hisifd, pov_req, cmdlist_idxs, mctl_idx); + cmdlist_idxs_temp = start_sel_temp; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, mctl_idx, 3, 2); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + if (mctl_idx >= DSS_MCTL2) { + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + + i * offset, 0x6, 3, 2); + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + + i * offset, 0x0, 1, 0); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + } + + HISI_FB_DEBUG("fb%d, -.\n", hisifd->index); + return; +} + +int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_pre_idxs) +{ + dss_overlay_t *pov_req = NULL; + char __iomem *cmdlist_base = NULL; + int i = 0; + uint32_t tmp = 0; + uint32_t offset = 0; + int ret = 0; + + BUG_ON(hisifd = NULL); + pov_req = &(hisifd->ov_req); + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + offset = 0x40; + + ret + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, 0, 1, 1, 1, 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + + for (i = 0; i < DSS_WCHN_W0; i++) { + tmp = (0x1 << i); + hisifd->cmdlist_idx = i; + + if ((cmdlist_pre_idxs & tmp) = tmp) { + hisifd->set_reg(hisifd, + hisifd->dss_module.mctl_base[pov_req-> + ovl_idx] + + MCTL_CTL_MUTEX_RCH0 + i * 0x4, 0, 32, + 0); + hisifd->set_reg(hisifd, cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2); + } + } + + return 0; + + err_return: + return ret; +} + +void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *cmdlist_base = NULL; + + BUG_ON(hisifd = NULL); + + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + set_reg(cmdlist_base + CMDLIST_CTRL, 0x3, 2, 4); +} + +void hisi_dump_cmdlist_node_items(cmd_item_t *item, uint32_t count) +{ + uint32_t index = 0; + uint32_t addr = 0; + + for (index = 0; index < count; index++) { + addr = item[index].reg_addr.bits.add0; + addr = addr & CMDLIST_ADDR_OFFSET; + addr = addr << 2; + HISI_FB_INFO + ("set addr:0x%x value:0x%x add1:0x%x value:0x%x " + "add2:0x%x value:0x%x \n", + addr, item[index].data0, + item[index].reg_addr.bits.add1 << 2, item[index].data1, + item[index].reg_addr.bits.add2 << 2, item[index].data2); + } +} + +static void hisi_dump_cmdlist_content(struct list_head *cmdlist_head, + char *filename, uint32_t addr) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + + BUG_ON(cmdlist_head = NULL); + BUG_ON(filename = NULL); + + if (g_dump_cmdlist_content = 0) + return; + + HISI_FB_INFO("%s\n", filename); + + list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) { + if (node->header_phys = addr) { + hisifb_save_file(filename, (char *)(node->list_header), + CMDLIST_HEADER_LEN); + } + + if (node->item_phys = addr) { + hisifb_save_file(filename, (char *)(node->list_item), + CMDLIST_ITEM_LEN); + } + } +} + +static void hisi_dump_cmdlist_one_node(struct list_head *cmdlist_head, + uint32_t cmdlist_idx) +{ + dss_cmdlist_node_t *node = NULL; + dss_cmdlist_node_t *_node_ = NULL; + uint32_t count = 0; + int i = 0; + char filename[256] = { 0 }; + + BUG_ON(cmdlist_head = NULL); + + list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) { + if (node->node_type = CMDLIST_NODE_NOP) { + HISI_FB_INFO("node type = NOP node\n"); + } else if (node->node_type = CMDLIST_NODE_FRAME) { + HISI_FB_INFO("node type = Frame node\n"); + } + + HISI_FB_INFO + ("\t qos | flag | pending | tast_end | last | event_list | list_addr | next_list | count | id | is_used | reserved | cmdlist_idx\n"); + HISI_FB_INFO + ("\t ------+---------+------------+------------+------------+------------\n"); + HISI_FB_INFO + ("\t 0x%2x | 0x%2x |0x%6x | 0x%5x | 0x%3x | 0x%8x | 0x%8x | 0x%8x | 0x%3x | 0x%2x | 0x%2x | 0x%2x | 0x%2x\n", + node->list_header->flag.bits.qos, + node->list_header->flag.bits.valid_flag, + node->list_header->flag.bits.pending, + node->list_header->flag.bits.task_end, + node->list_header->flag.bits.last, + node->list_header->flag.bits.event_list, + node->list_header->list_addr, node->list_header->next_list, + node->list_header->total_items.bits.count, + node->list_header->flag.bits.id, node->is_used, + node->reserved, cmdlist_idx); + + if (i = 0) { + snprintf(filename, 256, + "/data/dssdump/list_start_0x%x.txt", + (uint32_t) node->header_phys); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->header_phys); + } +#if 0 + if ((node->list_header->next_list != 0x0) && + (node->list_header->next_list != 0xFFFFFFFF)) { + snprintf(filename, 256, + "/data/dssdump/next_list_0x%x.txt", + node->list_header->next_list); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->list_header->next_list); + } + + if ((node->list_header->list_addr != 0x0) && + (node->list_header->list_addr != 0xFFFFFFFF)) { + snprintf(filename, 256, + "/data/dssdump/list_addr_0x%x.txt", + node->list_header->list_addr); + hisi_dump_cmdlist_content(cmdlist_head, filename, + node->list_header->list_addr); + } +#endif + count = node->list_header->total_items.bits.count; + hisi_dump_cmdlist_node_items(node->list_item, count); + + i++; + } +} + +int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + int i = 0; + uint32_t cmdlist_idxs_temp = 0; + uint32_t wb_compose_type = 0; + + BUG_ON(hisifd = NULL); + + if (pov_req) { + if (pov_req->wb_enable) + wb_compose_type = pov_req->wb_compose_type; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if (0x1 = (cmdlist_idxs_temp & 0x1)) { + if (pov_req && pov_req->wb_enable) { + hisi_dump_cmdlist_one_node(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i]), i); + } else { + hisi_dump_cmdlist_one_node(& + (hisifd->cmdlist_data->cmdlist_head_temp[i]), i); + } + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + + return 0; +} + +int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs) +{ + int i = 0; + uint32_t cmdlist_idxs_temp = 0; + uint32_t wb_compose_type = 0; + + BUG_ON(hisifd = NULL); + + if (pov_req) { + if (pov_req->wb_enable) + wb_compose_type = pov_req->wb_compose_type; + } + + cmdlist_idxs_temp = cmdlist_idxs; + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) = 0x1) { + if (pov_req && pov_req->wb_enable) { + hisi_cmdlist_del_all_node(&(hisifd->cmdlist_data_tmp + [wb_compose_type]->cmdlist_head_temp[i])); + } else { + hisi_cmdlist_del_all_node(& + (hisifd->cmdlist_data->cmdlist_head_temp[i])); + } + } + cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1); + } + + return 0; +} + +static dss_cmdlist_data_t *hisi_cmdlist_data_alloc(struct hisi_fb_data_type + *hisifd) +{ + int i = 0; + int j = 0; + dss_cmdlist_data_t *cmdlist_data = NULL; + + BUG_ON(hisifd = NULL); + + cmdlist_data + (dss_cmdlist_data_t *) kmalloc(sizeof(dss_cmdlist_data_t), + GFP_ATOMIC); + if (cmdlist_data) { + memset(cmdlist_data, 0, sizeof(dss_cmdlist_data_t)); + } else { + HISI_FB_ERR("failed to kmalloc cmdlist_data!\n"); + return NULL; + } + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + INIT_LIST_HEAD(&(cmdlist_data->cmdlist_head_temp[i])); + + for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) { + cmdlist_data->cmdlist_nodes_temp[i][j] + hisi_cmdlist_node_alloc(hisifd->ion_client); + if (cmdlist_data->cmdlist_nodes_temp[i][j] = NULL) { + HISI_FB_ERR + ("failed to hisi_cmdlist_node_alloc!\n"); + kfree(cmdlist_data); + return NULL; + } + } + } + + return cmdlist_data; +} + +static void hisi_cmdlist_data_free(struct hisi_fb_data_type *hisifd, + dss_cmdlist_data_t *cmdlist_data) +{ + int i = 0; + int j = 0; + + BUG_ON(hisifd = NULL); + BUG_ON(cmdlist_data = NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) { + hisi_cmdlist_node_free(hisifd->ion_client, + hisifd->cmdlist_data->cmdlist_nodes_temp[i][j]); + } + } +} + +static dss_cmdlist_info_t *hisi_cmdlist_info_alloc(struct hisi_fb_data_type + *hisifd) +{ + int i = 0; + dss_cmdlist_info_t *cmdlist_info = NULL; + + BUG_ON(hisifd = NULL); + + cmdlist_info + (dss_cmdlist_info_t *) kmalloc(sizeof(dss_cmdlist_info_t), GFP_ATOMIC); + if (cmdlist_info) { + memset(cmdlist_info, 0, sizeof(dss_cmdlist_info_t)); + } else { + HISI_FB_ERR("failed to kmalloc cmdlist_info!\n"); + return NULL; + } + + sema_init(&(cmdlist_info->cmdlist_wb_common_sem), 1); + + for (i = 0; i < WB_TYPE_MAX; i++) { + sema_init(&(cmdlist_info->cmdlist_wb_sem[i]), 1); + init_waitqueue_head(&(cmdlist_info->cmdlist_wb_wq[i])); + cmdlist_info->cmdlist_wb_done[i] = 0; + cmdlist_info->cmdlist_wb_flag[i] = 0; + } + + return cmdlist_info; +} + +static dss_copybit_info_t *hisi_copybit_info_alloc(struct hisi_fb_data_type + *hisifd) +{ + dss_copybit_info_t *copybit_info = NULL; + + BUG_ON(hisifd = NULL); + + copybit_info + (dss_copybit_info_t *) kmalloc(sizeof(dss_copybit_info_t), + GFP_ATOMIC); + if (copybit_info) { + memset(copybit_info, 0, sizeof(dss_copybit_info_t)); + } else { + HISI_FB_ERR("failed to kmalloc copybit_info!\n"); + return NULL; + } + + sema_init(&(copybit_info->copybit_sem), 1); + + init_waitqueue_head(&(copybit_info->copybit_wq)); + copybit_info->copybit_done = 0; + + return copybit_info; +} + +void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd) +{ + int tmp = 0; + + BUG_ON(hisifd = NULL); + + tmp = (hisifd->frame_count + 1) % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp]; + hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX); + + tmp = hisifd->frame_count % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp]; + hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX); +} + +int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + int i = 0; + + BUG_ON(hisifd = NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) { + hisifd->ov_block_rects[i] + (dss_rect_t *) kmalloc(sizeof(dss_rect_t), GFP_ATOMIC); + if (!hisifd->ov_block_rects[i]) { + HISI_FB_ERR("ov_block_rects[%d] failed to alloc!", i); + return -EINVAL; + } + } + + if (hisifd->index = AUXILIARY_PANEL_IDX) { + hisifd->cmdlist_data_tmp[0] = hisi_cmdlist_data_alloc(hisifd); + hisifd->cmdlist_data_tmp[1] = hisi_cmdlist_data_alloc(hisifd); + hisifd->cmdlist_info = hisi_cmdlist_info_alloc(hisifd); + hisifd->copybit_info = hisi_copybit_info_alloc(hisifd); + } else { + if (hisifd->index = PRIMARY_PANEL_IDX + || (hisifd->index = EXTERNAL_PANEL_IDX + && !hisifd->panel_info.fake_hdmi)) { + for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) { + hisifd->cmdlist_data_tmp[i] + hisi_cmdlist_data_alloc(hisifd); + } + } + } + + hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[0]; + hisifd->cmdlist_idx = -1; + + return ret; +} + +int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd) +{ + int i = 0; + + BUG_ON(hisifd = NULL); + + for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) { + if (hisifd->ov_block_rects[i]) { + kfree(hisifd->ov_block_rects[i]); + hisifd->ov_block_rects[i] = NULL; + } + } + + for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) { + if (hisifd->cmdlist_data_tmp[i]) { + hisi_cmdlist_data_free(hisifd, + hisifd->cmdlist_data_tmp[i]); + kfree(hisifd->cmdlist_data_tmp[i]); + hisifd->cmdlist_data_tmp[i] = NULL; + } + } + + if (hisifd->index = AUXILIARY_PANEL_IDX) { + if (hisifd->cmdlist_info) { + kfree(hisifd->cmdlist_info); + hisifd->cmdlist_info = NULL; + } + + if (hisifd->copybit_info) { + kfree(hisifd->copybit_info); + hisifd->copybit_info = NULL; + } + } + + return 0; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h new file mode 100755 index 000000000000..5f5d8c0fd506 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h @@ -0,0 +1,249 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef _CMD_LIST_UTILS_H_ +#define _CMD_LIST_UTILS_H_ +#include "hisi_overlay_utils_hi3660.h" + +#define HISI_DSS_CMDLIST_DATA_MAX (3) +#define HISI_DSS_CMDLIST_NODE_MAX (32) +#define HISI_DSS_CMDLIST_BLOCK_MAX (32) + +#define HISI_DSS_SUPPORT_DPP_MODULE_BIT(module) \ + (BIT(module) & HISI_DSS_DPP_MAX_SUPPORT_BIT) + +enum dpp_module_idx { + DPP_MODULE_POST_SCF = 0, + DPP_MODULE_DBUF, + DPP_MODULE_SBL, + DPP_MODULE_ACM, + DPP_MODULE_ACE, + DPP_MODULE_LCP_IGM, + DPP_MODULE_LCP_GMP, + DPP_MODULE_LCP_XCC, + DPP_MODULE_GAMA, + DPP_MODULE_DITHER, + DPP_MODULE_IFBC, + DPP_MODULE_MAX +}; + +enum wb_type { + WB_TYPE_WCH0, + WB_TYPE_WCH1, + WB_TYPE_WCH2, + WB_TYPE_WCH0_WCH1, + + WB_TYPE_MAX, +}; + +enum dss_cmdlist_idx { + DSS_CMDLIST_NONE = -1, + DSS_CMDLIST_D2 = 0, + DSS_CMDLIST_D3, + DSS_CMDLIST_V0, + DSS_CMDLIST_G0, + DSS_CMDLIST_V1, + DSS_CMDLIST_G1, + DSS_CMDLIST_D0, + DSS_CMDLIST_D1, + + DSS_CMDLIST_W0, + DSS_CMDLIST_W1, + + DSS_CMDLIST_OV0, + DSS_CMDLIST_OV1, + DSS_CMDLIST_OV2, + DSS_CMDLIST_OV3, + + DSS_CMDLIST_V2, + DSS_CMDLIST_W2, + DSS_CMDLIST_MAX, +}; + +typedef union { + struct { + uint32_t exec:1; + uint32_t last:1; + uint32_t nop:1; + uint32_t interrupt:1; + uint32_t pending:1; + uint32_t id:10; + uint32_t event_list:6; + uint32_t qos:1; + uint32_t task_end:1; + uint32_t reserved:1; + uint32_t valid_flag:8; + } bits; + uint32_t ul32; +} cmd_flag_t; + +typedef union { + struct { + uint32_t count:14; + uint32_t reserved:18; + } bits; + uint32_t ul32; +} total_items_t; + +typedef union { + struct { + uint32_t add0:18; + uint32_t add1:6; + uint32_t add2:6; + uint32_t cnt:2; + } bits; + uint32_t ul32; +} reg_addr_t; + +typedef struct cmd_item { + reg_addr_t reg_addr; + uint32_t data0; + uint32_t data1; + uint32_t data2; +} cmd_item_t; + +typedef struct cmd_header { + cmd_flag_t flag; + uint32_t next_list; + total_items_t total_items; + uint32_t list_addr; +} cmd_header_t; + +enum dss_cmdlist_node_valid { + CMDLIST_NODE_INVALID = 0x0, + CMDLIST_NODE_VALID = 0xA5, +}; + +enum dss_cmdlist_node_type { + CMDLIST_NODE_NONE = 0x0, + CMDLIST_NODE_NOP = 0x1, + CMDLIST_NODE_FRAME = 0x2, +}; + +enum dss_cmdlist_status { + e_status_idle = 0x0, + e_status_wait = 0x1, + e_status_other, +}; + +/* + ** for normal node,all variable should be filled. + ** for NOP node, just the list_header,header_ion_handle, list_node, node_flag should be filled. + ** node_type must be CMDLIST_NODE_NOP when it is NOP node. + ** And item_ion_handle in NOP node should be NULL. + */ +typedef struct dss_cmdlist_node { + struct list_head list_node; + + struct ion_handle *header_ion_handle; + ion_phys_addr_t header_phys; + cmd_header_t *list_header; + + struct ion_handle *item_ion_handle; + ion_phys_addr_t item_phys; + cmd_item_t *list_item; + + uint32_t item_index; + int item_flag; + uint32_t node_type; + int is_used; + int reserved; +} dss_cmdlist_node_t; + +typedef struct dss_cmdlist_heads { + struct list_head cmdlist_head; + + dss_cmdlist_node_t *cmdlist_nodes[HISI_DSS_CMDLIST_NODE_MAX]; +} dss_cmdlist_heads_t; + +typedef struct dss_cmdlist_data { + dss_cmdlist_heads_t *cmdlist_heads[HISI_DSS_CMDLIST_MAX]; + struct list_head cmdlist_head_temp[HISI_DSS_CMDLIST_MAX]; + dss_cmdlist_node_t + *cmdlist_nodes_temp[HISI_DSS_CMDLIST_MAX] + [HISI_DSS_CMDLIST_NODE_MAX]; +} dss_cmdlist_data_t; + +typedef struct dss_cmdlist_info { + struct semaphore cmdlist_wb_common_sem; + struct semaphore cmdlist_wb_sem[WB_TYPE_MAX]; + wait_queue_head_t cmdlist_wb_wq[WB_TYPE_MAX]; + uint32_t cmdlist_wb_done[WB_TYPE_MAX]; + uint32_t cmdlist_wb_flag[WB_TYPE_MAX]; +} dss_cmdlist_info_t; + +typedef struct dss_copybit_info { + struct semaphore copybit_sem; + wait_queue_head_t copybit_wq; + uint32_t copybit_flag; + uint32_t copybit_done; +} dss_copybit_info_t; + +typedef struct dss_wb_info { + uint32_t to_be_continued; + uint32_t cmdlist_idxs; + uint32_t wb_compose_type; + uint32_t mctl_idx; +} dss_wb_info_t; + +extern dss_cmdlist_data_t *g_cmdlist_data; + +/****************************************************************************** + ** FUNCTIONS PROTOTYPES + */ +void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *addr, uint32_t value, uint8_t bw, + uint8_t bs); +void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd, + struct ion_client *ion_client, + uint32_t cmdlist_idxs); + +dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client); +void hisi_cmdlist_node_free(struct ion_client *ion_client, + dss_cmdlist_node_t *node); + +uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); + +int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req, + uint32_t *cmdlist_pre_idxs, + uint32_t *cmdlist_idxs); +void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd); + +int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int reserved); +int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs, int pending, int task_end, + int remove, int last, uint32_t wb_type); +int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads); + +int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs, uint32_t wb_compose_type); +int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); +void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); + +int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); +int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd, + uint32_t cmdlist_idxs); + +int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs); +void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd); +int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, uint32_t cmdlist_idxs); + +int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd); +int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd); + +#endif -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 7/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei ` (5 preceding siblings ...) (?) @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- drivers/video/fbdev/hisi/dss/hisi_overlay_online.c | 733 ++ drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c | 8495 ++++++++++++++++++++ drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h | 269 + .../fbdev/hisi/dss/hisi_overlay_utils_hi3660.c | 2741 +++++++ .../fbdev/hisi/dss/hisi_overlay_utils_hi3660.h | 73 + 5 files changed, 12311 insertions(+) create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_online.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c new file mode 100755 index 000000000000..9cb65225dc63 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_online.c @@ -0,0 +1,733 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_overlay_utils.h" +#include "hisi_dpe_utils.h" + +static int hisi_get_ov_data_from_user(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + void __user *argp) +{ + int ret = 0; + dss_overlay_block_t *pov_h_block_infos = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (NULL == argp) { + HISI_FB_ERR("user data is invalid\n"); + return -EINVAL; + } + pov_h_block_infos = hisifd->ov_block_infos; + + ret = copy_from_user(pov_req, argp, sizeof(dss_overlay_t)); + if (ret) { + HISI_FB_ERR("fb%d, copy_from_user failed!\n", hisifd->index); + return -EINVAL; + } + + if ((pov_req->ov_block_nums <= 0) || + (pov_req->ov_block_nums > HISI_DSS_OV_BLOCK_NUMS)) { + HISI_FB_ERR("fb%d, ov_block_nums(%d) is out of range!\n", + hisifd->index, pov_req->ov_block_nums); + return -EINVAL; + } + + ret = + copy_from_user(pov_h_block_infos, + (dss_overlay_block_t *) pov_req->ov_block_infos_ptr, + pov_req->ov_block_nums * + sizeof(dss_overlay_block_t)); + if (ret) { + HISI_FB_ERR + ("fb%d, dss_overlay_block_t copy_from_user failed!\n", + hisifd->index); + return -EINVAL; + } + + ret = hisi_dss_check_userdata(hisifd, pov_req, pov_h_block_infos); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_check_userdata failed!\n", + hisifd->index); + return -EINVAL; + } + + pov_req->ov_block_infos_ptr = (uint64_t) pov_h_block_infos; + + return ret; +} + +int hisi_overlay_pan_display(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + struct fb_info *fbi = NULL; + dss_overlay_t *pov_req = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + dss_rect_ltrb_t clip_rect; + dss_rect_t aligned_rect; + bool rdma_stretch_enable = false; + uint32_t offset = 0; + uint32_t addr = 0; + int hal_format = 0; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + bool has_base = false; + + if (NULL == hisifd) { + HISI_FB_ERR("hisi fd is invalid\n"); + return -EINVAL; + } + fbi = hisifd->fbi; + if (NULL == fbi) { + HISI_FB_ERR("hisifd fbi is invalid\n"); + return -EINVAL; + } + + pov_req = &(hisifd->ov_req); + pov_req_prev = &(hisifd->ov_req_prev); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + return 0; + } + + if (g_debug_ldi_underflow) { + if (g_err_status & + (DSS_PDP_LDI_UNDERFLOW | DSS_SDP_LDI_UNDERFLOW)) + return 0; + } + + offset = fbi->var.xoffset * (fbi->var.bits_per_pixel >> 3) + + fbi->var.yoffset * fbi->fix.line_length; + addr = fbi->fix.smem_start + offset; + if (!fbi->fix.smem_start) { + HISI_FB_ERR("fb%d, smem_start is null!\n", hisifd->index); + return -EINVAL; + } + + if (fbi->fix.smem_len <= 0) { + HISI_FB_ERR("fb%d, smem_len(%d) is out of range!\n", + hisifd->index, fbi->fix.smem_len); + return -EINVAL; + } + + hal_format = hisi_get_hal_format(fbi); + if (hal_format < 0) { + HISI_FB_ERR("fb%d, not support this fb_info's format!\n", + hisifd->index); + return -EINVAL; + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + hisifb_activate_vsync(hisifd); + + ret = hisi_vactive0_start_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_vactive0_start_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (g_debug_ovl_online_composer == 1) { + dumpDssOverlay(hisifd, pov_req, false); + } + + memset(pov_req, 0, sizeof(dss_overlay_t)); + pov_req->ov_block_infos_ptr = (uint64_t) (&(hisifd->ov_block_infos)); + pov_req->ov_block_nums = 1; + pov_req->ovl_idx = DSS_OVL0; + pov_req->dirty_rect.x = 0; + pov_req->dirty_rect.y = 0; + pov_req->dirty_rect.w = fbi->var.xres; + pov_req->dirty_rect.h = fbi->var.yres; + + pov_req->res_updt_rect.x = 0; + pov_req->res_updt_rect.y = 0; + pov_req->res_updt_rect.w = fbi->var.xres; + pov_req->res_updt_rect.h = fbi->var.yres; + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + pov_h_block = &(pov_h_block_infos[0]); + pov_h_block->layer_nums = 1; + + layer = &(pov_h_block->layer_infos[0]); + layer->img.format = hal_format; + layer->img.width = fbi->var.xres; + layer->img.height = fbi->var.yres; + layer->img.bpp = fbi->var.bits_per_pixel >> 3; + layer->img.stride = fbi->fix.line_length; + layer->img.buf_size = layer->img.stride * layer->img.height; + layer->img.phy_addr = addr; + layer->img.vir_addr = addr; + layer->img.mmu_enable = 1; + layer->src_rect.x = 0; + layer->src_rect.y = 0; + layer->src_rect.w = fbi->var.xres; + layer->src_rect.h = fbi->var.yres; + layer->dst_rect.x = 0; + layer->dst_rect.y = 0; + layer->dst_rect.w = fbi->var.xres; + layer->dst_rect.h = fbi->var.yres; + layer->transform = HISI_FB_TRANSFORM_NOP; + layer->blending = HISI_FB_BLENDING_NONE; + layer->glb_alpha = 0xFF; + layer->color = 0x0; + layer->layer_idx = 0x0; + layer->chn_idx = DSS_RCHN_D2; + layer->need_cap = 0; + + hisi_dss_handle_cur_ovl_req(hisifd, pov_req); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_mmbuf_info_get_online(hisifd); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req_prev failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req, &cmdlist_pre_idxs, + &cmdlist_idxs); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, pov_req->ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, cmdlist_pre_idxs, + enable_cmdlist, NULL); + + hisi_dss_aif_handler(hisifd, pov_req, pov_h_block); + + ret = + hisi_dss_ovl_base_config(hisifd, pov_req, NULL, NULL, + pov_req->ovl_idx, 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_ovl_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_ov_compose_handler(hisifd, pov_req, pov_h_block, layer, NULL, + NULL, &clip_rect, &aligned_rect, + &rdma_stretch_enable, &has_base, true, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR("hisi_ov_compose_handler failed! ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, pov_req, pov_req->ovl_idx, has_base, + true); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_mctl_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (hisifd->panel_info.dirty_region_updt_support) { + ret = hisi_dss_dirty_region_dbuf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + ret = hisi_dss_post_scf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_post_scf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, pov_req, pov_req->ovl_idx, + enable_cmdlist, 0, 0, true); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_dss_unflow_handler(hisifd, pov_req, true); + + if (enable_cmdlist) { + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, cmdlist_idxs); + } + + hisi_cmdlist_config_start(hisifd, pov_req->ovl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, pov_req->ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, pov_req); + } + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + + hisifb_deactivate_vsync(hisifd); + + hisifd->frame_count++; + memcpy(&hisifd->ov_req_prev_prev, &hisifd->ov_req_prev, + sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev_prev), + &(hisifd->ov_block_infos_prev), + hisifd->ov_req_prev.ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev_prev)); + + memcpy(&hisifd->ov_req_prev, pov_req, sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev), &(hisifd->ov_block_infos), + pov_req->ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + + return 0; + + err_return: + if (is_mipi_cmd_panel(hisifd)) { + hisifd->vactive0_start_flag = 1; + } else { + single_frame_update(hisifd); + } + hisifb_deactivate_vsync(hisifd); + + return ret; +} + +int hisi_ov_online_play(struct hisi_fb_data_type *hisifd, void __user *argp) +{ + static int dss_free_buffer_refcount; + dss_overlay_t *pov_req = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + dss_rect_ltrb_t clip_rect; + dss_rect_t aligned_rect; + bool rdma_stretch_enable = false; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + bool has_base = false; +#ifdef CONFIG_BUF_SYNC_USED + unsigned long flags = 0; +#endif + int need_skip = 0; + int i = 0; + int m = 0; + int ret = 0; + uint32_t timediff = 0; + struct list_head lock_list; + struct timeval tv0; + struct timeval tv1; + struct timeval tv2; + struct timeval tv3; + + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + if (NULL == argp) { + HISI_FB_ERR("NULL Pointer!\n"); + return -EINVAL; + } + + pov_req = &(hisifd->ov_req); + pov_req_prev = &(hisifd->ov_req_prev); + INIT_LIST_HEAD(&lock_list); + + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!\n", hisifd->index); + return 0; + } + + if (g_debug_ovl_online_composer_return) { + return 0; + } + + if (g_debug_ovl_online_composer_timediff & 0x2) { + hisifb_get_timestamp(&tv0); + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) { + enable_cmdlist = 0; + } + + hisifb_activate_vsync(hisifd); + + if (g_debug_ovl_online_composer_timediff & 0x4) { + hisifb_get_timestamp(&tv2); + } + + ret = hisi_get_ov_data_from_user(hisifd, pov_req, argp); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_get_ov_data_from_user failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } +#ifdef CONFIG_BUF_SYNC_USED + if (is_mipi_video_panel(hisifd)) { + ret = hisifb_buf_sync_handle(hisifd, pov_req); + if (ret < 0) { + HISI_FB_ERR + ("fb%d, hisifb_buf_sync_handle failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } + } +#endif + + ret = hisi_vactive0_start_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_vactive0_start_config failed! ret=%d\n", + hisifd->index, ret); + need_skip = 1; + goto err_return; + } + down(&hisifd->blank_sem0); + + if (g_debug_ovl_online_composer_timediff & 0x4) { + hisifb_get_timestamp(&tv3); + timediff = hisifb_timestamp_diff(&tv2, &tv3); + if (timediff >= g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR("ONLINE_VACTIVE_TIMEDIFF is %u us!\n", + timediff); + } + + if (g_debug_ovl_online_composer == 1) { + dumpDssOverlay(hisifd, pov_req, false); + } + + ret = hisifb_layerbuf_lock(hisifd, pov_req, &lock_list); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisifb_layerbuf_lock failed! ret=%d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_dss_handle_cur_ovl_req(hisifd, pov_req); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_mmbuf_info_get_online(hisifd); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req_prev failed! " + "ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req, &cmdlist_pre_idxs, + &cmdlist_idxs); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs pov_req failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + hisi_dss_mctl_mutex_lock(hisifd, pov_req->ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, cmdlist_pre_idxs, + enable_cmdlist, NULL); + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_module_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + hisi_dss_aif_handler(hisifd, pov_req, pov_h_block); + + ret = + hisi_dss_ovl_base_config(hisifd, pov_req, pov_h_block, NULL, + pov_req->ovl_idx, m); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_ovl_init failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + memset(&clip_rect, 0, sizeof(dss_rect_ltrb_t)); + memset(&aligned_rect, 0, sizeof(dss_rect_ltrb_t)); + rdma_stretch_enable = false; + + ret = + hisi_ov_compose_handler(hisifd, pov_req, + pov_h_block, layer, NULL, + NULL, &clip_rect, + &aligned_rect, + &rdma_stretch_enable, + &has_base, true, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_ov_compose_handler failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + ret = + hisi_dss_mctl_ov_config(hisifd, pov_req, pov_req->ovl_idx, + has_base, (m == 0)); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_mctl_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + if (m == 0) { + if (hisifd->panel_info.dirty_region_updt_support) { + ret = + hisi_dss_dirty_region_dbuf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + } + + ret = hisi_dss_post_scf_config(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_post_scf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, pov_req, + pov_req->ovl_idx, + enable_cmdlist, 0, 0, (m == 0)); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_module_config failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + } + + if (enable_cmdlist) { + g_online_cmdlist_idxs |= cmdlist_idxs; + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + } + + ret = hisi_crc_enable(hisifd, pov_req); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_crc_enable failed!\n", hisifd->index); + goto err_return; + } + hisi_dss_unflow_handler(hisifd, pov_req, true); + +#ifdef CONFIG_BUF_SYNC_USED + if (is_mipi_cmd_panel(hisifd)) { + ret = hisifb_buf_sync_handle(hisifd, pov_req); + if (ret < 0) { + HISI_FB_ERR + ("fb%d, hisifb_buf_sync_handle failed! ret=%d\n", + hisifd->index, ret); + goto err_return; + } + } + + pov_req->release_fence = + hisifb_buf_sync_create_fence(hisifd, + ++hisifd->buf_sync_ctrl.timeline_max); + if (pov_req->release_fence < 0) { + HISI_FB_INFO + ("fb%d, hisi_create_fence failed! pov_req->release_fence = 0x%x\n", + hisifd->index, pov_req->release_fence); + } + + spin_lock_irqsave(&hisifd->buf_sync_ctrl.refresh_lock, flags); + hisifd->buf_sync_ctrl.refresh++; + spin_unlock_irqrestore(&hisifd->buf_sync_ctrl.refresh_lock, flags); +#endif + + if (enable_cmdlist) { + hisi_cmdlist_config_start(hisifd, pov_req->ovl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, pov_req->ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, pov_req); + } + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + hisi_crc_config(hisifd, pov_req); + + if (copy_to_user((struct dss_overlay_t __user *)argp, + pov_req, sizeof(dss_overlay_t))) { + ret = -EFAULT; + + if (pov_req->release_fence >= 0) + put_unused_fd(pov_req->release_fence); + + goto err_return; + } + + hisifb_deactivate_vsync(hisifd); + hisifb_layerbuf_flush(hisifd, &lock_list); + + if ((hisifd->index == PRIMARY_PANEL_IDX) + && (dss_free_buffer_refcount > 1)) { + if (!hisifd->fb_mem_free_flag) { + hisifb_free_fb_buffer(hisifd); + hisifd->fb_mem_free_flag = true; + } + } + + if (g_debug_ovl_online_composer == 2) { + dumpDssOverlay(hisifd, pov_req, true); + } + + if (g_debug_ovl_cmdlist && enable_cmdlist) + hisi_cmdlist_dump_all_node(hisifd, NULL, cmdlist_idxs); + + hisifd->frame_count++; + dss_free_buffer_refcount++; + memcpy(&hisifd->ov_req_prev_prev, &hisifd->ov_req_prev, + sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev_prev), + &(hisifd->ov_block_infos_prev), + hisifd->ov_req_prev.ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev_prev)); + + memcpy(&hisifd->ov_req_prev, pov_req, sizeof(dss_overlay_t)); + memcpy(&(hisifd->ov_block_infos_prev), &(hisifd->ov_block_infos), + pov_req->ov_block_nums * sizeof(dss_overlay_block_t)); + hisifd->ov_req_prev.ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + + if (g_debug_ovl_online_composer_timediff & 0x2) { + hisifb_get_timestamp(&tv1); + timediff = hisifb_timestamp_diff(&tv0, &tv1); + if (timediff >= g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR("ONLINE_TIMEDIFF is %u us!\n", timediff); + } + up(&hisifd->blank_sem0); + + return 0; + + err_return: + if (is_mipi_cmd_panel(hisifd)) { + hisifd->vactive0_start_flag = 1; + } + hisifb_layerbuf_lock_exception(hisifd, &lock_list); + hisifb_deactivate_vsync(hisifd); + if (!need_skip) { + up(&hisifd->blank_sem0); + } + return ret; +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c new file mode 100755 index 000000000000..97d71df5a38d --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.c @@ -0,0 +1,8495 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +/*lint -e778 -e732*/ + +#include "hisi_overlay_utils.h" +#include "hisi_dpe_utils.h" + +#define SMMU_RW_ERR_ADDR_SIZE (128) + +/* mmbuf gen pool */ +static struct gen_pool *g_mmbuf_gen_pool = NULL; +static dss_mmbuf_t g_pre_online_mmbuf[DSS_CHN_MAX_DEFINE] = { {0, 0} }; + +static uint32_t vactive_timeout_count = 0; + +static inline bool hisi_dss_is_sharpness_support(int32_t width, int32_t height) +{ + return ((16 <= width) && (width <= 1600) && (4 <= height) + && (height <= 2560)); +} + +/******************************************************************************* + ** + */ +static int32_t hisi_transform2degree(uint32_t transform) +{ + int ret = 0; + + switch (transform) { + case HISI_FB_TRANSFORM_NOP: + case HISI_FB_TRANSFORM_FLIP_H: + case HISI_FB_TRANSFORM_FLIP_V: + ret = 0; + break; + case HISI_FB_TRANSFORM_ROT_90: + ret = 90; + break; + case HISI_FB_TRANSFORM_ROT_180: + ret = 180; + break; + case HISI_FB_TRANSFORM_ROT_270: + ret = 270; + break; + default: + ret = -1; + HISI_FB_ERR("not support transform(%d)!", transform); + break; + } + + return ret; +} + +#define DUMP_BUF_SIZE SZ_256K + +struct dss_dump_data_type { + char *dss_buf; + uint32_t dss_buf_len; + char dss_filename[256]; + + char *scene_buf; + uint32_t scene_buf_len; + char scene_filename[256]; + + char image_bin_filename[MAX_DSS_SRC_NUM][256]; +}; + +void dumpDssOverlay(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req, + bool isNeedSaveFile) +{ + uint32_t i = 0; + uint32_t k = 0; + dss_layer_t const *layer = NULL; + dss_wb_layer_t const *wb_layer = NULL; + struct timeval tv; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_block_info = NULL; + + struct dss_dump_data_type *dumpDss = NULL; + char *image_src_addr = NULL; + struct ion_handle *ionhnd = NULL; + + static const char *const layer_format[] = { + "RGB565", "RGBX4444", "RGBA4444", "RGBX5551", "RGBA5551", + "RGBX8888", "RGBA8888", + "BGR565", "BGRX4444", "BGRA4444", "BGRX5551", "BGRA5551", + "BGRX8888", "BGRA8888", + "YCbYCr", "", "", "NV12", "NV21", "", "", "", "YV12", "", "" + }; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((pov_req->ovl_idx < DSS_OVL0) + || (pov_req->ovl_idx >= DSS_OVL_IDX_MAX)); + + dumpDss = kmalloc(sizeof(struct dss_dump_data_type), GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss)) { + HISI_FB_ERR("alloc dumpDss failed!\n"); + goto alloc_dump_dss_data_err; + } + memset(dumpDss, 0, sizeof(struct dss_dump_data_type)); + + if (isNeedSaveFile) { + hisifb_get_timestamp(&tv); + snprintf(dumpDss->scene_filename, + sizeof(dumpDss->scene_filename), + "/data/dssdump/Scene_%ld.sce", tv.tv_sec); + snprintf(dumpDss->dss_filename, sizeof(dumpDss->dss_filename), + "/data/dssdump/Dss_%ld.txt", tv.tv_sec); + + + dumpDss->scene_buf_len = 0; + dumpDss->scene_buf = kmalloc(DUMP_BUF_SIZE, GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss->scene_buf)) { + HISI_FB_ERR("alloc scene_buf failed!\n"); + goto alloc_scene_buf_err; + } + memset(dumpDss->scene_buf, 0, DUMP_BUF_SIZE); + } + + dumpDss->dss_buf_len = 0; + dumpDss->dss_buf = kmalloc(DUMP_BUF_SIZE, GFP_KERNEL); + if (IS_ERR_OR_NULL(dumpDss->dss_buf)) { + HISI_FB_ERR("alloc dss_buf failed!\n"); + goto alloc_dss_buf_err; + } + memset(dumpDss->dss_buf, 0, DUMP_BUF_SIZE); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\n\n----------------------------<dump begin>----------------------------\n" + "frame_no=%d\n" "ovl_idx=%d\n" + "res_updt_rect(%d, %d, %d, %d)\n" + "dirty_rect(%d,%d, %d,%d)\n" "release_fence=%d\n" + "crc_enable_status=%d\n" "crc_info(%d,%d)\n" + "ov_block_nums=%d\n" "ov_block_infos_ptr=0x%llx\n" + "wb_enable=%d\n" "wb_layer_nums=%d\n" + "wb_ov_rect(%d,%d, %d,%d)\n", pov_req->frame_no, + pov_req->ovl_idx, pov_req->res_updt_rect.x, + pov_req->res_updt_rect.y, pov_req->res_updt_rect.w, + pov_req->res_updt_rect.h, pov_req->dirty_rect.x, + pov_req->dirty_rect.y, pov_req->dirty_rect.w, + pov_req->dirty_rect.h, pov_req->release_fence, + pov_req->crc_enable_status, + pov_req->crc_info.crc_ov_result, + pov_req->crc_info.err_status, pov_req->ov_block_nums, + pov_req->ov_block_infos_ptr, pov_req->wb_enable, + pov_req->wb_layer_nums, pov_req->wb_ov_rect.x, + pov_req->wb_ov_rect.y, pov_req->wb_ov_rect.w, + pov_req->wb_ov_rect.h); + + for (i = 0; i < pov_req->ov_block_nums; i++) { + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + pov_block_info = &(pov_h_block_infos[i]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\nov_block_rect(%d,%d, %d,%d)\n" + "layer_nums=%d\n", pov_block_info->ov_block_rect.x, + pov_block_info->ov_block_rect.y, + pov_block_info->ov_block_rect.w, + pov_block_info->ov_block_rect.h, + pov_block_info->layer_nums); + + for (k = 0; k < pov_block_info->layer_nums; k++) { + layer = &(pov_block_info->layer_infos[k]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, + 4 * SZ_1K, + "\nLayerInfo[%d]:\n" "format=%d\n" + "width=%d\n" "height=%d\n" "bpp=%d\n" + "buf_size=%d\n" "stride=%d\n" + "stride_plane1=0x%x\n" + "stride_plane2=0x%x\n" "phy_addr=0x%llx\n" + "vir_addr=0x%llx\n" "offset_plane1=%d\n" + "offset_plane2=%d\n" + "afbc_header_addr=0x%llx\n" + "afbc_payload_addr=0x%llx\n" + "afbc_header_stride=%d\n" + "afbc_payload_stride=%d\n" + "afbc_scramble_mode=%d\n" + "mmbuf_base=0x%x\n" "mmbuf_size=%d\n" + "mmu_enable=%d\n" "csc_mode=%d\n" + "secure_mode=%d\n" "shared_fd=%d\n" + "src_rect(%d,%d, %d,%d)\n" + "src_rect_mask(%d,%d, %d,%d)\n" + "dst_rect(%d,%d, %d,%d)\n" "transform=%d\n" + "blending=%d\n" "glb_alpha=0x%x\n" + "color=0x%x\n" "layer_idx=%d\n" + "chn_idx=%d\n" "need_cap=0x%x\n" + "acquire_fence=%d\n", k, layer->img.format, + layer->img.width, layer->img.height, + layer->img.bpp, layer->img.buf_size, + layer->img.stride, + layer->img.stride_plane1, + layer->img.stride_plane2, + layer->img.phy_addr, layer->img.vir_addr, + layer->img.offset_plane1, + layer->img.offset_plane2, + layer->img.afbc_header_addr, + layer->img.afbc_payload_addr, + layer->img.afbc_header_stride, + layer->img.afbc_payload_stride, + layer->img.afbc_scramble_mode, + layer->img.mmbuf_base, + layer->img.mmbuf_size, + layer->img.mmu_enable, layer->img.csc_mode, + layer->img.secure_mode, + layer->img.shared_fd, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->src_rect_mask.x, + layer->src_rect_mask.y, + layer->src_rect_mask.w, + layer->src_rect_mask.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, layer->transform, + layer->blending, layer->glb_alpha, + layer->color, layer->layer_idx, + layer->chn_idx, layer->need_cap, + layer->acquire_fence); + + + if (isNeedSaveFile) { + if (layer->dst_rect.y < + pov_block_info->ov_block_rect.y) + continue; + + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, SZ_1K, + "[BaseColor]=0x%x\n" + "[ScreenSize]=(%u,%u)\n\n" + "[BlendMode]=%d\n" "[Caption]=\n" + "[Channel]=%u\n" + "[CropLoc]=(%u,%u)\n" + "[CropSize]=(%u,%u)\n" + "[FlipHV]=(%u,%u)\n" + "[Format]=%s\n" + "[GlobalAlpha]=%u\n", + hisifd->dss_module.ov[pov_req-> + ovl_idx]. + ovl_bg_color, + get_panel_xres(hisifd), + get_panel_yres(hisifd), + layer->blending, layer->chn_idx, 0, + 0, layer->src_rect.w, + layer->src_rect.h, + (layer-> + transform & + HISI_FB_TRANSFORM_FLIP_H), + (layer-> + transform & + HISI_FB_TRANSFORM_FLIP_V), + layer_format[layer->img.format], + layer->glb_alpha); + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR | + CAP_BASE)) { + if (layer->need_cap & CAP_BASE) { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[BaseColor]=0x%x\n", + layer->color); + } else if (layer->need_cap & CAP_PURE_COLOR) { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[Color]=0x%x\n", + layer->color); + } + } else { + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, + SZ_1K, + "[ImageSource]=pic%d_%ld.bin\n", + k, tv.tv_sec); + } + + dumpDss->scene_buf_len += + snprintf(dumpDss->scene_buf + + dumpDss->scene_buf_len, SZ_1K, + "[Location]=(%u,%u)\n" + "[Rotate]=%u\n" "[Scale]=(%u,%u)\n" + "[Size]=(%u,%u)\n\n", + layer->dst_rect.x, + layer->dst_rect.y, + hisi_transform2degree(layer->transform), + layer->dst_rect.w, + layer->dst_rect.h, + layer->dst_rect.w, + layer->dst_rect.h); + + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR | + CAP_BASE)) + continue; + + if (layer->img.shared_fd < 0) + continue; + + ionhnd = + ion_import_dma_buf(hisifd->ion_client, + layer->img.shared_fd); + if (IS_ERR(ionhnd)) { + HISI_FB_ERR + ("ion import dma buf err, ionclient %p, share_fd %d, layer index %d", + hisifd->ion_client, + layer->img.shared_fd, i); + continue; + } + + snprintf(dumpDss->image_bin_filename[k], + sizeof(dumpDss->image_bin_filename[k]), + "/data/dssdump/pic%d_%ld.bin", k, + tv.tv_sec); + + image_src_addr = + ion_map_kernel(hisifd->ion_client, ionhnd); + if (image_src_addr) { + hisifb_save_file(dumpDss->image_bin_filename[k], + image_src_addr, + layer->img.buf_size); + ion_unmap_kernel(hisifd->ion_client, ionhnd); + } + + ion_free(hisifd->ion_client, ionhnd); + ionhnd = NULL; + } + } + } + + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "\nWbLayerInfo[%d]:\n" "format=%d\n" "width=%d\n" + "height=%d\n" "bpp=%d\n" "buf_size=%d\n" + "stride=%d\n" "stride_plane1=%d\n" + "stride_plane2=%d\n" "phy_addr=0x%llx\n" + "vir_addr=0x%llx\n" "offset_plane1=%d\n" + "offset_plane2=%d\n" "afbc_header_addr=0x%llx\n" + "afbc_payload_addr=0x%llx\n" + "afbc_header_stride=%d\n" + "afbc_payload_stride=%d\n" + "afbc_scramble_mode=%d\n" "mmbuf_base=0x%x\n" + "mmbuf_size=%d\n" "mmu_enable=%d\n" "csc_mode=%d\n" + "secure_mode=%d\n" "shared_fd=%d\n" + "src_rect(%d,%d, %d,%d)\n" + "dst_rect(%d,%d, %d,%d)\n" "transform=%d\n" + "chn_idx=%d\n" "need_cap=0x%x\n" + "acquire_fence=%d\n" "release_fence=%d\n", k, + wb_layer->dst.format, wb_layer->dst.width, + wb_layer->dst.height, wb_layer->dst.bpp, + wb_layer->dst.buf_size, wb_layer->dst.stride, + wb_layer->dst.stride_plane1, + wb_layer->dst.stride_plane2, + wb_layer->dst.phy_addr, wb_layer->dst.vir_addr, + wb_layer->dst.offset_plane1, + wb_layer->dst.offset_plane2, + wb_layer->dst.afbc_header_addr, + wb_layer->dst.afbc_payload_addr, + wb_layer->dst.afbc_header_stride, + wb_layer->dst.afbc_payload_stride, + wb_layer->dst.afbc_scramble_mode, + wb_layer->dst.mmbuf_base, wb_layer->dst.mmbuf_size, + wb_layer->dst.mmu_enable, wb_layer->dst.csc_mode, + wb_layer->dst.secure_mode, wb_layer->dst.shared_fd, + wb_layer->src_rect.x, wb_layer->src_rect.y, + wb_layer->src_rect.w, wb_layer->src_rect.h, + wb_layer->dst_rect.x, wb_layer->dst_rect.y, + wb_layer->dst_rect.w, wb_layer->dst_rect.h, + wb_layer->transform, wb_layer->chn_idx, + wb_layer->need_cap, wb_layer->acquire_fence, + wb_layer->release_fence); + } + + dumpDss->dss_buf_len += + snprintf(dumpDss->dss_buf + dumpDss->dss_buf_len, 4 * SZ_1K, + "----------------------------<dump end>----------------------------\n\n"); + + for (k = 0; k < dumpDss->dss_buf_len; k += 255) { + printk("%.255s", dumpDss->dss_buf + k); + } + + if (isNeedSaveFile) { + if (dumpDss->scene_buf) + hisifb_save_file(dumpDss->scene_filename, + dumpDss->scene_buf, + dumpDss->scene_buf_len); + + if (dumpDss->dss_buf) + hisifb_save_file(dumpDss->dss_filename, + dumpDss->dss_buf, + dumpDss->dss_buf_len); + } + + if (dumpDss->dss_buf) { + kfree(dumpDss->dss_buf); + dumpDss->dss_buf = NULL; + dumpDss->dss_buf_len = 0; + } + + alloc_dss_buf_err: + if (dumpDss->scene_buf) { + kfree(dumpDss->scene_buf); + dumpDss->scene_buf = NULL; + dumpDss->scene_buf_len = 0; + } + + alloc_scene_buf_err: + if (dumpDss) { + kfree(dumpDss); + dumpDss = NULL; + } + + alloc_dump_dss_data_err: + return; +} + +static int hisi_dss_lcd_refresh_direction_layer(struct hisi_fb_data_type + *hisifd, + dss_overlay_t *pov_req, + dss_layer_t *layer) +{ + struct hisi_panel_info *pinfo = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(layer == NULL); + + pinfo = &(hisifd->panel_info); + + if ((pov_req->ovl_idx != DSS_OVL0) && (pov_req->ovl_idx != DSS_OVL1)) + return 0; + + if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_TOP) { + ; + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_RIGHT_TOP) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.x = + (pov_req->dirty_rect.w - + (layer->dst_rect.x + layer->dst_rect.w)); + } else { + layer->dst_rect.x = + (get_panel_xres(hisifd) - + (layer->dst_rect.x + layer->dst_rect.w)); + } + } + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_BOTTOM) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.y = + (pov_req->dirty_rect.h - + (layer->dst_rect.y + layer->dst_rect.h)); + } else { + layer->dst_rect.y = + (get_panel_yres(hisifd) - + (layer->dst_rect.y + layer->dst_rect.h)); + } + } + } else if (pinfo->lcd_refresh_direction_ctrl == + LCD_REFRESH_RIGHT_BOTTOM) { + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + layer->transform = HISI_FB_TRANSFORM_ROT_180; + break; + case HISI_FB_TRANSFORM_FLIP_H: + layer->transform = HISI_FB_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_FLIP_V: + layer->transform = HISI_FB_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_ROT_90: + layer->transform = HISI_FB_TRANSFORM_ROT_270; + break; + case HISI_FB_TRANSFORM_ROT_180: + layer->transform = HISI_FB_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_ROT_270: + layer->transform = HISI_FB_TRANSFORM_ROT_90; + break; + + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H): + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V); + break; + case (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V): + layer->transform = + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_H); + break; + + default: + HISI_FB_ERR("not support this transform(%d).\n", + layer->transform); + ret = -1; + break; + } + + if (ret == 0) { + if ((pinfo->dirty_region_updt_support == 1) && + (pov_req->dirty_rect.w > 0) && + (pov_req->dirty_rect.h > 0)) { + layer->dst_rect.x = + (pov_req->dirty_rect.w - + (layer->dst_rect.x + layer->dst_rect.w)); + layer->dst_rect.y = + (pov_req->dirty_rect.h - + (layer->dst_rect.y + layer->dst_rect.h)); + } else { + layer->dst_rect.x = + (get_panel_xres(hisifd) - + (layer->dst_rect.x + layer->dst_rect.w)); + layer->dst_rect.y = + (get_panel_yres(hisifd) - + (layer->dst_rect.y + layer->dst_rect.h)); + } + } + } else { + HISI_FB_ERR + ("fb%d, not support this lcd_refresh_direction_ctrl(%d)!\n", + hisifd->index, pinfo->lcd_refresh_direction_ctrl); + ret = -1; + } + + return ret; +} + +static int hisi_dss_lcd_refresh_direction_dirty_region(struct hisi_fb_data_type + *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + pinfo = &(hisifd->panel_info); + if ((pov_req->ovl_idx != DSS_OVL0) && (pov_req->ovl_idx != DSS_OVL1)) + return 0; + + if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_TOP) { + ; + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_RIGHT_TOP) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.x = + (get_panel_xres(hisifd) - + (pov_req->dirty_rect.x + pov_req->dirty_rect.w)); + } + } else if (pinfo->lcd_refresh_direction_ctrl == LCD_REFRESH_LEFT_BOTTOM) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.y = + (get_panel_yres(hisifd) - + (pov_req->dirty_rect.y + pov_req->dirty_rect.h)); + } + } else if (pinfo->lcd_refresh_direction_ctrl == + LCD_REFRESH_RIGHT_BOTTOM) { + if (pinfo->dirty_region_updt_support == 1) { + pov_req->dirty_rect.x = + (get_panel_xres(hisifd) - + (pov_req->dirty_rect.x + pov_req->dirty_rect.w)); + pov_req->dirty_rect.y = + (get_panel_yres(hisifd) - + (pov_req->dirty_rect.y + pov_req->dirty_rect.h)); + } + } else { + HISI_FB_ERR + ("fb%d, not support this lcd_refresh_direction_ctrl(%d)!\n", + hisifd->index, pinfo->lcd_refresh_direction_ctrl); + ret = -1; + } + + return ret; +} + +int hisi_dss_handle_cur_ovl_req(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + int i = 0; + int m = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + pinfo = &(hisifd->panel_info); + + hisifd->resolution_rect = pov_req->res_updt_rect; + + pov_h_block_infos = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + + hisi_dss_lcd_refresh_direction_layer(hisifd, pov_req, + layer); + } + } + hisi_dss_lcd_refresh_direction_dirty_region(hisifd, pov_req); + + return 0; +} + +/******************************************************************************* + ** + */ +int hisi_get_hal_format(struct fb_info *info) +{ + struct fb_var_screeninfo *var = NULL; + int hal_format = 0; + + BUG_ON(info == NULL); + var = &info->var; + + switch (var->bits_per_pixel) { + case 16: + if (var->blue.offset == 0) { + if (var->red.offset == 8) { + hal_format = (var->transp.offset == 12) ? + HISI_FB_PIXEL_FORMAT_BGRA_4444 : + HISI_FB_PIXEL_FORMAT_BGRX_4444; + } else if (var->red.offset == 10) { + hal_format = (var->transp.offset == 12) ? + HISI_FB_PIXEL_FORMAT_BGRA_5551 : + HISI_FB_PIXEL_FORMAT_BGRX_5551; + } else if (var->red.offset == 11) { + hal_format = HISI_FB_PIXEL_FORMAT_RGB_565; + } + } + break; + + case 32: + if (var->blue.offset == 0) { + /* BUGFIX: Modified for Standard Android Format */ + /* hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_BGRA_8888 : HISI_FB_PIXEL_FORMAT_BGRX_8888; */ + hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_RGBA_8888 : + HISI_FB_PIXEL_FORMAT_RGBX_8888; + } else { + hal_format = (var->transp.length == 8) ? + HISI_FB_PIXEL_FORMAT_RGBA_8888 : + HISI_FB_PIXEL_FORMAT_RGBX_8888; + } + break; + + default: + goto err_return; + } + + return hal_format; + + err_return: + HISI_FB_ERR("not support this bits_per_pixel(%d)!\n", + var->bits_per_pixel); + return -1; +} + +static bool hal_format_has_alpha(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + return true; + + default: + return false; + } +} + +bool isYUVPackage(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + return true; + + default: + return false; + } +} + +bool isYUVSemiPlanar(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + return true; + + default: + return false; + } +} + +bool isYUVPlanar(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return true; + + default: + return false; + } +} + +bool isYUV(uint32_t format) +{ + return isYUVPackage(format) || + isYUVSemiPlanar(format) || isYUVPlanar(format); +} + +bool is_YUV_SP_420(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + return true; + + default: + return false; + } +} + +bool is_YUV_SP_422(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + return true; + + default: + return false; + } +} + +bool is_YUV_P_420(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return true; + + default: + return false; + } +} + +bool is_YUV_P_422(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + return true; + + default: + return false; + } +} + +bool is_RGBX(uint32_t format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + return true; + + default: + return false; + } +} + +bool isNeedDither(int fmt) +{ + return (fmt == DFC_PIXEL_FORMAT_RGB_565) || + (fmt == DFC_PIXEL_FORMAT_BGR_565); +} + +static bool isNeedRectClip(dss_rect_ltrb_t clip_rect) +{ + return ((clip_rect.left > 0) || (clip_rect.top > 0) || + (clip_rect.right > 0) || (clip_rect.bottom > 0)); +} + +static bool isSrcRectMasked(dss_layer_t *layer, int aligned_pixel) +{ + BUG_ON(layer == NULL); + + return ((layer->src_rect_mask.w != 0) && + (layer->src_rect_mask.h != 0) && + (ALIGN_DOWN + (layer->src_rect_mask.x + layer->src_rect_mask.w, + aligned_pixel) > 1)); +} + +static uint32_t isNeedRdmaStretchBlt(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer) +{ + uint32_t v_stretch_ratio_threshold = 0; + uint32_t v_stretch_ratio = 0; + + BUG_ON(layer == NULL); + + if (layer->need_cap & CAP_AFBCD) { +#if 0 + v_stretch_ratio = layer->src_rect.h / layer->dst_rect.h; + if (v_stretch_ratio < 2) + v_stretch_ratio = 0; +#else + v_stretch_ratio = 0; +#endif + } else { + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + v_stretch_ratio_threshold = + ((layer->src_rect.h + layer->dst_rect.h - + 1) / layer->dst_rect.h); + v_stretch_ratio = + ((layer->src_rect.h / layer->dst_rect.h) / 2) * 2; + } else { + v_stretch_ratio_threshold = + ((layer->src_rect.h + layer->dst_rect.h - + 1) / layer->dst_rect.h); + v_stretch_ratio = + (layer->src_rect.h / layer->dst_rect.h); + } + + if (v_stretch_ratio_threshold <= g_rdma_stretch_threshold) + v_stretch_ratio = 0; + } + + return v_stretch_ratio; +} + +static int hisi_adjust_clip_rect(dss_layer_t *layer, + dss_rect_ltrb_t *clip_rect) +{ + int ret = 0; + uint32_t temp = 0; + + BUG_ON(layer == NULL); + BUG_ON(clip_rect == NULL); + + if ((clip_rect->left < 0 || clip_rect->left > DFC_MAX_CLIP_NUM) || + (clip_rect->right < 0 || clip_rect->right > DFC_MAX_CLIP_NUM) || + (clip_rect->top < 0 || clip_rect->top > DFC_MAX_CLIP_NUM) || + (clip_rect->bottom < 0 || clip_rect->bottom > DFC_MAX_CLIP_NUM)) { + return -EINVAL; + } + + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + + break; + case HISI_FB_TRANSFORM_FLIP_H: + { + temp = clip_rect->left; + clip_rect->left = clip_rect->right; + clip_rect->right = temp; + } + break; + case HISI_FB_TRANSFORM_FLIP_V: + { + temp = clip_rect->top; + clip_rect->top = clip_rect->bottom; + clip_rect->bottom = temp; + } + break; + case HISI_FB_TRANSFORM_ROT_180: + { + temp = clip_rect->left; + clip_rect->left = clip_rect->right; + clip_rect->right = temp; + + temp = clip_rect->top; + clip_rect->top = clip_rect->bottom; + clip_rect->bottom = temp; + } + break; + default: + HISI_FB_ERR("not supported this transform(%d)!", + layer->transform); + break; + } + + return ret; +} + +static int hisi_pixel_format_hal2dma(int format) +{ + int ret = 0; + + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGB_565: + case HISI_FB_PIXEL_FORMAT_BGR_565: + ret = DMA_PIXEL_FORMAT_RGB_565; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + ret = DMA_PIXEL_FORMAT_XRGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + ret = DMA_PIXEL_FORMAT_ARGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + ret = DMA_PIXEL_FORMAT_XRGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + ret = DMA_PIXEL_FORMAT_ARGB_5551; + break; + + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + ret = DMA_PIXEL_FORMAT_XRGB_8888; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + ret = DMA_PIXEL_FORMAT_ARGB_8888; + break; + + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + ret = DMA_PIXEL_FORMAT_YUYV_422_Pkg; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + ret = DMA_PIXEL_FORMAT_YUV_422_P_HP; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + ret = DMA_PIXEL_FORMAT_YUV_420_P_HP; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + ret = DMA_PIXEL_FORMAT_YUV_422_SP_HP; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + ret = DMA_PIXEL_FORMAT_YUV_420_SP_HP; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", format); + ret = -1; + break; + } + + return ret; +} + +static int hisi_transform_hal2dma(int transform, int chn_idx) +{ + int ret = 0; + + if (chn_idx < DSS_WCHN_W0 || chn_idx == DSS_RCHN_V2) { + switch (transform) { + case HISI_FB_TRANSFORM_NOP: + ret = DSS_TRANSFORM_NOP; + break; + case HISI_FB_TRANSFORM_FLIP_H: + ret = DSS_TRANSFORM_FLIP_H; + break; + case HISI_FB_TRANSFORM_FLIP_V: + ret = DSS_TRANSFORM_FLIP_V; + break; + case HISI_FB_TRANSFORM_ROT_180: + ret = DSS_TRANSFORM_FLIP_V | DSS_TRANSFORM_FLIP_H; + break; + default: + ret = -1; + HISI_FB_ERR("Transform %d is not supported", transform); + break; + } + } else { + if (transform == HISI_FB_TRANSFORM_NOP) { + ret = DSS_TRANSFORM_NOP; + } else if (transform == + (HISI_FB_TRANSFORM_ROT_90 | + HISI_FB_TRANSFORM_FLIP_V)) { + ret = DSS_TRANSFORM_ROT; + } else { + ret = -1; + HISI_FB_ERR("Transform %d is not supported", transform); + } + } + + return ret; +} + +static int hisi_pixel_format_hal2dfc(int format) +{ + int ret = 0; + + switch (format) { + case HISI_FB_PIXEL_FORMAT_RGB_565: + ret = DFC_PIXEL_FORMAT_RGB_565; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_4444: + ret = DFC_PIXEL_FORMAT_XBGR_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_4444: + ret = DFC_PIXEL_FORMAT_ABGR_4444; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_5551: + ret = DFC_PIXEL_FORMAT_XBGR_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_5551: + ret = DFC_PIXEL_FORMAT_ABGR_5551; + break; + case HISI_FB_PIXEL_FORMAT_RGBX_8888: + ret = DFC_PIXEL_FORMAT_XBGR_8888; + break; + case HISI_FB_PIXEL_FORMAT_RGBA_8888: + ret = DFC_PIXEL_FORMAT_ABGR_8888; + break; + + case HISI_FB_PIXEL_FORMAT_BGR_565: + ret = DFC_PIXEL_FORMAT_BGR_565; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + ret = DFC_PIXEL_FORMAT_XRGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + ret = DFC_PIXEL_FORMAT_ARGB_4444; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + ret = DFC_PIXEL_FORMAT_XRGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + ret = DFC_PIXEL_FORMAT_ARGB_5551; + break; + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + ret = DFC_PIXEL_FORMAT_XRGB_8888; + break; + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + ret = DFC_PIXEL_FORMAT_ARGB_8888; + break; + + case HISI_FB_PIXEL_FORMAT_YUV_422_I: + case HISI_FB_PIXEL_FORMAT_YUYV_422_Pkg: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YVYU_422_Pkg: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + case HISI_FB_PIXEL_FORMAT_UYVY_422_Pkg: + ret = DFC_PIXEL_FORMAT_UYVY422; + break; + case HISI_FB_PIXEL_FORMAT_VYUY_422_Pkg: + ret = DFC_PIXEL_FORMAT_VYUY422; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_SP: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + case HISI_FB_PIXEL_FORMAT_YCbCr_420_SP: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + + case HISI_FB_PIXEL_FORMAT_YCbCr_422_P: + case HISI_FB_PIXEL_FORMAT_YCbCr_420_P: + ret = DFC_PIXEL_FORMAT_YUYV422; + break; + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + ret = DFC_PIXEL_FORMAT_YVYU422; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", format); + ret = -1; + break; + } + + return ret; +} + +static int hisi_rb_swap(int format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_BGR_565: + case HISI_FB_PIXEL_FORMAT_BGRX_4444: + case HISI_FB_PIXEL_FORMAT_BGRA_4444: + case HISI_FB_PIXEL_FORMAT_BGRX_5551: + case HISI_FB_PIXEL_FORMAT_BGRA_5551: + case HISI_FB_PIXEL_FORMAT_BGRX_8888: + case HISI_FB_PIXEL_FORMAT_BGRA_8888: + return 1; + default: + return 0; + } +} + +static int hisi_uv_swap(int format) +{ + switch (format) { + case HISI_FB_PIXEL_FORMAT_YCrCb_422_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_SP: + case HISI_FB_PIXEL_FORMAT_YCrCb_422_P: + case HISI_FB_PIXEL_FORMAT_YCrCb_420_P: + return 1; + + default: + return 0; + } +} + +static int hisi_dfc_get_bpp(int dfc_format) +{ + int ret = 0; + + switch (dfc_format) { + case DFC_PIXEL_FORMAT_RGB_565: + case DFC_PIXEL_FORMAT_XRGB_4444: + case DFC_PIXEL_FORMAT_ARGB_4444: + case DFC_PIXEL_FORMAT_XRGB_5551: + case DFC_PIXEL_FORMAT_ARGB_5551: + + case DFC_PIXEL_FORMAT_BGR_565: + case DFC_PIXEL_FORMAT_XBGR_4444: + case DFC_PIXEL_FORMAT_ABGR_4444: + case DFC_PIXEL_FORMAT_XBGR_5551: + case DFC_PIXEL_FORMAT_ABGR_5551: + ret = 2; + break; + + case DFC_PIXEL_FORMAT_XRGB_8888: + case DFC_PIXEL_FORMAT_ARGB_8888: + case DFC_PIXEL_FORMAT_XBGR_8888: + case DFC_PIXEL_FORMAT_ABGR_8888: + ret = 4; + break; + + case DFC_PIXEL_FORMAT_YUV444: + case DFC_PIXEL_FORMAT_YVU444: + ret = 3; + break; + + case DFC_PIXEL_FORMAT_YUYV422: + case DFC_PIXEL_FORMAT_YVYU422: + case DFC_PIXEL_FORMAT_VYUY422: + case DFC_PIXEL_FORMAT_UYVY422: + ret = 2; + break; + + default: + HISI_FB_ERR("not support format(%d)!\n", dfc_format); + ret = -1; + break; + } + + return ret; +} + +static uint32_t hisi_calculate_display_addr(bool mmu_enable, + dss_layer_t *layer, + dss_rect_ltrb_t *aligned_rect, + int add_type) +{ + uint32_t addr = 0; + uint32_t src_addr = 0; + uint32_t stride = 0; + uint32_t offset = 0; + int bpp = 0; + int left = 0; + int right = 0; + int top = 0; + int bottom = 0; + + left = aligned_rect->left; + right = aligned_rect->right; + top = aligned_rect->top; + bottom = aligned_rect->bottom; + + if (add_type == DSS_ADDR_PLANE0) { + stride = layer->img.stride; + offset = 0; + src_addr = + mmu_enable ? layer->img.vir_addr : layer->img.phy_addr; + bpp = layer->img.bpp; + } else if (add_type == DSS_ADDR_PLANE1) { + stride = layer->img.stride_plane1; + offset = layer->img.offset_plane1; + src_addr = mmu_enable ? (layer->img.vir_addr + offset) : + (layer->img.phy_addr + offset); + bpp = 1; + + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + left /= 2; + right /= 2; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + top /= 2; + bottom /= 2; + } + } else if (add_type == DSS_ADDR_PLANE2) { + stride = layer->img.stride_plane2; + offset = layer->img.offset_plane2; + src_addr = mmu_enable ? (layer->img.vir_addr + offset) : + (layer->img.phy_addr + offset); + bpp = 1; + + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + left /= 2; + right /= 2; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + top /= 2; + bottom /= 2; + } + } else { + HISI_FB_ERR("NOT SUPPORT this add_type(%d).\n", add_type); + BUG_ON(1); + } + + switch (layer->transform) { + case HISI_FB_TRANSFORM_NOP: + addr = src_addr + top * stride + left * bpp; + break; + case HISI_FB_TRANSFORM_FLIP_H: + addr = src_addr + top * stride + right * bpp; + break; + case HISI_FB_TRANSFORM_FLIP_V: + addr = src_addr + bottom * stride + left * bpp; + break; + case HISI_FB_TRANSFORM_ROT_180: + addr = src_addr + bottom * stride + right * bpp; + break; + default: + HISI_FB_ERR("not supported this transform(%d)!", + layer->transform); + break; + } + + return addr; +} + +/******************************************************************************* + ** DSS MIF + */ +static void hisi_dss_mif_init(char __iomem *mif_ch_base, + dss_mif_t *s_mif, int chn_idx) +{ + uint32_t rw_type = 0; + + BUG_ON(mif_ch_base == NULL); + BUG_ON(s_mif == NULL); + + memset(s_mif, 0, sizeof(dss_mif_t)); + + s_mif->mif_ctrl1 = 0x00000020; + s_mif->mif_ctrl2 = 0x0; + s_mif->mif_ctrl3 = 0x0; + s_mif->mif_ctrl4 = 0x0; + s_mif->mif_ctrl5 = 0x0; + rw_type = (chn_idx < DSS_WCHN_W0 || chn_idx == DSS_RCHN_V2) ? 0x0 : 0x1; + + s_mif->mif_ctrl1 = set_bits32(s_mif->mif_ctrl1, 0x0, 1, 5); + s_mif->mif_ctrl1 = set_bits32(s_mif->mif_ctrl1, rw_type, 1, 17); +} + +static void hisi_dss_mif_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mif_ch_base, dss_mif_t *s_mif, + int chn_idx) +{ + BUG_ON(hisifd == NULL); + BUG_ON(mif_ch_base == NULL); + BUG_ON(s_mif == NULL); + + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL1, + s_mif->mif_ctrl1, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL2, + s_mif->mif_ctrl2, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL3, + s_mif->mif_ctrl3, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL4, + s_mif->mif_ctrl4, 32, 0); + hisifd->set_reg(hisifd, mif_ch_base + MIF_CTRL5, + s_mif->mif_ctrl5, 32, 0); +} + +void hisi_dss_mif_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *mif_base = NULL; + + BUG_ON(hisifd == NULL); + + mif_base = hisifd->dss_base + DSS_MIF_OFFSET; + + set_reg(mif_base + MIF_ENABLE, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH0_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH1_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH2_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH3_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH4_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH5_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH6_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH7_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH8_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH9_OFFSET + MIF_CTRL0, 0x1, 1, 0); + + set_reg(hisifd->dss_base + MIF_CH10_OFFSET + MIF_CTRL0, 0x1, 1, 0); + set_reg(hisifd->dss_base + MIF_CH11_OFFSET + MIF_CTRL0, 0x1, 1, 0); +} + +int hisi_dss_mif_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer, + bool rdma_stretch_enable) +{ + dss_mif_t *mif = NULL; + int chn_idx = 0; + dss_img_t *img = NULL; + uint32_t transform = 0; + uint32_t invalid_sel = 0; + uint32_t need_cap = 0; + uint32_t *semi_plane1 = NULL; + int v_scaling_factor = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + img = &(wb_layer->dst); + chn_idx = wb_layer->chn_idx; + transform = wb_layer->transform; + need_cap = wb_layer->need_cap; + v_scaling_factor = 1; + } else { + img = &(layer->img); + chn_idx = layer->chn_idx; + transform = layer->transform; + need_cap = layer->need_cap; + v_scaling_factor = + layer->src_rect.h / layer->dst_rect.h + + ((layer->src_rect.h % layer->dst_rect.h) > 0 ? 1 : 0); + } + + mif = &(hisifd->dss_module.mif[chn_idx]); + hisifd->dss_module.mif_used[chn_idx] = 1; + + semi_plane1 = &mif->mif_ctrl4; + + if (img->mmu_enable == 0) { + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, 0x1, 1, 5); + } else { + if (need_cap & (CAP_AFBCD | CAP_AFBCE)) { + invalid_sel = 0; + } else { + invalid_sel = + hisi_dss_mif_get_invalid_sel(img, transform, + v_scaling_factor, + ((need_cap & CAP_TILE) + ? 1 : 0), + rdma_stretch_enable); + } + + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, 0x0, 1, 5); + mif->mif_ctrl1 = set_bits32(mif->mif_ctrl1, invalid_sel, 2, 10); + mif->mif_ctrl1 = + set_bits32(mif->mif_ctrl1, ((invalid_sel == 0) ? 0x1 : 0x0), + 1, 19); + + if (invalid_sel == 0) { + mif->mif_ctrl2 = set_bits32(mif->mif_ctrl2, 0x0, 20, 0); + mif->mif_ctrl3 = set_bits32(mif->mif_ctrl3, 0x0, 20, 0); + mif->mif_ctrl4 = set_bits32(mif->mif_ctrl4, 0x0, 20, 0); + mif->mif_ctrl5 = set_bits32(mif->mif_ctrl5, 0x0, 20, 0); + } else if ((invalid_sel == 1) || (invalid_sel == 2)) { + if (img->stride > 0) { + mif->mif_ctrl5 = set_bits32(mif->mif_ctrl5, + ((img->stride /MIF_STRIDE_UNIT) + + (((img->stride % MIF_STRIDE_UNIT) > 0) ? + 1 : 0)), 20, 0); + } + + if (isYUVSemiPlanar(img->format)) { + if (img->stride_plane1 > 0) { + *semi_plane1 = set_bits32(*semi_plane1, + ((img->stride_plane1 / MIF_STRIDE_UNIT) + + (((img->stride_plane1 % MIF_STRIDE_UNIT) >0) ? + 1 : 0)), 20, 0); + } + } else if (isYUVPlanar(img->format)) { + if (img->stride_plane1 > 0) { + mif->mif_ctrl4 = + set_bits32(mif->mif_ctrl4, + ((img->stride_plane1 / + MIF_STRIDE_UNIT) + + (((img->stride_plane1 % + MIF_STRIDE_UNIT) > + 0) ? 1 : 0)), 20, 0); + } + + if (img->stride_plane2 > 0) { + mif->mif_ctrl3 = + set_bits32(mif->mif_ctrl3, + ((img->stride_plane2 / + MIF_STRIDE_UNIT) + + (((img->stride_plane2 % + MIF_STRIDE_UNIT) > + 0) ? 1 : 0)), 20, 0); + } + } else { + ; + } + } else if (invalid_sel == 3) { + if (img->stride > 0) { + mif->mif_ctrl5 = + set_bits32(mif->mif_ctrl5, + DSS_MIF_CTRL2_INVAL_SEL3_STRIDE_MASK, 4, 16); + } + if (isYUVSemiPlanar(img->format)) { + if (img->stride_plane1 > 0) + *semi_plane1 = + set_bits32(*semi_plane1, 0xE, 4, 16); + + } else if (isYUVPlanar(img->format)) { + if (img->stride_plane1 > 0) + mif->mif_ctrl3 = + set_bits32(mif->mif_ctrl3, 0xE, 4, 16); + + if (img->stride_plane2 > 0) + mif->mif_ctrl4 = + set_bits32(mif->mif_ctrl4, 0xE, 4, 16); + } else { + ; + } + } else { + HISI_FB_ERR("fb%d, invalid_sel(%d) not support!\n", + hisifd->index, invalid_sel); + } + } + + return 0; +} + +/******************************************************************************* + ** DSS RDMA + */ +static void hisi_dss_rdma_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + memset(s_dma, 0, sizeof(dss_rdma_t)); + + s_dma->oft_x0 = inp32(dma_base + DMA_OFT_X0); + s_dma->oft_y0 = inp32(dma_base + DMA_OFT_Y0); + s_dma->oft_x1 = inp32(dma_base + DMA_OFT_X1); + s_dma->oft_y1 = inp32(dma_base + DMA_OFT_Y1); + s_dma->mask0 = inp32(dma_base + DMA_MASK0); + s_dma->mask1 = inp32(dma_base + DMA_MASK1); + s_dma->stretch_size_vrt = inp32(dma_base + DMA_STRETCH_SIZE_VRT); + s_dma->ctrl = inp32(dma_base + DMA_CTRL); + s_dma->tile_scram = inp32(dma_base + DMA_TILE_SCRAM); + + s_dma->ch_rd_shadow = inp32(dma_base + CH_RD_SHADOW); + s_dma->ch_ctl = inp32(dma_base + CH_CTL); + + s_dma->data_addr0 = inp32(dma_base + DMA_DATA_ADDR0); + s_dma->stride0 = inp32(dma_base + DMA_STRIDE0); + s_dma->stretch_stride0 = inp32(dma_base + DMA_STRETCH_STRIDE0); + s_dma->data_num0 = inp32(dma_base + DMA_DATA_NUM0); + + s_dma->vpp_ctrl = inp32(dma_base + VPP_CTRL); + s_dma->vpp_mem_ctrl = inp32(dma_base + VPP_MEM_CTRL); + + s_dma->dma_buf_ctrl = inp32(dma_base + DMA_BUF_CTRL); + + s_dma->afbcd_hreg_hdr_ptr_lo = inp32(dma_base + AFBCD_HREG_HDR_PTR_LO); + s_dma->afbcd_hreg_pic_width = inp32(dma_base + AFBCD_HREG_PIC_WIDTH); + s_dma->afbcd_hreg_pic_height = inp32(dma_base + AFBCD_HREG_PIC_HEIGHT); + s_dma->afbcd_hreg_format = inp32(dma_base + AFBCD_HREG_FORMAT); + s_dma->afbcd_ctl = inp32(dma_base + AFBCD_CTL); + s_dma->afbcd_str = inp32(dma_base + AFBCD_STR); + s_dma->afbcd_line_crop = inp32(dma_base + AFBCD_LINE_CROP); + s_dma->afbcd_input_header_stride = + inp32(dma_base + AFBCD_INPUT_HEADER_STRIDE); + s_dma->afbcd_payload_stride = inp32(dma_base + AFBCD_PAYLOAD_STRIDE); + s_dma->afbcd_mm_base_0 = inp32(dma_base + AFBCD_MM_BASE_0); + s_dma->afbcd_afbcd_payload_pointer = + inp32(dma_base + AFBCD_AFBCD_PAYLOAD_POINTER); + s_dma->afbcd_height_bf_str = inp32(dma_base + AFBCD_HEIGHT_BF_STR); + s_dma->afbcd_os_cfg = inp32(dma_base + AFBCD_OS_CFG); + s_dma->afbcd_mem_ctrl = inp32(dma_base + AFBCD_MEM_CTRL); +} + +static void hisi_dss_rdma_u_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + s_dma->data_addr1 = inp32(dma_base + DMA_DATA_ADDR1); + s_dma->stride1 = inp32(dma_base + DMA_STRIDE1); + s_dma->stretch_stride1 = inp32(dma_base + DMA_STRETCH_STRIDE1); + s_dma->data_num1 = inp32(dma_base + DMA_DATA_NUM1); +} + +static void hisi_dss_rdma_v_init(char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + s_dma->data_addr2 = inp32(dma_base + DMA_DATA_ADDR2); + s_dma->stride2 = inp32(dma_base + DMA_STRIDE2); + s_dma->stretch_stride2 = inp32(dma_base + DMA_STRETCH_STRIDE2); + s_dma->data_num2 = inp32(dma_base + DMA_DATA_NUM2); +} + +void hisi_dss_chn_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x0, 32, 0); +} + +static void hisi_dss_rdma_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_REG_DEFAULT, 0x0, 32, 0); + + hisifd->set_reg(hisifd, dma_base + DMA_OFT_X0, s_dma->oft_x0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_Y0, s_dma->oft_y0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_X1, s_dma->oft_x1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_OFT_Y1, s_dma->oft_y1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_MASK0, s_dma->mask0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_MASK1, s_dma->mask1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_SIZE_VRT, + s_dma->stretch_size_vrt, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_CTRL, s_dma->ctrl, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_TILE_SCRAM, s_dma->tile_scram, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR0, s_dma->data_addr0, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE0, s_dma->stride0, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE0, + s_dma->stretch_stride0, 32, 0); + + hisifd->set_reg(hisifd, dma_base + CH_RD_SHADOW, s_dma->ch_rd_shadow, + 32, 0); + hisifd->set_reg(hisifd, dma_base + CH_CTL, s_dma->ch_ctl, 32, 0); + + if (s_dma->vpp_used) { + hisifd->set_reg(hisifd, dma_base + VPP_CTRL, s_dma->vpp_ctrl, + 32, 0); + } + + hisifd->set_reg(hisifd, dma_base + DMA_BUF_CTRL, s_dma->dma_buf_ctrl, + 32, 0); + + if (s_dma->afbc_used) { + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_HDR_PTR_LO, + s_dma->afbcd_hreg_hdr_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_PIC_WIDTH, + s_dma->afbcd_hreg_pic_width, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_PIC_HEIGHT, + s_dma->afbcd_hreg_pic_height, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HREG_FORMAT, + s_dma->afbcd_hreg_format, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_CTL, s_dma->afbcd_ctl, + 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_STR, s_dma->afbcd_str, + 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_LINE_CROP, + s_dma->afbcd_line_crop, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_INPUT_HEADER_STRIDE, + s_dma->afbcd_input_header_stride, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_PAYLOAD_STRIDE, + s_dma->afbcd_payload_stride, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_MM_BASE_0, + s_dma->afbcd_mm_base_0, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_AFBCD_PAYLOAD_POINTER, + s_dma->afbcd_afbcd_payload_pointer, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HEIGHT_BF_STR, + s_dma->afbcd_height_bf_str, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_OS_CFG, + s_dma->afbcd_os_cfg, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_SCRAMBLE_MODE, + s_dma->afbcd_scramble_mode, 32, 0); + hisifd->set_reg(hisifd, dma_base + AFBCD_HEADER_POINTER_OFFSET, + s_dma->afbcd_header_pointer_offset, 32, 0); + } +} + +static void hisi_dss_rdma_u_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR1, s_dma->data_addr1, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE1, s_dma->stride1, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE1, + s_dma->stretch_stride1, 32, 0); +} + +static void hisi_dss_rdma_v_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base, dss_rdma_t *s_dma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dma_base == NULL); + BUG_ON(s_dma == NULL); + + hisifd->set_reg(hisifd, dma_base + DMA_DATA_ADDR2, s_dma->data_addr2, + 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRIDE2, s_dma->stride2, 32, 0); + hisifd->set_reg(hisifd, dma_base + DMA_STRETCH_STRIDE2, + s_dma->stretch_stride2, 32, 0); +} + +static int hisi_get_rdma_tile_interleave(uint32_t stride) +{ + int i = 0; + uint32_t interleave[MAX_TILE_SURPORT_NUM] = { + 256, 512, 1024, 2048, 4096, 8192, + }; + + for (i = 0; i < MAX_TILE_SURPORT_NUM; i++) { + if (interleave[i] == stride) + return MIN_INTERLEAVE + i; + } + + return 0; +} + +int hisi_dss_rdma_config(struct hisi_fb_data_type *hisifd, int ovl_idx, + dss_layer_t *layer, dss_rect_ltrb_t *clip_rect, + dss_rect_t *out_aligned_rect, + bool *rdma_stretch_enable) +{ + dss_rdma_t *dma = NULL; + + bool mmu_enable = false; + bool is_yuv_semi_planar = false; + bool is_yuv_planar = false; + bool src_rect_mask_enable = false; + + uint32_t rdma_addr = 0; + uint32_t rdma_stride = 0; + int rdma_format = 0; + int rdma_transform = 0; + int rdma_data_num = 0; + uint32_t stretch_size_vrt = 0; + uint32_t stretched_line_num = 0; + uint32_t stretched_stride = 0; + + int bpp = 0; + int aligned_pixel = 0; + int rdma_oft_x0 = 0; + int rdma_oft_y0 = 0; + int rdma_oft_x1 = 0; + int rdma_oft_y1 = 0; + int rdma_mask_x0 = 0; + int rdma_mask_y0 = 0; + int rdma_mask_x1 = 0; + int rdma_mask_y1 = 0; + + int chn_idx = 0; + uint32_t l2t_interleave_n = 0; + dss_rect_ltrb_t aligned_rect = { 0, 0, 0, 0 }; + dss_rect_ltrb_t aligned_mask_rect = { 0, 0, 0, 0 }; + dss_rect_t new_src_rect; + + uint32_t afbcd_half_block_mode = 0; + uint32_t afbcd_stretch_acc = 0; + uint32_t afbcd_stretch_inc = 0; + uint32_t afbcd_height_bf_str = 0; + uint32_t afbcd_top_crop_num = 0; + uint32_t afbcd_bottom_crop_num = 0; + uint32_t afbc_header_addr = 0; + uint32_t afbc_header_stride = 0; + uint32_t afbc_payload_addr = 0; + uint32_t afbc_payload_stride = 0; + uint32_t afbc_header_start_pos = 0; + uint32_t afbc_header_pointer_offset = 0; + uint32_t stride_align = 0; + uint32_t addr_align = 0; + dss_rect_ltrb_t afbc_rect; + uint32_t mm_base_0 = 0; + uint32_t mm_base_1 = 0; + bool mm_alloc_needed = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + chn_idx = layer->chn_idx; + new_src_rect = layer->src_rect; + + stretched_line_num = isNeedRdmaStretchBlt(hisifd, layer); + *rdma_stretch_enable = (stretched_line_num > 0) ? true : false; + + mmu_enable = (layer->img.mmu_enable == 1) ? true : false; + is_yuv_semi_planar = isYUVSemiPlanar(layer->img.format); + is_yuv_planar = isYUVPlanar(layer->img.format); + + rdma_format = hisi_pixel_format_hal2dma(layer->img.format); + if (rdma_format < 0) { + HISI_FB_ERR("layer format(%d) not support !\n", + layer->img.format); + return -EINVAL; + } + + rdma_transform = hisi_transform_hal2dma(layer->transform, chn_idx); + if (rdma_transform < 0) { + HISI_FB_ERR("layer transform(%d) not support!\n", + layer->transform); + return -EINVAL; + } + + bpp = (is_yuv_semi_planar || is_yuv_planar) ? 1 : layer->img.bpp; + aligned_pixel = DMA_ALIGN_BYTES / bpp; + + src_rect_mask_enable = isSrcRectMasked(layer, aligned_pixel); + + dma = &(hisifd->dss_module.rdma[chn_idx]); + hisifd->dss_module.dma_used[chn_idx] = 1; + + if (layer->need_cap & CAP_YUV_DEINTERLACE) { + dma->vpp_used = 1; + + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + dma->vpp_ctrl = set_bits32(dma->vpp_ctrl, 0x2, 2, 0); + } else { + dma->vpp_ctrl = set_bits32(dma->vpp_ctrl, 0x3, 2, 0); + } + } + + if (layer->need_cap & CAP_AFBCD) { + if ((layer->img.mmbuf_base > 0) && (layer->img.mmbuf_size > 0)) { + mm_base_0 = layer->img.mmbuf_base; + mm_base_1 = + layer->img.mmbuf_base + layer->img.mmbuf_size / 2; + } else { + BUG_ON(hisifd->mmbuf_info == NULL); + + if (ovl_idx <= DSS_OVL1) { + mm_alloc_needed = true; + } else { + if (hisifd->mmbuf_info->mm_used[chn_idx] == 1) + mm_alloc_needed = false; + else + mm_alloc_needed = true; + } + + if (mm_alloc_needed) { + afbc_rect.left = + ALIGN_DOWN(new_src_rect.x, + MMBUF_ADDR_ALIGN); + afbc_rect.right = + ALIGN_UP(new_src_rect.x - afbc_rect.left + + new_src_rect.w, MMBUF_ADDR_ALIGN); + hisifd->mmbuf_info->mm_size[chn_idx] = + afbc_rect.right * layer->img.bpp * + MMBUF_LINE_NUM; + hisifd->mmbuf_info->mm_base[chn_idx] = + hisi_dss_mmbuf_alloc(g_mmbuf_gen_pool, + hisifd->mmbuf_info->mm_size[chn_idx]); + if (hisifd->mmbuf_info->mm_base[chn_idx] < + MMBUF_BASE) { + HISI_FB_ERR + ("fb%d, chn%d failed to alloc mmbuf, mm_base=0x%x.\n", + hisifd->index, chn_idx, + hisifd->mmbuf_info->mm_base[chn_idx]); + return -EINVAL; + } + } + + mm_base_0 = hisifd->mmbuf_info->mm_base[chn_idx]; + mm_base_1 = hisifd->mmbuf_info->mm_base[chn_idx] + + hisifd->mmbuf_info->mm_size[chn_idx] / 2; + hisifd->mmbuf_info->mm_used[chn_idx] = 1; + } + + mm_base_0 -= MMBUF_BASE; + mm_base_1 -= MMBUF_BASE; + + if ((layer->img.width & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (layer->img.height & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d img width(%d) is not %d bytes aligned, or " + "img heigh(%d) is not %d bytes aligned!\n", + layer->layer_idx, layer->img.width, + AFBC_HEADER_ADDR_ALIGN, layer->img.height, + AFBC_BLOCK_ALIGN); + return -EINVAL; + } + + if ((mm_base_0 & (MMBUF_ADDR_ALIGN - 1)) || + (mm_base_1 & (MMBUF_ADDR_ALIGN - 1)) || + (layer->img.mmbuf_size & (MMBUF_ADDR_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d mm_base_0(0x%x) is not %d bytes aligned, or " + "mm_base_1(0x%x) is not %d bytes aligned, or mmbuf_size(0x%x) is " + "not %d bytes aligned!\n", layer->layer_idx, + mm_base_0, MMBUF_ADDR_ALIGN, mm_base_1, + MMBUF_ADDR_ALIGN, layer->img.mmbuf_size, + MMBUF_ADDR_ALIGN); + return -EINVAL; + } + + dma->afbc_used = 1; + + aligned_rect.left = + ALIGN_DOWN(new_src_rect.x, AFBC_BLOCK_ALIGN); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + AFBC_BLOCK_ALIGN) - 1; + aligned_rect.top = ALIGN_DOWN(new_src_rect.y, AFBC_BLOCK_ALIGN); + aligned_rect.bottom = + ALIGN_UP(new_src_rect.y + new_src_rect.h, + AFBC_BLOCK_ALIGN) - 1; + + out_aligned_rect->x = 0; + out_aligned_rect->y = 0; + out_aligned_rect->w = + aligned_rect.right - aligned_rect.left + 1; + out_aligned_rect->h = + aligned_rect.bottom - aligned_rect.top + 1; + + afbcd_height_bf_str = + aligned_rect.bottom - aligned_rect.top + 1; + + if (*rdma_stretch_enable) { + afbcd_stretch_inc = 0; + afbcd_stretch_acc = 0; + + out_aligned_rect->h /= 2; + if (layer->transform & HISI_FB_TRANSFORM_FLIP_V) { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_LOWER_ONLY; + } else { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_UPPER_ONLY; + } + } else { + if (layer->transform & HISI_FB_TRANSFORM_FLIP_V) { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_LOWER_UPPER_ALL; + } else { + afbcd_half_block_mode = + AFBC_HALF_BLOCK_UPPER_LOWER_ALL; + } + } + + if (layer->img. + afbc_header_addr & (AFBC_SUPER_GRAPH_HEADER_ADDR_ALIGN - + 1)) { + HISI_FB_ERR + ("layer%d super graph afbc_header_addr(0x%x) " + "is not %d bytes aligned!\n", + layer->layer_idx, afbc_header_addr, + AFBC_SUPER_GRAPH_HEADER_ADDR_ALIGN); + return -EINVAL; + } + + clip_rect->left = new_src_rect.x - aligned_rect.left; + clip_rect->right = + aligned_rect.right - DSS_WIDTH(new_src_rect.x + + new_src_rect.w); + clip_rect->top = new_src_rect.y - aligned_rect.top; + clip_rect->bottom = + aligned_rect.bottom - DSS_HEIGHT(new_src_rect.y + + new_src_rect.h); + if (hisi_adjust_clip_rect(layer, clip_rect) < 0) { + HISI_FB_ERR + ("clip rect invalid => layer_idx=%d, chn_idx=%d, " + "clip_rect(%d, %d, %d, %d).\n", + layer->layer_idx, chn_idx, clip_rect->left, + clip_rect->right, clip_rect->top, + clip_rect->bottom); + return -EINVAL; + } + + afbcd_top_crop_num = (clip_rect->top > AFBCD_TOP_CROP_MAX) ? + AFBCD_TOP_CROP_MAX : clip_rect->top; + afbcd_bottom_crop_num = + (clip_rect->bottom > + AFBCD_BOTTOM_CROP_MAX) ? AFBCD_BOTTOM_CROP_MAX : + clip_rect->bottom; + + clip_rect->top -= afbcd_top_crop_num; + BUG_ON(clip_rect->top < 0); + clip_rect->bottom -= afbcd_bottom_crop_num; + BUG_ON(clip_rect->bottom < 0); + + out_aligned_rect->h -= + (afbcd_top_crop_num + afbcd_bottom_crop_num); + + rdma_oft_x0 = aligned_rect.left / aligned_pixel; + rdma_oft_x1 = aligned_rect.right / aligned_pixel; + stretch_size_vrt = DSS_HEIGHT(out_aligned_rect->h); + stretched_line_num = 0; + + afbc_rect = aligned_rect; + afbc_rect.left = + ALIGN_DOWN(new_src_rect.x, AFBC_HEADER_ADDR_ALIGN); + afbc_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + AFBC_HEADER_ADDR_ALIGN) - 1; + + afbc_header_stride = + (layer->img.width / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + afbc_header_pointer_offset = + (afbc_rect.top / AFBC_BLOCK_ALIGN) * afbc_header_stride + + (afbc_rect.left / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + afbc_header_addr = + layer->img.afbc_header_addr + afbc_header_pointer_offset; + + if ((afbc_header_addr & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (afbc_header_stride & (AFBC_HEADER_STRIDE_ALIGN - 1))) { + HISI_FB_ERR + ("layer%d afbc_header_addr(0x%x) is not %d bytes aligned, or " + "afbc_header_stride(0x%x) is not %d bytes aligned!\n", + layer->layer_idx, afbc_header_addr, + AFBC_HEADER_ADDR_ALIGN, afbc_header_stride, + AFBC_HEADER_STRIDE_ALIGN); + return -EINVAL; + } + + BUG_ON((aligned_rect.left - afbc_rect.left) < 0); + afbc_header_start_pos = + (aligned_rect.left - afbc_rect.left) / AFBC_BLOCK_ALIGN; + + if (layer->img.bpp == 4) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_32; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_32; + } else if (layer->img.bpp == 2) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_16; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_16; + } else { + HISI_FB_ERR("bpp(%d) not supported!\n", layer->img.bpp); + return -EINVAL; + } + + afbc_payload_stride = layer->img.afbc_payload_stride; + if (layer->img.afbc_scramble_mode != DSS_AFBC_SCRAMBLE_MODE2) { + afbc_payload_stride = + (layer->img.width / AFBC_BLOCK_ALIGN) * + stride_align; + } + afbc_payload_addr = layer->img.afbc_payload_addr + + (aligned_rect.top / AFBC_BLOCK_ALIGN) * + afbc_payload_stride + + (aligned_rect.left / AFBC_BLOCK_ALIGN) * stride_align; + + if ((afbc_payload_addr & (addr_align - 1)) || + (afbc_payload_stride & (stride_align - 1))) { + HISI_FB_ERR + ("layer%d afbc_payload_addr(0x%x) is not %d bytes aligned, or " + "afbc_payload_stride(0x%x) is not %d bytes aligned!\n", + layer->layer_idx, afbc_payload_addr, addr_align, + afbc_payload_stride, stride_align); + return -EINVAL; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, mm_base_0=0x%x, mm_base_1=0x%x, mmbuf_size=%d, " + "aligned_rect(%d,%d,%d,%d), afbc_rect(%d,%d,%d,%d)!\n", + hisifd->index, mm_base_0, mm_base_1, + layer->img.mmbuf_size, aligned_rect.left, + aligned_rect.top, aligned_rect.right, + aligned_rect.bottom, afbc_rect.left, afbc_rect.top, + afbc_rect.right, afbc_rect.bottom); + } + + dma->oft_x0 = set_bits32(dma->oft_x0, rdma_oft_x0, 16, 0); + dma->oft_x1 = set_bits32(dma->oft_x1, rdma_oft_x1, 16, 0); + dma->stretch_size_vrt = set_bits32(dma->stretch_size_vrt, + (stretch_size_vrt | + (stretched_line_num << 13)), + 19, 0); + dma->ctrl = set_bits32(dma->ctrl, rdma_format, 5, 3); + dma->ctrl = + set_bits32(dma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + dma->ctrl = set_bits32(dma->ctrl, rdma_transform, 3, 9); + dma->ctrl = + set_bits32(dma->ctrl, (*rdma_stretch_enable ? 1 : 0), 1, + 12); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 0); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 2); + + dma->afbcd_hreg_pic_width = + set_bits32(dma->afbcd_hreg_pic_width, + (aligned_rect.right - aligned_rect.left), 16, 0); + dma->afbcd_hreg_pic_height = + set_bits32(dma->afbcd_hreg_pic_height, + (aligned_rect.bottom - aligned_rect.top), 16, 0); + dma->afbcd_hreg_format = + set_bits32(dma->afbcd_hreg_format, 0x1, 1, 0); + dma->afbcd_hreg_format = + set_bits32(dma->afbcd_hreg_format, + (isYUVPackage(layer->img.format) ? 0x0 : 0x1), 1, + 21); + dma->afbcd_ctl = + set_bits32(dma->afbcd_ctl, afbcd_half_block_mode, 2, 6); + dma->afbcd_str = + set_bits32(dma->afbcd_str, + (afbcd_stretch_acc << 8 | afbcd_stretch_inc), 12, + 0); + dma->afbcd_line_crop = + set_bits32(dma->afbcd_line_crop, + (afbcd_top_crop_num << 4 | + afbcd_bottom_crop_num), 8, 0); + dma->afbcd_hreg_hdr_ptr_lo = + set_bits32(dma->afbcd_hreg_hdr_ptr_lo, afbc_header_addr, 32, + 0); + dma->afbcd_input_header_stride = + set_bits32(dma->afbcd_input_header_stride, + (afbc_header_start_pos << 14) | + afbc_header_stride, 16, 0); + dma->afbcd_payload_stride = + set_bits32(dma->afbcd_payload_stride, afbc_payload_stride, + 20, 0); + dma->afbcd_mm_base_0 = + set_bits32(dma->afbcd_mm_base_0, mm_base_0, 32, 0); + dma->afbcd_afbcd_payload_pointer = + set_bits32(dma->afbcd_afbcd_payload_pointer, + afbc_payload_addr, 32, 0); + dma->afbcd_height_bf_str = + set_bits32(dma->afbcd_height_bf_str, + DSS_HEIGHT(afbcd_height_bf_str), 16, 0); + dma->afbcd_header_pointer_offset = + set_bits32(dma->afbcd_header_pointer_offset, + afbc_header_pointer_offset, 32, 0); + dma->afbcd_scramble_mode = + set_bits32(dma->afbcd_scramble_mode, + layer->img.afbc_scramble_mode, 2, 0); + + return 0; + } + + rdma_addr = mmu_enable ? layer->img.vir_addr : layer->img.phy_addr; + if (rdma_addr & (DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("layer%d rdma_addr(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, rdma_addr, DMA_ADDR_ALIGN); + return -EINVAL; + } + + if (layer->img.stride & (DMA_STRIDE_ALIGN - 1)) { + HISI_FB_ERR("layer%d stride(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, layer->img.stride, + DMA_STRIDE_ALIGN); + return -EINVAL; + } + + if (layer->need_cap & CAP_TILE) { + l2t_interleave_n = + hisi_get_rdma_tile_interleave(layer->img.stride); + if (l2t_interleave_n < MIN_INTERLEAVE) { + HISI_FB_ERR + ("tile stride should be 256*2^n, error stride:%d!\n", + layer->img.stride); + return -EINVAL; + } + + if (rdma_addr & (TILE_DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("layer%d tile rdma_addr(0x%x) is not %d bytes aligned.\n", + layer->layer_idx, rdma_addr, TILE_DMA_ADDR_ALIGN); + return -EINVAL; + } + } + + if (is_YUV_P_420(layer->img.format) || is_YUV_P_422(layer->img.format)) { + aligned_rect.left = + ALIGN_DOWN(new_src_rect.x, 2 * aligned_pixel); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + 2 * aligned_pixel) - 1; + } else { + aligned_rect.left = ALIGN_DOWN(new_src_rect.x, aligned_pixel); + aligned_rect.right = + ALIGN_UP(new_src_rect.x + new_src_rect.w, + aligned_pixel) - 1; + } + + if (is_YUV_SP_420(layer->img.format) || is_YUV_P_420(layer->img.format)) { + aligned_rect.top = ALIGN_DOWN(new_src_rect.y, 2); + aligned_rect.bottom = + ALIGN_UP(new_src_rect.y + new_src_rect.h, 2) - 1; + } else { + aligned_rect.top = new_src_rect.y; + aligned_rect.bottom = + DSS_HEIGHT(new_src_rect.y + new_src_rect.h); + } + + if (src_rect_mask_enable) { + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + aligned_mask_rect.left = + ALIGN_UP(layer->src_rect_mask.x, 2 * aligned_pixel); + aligned_mask_rect.right = + ALIGN_DOWN(layer->src_rect_mask.x + + layer->src_rect_mask.w, + 2 * aligned_pixel) - 1; + } else { + aligned_mask_rect.left = + ALIGN_UP(layer->src_rect_mask.x, aligned_pixel); + aligned_mask_rect.right = + ALIGN_DOWN(layer->src_rect_mask.x + + layer->src_rect_mask.w, + aligned_pixel) - 1; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + aligned_mask_rect.top = + ALIGN_UP(layer->src_rect_mask.y, 2); + aligned_mask_rect.bottom = + ALIGN_DOWN(layer->src_rect_mask.y + + layer->src_rect_mask.h, 2) - 1; + } else { + aligned_mask_rect.top = layer->src_rect_mask.y; + aligned_mask_rect.bottom = + DSS_HEIGHT(layer->src_rect_mask.y + + layer->src_rect_mask.h); + } + } + + out_aligned_rect->x = 0; + out_aligned_rect->y = 0; + out_aligned_rect->w = aligned_rect.right - aligned_rect.left + 1; + out_aligned_rect->h = aligned_rect.bottom - aligned_rect.top + 1; + if (stretched_line_num > 0) { + stretch_size_vrt = (out_aligned_rect->h / stretched_line_num) + + ((out_aligned_rect->h % stretched_line_num) ? 1 : 0) - 1; + + out_aligned_rect->h = stretch_size_vrt + 1; + } else { + stretch_size_vrt = 0x0; + } + + clip_rect->left = new_src_rect.x - aligned_rect.left; + clip_rect->right = + aligned_rect.right - DSS_WIDTH(new_src_rect.x + new_src_rect.w); + clip_rect->top = new_src_rect.y - aligned_rect.top; + clip_rect->bottom = + aligned_rect.bottom - DSS_HEIGHT(new_src_rect.y + new_src_rect.h); + + if (hisi_adjust_clip_rect(layer, clip_rect) < 0) { + HISI_FB_ERR + ("clip rect invalid => layer_idx=%d, chn_idx=%d, " + "clip_rect(%d, %d, %d, %d).\n", + layer->layer_idx, chn_idx, clip_rect->left, + clip_rect->right, clip_rect->top, clip_rect->bottom); + return -EINVAL; + } + + rdma_oft_y0 = aligned_rect.top; + rdma_oft_y1 = aligned_rect.bottom; + rdma_oft_x0 = aligned_rect.left / aligned_pixel; + rdma_oft_x1 = aligned_rect.right / aligned_pixel; + + if ((rdma_oft_x1 - rdma_oft_x0) < 0 || + (rdma_oft_x1 - rdma_oft_x0 + 1) > DMA_IN_WIDTH_MAX) { + HISI_FB_ERR + ("out of range, rdma_oft_x0 = %d, rdma_oft_x1 = %d!\n", + rdma_oft_x0, rdma_oft_x1); + return -EINVAL; + } + + if ((rdma_oft_y1 - rdma_oft_y0) < 0 || + (rdma_oft_y1 - rdma_oft_y0 + 1) > DMA_IN_HEIGHT_MAX) { + HISI_FB_ERR + ("out of range, rdma_oft_y0 = %d, rdma_oft_y1 = %d\n", + rdma_oft_y0, rdma_oft_y1); + return -EINVAL; + } + + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, &aligned_rect, + DSS_ADDR_PLANE0); + rdma_stride = layer->img.stride; + rdma_data_num = + (rdma_oft_x1 - rdma_oft_x0 + 1) * (rdma_oft_y1 - rdma_oft_y0 + 1); + + if (src_rect_mask_enable) { + rdma_mask_y0 = aligned_mask_rect.top; + rdma_mask_y1 = aligned_mask_rect.bottom; + rdma_mask_x0 = aligned_mask_rect.left / aligned_pixel; + rdma_mask_x1 = aligned_mask_rect.right / aligned_pixel; + + if ((rdma_mask_x1 - rdma_mask_x0) > 2) + rdma_mask_x0 += 2; + + if ((rdma_mask_x0 <= rdma_oft_x0) + || (rdma_mask_x1 >= rdma_oft_x1) + || (rdma_mask_y0 <= rdma_oft_y0) + || (rdma_mask_y1 >= rdma_oft_y1)) { + src_rect_mask_enable = false; + rdma_mask_x0 = 0; + rdma_mask_y0 = 0; + rdma_mask_x1 = 0; + rdma_mask_y1 = 0; + } + } + + if (stretched_line_num > 0) { + stretched_stride = + stretched_line_num * rdma_stride / DMA_ALIGN_BYTES; + rdma_data_num = + (stretch_size_vrt + 1) * (rdma_oft_x1 - rdma_oft_x0 + 1); + } else { + stretch_size_vrt = rdma_oft_y1 - rdma_oft_y0; + stretched_line_num = 0x0; + stretched_stride = 0x0; + } + + dma->oft_x0 = set_bits32(dma->oft_x0, rdma_oft_x0, 16, 0); + dma->oft_y0 = set_bits32(dma->oft_y0, rdma_oft_y0, 16, 0); + dma->oft_x1 = set_bits32(dma->oft_x1, rdma_oft_x1, 16, 0); + dma->oft_y1 = set_bits32(dma->oft_y1, rdma_oft_y1, 16, 0); + dma->mask0 = set_bits32(dma->mask0, + (rdma_mask_y0 | (rdma_mask_x0 << 16)), 32, 0); + dma->mask1 = set_bits32(dma->mask1, + (rdma_mask_y1 | (rdma_mask_x1 << 16)), 32, 0); + dma->stretch_size_vrt = set_bits32(dma->stretch_size_vrt, + (stretch_size_vrt | + (stretched_line_num << 13)), 19, 0); + dma->ctrl = + set_bits32(dma->ctrl, ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, + 1); + dma->ctrl = set_bits32(dma->ctrl, rdma_format, 5, 3); + dma->ctrl = set_bits32(dma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + dma->ctrl = set_bits32(dma->ctrl, rdma_transform, 3, 9); + dma->ctrl = + set_bits32(dma->ctrl, ((stretched_line_num > 0) ? 0x1 : 0x0), 1, + 12); + dma->ctrl = + set_bits32(dma->ctrl, (src_rect_mask_enable ? 0x1 : 0x0), 1, 17); + dma->tile_scram = + set_bits32(dma->tile_scram, + ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, 0); + dma->ch_ctl = set_bits32(dma->ch_ctl, 0x1, 1, 0); + + dma->data_addr0 = set_bits32(dma->data_addr0, rdma_addr, 32, 0); + dma->stride0 = set_bits32(dma->stride0, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << + 16)), 20, 0); + dma->stretch_stride0 = + set_bits32(dma->stretch_stride0, stretched_stride, 19, 0); + dma->data_num0 = set_bits32(dma->data_num0, rdma_data_num, 30, 0); + + if (is_yuv_semi_planar || is_yuv_planar) { + if (is_YUV_P_420(layer->img.format) + || is_YUV_P_422(layer->img.format)) { + rdma_oft_x0 /= 2; + rdma_oft_x1 = (rdma_oft_x1 + 1) / 2 - 1; + } + + if (is_YUV_SP_420(layer->img.format) + || is_YUV_P_420(layer->img.format)) { + rdma_oft_y0 /= 2; + rdma_oft_y1 = (rdma_oft_y1 + 1) / 2 - 1; + + stretched_line_num /= 2; + } + + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, + &aligned_rect, DSS_ADDR_PLANE1); + rdma_stride = layer->img.stride_plane1; + rdma_data_num = + (rdma_oft_x1 - rdma_oft_x0 + 1) * (rdma_oft_y1 - + rdma_oft_y0 + 1) * 2; + + if (*rdma_stretch_enable) { + stretched_stride = + stretched_line_num * rdma_stride / DMA_ALIGN_BYTES; + rdma_data_num = + (stretch_size_vrt + 1) * (rdma_oft_x1 - + rdma_oft_x0 + 1) * 2; + } else { + stretch_size_vrt = 0; + stretched_line_num = 0; + stretched_stride = 0; + } + + dma->data_addr1 = set_bits32(dma->data_addr1, rdma_addr, 32, 0); + dma->stride1 = set_bits32(dma->stride1, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << 16)), 20, 0); + dma->stretch_stride1 = + set_bits32(dma->stretch_stride1, stretched_stride, 19, 0); + dma->data_num1 = + set_bits32(dma->data_num1, rdma_data_num, 30, 0); + + if (is_yuv_planar) { + rdma_addr = + hisi_calculate_display_addr(mmu_enable, layer, + &aligned_rect, + DSS_ADDR_PLANE2); + rdma_stride = layer->img.stride_plane2; + + dma->data_addr2 = + set_bits32(dma->data_addr2, rdma_addr, 32, 0); + dma->stride2 = + set_bits32(dma->stride2, + ((rdma_stride / + DMA_ALIGN_BYTES) | (l2t_interleave_n << 16)), 20, 0); + dma->stretch_stride2 = + set_bits32(dma->stretch_stride1, stretched_stride, + 19, 0); + dma->data_num2 = + set_bits32(dma->data_num1, rdma_data_num, 30, 0); + } + } + + return 0; +} + +/******************************************************************************* + ** DSS DFC + */ +static void hisi_dss_dfc_init(char __iomem *dfc_base, dss_dfc_t *s_dfc) +{ + BUG_ON(dfc_base == NULL); + BUG_ON(s_dfc == NULL); + + memset(s_dfc, 0, sizeof(dss_dfc_t)); + + s_dfc->disp_size = inp32(dfc_base + DFC_DISP_SIZE); + s_dfc->pix_in_num = inp32(dfc_base + DFC_PIX_IN_NUM); + s_dfc->disp_fmt = inp32(dfc_base + DFC_DISP_FMT); + s_dfc->clip_ctl_hrz = inp32(dfc_base + DFC_CLIP_CTL_HRZ); + s_dfc->clip_ctl_vrz = inp32(dfc_base + DFC_CLIP_CTL_VRZ); + s_dfc->ctl_clip_en = inp32(dfc_base + DFC_CTL_CLIP_EN); + s_dfc->icg_module = inp32(dfc_base + DFC_ICG_MODULE); + s_dfc->dither_enable = inp32(dfc_base + DFC_DITHER_ENABLE); + s_dfc->padding_ctl = inp32(dfc_base + DFC_PADDING_CTL); +} + +static void hisi_dss_dfc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dfc_base, dss_dfc_t *s_dfc) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dfc_base == NULL); + BUG_ON(s_dfc == NULL); + + hisifd->set_reg(hisifd, dfc_base + DFC_DISP_SIZE, s_dfc->disp_size, 32, + 0); + hisifd->set_reg(hisifd, dfc_base + DFC_PIX_IN_NUM, s_dfc->pix_in_num, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_DISP_FMT, s_dfc->disp_fmt, 32, + 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CLIP_CTL_HRZ, + s_dfc->clip_ctl_hrz, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CLIP_CTL_VRZ, + s_dfc->clip_ctl_vrz, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_CTL_CLIP_EN, s_dfc->ctl_clip_en, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_ICG_MODULE, s_dfc->icg_module, + 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_DITHER_ENABLE, + s_dfc->dither_enable, 32, 0); + hisifd->set_reg(hisifd, dfc_base + DFC_PADDING_CTL, s_dfc->padding_ctl, + 32, 0); +} + +int hisi_dss_rdfc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, dss_rect_ltrb_t clip_rect) +{ + dss_dfc_t *dfc = NULL; + int chn_idx = 0; + int dfc_fmt = 0; + int dfc_bpp = 0; + int dfc_pix_in_num = 0; + int dfc_aligned = 0; + int size_hrz = 0; + int size_vrt = 0; + int dfc_hrz_clip = 0; + bool need_clip = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + + dfc = &(hisifd->dss_module.dfc[chn_idx]); + hisifd->dss_module.dfc_used[chn_idx] = 1; + + dfc_fmt = hisi_pixel_format_hal2dfc(layer->img.format); + if (dfc_fmt < 0) { + HISI_FB_ERR("layer format (%d) not support !\n", + layer->img.format); + return -EINVAL; + } + + dfc_bpp = hisi_dfc_get_bpp(dfc_fmt); + if (dfc_bpp <= 0) { + HISI_FB_ERR("dfc_bpp(%d) not support !\n", dfc_bpp); + return -EINVAL; + } + + dfc_pix_in_num = (dfc_bpp <= 2) ? 0x1 : 0x0; + dfc_aligned = (dfc_bpp <= 2) ? 4 : 2; + + need_clip = isNeedRectClip(clip_rect); + + size_hrz = DSS_WIDTH(aligned_rect->w); + size_vrt = DSS_HEIGHT(aligned_rect->h); + + if (((size_hrz + 1) % dfc_aligned) != 0) { + size_hrz -= 1; + HISI_FB_ERR("SIZE_HRT=%d mismatch!bpp=%d\n", size_hrz, + layer->img.bpp); + + HISI_FB_ERR("layer_idx%d, format=%d, transform=%d, " + "original_src_rect(%d,%d,%d,%d), rdma_out_rect(%d,%d,%d,%d), " + "dst_rect(%d,%d,%d,%d)!\n", + layer->layer_idx, layer->img.format, + layer->transform, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, aligned_rect->x, aligned_rect->y, + aligned_rect->w, aligned_rect->h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + dfc_hrz_clip = (size_hrz + 1) % dfc_aligned; + if (dfc_hrz_clip) { + clip_rect.right += dfc_hrz_clip; + size_hrz += dfc_hrz_clip; + need_clip = true; + } + + dfc->disp_size = + set_bits32(dfc->disp_size, (size_vrt | (size_hrz << 16)), 29, 0); + dfc->pix_in_num = set_bits32(dfc->pix_in_num, dfc_pix_in_num, 1, 0); + dfc->disp_fmt = set_bits32(dfc->disp_fmt, + ((dfc_fmt << 1) | + (hisi_uv_swap(layer->img.format) << 6) | + (hisi_rb_swap(layer->img.format) << 7)), 8, 0); + + if (need_clip) { + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, + (clip_rect.right | (clip_rect.left << 16)), + 32, 0); + dfc->clip_ctl_vrz = + set_bits32(dfc->clip_ctl_vrz, + (clip_rect.bottom | (clip_rect.top << 16)), 32, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x1, 1, 0); + } else { + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, 0x0, 32, 0); + dfc->clip_ctl_vrz = set_bits32(dfc->clip_ctl_vrz, 0x0, 32, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x1, 1, 0); + } + dfc->icg_module = set_bits32(dfc->icg_module, 0x1, 1, 0); + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x0, 1, 0); + dfc->padding_ctl = set_bits32(dfc->padding_ctl, 0x0, 17, 0); + + if (need_clip) { + aligned_rect->w -= (clip_rect.left + clip_rect.right); + aligned_rect->h -= (clip_rect.top + clip_rect.bottom); + } + + return 0; +} + +/******************************************************************************* + ** DSS SCF + */ + +/* Filter coefficients for SCF */ +#define PHASE_NUM (66) +#define TAP4 (4) +#define TAP5 (5) +#define TAP6 (6) +#define COEF_LUT_NUM (2) + +static const int COEF_LUT_TAP4[SCL_COEF_IDX_MAX][PHASE_NUM][TAP4] = { + /* YUV_COEF_IDX */ + { + {214, 599, 214, -3}, + {207, 597, 223, -3}, + {200, 596, 231, -3}, + {193, 596, 238, -3}, + {186, 595, 246, -3}, + {178, 594, 255, -3}, + {171, 593, 263, -3}, + {165, 591, 271, -3}, + {158, 589, 279, -2}, + {151, 587, 288, -2}, + {145, 584, 296, -1}, + {139, 582, 304, -1}, + {133, 578, 312, 1}, + {127, 575, 321, 1}, + {121, 572, 329, 2}, + {115, 568, 337, 4}, + {109, 564, 346, 5}, + {104, 560, 354, 6}, + {98, 555, 362, 9}, + {94, 550, 370, 10}, + {88, 546, 379, 11}, + {84, 540, 387, 13}, + {79, 535, 395, 15}, + {74, 530, 403, 17}, + {70, 524, 411, 19}, + {66, 518, 419, 21}, + {62, 512, 427, 23}, + {57, 506, 435, 26}, + {54, 499, 443, 28}, + {50, 492, 451, 31}, + {47, 486, 457, 34}, + {43, 479, 465, 37}, + {40, 472, 472, 40}, + {214, 599, 214, -3}, + {207, 597, 223, -3}, + {200, 596, 231, -3}, + {193, 596, 238, -3}, + {186, 595, 246, -3}, + {178, 594, 255, -3}, + {171, 593, 263, -3}, + {165, 591, 271, -3}, + {158, 589, 279, -2}, + {151, 587, 288, -2}, + {145, 584, 296, -1}, + {139, 582, 304, -1}, + {133, 578, 312, 1}, + {127, 575, 321, 1}, + {121, 572, 329, 2}, + {115, 568, 337, 4}, + {109, 564, 346, 5}, + {104, 560, 354, 6}, + {98, 555, 362, 9}, + {94, 550, 370, 10}, + {88, 546, 379, 11}, + {84, 540, 387, 13}, + {79, 535, 395, 15}, + {74, 530, 403, 17}, + {70, 524, 411, 19}, + {66, 518, 419, 21}, + {62, 512, 427, 23}, + {57, 506, 435, 26}, + {54, 499, 443, 28}, + {50, 492, 451, 31}, + {47, 486, 457, 34}, + {43, 479, 465, 37}, + {40, 472, 472, 40} + }, + + /* RGB_COEF_IDX */ + { + {0, 1024, 0, 0}, + {0, 1008, 16, 0}, + {0, 992, 32, 0}, + {0, 976, 48, 0}, + {0, 960, 64, 0}, + {0, 944, 80, 0}, + {0, 928, 96, 0}, + {0, 912, 112, 0}, + {0, 896, 128, 0}, + {0, 880, 144, 0}, + {0, 864, 160, 0}, + {0, 848, 176, 0}, + {0, 832, 192, 0}, + {0, 816, 208, 0}, + {0, 800, 224, 0}, + {0, 784, 240, 0}, + {0, 768, 256, 0}, + {0, 752, 272, 0}, + {0, 736, 288, 0}, + {0, 720, 304, 0}, + {0, 704, 320, 0}, + {0, 688, 336, 0}, + {0, 672, 352, 0}, + {0, 656, 368, 0}, + {0, 640, 384, 0}, + {0, 624, 400, 0}, + {0, 608, 416, 0}, + {0, 592, 432, 0}, + {0, 576, 448, 0}, + {0, 560, 464, 0}, + {0, 544, 480, 0}, + {0, 528, 496, 0}, + {0, 512, 512, 0}, + {0, 1024, 0, 0}, + {0, 1008, 16, 0}, + {0, 992, 32, 0}, + {0, 976, 48, 0}, + {0, 960, 64, 0}, + {0, 944, 80, 0}, + {0, 928, 96, 0}, + {0, 912, 112, 0}, + {0, 896, 128, 0}, + {0, 880, 144, 0}, + {0, 864, 160, 0}, + {0, 848, 176, 0}, + {0, 832, 192, 0}, + {0, 816, 208, 0}, + {0, 800, 224, 0}, + {0, 784, 240, 0}, + {0, 768, 256, 0}, + {0, 752, 272, 0}, + {0, 736, 288, 0}, + {0, 720, 304, 0}, + {0, 704, 320, 0}, + {0, 688, 336, 0}, + {0, 672, 352, 0}, + {0, 656, 368, 0}, + {0, 640, 384, 0}, + {0, 624, 400, 0}, + {0, 608, 416, 0}, + {0, 592, 432, 0}, + {0, 576, 448, 0}, + {0, 560, 464, 0}, + {0, 544, 480, 0}, + {0, 528, 496, 0}, + {0, 512, 512, 0} + } +}; + +static const int COEF_LUT_TAP5[SCL_COEF_IDX_MAX][PHASE_NUM][TAP5] = { + /* YUV_COEF_IDX */ + { + {98, 415, 415, 98, -2}, + {95, 412, 418, 103, -4}, + {91, 408, 422, 107, -4}, + {87, 404, 426, 111, -4}, + {84, 399, 430, 115, -4}, + {80, 395, 434, 119, -4}, + {76, 390, 438, 124, -4}, + {73, 386, 440, 128, -3}, + {70, 381, 444, 132, -3}, + {66, 376, 448, 137, -3}, + {63, 371, 451, 142, -3}, + {60, 366, 455, 146, -3}, + {57, 361, 457, 151, -2}, + {54, 356, 460, 156, -2}, + {51, 351, 463, 161, -2}, + {49, 346, 465, 165, -1}, + {46, 341, 468, 170, -1}, + {43, 336, 470, 175, 0}, + {41, 331, 472, 180, 0}, + {38, 325, 474, 186, 1}, + {36, 320, 476, 191, 1}, + {34, 315, 477, 196, 2}, + {32, 309, 479, 201, 3}, + {29, 304, 481, 206, 4}, + {27, 299, 481, 212, 5}, + {26, 293, 482, 217, 6}, + {24, 288, 484, 222, 6}, + {22, 282, 484, 228, 8}, + {20, 277, 485, 233, 9}, + {19, 271, 485, 238, 11}, + {17, 266, 485, 244, 12}, + {16, 260, 485, 250, 13}, + {14, 255, 486, 255, 14}, + {-94, 608, 608, -94, -4}, + {-94, 594, 619, -91, -4}, + {-96, 579, 635, -89, -5}, + {-96, 563, 650, -87, -6}, + {-97, 548, 665, -85, -7}, + {-97, 532, 678, -82, -7}, + {-98, 516, 693, -79, -8}, + {-97, 500, 705, -75, -9}, + {-97, 484, 720, -72, -11}, + {-97, 468, 733, -68, -12}, + {-96, 452, 744, -63, -13}, + {-95, 436, 755, -58, -14}, + {-94, 419, 768, -53, -16}, + {-93, 403, 779, -48, -17}, + {-92, 387, 789, -42, -18}, + {-90, 371, 799, -36, -20}, + {-89, 355, 809, -29, -22}, + {-87, 339, 817, -22, -23}, + {-86, 324, 826, -15, -25}, + {-84, 308, 835, -8, -27}, + {-82, 293, 842, 0, -29}, + {-80, 277, 849, 9, -31}, + {-78, 262, 855, 18, -33}, + {-75, 247, 860, 27, -35}, + {-73, 233, 865, 36, -37}, + {-71, 218, 870, 46, -39}, + {-69, 204, 874, 56, -41}, + {-66, 190, 876, 67, -43}, + {-64, 176, 879, 78, -45}, + {-62, 163, 882, 89, -48}, + {-59, 150, 883, 100, -50}, + {-57, 137, 883, 112, -51}, + {-55, 125, 884, 125, -55} + }, + + /* RGB_COEF_IDX */ + { + {0, 512, 512, 0, 0}, + {0, 496, 528, 0, 0}, + {0, 480, 544, 0, 0}, + {0, 464, 560, 0, 0}, + {0, 448, 576, 0, 0}, + {0, 432, 592, 0, 0}, + {0, 416, 608, 0, 0}, + {0, 400, 624, 0, 0}, + {0, 384, 640, 0, 0}, + {0, 368, 656, 0, 0}, + {0, 352, 672, 0, 0}, + {0, 336, 688, 0, 0}, + {0, 320, 704, 0, 0}, + {0, 304, 720, 0, 0}, + {0, 288, 736, 0, 0}, + {0, 272, 752, 0, 0}, + {0, 256, 768, 0, 0}, + {0, 240, 784, 0, 0}, + {0, 224, 800, 0, 0}, + {0, 208, 816, 0, 0}, + {0, 192, 832, 0, 0}, + {0, 176, 848, 0, 0}, + {0, 160, 864, 0, 0}, + {0, 144, 880, 0, 0}, + {0, 128, 896, 0, 0}, + {0, 112, 912, 0, 0}, + {0, 96, 928, 0, 0}, + {0, 80, 944, 0, 0}, + {0, 64, 960, 0, 0}, + {0, 48, 976, 0, 0}, + {0, 32, 992, 0, 0}, + {0, 16, 1008, 0, 0}, + {0, 0, 1024, 0, 0}, + {0, 512, 512, 0, 0}, + {0, 496, 528, 0, 0}, + {0, 480, 544, 0, 0}, + {0, 464, 560, 0, 0}, + {0, 448, 576, 0, 0}, + {0, 432, 592, 0, 0}, + {0, 416, 608, 0, 0}, + {0, 400, 624, 0, 0}, + {0, 384, 640, 0, 0}, + {0, 368, 656, 0, 0}, + {0, 352, 672, 0, 0}, + {0, 336, 688, 0, 0}, + {0, 320, 704, 0, 0}, + {0, 304, 720, 0, 0}, + {0, 288, 736, 0, 0}, + {0, 272, 752, 0, 0}, + {0, 256, 768, 0, 0}, + {0, 240, 784, 0, 0}, + {0, 224, 800, 0, 0}, + {0, 208, 816, 0, 0}, + {0, 192, 832, 0, 0}, + {0, 176, 848, 0, 0}, + {0, 160, 864, 0, 0}, + {0, 144, 880, 0, 0}, + {0, 128, 896, 0, 0}, + {0, 112, 912, 0, 0}, + {0, 96, 928, 0, 0}, + {0, 80, 944, 0, 0}, + {0, 64, 960, 0, 0}, + {0, 48, 976, 0, 0}, + {0, 32, 992, 0, 0}, + {0, 16, 1008, 0, 0}, + {0, 0, 1024, 0, 0} + } +}; + +static const int COEF_LUT_TAP6[SCL_COEF_IDX_MAX][PHASE_NUM][TAP6] = { + /* YUV_COEF_IDX */ + { + {2, 264, 500, 264, 2, -8}, + {2, 257, 499, 268, 6, -8}, + {1, 252, 498, 274, 8, -9}, + {-1, 246, 498, 281, 9, -9}, + {-2, 241, 497, 286, 12, -10}, + {-3, 235, 497, 292, 13, -10}, + {-5, 230, 496, 298, 15, -10}, + {-6, 225, 495, 303, 18, -11}, + {-7, 219, 494, 309, 20, -11}, + {-7, 213, 493, 314, 23, -12}, + {-9, 208, 491, 320, 26, -12}, + {-10, 203, 490, 325, 28, -12}, + {-10, 197, 488, 331, 31, -13}, + {-10, 192, 486, 336, 33, -13}, + {-12, 186, 485, 342, 36, -13}, + {-12, 181, 482, 347, 39, -13}, + {-13, 176, 480, 352, 42, -13}, + {-14, 171, 478, 358, 45, -14}, + {-14, 166, 476, 363, 48, -15}, + {-14, 160, 473, 368, 52, -15}, + {-14, 155, 470, 373, 55, -15}, + {-15, 150, 467, 378, 59, -15}, + {-15, 145, 464, 383, 62, -15}, + {-16, 141, 461, 388, 65, -15}, + {-16, 136, 458, 393, 68, -15}, + {-16, 131, 455, 398, 72, -16}, + {-16, 126, 451, 402, 77, -16}, + {-16, 122, 448, 407, 79, -16}, + {-16, 117, 444, 411, 84, -16}, + {-17, 113, 441, 416, 87, -16}, + {-17, 108, 437, 420, 92, -16}, + {-17, 104, 433, 424, 96, -16}, + {-17, 100, 429, 429, 100, -17}, + {-187, 105, 1186, 105, -187, 2}, + {-182, 86, 1186, 124, -192, 2}, + {-176, 67, 1185, 143, -197, 2}, + {-170, 49, 1182, 163, -202, 2}, + {-166, 32, 1180, 184, -207, 1}, + {-160, 15, 1176, 204, -212, 1}, + {-155, -2, 1171, 225, -216, 1}, + {-149, -18, 1166, 246, -221, 0}, + {-145, -34, 1160, 268, -225, 0}, + {-139, -49, 1153, 290, -230, -1}, + {-134, -63, 1145, 312, -234, -2}, + {-129, -78, 1137, 334, -238, -2}, + {-124, -91, 1128, 357, -241, -5}, + {-119, -104, 1118, 379, -245, -5}, + {-114, -117, 1107, 402, -248, -6}, + {-109, -129, 1096, 425, -251, -8}, + {-104, -141, 1083, 448, -254, -8}, + {-100, -152, 1071, 471, -257, -9}, + {-95, -162, 1057, 494, -259, -11}, + {-90, -172, 1043, 517, -261, -13}, + {-86, -181, 1028, 540, -263, -14}, + {-82, -190, 1013, 563, -264, -16}, + {-77, -199, 997, 586, -265, -18}, + {-73, -207, 980, 609, -266, -19}, + {-69, -214, 963, 632, -266, -22}, + {-65, -221, 945, 655, -266, -24}, + {-62, -227, 927, 678, -266, -26}, + {-58, -233, 908, 700, -265, -28}, + {-54, -238, 889, 722, -264, -31}, + {-51, -243, 870, 744, -262, -34}, + {-48, -247, 850, 766, -260, -37}, + {-45, -251, 829, 787, -257, -39}, + {-42, -255, 809, 809, -255, -42} + }, + + /* RGB_COEF_IDX */ + { + {0, 0, 1024, 0, 0, 0}, + {0, 0, 1008, 16, 0, 0}, + {0, 0, 992, 32, 0, 0}, + {0, 0, 976, 48, 0, 0}, + {0, 0, 960, 64, 0, 0}, + {0, 0, 944, 80, 0, 0}, + {0, 0, 928, 96, 0, 0}, + {0, 0, 912, 112, 0, 0}, + {0, 0, 896, 128, 0, 0}, + {0, 0, 880, 144, 0, 0}, + {0, 0, 864, 160, 0, 0}, + {0, 0, 848, 176, 0, 0}, + {0, 0, 832, 192, 0, 0}, + {0, 0, 816, 208, 0, 0}, + {0, 0, 800, 224, 0, 0}, + {0, 0, 784, 240, 0, 0}, + {0, 0, 768, 256, 0, 0}, + {0, 0, 752, 272, 0, 0}, + {0, 0, 736, 288, 0, 0}, + {0, 0, 720, 304, 0, 0}, + {0, 0, 704, 320, 0, 0}, + {0, 0, 688, 336, 0, 0}, + {0, 0, 672, 352, 0, 0}, + {0, 0, 656, 368, 0, 0}, + {0, 0, 640, 384, 0, 0}, + {0, 0, 624, 400, 0, 0}, + {0, 0, 608, 416, 0, 0}, + {0, 0, 592, 432, 0, 0}, + {0, 0, 576, 448, 0, 0}, + {0, 0, 560, 464, 0, 0}, + {0, 0, 544, 480, 0, 0}, + {0, 0, 528, 496, 0, 0}, + {0, 0, 512, 512, 0, 0}, + {0, 0, 1024, 0, 0, 0}, + {0, 0, 1008, 16, 0, 0}, + {0, 0, 992, 32, 0, 0}, + {0, 0, 976, 48, 0, 0}, + {0, 0, 960, 64, 0, 0}, + {0, 0, 944, 80, 0, 0}, + {0, 0, 928, 96, 0, 0}, + {0, 0, 912, 112, 0, 0}, + {0, 0, 896, 128, 0, 0}, + {0, 0, 880, 144, 0, 0}, + {0, 0, 864, 160, 0, 0}, + {0, 0, 848, 176, 0, 0}, + {0, 0, 832, 192, 0, 0}, + {0, 0, 816, 208, 0, 0}, + {0, 0, 800, 224, 0, 0}, + {0, 0, 784, 240, 0, 0}, + {0, 0, 768, 256, 0, 0}, + {0, 0, 752, 272, 0, 0}, + {0, 0, 736, 288, 0, 0}, + {0, 0, 720, 304, 0, 0}, + {0, 0, 704, 320, 0, 0}, + {0, 0, 688, 336, 0, 0}, + {0, 0, 672, 352, 0, 0}, + {0, 0, 656, 368, 0, 0}, + {0, 0, 640, 384, 0, 0}, + {0, 0, 624, 400, 0, 0}, + {0, 0, 608, 416, 0, 0}, + {0, 0, 592, 432, 0, 0}, + {0, 0, 576, 448, 0, 0}, + {0, 0, 560, 464, 0, 0}, + {0, 0, 544, 480, 0, 0}, + {0, 0, 528, 496, 0, 0}, + {0, 0, 512, 512, 0, 0} + } +}; + +static void hisi_dss_scl_init(char __iomem *scl_base, dss_scl_t *s_scl) +{ + BUG_ON(scl_base == NULL); + BUG_ON(s_scl == NULL); + + memset(s_scl, 0, sizeof(dss_scl_t)); + + s_scl->en_hscl_str = inp32(scl_base + SCF_EN_HSCL_STR); + s_scl->en_vscl_str = inp32(scl_base + SCF_EN_VSCL_STR); + s_scl->h_v_order = inp32(scl_base + SCF_H_V_ORDER); + s_scl->input_width_height = inp32(scl_base + SCF_INPUT_WIDTH_HEIGHT); + s_scl->output_width_height = inp32(scl_base + SCF_OUTPUT_WIDTH_HEIGHT); + s_scl->en_hscl = inp32(scl_base + SCF_EN_HSCL); + s_scl->en_vscl = inp32(scl_base + SCF_EN_VSCL); + s_scl->acc_hscl = inp32(scl_base + SCF_ACC_HSCL); + s_scl->inc_hscl = inp32(scl_base + SCF_INC_HSCL); + s_scl->inc_vscl = inp32(scl_base + SCF_INC_VSCL); + s_scl->en_mmp = inp32(scl_base + SCF_EN_MMP); +} + +void hisi_dss_scl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *scl_base, dss_scl_t *s_scl) +{ + BUG_ON(scl_base == NULL); + BUG_ON(s_scl == NULL); + + if (hisifd) { + hisifd->set_reg(hisifd, scl_base + SCF_EN_HSCL_STR, + s_scl->en_hscl_str, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_VSCL_STR, + s_scl->en_vscl_str, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_H_V_ORDER, + s_scl->h_v_order, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INPUT_WIDTH_HEIGHT, + s_scl->input_width_height, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_OUTPUT_WIDTH_HEIGHT, + s_scl->output_width_height, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_HSCL, + s_scl->en_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_VSCL, + s_scl->en_vscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_ACC_HSCL, + s_scl->acc_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INC_HSCL, + s_scl->inc_hscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_INC_VSCL, + s_scl->inc_vscl, 32, 0); + hisifd->set_reg(hisifd, scl_base + SCF_EN_MMP, + s_scl->en_mmp, 32, 0); + } else { + set_reg(scl_base + SCF_EN_HSCL_STR, s_scl->en_hscl_str, 32, 0); + set_reg(scl_base + SCF_EN_VSCL_STR, s_scl->en_vscl_str, 32, 0); + set_reg(scl_base + SCF_H_V_ORDER, s_scl->h_v_order, 32, 0); + set_reg(scl_base + SCF_INPUT_WIDTH_HEIGHT, + s_scl->input_width_height, 32, 0); + set_reg(scl_base + SCF_OUTPUT_WIDTH_HEIGHT, + s_scl->output_width_height, 32, 0); + set_reg(scl_base + SCF_EN_HSCL, s_scl->en_hscl, 32, 0); + set_reg(scl_base + SCF_EN_VSCL, s_scl->en_vscl, 32, 0); + set_reg(scl_base + SCF_ACC_HSCL, s_scl->acc_hscl, 32, 0); + set_reg(scl_base + SCF_INC_HSCL, s_scl->inc_hscl, 32, 0); + set_reg(scl_base + SCF_INC_VSCL, s_scl->inc_vscl, 32, 0); + set_reg(scl_base + SCF_EN_MMP, s_scl->en_mmp, 32, 0); + } +} + +int hisi_dss_scl_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int groups[3] = { 0 }; + int offset = 0; + int valid_num = 0; + int i = 0; + int j = 0; + int k = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != PHASE_NUM) || (col < TAP4 || col > TAP6)) { + HISI_FB_ERR + ("SCF filter coefficients is err, phase_num = %d, tap_num = %d\n", + row, col); + return -EINVAL; + } + + /*byte */ + offset = (col == TAP4) ? 8 : 16; + valid_num = (offset == 16) ? 3 : 2; + + for (i = 0; i < row; i++) { + for (j = 0; j < col; j += 2) { + if ((col % 2) && (j == col - 1)) { + groups[j / 2] = + (*((int *)p + i * col + j) & 0xFFF) | (0 << + 16); + } else { + groups[j / 2] = + (*((int *)p + i * col + j) & 0xFFF) | + (*((int *)p + i * col + j + 1) << 16); + } + } + + for (k = 0; k < valid_num; k++) { + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + offset * i + + k * sizeof(int), groups[k], 32, + 0); + } else { + set_reg(addr + offset * i + k * sizeof(int), + groups[k], 32, 0); + } + groups[k] = 0; + } + } + + return 0; +} + +int hisi_dss_chn_scl_load_filter_coef_set_reg(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, int chn_idx, + uint32_t format) +{ + uint32_t module_base = 0; + char __iomem *h0_y_addr = NULL; + char __iomem *y_addr = NULL; + char __iomem *uv_addr = NULL; + int ret = 0; + int chn_coef_idx = SCL_COEF_YUV_IDX; + + BUG_ON(hisifd == NULL); + if ((chn_idx != DSS_RCHN_V0) && (chn_idx != DSS_RCHN_V1) + && (chn_idx != DSS_RCHN_V2)) + return 0; + + if (isYUV(format)) { + chn_coef_idx = SCL_COEF_YUV_IDX; + } else { + chn_coef_idx = SCL_COEF_RGB_IDX; + } + + if (g_scf_lut_chn_coef_idx[chn_idx] == chn_coef_idx) + return 0; + + g_scf_lut_chn_coef_idx[chn_idx] = chn_coef_idx; + + module_base = g_dss_module_base[chn_idx][MODULE_SCL_LUT]; + BUG_ON(module_base == 0); + + h0_y_addr = hisifd->dss_base + module_base + DSS_SCF_H0_Y_COEF_OFFSET; + y_addr = hisifd->dss_base + module_base + DSS_SCF_Y_COEF_OFFSET; + uv_addr = hisifd->dss_base + module_base + DSS_SCF_UV_COEF_OFFSET; + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, h0_y_addr, + (const int **)COEF_LUT_TAP6[chn_coef_idx], + PHASE_NUM, TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write H0_Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, y_addr, + (const int **)COEF_LUT_TAP5[chn_coef_idx], + PHASE_NUM, TAP5); + if (ret < 0) { + HISI_FB_ERR("Error to write Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, uv_addr, + (const int **)COEF_LUT_TAP4[chn_coef_idx], + PHASE_NUM, TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write UV_COEF coefficients.\n"); + } + + return ret; +} + +int hisi_dss_scl_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist, + int coef_lut_idx) +{ + int i = 0; + uint32_t module_base = 0; + char __iomem *h0_y_addr = NULL; + char __iomem *y_addr = NULL; + char __iomem *uv_addr = NULL; + int ret = 0; + + BUG_ON(hisifd == NULL); + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + module_base = g_dss_module_base[i][MODULE_SCL_LUT]; + if (module_base != 0) { + h0_y_addr = + hisifd->dss_base + module_base + + DSS_SCF_H0_Y_COEF_OFFSET; + y_addr = + hisifd->dss_base + module_base + + DSS_SCF_Y_COEF_OFFSET; + uv_addr = + hisifd->dss_base + module_base + + DSS_SCF_UV_COEF_OFFSET; + + g_scf_lut_chn_coef_idx[i] = coef_lut_idx; + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, + h0_y_addr, + (const int **) + COEF_LUT_TAP6 + [coef_lut_idx], PHASE_NUM, + TAP6); + if (ret < 0) { + HISI_FB_ERR + ("Error to write H0_Y_COEF coefficients.\n"); + } + + if (i == DSS_RCHN_V0) { + hisi_dss_arsr2p_coef_on(hisifd, enable_cmdlist); + continue; + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, y_addr, + (const int **)COEF_LUT_TAP5[coef_lut_idx], + PHASE_NUM, TAP5); + if (ret < 0) { + HISI_FB_ERR + ("Error to write Y_COEF coefficients.\n"); + } + + ret = + hisi_dss_scl_write_coefs(hisifd, enable_cmdlist, uv_addr, + (const int **)COEF_LUT_TAP4[coef_lut_idx], + PHASE_NUM, TAP4); + if (ret < 0) { + HISI_FB_ERR + ("Error to write UV_COEF coefficients.\n"); + } + } + } + + return 0; +} + +int hisi_dss_scl_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, + bool rdma_stretch_enable) +{ + dss_scl_t *scl = NULL; + dss_rect_t src_rect; + dss_rect_t dst_rect; + uint32_t need_cap = 0; + int chn_idx = 0; + uint32_t transform = 0; + dss_block_info_t *pblock_info = NULL; + + bool has_pixel_alpha = false; + bool en_hscl = false; + bool en_vscl = false; + bool en_mmp = false; + uint32_t h_ratio = 0; + uint32_t v_ratio = 0; + uint32_t h_v_order = 0; + uint32_t acc_hscl = 0; + uint32_t acc_vscl = 0; + uint32_t scf_en_vscl = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + need_cap = layer->need_cap; + chn_idx = layer->chn_idx; + transform = layer->transform; + if (aligned_rect) + src_rect = *aligned_rect; + else + src_rect = layer->src_rect; + dst_rect = layer->dst_rect; + pblock_info = &(layer->block_info); + + if (pblock_info && pblock_info->both_vscfh_arsr2p_used) { + dst_rect = pblock_info->arsr2p_in_rect; + } + + if (chn_idx == DSS_RCHN_V0) { + dst_rect.h = src_rect.h; + } + + do { + if (chn_idx == DSS_RCHN_V0 && pblock_info->h_ratio_arsr2p + && pblock_info->h_ratio) { + h_ratio = pblock_info->h_ratio; + en_hscl = true; + break; + } else if (chn_idx == DSS_RCHN_V0 && !pblock_info->h_ratio + && pblock_info->h_ratio_arsr2p) { + break; + } + + if (pblock_info && (pblock_info->h_ratio != 0) + && (pblock_info->h_ratio != SCF_INC_FACTOR)) { + h_ratio = pblock_info->h_ratio; + en_hscl = true; + break; + } + + if (chn_idx == DSS_RCHN_V0) { + dst_rect.w = + (src_rect.w > dst_rect.w ? dst_rect.w : src_rect.w); + } + + if (src_rect.w == dst_rect.w) + break; + + en_hscl = true; + + if ((src_rect.w < SCF_MIN_INPUT) + || (dst_rect.w < SCF_MIN_OUTPUT)) { + HISI_FB_ERR + ("src_rect.w(%d) small than 16, " + "or dst_rect.w(%d) small than 16\n", + src_rect.w, dst_rect.w); + return -EINVAL; + } + + h_ratio = + (DSS_HEIGHT(src_rect.w) * SCF_INC_FACTOR + + SCF_INC_FACTOR / 2 - acc_hscl) / DSS_HEIGHT(dst_rect.w); + + if ((dst_rect.w > (src_rect.w * SCF_UPSCALE_MAX)) + || (src_rect.w > (dst_rect.w * SCF_DOWNSCALE_MAX))) { + HISI_FB_ERR + ("width out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), " + "dst_rect(%d, %d, %d, %d), rdma_stretch_enable=%d\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, src_rect.x, + src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h, + rdma_stretch_enable); + + return -EINVAL; + } + } while (0); + + do { + if (src_rect.h == dst_rect.h) + break; + + en_vscl = true; + scf_en_vscl = 1; + + v_ratio = + (DSS_HEIGHT(src_rect.h) * SCF_INC_FACTOR + + SCF_INC_FACTOR / 2 - acc_vscl) / DSS_HEIGHT(dst_rect.h); + + if ((dst_rect.h > (src_rect.h * SCF_UPSCALE_MAX)) + || (src_rect.h > (dst_rect.h * SCF_DOWNSCALE_MAX))) { + HISI_FB_ERR + ("height out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), " + "dst_rect(%d, %d, %d, %d), rdma_stretch_enable=%d.\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, src_rect.x, + src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h, + rdma_stretch_enable); + return -EINVAL; + } + } while (0); + + if (!en_hscl && !en_vscl) { + return 0; + } + + /* scale down, do hscl first; scale up, do vscl first */ + h_v_order = (src_rect.w > dst_rect.w) ? 0 : 1; + + if (pblock_info && (pblock_info->acc_hscl != 0)) { + acc_hscl = pblock_info->acc_hscl; + } + + scl = &(hisifd->dss_module.scl[chn_idx]); + hisifd->dss_module.scl_used[chn_idx] = 1; + + has_pixel_alpha = hal_format_has_alpha(layer->img.format); + + scl->en_hscl_str = set_bits32(scl->en_hscl_str, 0x0, 1, 0); + + if (v_ratio >= 2 * SCF_INC_FACTOR) { + if (has_pixel_alpha) + scl->en_vscl_str = + set_bits32(scl->en_vscl_str, 0x3, 2, 0); + else + scl->en_vscl_str = + set_bits32(scl->en_vscl_str, 0x1, 2, 0); + } else { + scl->en_vscl_str = set_bits32(scl->en_vscl_str, 0x0, 1, 0); + } + + if (src_rect.h > dst_rect.h) { + scf_en_vscl = 0x3; + } + en_mmp = 0x1; + + scl->h_v_order = set_bits32(scl->h_v_order, h_v_order, 1, 0); + scl->input_width_height = set_bits32(scl->input_width_height, + DSS_HEIGHT(src_rect.h), 13, 0); + scl->input_width_height = set_bits32(scl->input_width_height, + DSS_WIDTH(src_rect.w), 13, 16); + scl->output_width_height = set_bits32(scl->output_width_height, + DSS_HEIGHT(dst_rect.h), 13, 0); + scl->output_width_height = set_bits32(scl->output_width_height, + DSS_WIDTH(dst_rect.w), 13, 16); + scl->en_hscl = set_bits32(scl->en_hscl, (en_hscl ? 0x1 : 0x0), 1, 0); + scl->en_vscl = set_bits32(scl->en_vscl, scf_en_vscl, 2, 0); + scl->acc_hscl = set_bits32(scl->acc_hscl, acc_hscl, 31, 0); + scl->inc_hscl = set_bits32(scl->inc_hscl, h_ratio, 24, 0); + scl->inc_vscl = set_bits32(scl->inc_vscl, v_ratio, 24, 0); + scl->en_mmp = set_bits32(scl->en_mmp, en_mmp, 1, 0); + scl->fmt = layer->img.format; + + return 0; +} + +static void hisi_dss_post_scf_init(char __iomem *post_scf_base, + dss_arsr1p_t *s_post_scf) +{ + BUG_ON(post_scf_base == NULL); + BUG_ON(s_post_scf == NULL); + + memset(s_post_scf, 0, sizeof(dss_arsr1p_t)); + + s_post_scf->ihleft = inp32(post_scf_base + ARSR1P_IHLEFT); + s_post_scf->ihright = inp32(post_scf_base + ARSR1P_IHRIGHT); + s_post_scf->ihleft1 = inp32(post_scf_base + ARSR1P_IHLEFT1); + s_post_scf->ihright1 = inp32(post_scf_base + ARSR1P_IHRIGHT1); + s_post_scf->ivtop = inp32(post_scf_base + ARSR1P_IVTOP); + s_post_scf->ivbottom = inp32(post_scf_base + ARSR1P_IVBOTTOM); + s_post_scf->uv_offset = inp32(post_scf_base + ARSR1P_UV_OFFSET); + s_post_scf->ihinc = inp32(post_scf_base + ARSR1P_IHINC); + s_post_scf->ivinc = inp32(post_scf_base + ARSR1P_IVINC); + s_post_scf->mode = inp32(post_scf_base + ARSR1P_MODE); + s_post_scf->format = inp32(post_scf_base + ARSR1P_FORMAT); + + s_post_scf->skin_thres_y = inp32(post_scf_base + ARSR1P_SKIN_THRES_Y); + s_post_scf->skin_thres_u = inp32(post_scf_base + ARSR1P_SKIN_THRES_U); + s_post_scf->skin_thres_v = inp32(post_scf_base + ARSR1P_SKIN_THRES_V); + s_post_scf->skin_expected = inp32(post_scf_base + ARSR1P_SKIN_EXPECTED); + s_post_scf->skin_cfg = inp32(post_scf_base + ARSR1P_SKIN_CFG); + s_post_scf->shoot_cfg1 = inp32(post_scf_base + ARSR1P_SHOOT_CFG1); + s_post_scf->shoot_cfg2 = inp32(post_scf_base + ARSR1P_SHOOT_CFG2); + s_post_scf->sharp_cfg1 = inp32(post_scf_base + ARSR1P_SHARP_CFG1); + s_post_scf->sharp_cfg2 = inp32(post_scf_base + ARSR1P_SHARP_CFG2); + s_post_scf->sharp_cfg3 = inp32(post_scf_base + ARSR1P_SHARP_CFG3); + s_post_scf->sharp_cfg4 = inp32(post_scf_base + ARSR1P_SHARP_CFG4); + s_post_scf->sharp_cfg5 = inp32(post_scf_base + ARSR1P_SHARP_CFG5); + s_post_scf->sharp_cfg6 = inp32(post_scf_base + ARSR1P_SHARP_CFG6); + s_post_scf->sharp_cfg7 = inp32(post_scf_base + ARSR1P_SHARP_CFG7); + s_post_scf->sharp_cfg8 = inp32(post_scf_base + ARSR1P_SHARP_CFG8); + s_post_scf->sharp_cfg9 = inp32(post_scf_base + ARSR1P_SHARP_CFG9); + s_post_scf->sharp_cfg10 = inp32(post_scf_base + ARSR1P_SHARP_CFG10); + s_post_scf->sharp_cfg11 = inp32(post_scf_base + ARSR1P_SHARP_CFG11); + s_post_scf->diff_ctrl = inp32(post_scf_base + ARSR1P_DIFF_CTRL); + s_post_scf->lsc_cfg1 = inp32(post_scf_base + ARSR1P_LSC_CFG1); + s_post_scf->lsc_cfg2 = inp32(post_scf_base + ARSR1P_LSC_CFG2); + s_post_scf->lsc_cfg3 = inp32(post_scf_base + ARSR1P_LSC_CFG3); + s_post_scf->force_clk_on_cfg = + inp32(post_scf_base + ARSR1P_FORCE_CLK_ON_CFG); +} + +static void hisi_dss_post_scf_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *post_scf_base, + dss_arsr1p_t *s_post_scf) +{ + BUG_ON(hisifd == NULL); + BUG_ON(post_scf_base == NULL); + BUG_ON(s_post_scf == NULL); + + hisifd->set_reg(hisifd, + hisifd->dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_BEF_SR, + ((DSS_HEIGHT(s_post_scf->dpp_img_vrt_bef_sr) << 16) | + (DSS_WIDTH(s_post_scf->dpp_img_hrz_bef_sr))), 32, 0); + hisifd->set_reg(hisifd, + hisifd->dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_AFT_SR, + ((DSS_HEIGHT(s_post_scf->dpp_img_vrt_aft_sr) << 16) | + (DSS_WIDTH(s_post_scf->dpp_img_hrz_aft_sr))), 32, 0); + + outp32(post_scf_base + ARSR1P_IHLEFT, s_post_scf->ihleft); + outp32(post_scf_base + ARSR1P_IHRIGHT, s_post_scf->ihright); + outp32(post_scf_base + ARSR1P_IHLEFT1, s_post_scf->ihleft1); + outp32(post_scf_base + ARSR1P_IHRIGHT1, s_post_scf->ihright1); + outp32(post_scf_base + ARSR1P_IVTOP, s_post_scf->ivtop); + outp32(post_scf_base + ARSR1P_IVBOTTOM, s_post_scf->ivbottom); + outp32(post_scf_base + ARSR1P_UV_OFFSET, s_post_scf->uv_offset); + outp32(post_scf_base + ARSR1P_IHINC, s_post_scf->ihinc); + outp32(post_scf_base + ARSR1P_IVINC, s_post_scf->ivinc); + outp32(post_scf_base + ARSR1P_MODE, s_post_scf->mode); + outp32(post_scf_base + ARSR1P_FORMAT, s_post_scf->format); + + outp32(post_scf_base + ARSR1P_SKIN_THRES_Y, s_post_scf->skin_thres_y); + outp32(post_scf_base + ARSR1P_SKIN_THRES_U, s_post_scf->skin_thres_u); + outp32(post_scf_base + ARSR1P_SKIN_THRES_V, s_post_scf->skin_thres_v); + outp32(post_scf_base + ARSR1P_SKIN_EXPECTED, s_post_scf->skin_expected); + outp32(post_scf_base + ARSR1P_SKIN_CFG, s_post_scf->skin_cfg); + outp32(post_scf_base + ARSR1P_SHOOT_CFG1, s_post_scf->shoot_cfg1); + outp32(post_scf_base + ARSR1P_SHOOT_CFG2, s_post_scf->shoot_cfg2); + outp32(post_scf_base + ARSR1P_SHARP_CFG1, s_post_scf->sharp_cfg1); + outp32(post_scf_base + ARSR1P_SHARP_CFG2, s_post_scf->sharp_cfg2); + outp32(post_scf_base + ARSR1P_SHARP_CFG3, s_post_scf->sharp_cfg3); + outp32(post_scf_base + ARSR1P_SHARP_CFG4, s_post_scf->sharp_cfg4); + outp32(post_scf_base + ARSR1P_SHARP_CFG5, s_post_scf->sharp_cfg5); + outp32(post_scf_base + ARSR1P_SHARP_CFG6, s_post_scf->sharp_cfg6); + outp32(post_scf_base + ARSR1P_SHARP_CFG7, s_post_scf->sharp_cfg7); + outp32(post_scf_base + ARSR1P_SHARP_CFG8, s_post_scf->sharp_cfg8); + outp32(post_scf_base + ARSR1P_SHARP_CFG9, s_post_scf->sharp_cfg9); + outp32(post_scf_base + ARSR1P_SHARP_CFG10, s_post_scf->sharp_cfg10); + outp32(post_scf_base + ARSR1P_SHARP_CFG11, s_post_scf->sharp_cfg11); + outp32(post_scf_base + ARSR1P_DIFF_CTRL, s_post_scf->diff_ctrl); + outp32(post_scf_base + ARSR1P_LSC_CFG1, s_post_scf->lsc_cfg1); + outp32(post_scf_base + ARSR1P_LSC_CFG2, s_post_scf->lsc_cfg2); + outp32(post_scf_base + ARSR1P_LSC_CFG3, s_post_scf->lsc_cfg3); + outp32(post_scf_base + ARSR1P_FORCE_CLK_ON_CFG, + s_post_scf->force_clk_on_cfg); +} + +int hisi_dss_post_scf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dss_rect_t src_rect = { 0 }; + dss_rect_t dst_rect = { 0 }; + dss_arsr1p_t *post_scf = NULL; + + int32_t ihinc = 0; + int32_t ivinc = 0; + int32_t ihleft = 0; + int32_t ihright = 0; + int32_t ihleft1 = 0; + int32_t ihright1 = 0; + int32_t ivtop = 0; + int32_t ivbottom = 0; + int32_t extraw = 0; + int32_t extraw_left = 0; + int32_t extraw_right = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + pinfo = &(hisifd->panel_info); + + if (!HISI_DSS_SUPPORT_DPP_MODULE_BIT(DPP_MODULE_POST_SCF)) { + return 0; + } + + if ((pov_req->res_updt_rect.w == 0) && (pov_req->res_updt_rect.h == 0)) { + return 0; + } + + if ((pov_req->res_updt_rect.w < 0) || (pov_req->res_updt_rect.h < 0)) { + HISI_FB_ERR("fb%d, res_updt_rect[%d,%d, %d,%d] is invalid!\n", + hisifd->index, pov_req->res_updt_rect.x, + pov_req->res_updt_rect.y, pov_req->res_updt_rect.w, + pov_req->res_updt_rect.h); + return 0; + } + + if ((pov_req->res_updt_rect.w == hisifd->res_updt_rect.w) + && (pov_req->res_updt_rect.h == hisifd->res_updt_rect.h)) { + + return 0; + } + + HISI_FB_DEBUG + ("fb%d, post scf res_updt_rect[%d, %d]->lcd_rect[%d, %d]\n", + hisifd->index, pov_req->res_updt_rect.w, pov_req->res_updt_rect.h, + pinfo->xres, pinfo->yres); + + hisifd->res_updt_rect = pov_req->res_updt_rect; + + src_rect = pov_req->res_updt_rect; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.w = pinfo->xres; + dst_rect.h = pinfo->yres; + + post_scf = &(hisifd->dss_module.post_scf); + hisifd->dss_module.post_scf_used = 1; + + if ((src_rect.w < 16) || (src_rect.h < 16) + || (src_rect.w > 3840) || (src_rect.h > 8192) + || (dst_rect.w > 8192) || (dst_rect.h > 8192)) { + HISI_FB_ERR + ("invalid input size: src_rect(%d,%d,%d,%d) " + "should be larger than 16*16, less than 3840*8192!\n" + "invalid output size: dst_rect(%d,%d,%d,%d) " + "should be less than 8192*8192!\n", + src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_rect.x, + dst_rect.y, dst_rect.w, dst_rect.h); + post_scf->mode = 0x1; + return 0; + } + + ihinc = ARSR1P_INC_FACTOR * src_rect.w / dst_rect.w; + ivinc = ARSR1P_INC_FACTOR * src_rect.h / dst_rect.h; + + if ((ihinc == ARSR1P_INC_FACTOR) + && (ivinc == ARSR1P_INC_FACTOR) + && (pinfo->arsr1p_sharpness_support != 1)) { + post_scf->mode = 0x1; + return 0; + } + + /* 0x2000<=ihinc<=0x80000; 0x2000<=ivinc<=0x80000; */ + if ((ihinc < 0x2000) || (ihinc > ARSR1P_INC_FACTOR) + || (ivinc < 0x2000) || (ivinc > ARSR1P_INC_FACTOR)) { + HISI_FB_ERR("invalid ihinc(0x%x), ivinc(0x%x)!\n", ihinc, + ivinc); + post_scf->mode = 0x1; + return -1; + } + + if ((ihinc > ARSR1P_INC_FACTOR) || (ivinc > ARSR1P_INC_FACTOR)) { + HISI_FB_ERR + ("scaling down is not supported by ARSR1P, " + "ihinc = 0x%x, ivinc = 0x%x\n", + ihinc, ivinc); + post_scf->mode = 0x1; + return -1; + } + + post_scf->mode = 0x0; + if (pinfo->arsr1p_sharpness_support) { + post_scf->mode |= 0xe; + } + + post_scf->mode |= 0x20; + if ((ihinc < ARSR1P_INC_FACTOR) || (ivinc < ARSR1P_INC_FACTOR)) { + post_scf->mode |= 0x10; + } else { + post_scf->mode |= 0x40; + } + + post_scf->dpp_img_hrz_bef_sr = src_rect.w; + post_scf->dpp_img_vrt_bef_sr = src_rect.h; + post_scf->dpp_img_hrz_aft_sr = dst_rect.w; + post_scf->dpp_img_vrt_aft_sr = dst_rect.h; + + extraw = (8 * ARSR1P_INC_FACTOR) / ihinc; + extraw_left = (extraw % 2) ? (extraw + 1) : (extraw); + extraw = (2 * ARSR1P_INC_FACTOR) / ihinc; + extraw_right = (extraw % 2) ? (extraw + 1) : (extraw); + + ihleft1 = dst_rect.x * ihinc - src_rect.x * ARSR1P_INC_FACTOR; + if (ihleft1 < 0) + ihleft1 = 0; + ihleft = ihleft1 - extraw_left * ihinc; + if (ihleft < 0) + ihleft = 0; + + ihright1 = ihleft1 + (dst_rect.w - 1) * ihinc; + ihright = ihright1 + extraw_right * ihinc; + if (ihright >= src_rect.w * ARSR1P_INC_FACTOR) + ihright = src_rect.w * ARSR1P_INC_FACTOR - 1; + + ivtop = dst_rect.y * ivinc - src_rect.y * ARSR1P_INC_FACTOR; + if (ivtop < 0) + ivtop = 0; + ivbottom = ivtop + (dst_rect.h - 1) * ivinc; + if (ivbottom >= src_rect.h * ARSR1P_INC_FACTOR) + ivbottom = src_rect.h * ARSR1P_INC_FACTOR - 1; + + if ((ihleft1 - ihleft) % (ihinc)) { + HISI_FB_ERR + ("(ihleft1(%d)-ihleft(%d)) ihinc(%d) != 0, invalid!\n", + ihleft1, ihleft, ihinc); + post_scf->mode = 0x1; + return -1; + } + + if ((ihright1 - ihleft1) % ihinc) { + HISI_FB_ERR + ("(ihright1(%d)-ihleft1(%d)) ihinc(%d) != 0, invalid!\n", + ihright1, ihleft1, ihinc); + post_scf->mode = 0x1; + return -1; + } + + post_scf->ihleft = set_bits32(post_scf->ihleft, ihleft, 32, 0); + post_scf->ihright = set_bits32(post_scf->ihright, ihright, 32, 0); + post_scf->ihleft1 = set_bits32(post_scf->ihleft1, ihleft1, 32, 0); + post_scf->ihright1 = set_bits32(post_scf->ihright1, ihright1, 32, 0); + post_scf->ivtop = set_bits32(post_scf->ivtop, ivtop, 32, 0); + post_scf->ivbottom = set_bits32(post_scf->ivbottom, ivbottom, 32, 0); + post_scf->ihinc = set_bits32(post_scf->ihinc, ihinc, 32, 0); + post_scf->ivinc = set_bits32(post_scf->ivinc, ivinc, 32, 0); + + post_scf->skin_thres_y = + set_bits32(post_scf->skin_thres_y, 0x534b, 32, 0); + post_scf->skin_thres_u = + set_bits32(post_scf->skin_thres_u, 0x330a05, 32, 0); + post_scf->skin_thres_v = + set_bits32(post_scf->skin_thres_v, 0xaa0c06, 32, 0); + post_scf->skin_expected = + set_bits32(post_scf->skin_expected, 0x917198, 32, 0); + post_scf->skin_cfg = set_bits32(post_scf->skin_cfg, 0x30a06, 32, 0); + post_scf->shoot_cfg1 = set_bits32(post_scf->shoot_cfg1, 0x14, 32, 0); + post_scf->shoot_cfg2 = set_bits32(post_scf->shoot_cfg2, 0x1f0, 32, 0); + post_scf->sharp_cfg1 = + set_bits32(post_scf->sharp_cfg1, 0x40300602, 32, 0); + post_scf->sharp_cfg2 = + set_bits32(post_scf->sharp_cfg2, 0x40300602, 32, 0); + post_scf->sharp_cfg3 = + set_bits32(post_scf->sharp_cfg3, 0x12c0000, 32, 0); + post_scf->sharp_cfg4 = set_bits32(post_scf->sharp_cfg4, 0x0, 32, 0); + post_scf->sharp_cfg5 = + set_bits32(post_scf->sharp_cfg5, 0x1900000, 32, 0); + post_scf->sharp_cfg6 = + set_bits32(post_scf->sharp_cfg6, 0xffff641e, 32, 0); + post_scf->sharp_cfg7 = + set_bits32(post_scf->sharp_cfg7, 0x1a00018, 32, 0); + post_scf->sharp_cfg8 = + set_bits32(post_scf->sharp_cfg8, 0x200640, 32, 0); + post_scf->sharp_cfg9 = + set_bits32(post_scf->sharp_cfg9, 0x2006400, 32, 0); + post_scf->sharp_cfg10 = set_bits32(post_scf->sharp_cfg10, 0x0, 32, 0); + post_scf->sharp_cfg11 = set_bits32(post_scf->sharp_cfg11, 0x0, 32, 0); + + post_scf->diff_ctrl = set_bits32(post_scf->diff_ctrl, 0x1410, 32, 0); + post_scf->lsc_cfg1 = set_bits32(post_scf->lsc_cfg1, 0x3c618410, 32, 0); + post_scf->lsc_cfg2 = set_bits32(post_scf->lsc_cfg2, 0x0, 32, 0); + post_scf->lsc_cfg3 = set_bits32(post_scf->lsc_cfg3, 0x800600, 32, 0); + + return 0; +} + +/******************************************************************************* + ** DSS POST_CLIP + */ +static void hisi_dss_post_clip_init(char __iomem *post_clip_base, + dss_post_clip_t *s_post_clip) +{ + BUG_ON(post_clip_base == NULL); + BUG_ON(s_post_clip == NULL); + + memset(s_post_clip, 0, sizeof(dss_post_clip_t)); +} + +int hisi_dss_post_clip_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer) +{ + dss_post_clip_t *post_clip = NULL; + int chn_idx = 0; + dss_rect_t post_clip_rect; + + chn_idx = layer->chn_idx; + post_clip_rect = layer->dst_rect; + + if (((chn_idx >= DSS_RCHN_V0) && (chn_idx <= DSS_RCHN_G1)) + || (chn_idx == DSS_RCHN_V2)) { + post_clip = &(hisifd->dss_module.post_clip[chn_idx]); + hisifd->dss_module.post_cilp_used[chn_idx] = 1; + + post_clip->disp_size = + set_bits32(post_clip->disp_size, + DSS_HEIGHT(post_clip_rect.h), 13, 0); + post_clip->disp_size = + set_bits32(post_clip->disp_size, + DSS_WIDTH(post_clip_rect.w), 13, 16); + + if ((chn_idx == DSS_RCHN_V0) + && layer->block_info.arsr2p_left_clip) { + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, + layer->block_info.arsr2p_left_clip, 6, 16); + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, 0x0, 6, 0); + } else { + post_clip->clip_ctl_hrz = + set_bits32(post_clip->clip_ctl_hrz, 0x0, 32, 0); + } + + post_clip->clip_ctl_vrz = + set_bits32(post_clip->clip_ctl_vrz, 0x0, 32, 0); + post_clip->ctl_clip_en = + set_bits32(post_clip->ctl_clip_en, 0x1, 32, 0); + } + + return 0; +} + +void hisi_dss_post_clip_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *post_clip_base, + dss_post_clip_t *s_post_clip) +{ + BUG_ON(hisifd == NULL); + BUG_ON(post_clip_base == NULL); + BUG_ON(s_post_clip == NULL); + + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_DISP_SIZE, + s_post_clip->disp_size, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_CTL_HRZ, + s_post_clip->clip_ctl_hrz, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_CTL_VRZ, + s_post_clip->clip_ctl_vrz, 32, 0); + hisifd->set_reg(hisifd, post_clip_base + POST_CLIP_EN, + s_post_clip->ctl_clip_en, 32, 0); +} + +/******************************************************************************* + ** DSS MCTL + */ +static void hisi_dss_mctl_init(char __iomem *mctl_base, dss_mctl_t *s_mctl) +{ + BUG_ON(mctl_base == NULL); + BUG_ON(s_mctl == NULL); + + memset(s_mctl, 0, sizeof(dss_mctl_t)); +} + +static void hisi_dss_mctl_ch_starty_init(char __iomem *mctl_ch_starty_base, + dss_mctl_ch_t *s_mctl_ch) +{ + BUG_ON(mctl_ch_starty_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + memset(s_mctl_ch, 0, sizeof(dss_mctl_ch_t)); + + s_mctl_ch->chn_starty = inp32(mctl_ch_starty_base); +} + +static void hisi_dss_mctl_ch_mod_dbg_init(char __iomem *mctl_ch_dbg_base, + dss_mctl_ch_t *s_mctl_ch) +{ + BUG_ON(mctl_ch_dbg_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + s_mctl_ch->chn_mod_dbg = inp32(mctl_ch_dbg_base); +} + +static void hisi_dss_mctl_sys_init(char __iomem *mctl_sys_base, + dss_mctl_sys_t *s_mctl_sys) +{ + int i = 0; + + BUG_ON(mctl_sys_base == NULL); + BUG_ON(s_mctl_sys == NULL); + + memset(s_mctl_sys, 0, sizeof(dss_mctl_sys_t)); + + for (i = 0; i < DSS_OVL_IDX_MAX; i++) { + s_mctl_sys->chn_ov_sel[i] = 0xFFFFFFFF; + } + + for (i = 0; i < DSS_WCH_MAX; i++) { + s_mctl_sys->wchn_ov_sel[i] = 0x0; + } +} + +static void hisi_dss_mctl_sys_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_sys_base, + dss_mctl_sys_t *s_mctl_sys, int ovl_idx) +{ + int k = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_sys_base == NULL); + BUG_ON(s_mctl_sys == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (s_mctl_sys->chn_ov_sel_used[ovl_idx]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_RCH_OV0_SEL + ovl_idx * 0x4, + s_mctl_sys->chn_ov_sel[ovl_idx], 32, 0); + } + + for (k = 0; k < DSS_WCH_MAX; k++) { + if (s_mctl_sys->wch_ov_sel_used[k]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_WCH_OV2_SEL + k * 0x4, + s_mctl_sys->wchn_ov_sel[k], 32, 0); + } + } + + if (s_mctl_sys->ov_flush_en_used[ovl_idx]) { + hisifd->set_reg(hisifd, + mctl_sys_base + MCTL_OV0_FLUSH_EN + ovl_idx * 0x4, + s_mctl_sys->ov_flush_en[ovl_idx], 32, 0); + } +} + +static void hisi_dss_mctl_ov_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, + dss_mctl_t *s_mctl, int ovl_idx, + bool enable_cmdlist) +{ + BUG_ON(hisifd == NULL); + BUG_ON(mctl_base == NULL); + BUG_ON(s_mctl == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX_DBUF, + s_mctl->ctl_mutex_dbuf, 32, 0); + hisi_dss_mctl_ov_set_ctl_dbg_reg(hisifd, mctl_base, + enable_cmdlist); + } + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX_OV, + s_mctl->ctl_mutex_ov, 32, 0); +} + +static void hisi_dss_mctl_ch_set_reg(struct hisi_fb_data_type *hisifd, + dss_mctl_ch_base_t *mctl_ch_base, + dss_mctl_ch_t *s_mctl_ch, + int32_t mctl_idx) +{ + char __iomem *chn_mutex_base = NULL; + int i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_ch_base == NULL); + BUG_ON(s_mctl_ch == NULL); + BUG_ON((mctl_idx < DSS_MCTL0) || (mctl_idx >= DSS_MCTL_IDX_MAX)); + + for (i = 0; i < DSS_MCTL_IDX_MAX; i++) { + if (g_dss_module_ovl_base[i][MODULE_MCTL_BASE] == 0) + continue; + chn_mutex_base = mctl_ch_base->chn_mutex_base + + g_dss_module_ovl_base[i][MODULE_MCTL_BASE]; + + if (i != mctl_idx) { + hisifd->set_reg(hisifd, chn_mutex_base, 0, 32, 0); + } + } + + chn_mutex_base = mctl_ch_base->chn_mutex_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + BUG_ON(chn_mutex_base == NULL); + + hisifd->set_reg(hisifd, chn_mutex_base, s_mctl_ch->chn_mutex, 32, 0); +} + +static void hisi_dss_mctl_sys_ch_set_reg(struct hisi_fb_data_type *hisifd, + dss_mctl_ch_base_t *mctl_ch_base, + dss_mctl_ch_t *s_mctl_ch, int chn_idx, + bool normal) +{ + char __iomem *mctl_sys_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(mctl_ch_base == NULL); + BUG_ON(s_mctl_ch == NULL); + + mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET; + + if (normal == true) { + if (chn_idx == DSS_RCHN_V2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD19_DBG, + 0xA0000, 32, 0); + } + + if (chn_idx == DSS_WCHN_W2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD20_DBG, + 0xA0000, 32, 0); + } + } + + if (normal == false) { + if (chn_idx == DSS_RCHN_V2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD19_DBG, + 0xA0002, 32, 0); + } + + if (chn_idx == DSS_WCHN_W2) { + hisifd->set_reg(hisifd, mctl_sys_base + MCTL_MOD20_DBG, + 0xA0002, 32, 0); + } + } + + if (mctl_ch_base->chn_ov_en_base) { + hisifd->set_reg(hisifd, mctl_ch_base->chn_ov_en_base, + s_mctl_ch->chn_ov_oen, 32, 0); + } + + hisifd->set_reg(hisifd, mctl_ch_base->chn_flush_en_base, + s_mctl_ch->chn_flush_en, 32, 0); +} + +void hisi_dss_mctl_mutex_lock(struct hisi_fb_data_type *hisifd, int ovl_idx) +{ + char __iomem *mctl_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + mctl_base = hisifd->dss_module.mctl_base[ovl_idx]; + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX, 0x1, 1, 0); +} + +void hisi_dss_mctl_mutex_unlock(struct hisi_fb_data_type *hisifd, int ovl_idx) +{ + char __iomem *mctl_base = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + mctl_base = hisifd->dss_module.mctl_base[ovl_idx]; + + hisifd->set_reg(hisifd, mctl_base + MCTL_CTL_MUTEX, 0x0, 1, 0); +} + +void hisi_dss_mctl_on(struct hisi_fb_data_type *hisifd, int mctl_idx, + bool enable_cmdlist, bool fastboot_enable) +{ + char __iomem *mctl_base = NULL; + char __iomem *mctl_sys_base = NULL; + int i = 0; + int tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((mctl_idx < DSS_MCTL0) || (mctl_idx >= DSS_MCTL_IDX_MAX)); + + mctl_base = hisifd->dss_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET; + + set_reg(mctl_base + MCTL_CTL_EN, 0x1, 32, 0); + + if ((mctl_idx == DSS_MCTL0) || (mctl_idx == DSS_MCTL1)) { + set_reg(mctl_base + MCTL_CTL_MUTEX_ITF, mctl_idx + 1, 32, 0); + } + + if (enable_cmdlist) { + tmp = MCTL_MOD_DBG_CH_NUM + MCTL_MOD_DBG_OV_NUM + + MCTL_MOD_DBG_DBUF_NUM + MCTL_MOD_DBG_SCF_NUM; + for (i = 0; i < tmp; i++) { + set_reg(mctl_sys_base + MCTL_MOD0_DBG + i * 0x4, + 0xA0000, 32, 0); + } + + for (i = 0; i < MCTL_MOD_DBG_ITF_NUM; i++) { + set_reg(mctl_sys_base + MCTL_MOD17_DBG + i * 0x4, + 0xA0F00, 32, 0); + } + + if (!fastboot_enable) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } + } else { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB13A00, 32, 0); + if (is_mipi_cmd_panel(hisifd)) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } else { + if (mctl_idx == DSS_MCTL0) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x2, 32, 0); + } else if (mctl_idx == DSS_MCTL1) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x3, 32, 0); + } else { + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } + } + } +} + +int hisi_dss_mctl_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx, + dss_rect_t *wb_ov_block_rect, bool has_base) +{ + int chn_idx = 0; + int layer_idx = 0; + dss_mctl_ch_t *mctl_ch = NULL; + dss_mctl_sys_t *mctl_sys = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + mctl_ch = &(hisifd->dss_module.mctl_ch[chn_idx]); + hisifd->dss_module.mctl_ch_used[chn_idx] = 1; + + if (chn_idx != DSS_WCHN_W2) { + mctl_ch->chn_ov_oen = set_bits32(mctl_ch->chn_ov_oen, + (ovl_idx - 1), 32, 0); + + if (pov_req->wb_layer_nums == MAX_DSS_DST_NUM) { + mctl_sys->wchn_ov_sel[0] = + set_bits32(mctl_sys->wchn_ov_sel[0], 3, 32, 0); + mctl_sys->wch_ov_sel_used[0] = 1; + mctl_sys->wchn_ov_sel[1] = + set_bits32(mctl_sys->wchn_ov_sel[1], 3, 32, 0); + mctl_sys->wch_ov_sel_used[1] = 1; + } else { + mctl_sys->wchn_ov_sel[ovl_idx - DSS_OVL2] = + set_bits32(mctl_sys->wchn_ov_sel[ovl_idx - DSS_OVL2], + (chn_idx - DSS_WCHN_W0 + 1), 32, 0); + mctl_sys->wch_ov_sel_used[ovl_idx - DSS_OVL2] = 1; + } + } + + mctl_ch->chn_mutex = set_bits32(mctl_ch->chn_mutex, 0x1, 1, 0); + mctl_ch->chn_flush_en = + set_bits32(mctl_ch->chn_flush_en, 0x1, 1, 0); + } else { + chn_idx = layer->chn_idx; + layer_idx = layer->layer_idx; + + if (layer->need_cap & CAP_BASE) + return 0; + + if (has_base) { + layer_idx -= 1; + if (layer_idx < 0) { + HISI_FB_ERR + ("fb%d, layer_idx(%d) is out of range!", + hisifd->index, layer_idx); + return -EINVAL; + } + } + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR)) { + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], 0x8, 4, + (layer_idx + 1) * 4); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + } else { + mctl_ch = &(hisifd->dss_module.mctl_ch[chn_idx]); + hisifd->dss_module.mctl_ch_used[chn_idx] = 1; + + mctl_ch->chn_mutex = + set_bits32(mctl_ch->chn_mutex, 0x1, 1, 0); + mctl_ch->chn_flush_en = + set_bits32(mctl_ch->chn_flush_en, 0x1, 1, 0); + + if (chn_idx != DSS_RCHN_V2) { + mctl_ch->chn_ov_oen = + set_bits32(mctl_ch->chn_ov_oen, + ((1 << (layer_idx + 1)) | + (0x100 << ovl_idx)), 32, 0); + + if (wb_ov_block_rect) { + mctl_ch->chn_starty = + set_bits32(mctl_ch->chn_starty, + ((layer->dst_rect.y - + wb_ov_block_rect->y) | (0x8 << 16)), 32, 0); + } else { + mctl_ch->chn_starty = + set_bits32(mctl_ch->chn_starty, + (layer->dst_rect.y | (0x8 << 16)), 32, 0); + } + + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], + chn_idx, 4, (layer_idx + 1) * 4); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + } + } + } + + return 0; +} + +int hisi_dss_mctl_ov_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, bool has_base, + bool is_first_ov_block) +{ + dss_mctl_t *mctl = NULL; + dss_mctl_sys_t *mctl_sys = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + mctl = &(hisifd->dss_module.mctl[ovl_idx]); + hisifd->dss_module.mctl_used[ovl_idx] = 1; + + if (ovl_idx == DSS_OVL0) { + mctl->ctl_mutex_itf = + set_bits32(mctl->ctl_mutex_itf, 0x1, 2, 0); + mctl->ctl_mutex_dbuf = + set_bits32(mctl->ctl_mutex_dbuf, 0x1, 2, 0); + } else if (ovl_idx == DSS_OVL1) { + mctl->ctl_mutex_itf = + set_bits32(mctl->ctl_mutex_itf, 0x2, 2, 0); + mctl->ctl_mutex_dbuf = + set_bits32(mctl->ctl_mutex_dbuf, 0x2, 2, 0); + } else { + ; + } + + mctl->ctl_mutex_ov = set_bits32(mctl->ctl_mutex_ov, 1 << ovl_idx, 4, 0); + + mctl_sys = &(hisifd->dss_module.mctl_sys); + hisifd->dss_module.mctl_sys_used = 1; + + mctl_sys->chn_ov_sel[ovl_idx] = + set_bits32(mctl_sys->chn_ov_sel[ovl_idx], 0x8, 4, 0); + mctl_sys->chn_ov_sel_used[ovl_idx] = 1; + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + if (is_first_ov_block) { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0xd, 4, 0); + } else { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0x1, 1, 0); + } + mctl_sys->ov_flush_en_used[ovl_idx] = 1; + } else { + mctl_sys->ov_flush_en[ovl_idx] = + set_bits32(mctl_sys->ov_flush_en[ovl_idx], 0x1, 1, 0); + mctl_sys->ov_flush_en_used[ovl_idx] = 1; + } + + return 0; +} + +/******************************************************************************* + ** DSS OVL + */ +static dss_ovl_alpha_t g_ovl_alpha[DSS_BLEND_MAX] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 0}, + {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {3, 0, 0, 0, 1, 0, 3, 0, 0, 0, 1}, + {3, 0, 0, 0, 1, 0, 3, 2, 0, 0, 0}, + {3, 0, 0, 0, 1, 1, 3, 1, 0, 0, 1}, + {2, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0}, + {3, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 0, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 0, 3, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 3, 0, 1, 0, 0}, + + {2, 1, 0, 0, 0, 1, 3, 2, 0, 0, 0}, + {2, 1, 0, 0, 0, 1, 3, 1, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, +}; + +static uint32_t get_ovl_blending_mode(dss_overlay_t *pov_req, + dss_layer_t *layer) +{ + uint32_t blend_mode = 0; + bool has_per_pixel_alpha = false; + + BUG_ON(layer == NULL); + + has_per_pixel_alpha = hal_format_has_alpha(layer->img.format); + + /* delete it for DTS2015061204735 and DTS2015060408590 */ + /* + if (layer->layer_idx == 0) { + if (has_per_pixel_alpha) { + blend_mode = DSS_BLEND_SRC; + } else { + blend_mode= DSS_BLEND_FIX_PER17; + } + } else + */ + { + if (layer->blending == HISI_FB_BLENDING_PREMULT) { + if (has_per_pixel_alpha) { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER12 : + DSS_BLEND_SRC_OVER_DST; + } else { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER8 : DSS_BLEND_SRC; + } + } else if (layer->blending == HISI_FB_BLENDING_COVERAGE) { + if (has_per_pixel_alpha) { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER13 : + DSS_BLEND_FIX_OVER; + } else { + blend_mode = + (layer->glb_alpha < + 0xFF) ? DSS_BLEND_FIX_PER8 : DSS_BLEND_SRC; + } + } else { + if (has_per_pixel_alpha) { + blend_mode = DSS_BLEND_SRC; + } else { + blend_mode = DSS_BLEND_FIX_PER17; + } + } + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("layer_idx(%d), blending=%d, fomat=%d, " + "has_per_pixel_alpha=%d, blend_mode=%d.\n", + layer->layer_idx, layer->blending, layer->img.format, + has_per_pixel_alpha, blend_mode); + } + + return blend_mode; +} + +static void hisi_dss_ovl_init(char __iomem *ovl_base, dss_ovl_t *s_ovl, + int ovl_idx) +{ + int i = 0; + + BUG_ON(ovl_base == NULL); + BUG_ON(s_ovl == NULL); + + memset(s_ovl, 0, sizeof(dss_ovl_t)); + + s_ovl->ovl_size = inp32(ovl_base + OVL_SIZE); + s_ovl->ovl_bg_color = inp32(ovl_base + OVL_BG_COLOR); + s_ovl->ovl_dst_startpos = inp32(ovl_base + OVL_DST_STARTPOS); + s_ovl->ovl_dst_endpos = inp32(ovl_base + OVL_DST_ENDPOS); + s_ovl->ovl_gcfg = inp32(ovl_base + OVL_GCFG); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + for (i = 0; i < OVL_2LAYER_NUM; i++) { + s_ovl->ovl_layer[i].layer_pos = + inp32(ovl_base + OVL_LAYER0_POS + i * 0x3C); + s_ovl->ovl_layer[i].layer_size = + inp32(ovl_base + OVL_LAYER0_SIZE + i * 0x3C); + s_ovl->ovl_layer[i].layer_pattern = + inp32(ovl_base + OVL_LAYER0_PATTERN + i * 0x3C); + s_ovl->ovl_layer[i].layer_alpha = + inp32(ovl_base + OVL_LAYER0_ALPHA + i * 0x3C); + s_ovl->ovl_layer[i].layer_cfg = + inp32(ovl_base + OVL_LAYER0_CFG + i * 0x3C); + + s_ovl->ovl_layer_pos[i].layer_pspos = + inp32(ovl_base + OVL_LAYER0_PSPOS + i * 0x3C); + s_ovl->ovl_layer_pos[i].layer_pepos = + inp32(ovl_base + OVL_LAYER0_PEPOS + i * 0x3C); + } + + s_ovl->ovl_block_size = inp32(ovl_base + OVL2_BLOCK_SIZE); + } else { + for (i = 0; i < OVL_6LAYER_NUM; i++) { + s_ovl->ovl_layer[i].layer_pos = + inp32(ovl_base + OVL_LAYER0_POS + i * 0x3C); + s_ovl->ovl_layer[i].layer_size = + inp32(ovl_base + OVL_LAYER0_SIZE + i * 0x3C); + s_ovl->ovl_layer[i].layer_pattern = + inp32(ovl_base + OVL_LAYER0_PATTERN + i * 0x3C); + s_ovl->ovl_layer[i].layer_alpha = + inp32(ovl_base + OVL_LAYER0_ALPHA + i * 0x3C); + s_ovl->ovl_layer[i].layer_cfg = + inp32(ovl_base + OVL_LAYER0_CFG + i * 0x3C); + + s_ovl->ovl_layer_pos[i].layer_pspos = + inp32(ovl_base + OVL_LAYER0_PSPOS + i * 0x3C); + s_ovl->ovl_layer_pos[i].layer_pepos = + inp32(ovl_base + OVL_LAYER0_PEPOS + i * 0x3C); + } + + s_ovl->ovl_block_size = inp32(ovl_base + OVL6_BLOCK_SIZE); + } +} + +static void hisi_dss_ovl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, dss_ovl_t *s_ovl, + int ovl_idx) +{ + int i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(ovl_base == NULL); + BUG_ON(s_ovl == NULL); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x0, 32, 0); + } else { + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x0, 32, 0); + } + + hisifd->set_reg(hisifd, ovl_base + OVL_SIZE, s_ovl->ovl_size, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_BG_COLOR, + s_ovl->ovl_bg_color, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_DST_STARTPOS, + s_ovl->ovl_dst_startpos, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_DST_ENDPOS, + s_ovl->ovl_dst_endpos, 32, 0); + hisifd->set_reg(hisifd, ovl_base + OVL_GCFG, s_ovl->ovl_gcfg, 32, 0); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + for (i = 0; i < OVL_2LAYER_NUM; i++) { + if (s_ovl->ovl_layer_used[i] == 1) { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PATTERN + i * 0x3C, + s_ovl->ovl_layer[i].layer_pattern, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_ALPHA + i * 0x3C, + s_ovl->ovl_layer[i].layer_alpha, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PSPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pspos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PEPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pepos, 32, 0); + } else { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + } + } + + hisifd->set_reg(hisifd, ovl_base + OVL2_BLOCK_SIZE, + s_ovl->ovl_block_size, 32, 0); + } else { + for (i = 0; i < OVL_6LAYER_NUM; i++) { + if (s_ovl->ovl_layer_used[i] == 1) { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS + i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PATTERN + i * 0x3C, + s_ovl->ovl_layer[i].layer_pattern, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_ALPHA + i * 0x3C, + s_ovl->ovl_layer[i].layer_alpha, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PSPOS + i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pspos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_PEPOS +i * 0x3C, + s_ovl->ovl_layer_pos[i].layer_pepos, 32, 0); + } else { + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_POS +i * 0x3C, + s_ovl->ovl_layer[i].layer_pos, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_SIZE + i * 0x3C, + s_ovl->ovl_layer[i].layer_size, 32, 0); + hisifd->set_reg(hisifd, + ovl_base + OVL_LAYER0_CFG + i * 0x3C, + s_ovl->ovl_layer[i].layer_cfg, 32, 0); + } + } + + hisifd->set_reg(hisifd, ovl_base + OVL6_BLOCK_SIZE, + s_ovl->ovl_block_size, 32, 0); + } +} + +void hisi_dss_ov_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, int ovl_idx) +{ + BUG_ON(hisifd == NULL); + BUG_ON(ovl_base == NULL); + + if ((ovl_idx == DSS_OVL1) || (ovl_idx == DSS_OVL3)) { + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x1, 32, + 0); + hisifd->set_reg(hisifd, ovl_base + OVL2_REG_DEFAULT, 0x0, 32, + 0); + } else { + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x1, 32, + 0); + hisifd->set_reg(hisifd, ovl_base + OVL6_REG_DEFAULT, 0x0, 32, + 0); + } +} + +int hisi_dss_ovl_base_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_rect_t *wb_ov_block_rect, int ovl_idx, + int ov_h_block_idx) +{ + dss_ovl_t *ovl = NULL; + int img_width = 0; + int img_height = 0; + int block_size = 0x7FFF; + int temp = 0; + int i = 0; + int m = 0; + + dss_overlay_block_t *pov_h_block_infos_tmp = NULL; + dss_overlay_block_t *pov_h_block_tmp = NULL; + dss_layer_t *layer = NULL; + int pov_h_block_idx = 0; + int layer_idx = 0; + bool has_base = false; + + BUG_ON(hisifd == NULL); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + ovl = &(hisifd->dss_module.ov[ovl_idx]); + hisifd->dss_module.ov_used[ovl_idx] = 1; + + if (wb_ov_block_rect) { + img_width = wb_ov_block_rect->w; + img_height = wb_ov_block_rect->h; + } else { + if ((!pov_req) + || (pov_req->dirty_rect.x == 0 && pov_req->dirty_rect.y == 0 + && pov_req->dirty_rect.w == 0 + && pov_req->dirty_rect.h == 0)) { + img_width = get_panel_xres(hisifd); + img_height = get_panel_yres(hisifd); + } else { + img_width = pov_req->dirty_rect.w; + img_height = pov_req->dirty_rect.h; + } + } + + if (pov_h_block && (pov_req->ov_block_nums != 0)) { + if (pov_req->ov_block_nums > 1) { + pov_h_block_infos_tmp = + (dss_overlay_block_t *) (pov_req->ov_block_infos_ptr); + for (m = ov_h_block_idx; m < pov_req->ov_block_nums; + m++) { + pov_h_block_tmp = &(pov_h_block_infos_tmp[m]); + has_base = false; + + for (i = 0; i < pov_h_block_tmp->layer_nums; + i++) { + layer = + &(pov_h_block_tmp->layer_infos[i]); + if (layer->need_cap & CAP_BASE) { + HISI_FB_INFO + ("layer%d is base, i=%d!\n", + layer->layer_idx, i); + has_base = true; + continue; + } + + layer_idx = i; + if (has_base) { + layer_idx = i - 1; + } + + if (layer_idx >= pov_h_block_idx) { + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pos, 0, 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pos, + img_height, 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer + [layer_idx].layer_size, + img_width, 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer + [layer_idx].layer_size, + img_height + 1, 15, 16); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + + if (layer->need_cap & (CAP_DIM | + CAP_PURE_COLOR)) { + + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pattern, + layer->color, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 8); + } else { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer + [layer_idx].layer_pattern, + 0x0, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer + [layer_idx].layer_cfg, + 0x0, 1, 8); + } + + ovl->ovl_layer_used[layer_idx] = 1; + pov_h_block_idx = layer_idx + 1; + } + } + } + } + + if (wb_ov_block_rect) { + if ((pov_req->wb_layer_infos[0].transform & + HISI_FB_TRANSFORM_ROT_90) + || (pov_req->wb_layer_infos[1].transform & + HISI_FB_TRANSFORM_ROT_90)) { + block_size = DSS_HEIGHT(wb_ov_block_rect->h); + } else { + temp = + pov_h_block->ov_block_rect.y + + DSS_HEIGHT(pov_h_block->ov_block_rect.h) - + wb_ov_block_rect->y; + if (temp >= wb_ov_block_rect->h) { + block_size = + DSS_HEIGHT(wb_ov_block_rect->h); + } else { + block_size = temp; + } + } + } else { + block_size = + pov_h_block->ov_block_rect.y + + DSS_HEIGHT(pov_h_block->ov_block_rect.h); + } + } + + ovl->ovl_size = set_bits32(ovl->ovl_size, DSS_WIDTH(img_width), 15, 0); + ovl->ovl_size = + set_bits32(ovl->ovl_size, DSS_HEIGHT(img_height), 15, 16); +#ifdef CONFIG_HISI_FB_OV_BASE_USED + ovl->ovl_bg_color = set_bits32(ovl->ovl_bg_color, 0xFFFF0000, 32, 0); +#else + ovl->ovl_bg_color = set_bits32(ovl->ovl_bg_color, 0xFF000000, 32, 0); +#endif + ovl->ovl_dst_startpos = set_bits32(ovl->ovl_dst_startpos, 0x0, 32, 0); + ovl->ovl_dst_endpos = + set_bits32(ovl->ovl_dst_endpos, DSS_WIDTH(img_width), 15, 0); + ovl->ovl_dst_endpos = + set_bits32(ovl->ovl_dst_endpos, DSS_HEIGHT(img_height), 15, 16); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 0); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 16); + ovl->ovl_block_size = + set_bits32(ovl->ovl_block_size, block_size, 15, 16); + + return 0; +} + +int hisi_dss_ovl_layer_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_ov_block_rect, bool has_base) +{ + dss_ovl_t *ovl = NULL; + int ovl_idx = 0; + int layer_idx = 0; + int blend_mode = 0; + dss_rect_t wb_ov_rect; + dss_rect_t dst_rect; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + ovl_idx = hisifd->ov_req.ovl_idx; + layer_idx = layer->layer_idx; + + if (layer->chn_idx == DSS_RCHN_V2) { + return 0; + } + + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + ovl = &(hisifd->dss_module.ov[ovl_idx]); + hisifd->dss_module.ov_used[ovl_idx] = 1; + + if (layer->need_cap & CAP_BASE) { + ovl->ovl_bg_color = + set_bits32(ovl->ovl_bg_color, layer->color, 32, 0); + ovl->ovl_gcfg = set_bits32(ovl->ovl_gcfg, 0x1, 1, 16); + return 0; + } + + if (layer->glb_alpha < 0) { + layer->glb_alpha = 0; + HISI_FB_ERR("layer's glb_alpha(0x%x) is out of range!", + layer->glb_alpha); + } else if (layer->glb_alpha > 0xFF) { + layer->glb_alpha = 0xFF; + HISI_FB_ERR("layer's glb_alpha(0x%x) is out of range!", + layer->glb_alpha); + } + + blend_mode = get_ovl_blending_mode(pov_req, layer); + BUG_ON((blend_mode < 0) || (blend_mode >= DSS_BLEND_MAX)); + + if (has_base) { + layer_idx -= 1; + if (layer_idx < 0) { + HISI_FB_ERR("layer_idx(%d) is out of range!\n", + layer_idx); + return -EINVAL; + } + } + + ovl->ovl_layer_used[layer_idx] = 1; + + if ((layer->chn_idx == DSS_RCHN_V0) + && layer->block_info.arsr2p_left_clip) { + dst_rect.x = + layer->dst_rect.x + layer->block_info.arsr2p_left_clip; + dst_rect.y = layer->dst_rect.y; + dst_rect.w = + layer->dst_rect.w - layer->block_info.arsr2p_left_clip; + dst_rect.h = layer->dst_rect.h; + } else { + dst_rect = layer->dst_rect; + } + + if (wb_ov_block_rect) { + wb_ov_rect.x = pov_req->wb_ov_rect.x + wb_ov_block_rect->x; + wb_ov_rect.y = pov_req->wb_ov_rect.y; + + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, + (dst_rect.x - wb_ov_rect.x), 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, + (dst_rect.y - wb_ov_rect.y), 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + (dst_rect.x - wb_ov_rect.x + + DSS_WIDTH(dst_rect.w)), 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + (dst_rect.y - wb_ov_rect.y + + DSS_HEIGHT(dst_rect.h)), 15, 16); + } else { + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, dst_rect.x, + 15, 0); + ovl->ovl_layer[layer_idx].layer_pos = + set_bits32(ovl->ovl_layer[layer_idx].layer_pos, dst_rect.y, + 15, 16); + + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + DSS_WIDTH(dst_rect.x + dst_rect.w), 15, 0); + ovl->ovl_layer[layer_idx].layer_size = + set_bits32(ovl->ovl_layer[layer_idx].layer_size, + DSS_HEIGHT(dst_rect.y + dst_rect.h), 15, 16); + } + + ovl->ovl_layer[layer_idx].layer_alpha = + set_bits32(ovl->ovl_layer[layer_idx].layer_alpha, + ((layer->glb_alpha << 0) | + (g_ovl_alpha[blend_mode].fix_mode << 8) | + (g_ovl_alpha[blend_mode].dst_pmode << 9) | + (g_ovl_alpha[blend_mode].alpha_offdst << 10) | + (g_ovl_alpha[blend_mode].dst_gmode << 12) | + (g_ovl_alpha[blend_mode].dst_amode << 14) | + (layer->glb_alpha <<16) | + (g_ovl_alpha[blend_mode].alpha_smode << 24) | + (g_ovl_alpha[blend_mode].src_pmode << 25) | + (g_ovl_alpha[blend_mode].src_lmode << 26) | + (g_ovl_alpha[blend_mode].alpha_offdst << 27) | + (g_ovl_alpha[blend_mode].src_gmode << 28) | + (g_ovl_alpha[blend_mode].src_amode << 30)), 32, 0); + + if (layer->need_cap & (CAP_DIM | CAP_PURE_COLOR)) { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer[layer_idx].layer_pattern, + layer->color, 32, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 8); + } else { + ovl->ovl_layer[layer_idx].layer_pattern = + set_bits32(ovl->ovl_layer[layer_idx].layer_pattern, 0x0, 32, + 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x1, 1, 0); + ovl->ovl_layer[layer_idx].layer_cfg = + set_bits32(ovl->ovl_layer[layer_idx].layer_cfg, 0x0, 1, 8); + } + + ovl->ovl_layer_pos[layer_idx].layer_pspos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pspos, dst_rect.x, + 15, 0); + ovl->ovl_layer_pos[layer_idx].layer_pspos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pspos, dst_rect.y, + 15, 16); + ovl->ovl_layer_pos[layer_idx].layer_pepos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pepos, + DSS_WIDTH(dst_rect.x + dst_rect.w), 15, 0); + ovl->ovl_layer_pos[layer_idx].layer_pepos = + set_bits32(ovl->ovl_layer_pos[layer_idx].layer_pepos, + DSS_HEIGHT(dst_rect.y + dst_rect.h), 15, 16); + + return 0; +} + +/******************************************************************************* + ** dirty_region_updt + */ +static void hisi_dss_dirty_region_dbuf_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dss_base, + dirty_region_updt_t * + s_dirty_region_updt) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dss_base == NULL); + BUG_ON(s_dirty_region_updt == NULL); + + hisifd->set_reg(hisifd, dss_base + DSS_DBUF0_OFFSET + DBUF_FRM_SIZE, + s_dirty_region_updt->dbuf_frm_size, 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DBUF0_OFFSET + DBUF_FRM_HSIZE, + s_dirty_region_updt->dbuf_frm_hsize, 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_BEF_SR, + ((s_dirty_region_updt->dpp_img_vrt_bef_sr << 16) | + s_dirty_region_updt->dpp_img_hrz_bef_sr), 32, 0); + hisifd->set_reg(hisifd, dss_base + DSS_DPP_OFFSET + DPP_IMG_SIZE_AFT_SR, + ((s_dirty_region_updt->dpp_img_vrt_aft_sr << 16) | + s_dirty_region_updt->dpp_img_hrz_aft_sr), 32, 0); +} + +static void hisi_dss_dirty_region_updt_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *dss_base, + dirty_region_updt_t * + s_dirty_region_updt) +{ + BUG_ON(hisifd == NULL); + BUG_ON(dss_base == NULL); + BUG_ON(s_dirty_region_updt == NULL); + + set_reg(dss_base + DSS_MIPI_DSI0_OFFSET + MIPIDSI_EDPI_CMD_SIZE_OFFSET, + s_dirty_region_updt->edpi_cmd_size, 32, 0); + if (is_dual_mipi_panel(hisifd)) { + set_reg(dss_base + DSS_MIPI_DSI1_OFFSET + + MIPIDSI_EDPI_CMD_SIZE_OFFSET, + s_dirty_region_updt->edpi_cmd_size, 32, 0); + } + + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL0, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL1, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI0_HRZ_CTRL2, + s_dirty_region_updt->ldi_dpi0_hrz_ctrl2, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL0, + s_dirty_region_updt->ldi_vrt_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL1, + s_dirty_region_updt->ldi_vrt_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_VRT_CTRL2, + s_dirty_region_updt->ldi_vrt_ctrl2, 13, 0); + + if (is_dual_mipi_panel(hisifd)) { + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL0, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl0, 29, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL1, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl1, 13, 0); + set_reg(dss_base + DSS_LDI0_OFFSET + LDI_DPI1_HRZ_CTRL2, + s_dirty_region_updt->ldi_dpi1_hrz_ctrl2, 13, 0); + } + + if (hisifd->panel_info.ifbc_type != IFBC_TYPE_NONE) { + if (!is_ifbc_vesa_panel(hisifd)) { + set_reg(dss_base + DSS_IFBC_OFFSET + IFBC_SIZE, + s_dirty_region_updt->ifbc_size, 32, 0); + } else { + set_reg(dss_base + DSS_DSC_OFFSET + DSC_PIC_SIZE, + s_dirty_region_updt->ifbc_size, 32, 0); + } + } +} + +int hisi_dss_dirty_region_dbuf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_panel_info *pinfo = NULL; + dirty_region_updt_t *dirty_region_updt = NULL; + struct dss_rect dirty = { 0 }; + + BUG_ON(hisifd == NULL); + pinfo = &(hisifd->panel_info); + + if ((hisifd->index != PRIMARY_PANEL_IDX) || + !pinfo->dirty_region_updt_support) + return 0; + + if ((!pov_req) + || (pov_req->dirty_rect.x == 0 && pov_req->dirty_rect.y == 0 + && pov_req->dirty_rect.w == 0 && pov_req->dirty_rect.h == 0)) { + dirty.x = 0; + dirty.y = 0; + dirty.w = hisifd->panel_info.xres; + dirty.h = hisifd->panel_info.yres; + } else { + dirty = pov_req->dirty_rect; + } + + if ((dirty.x == hisifd->dirty_region_updt.x) + && (dirty.y == hisifd->dirty_region_updt.y) + && (dirty.w == hisifd->dirty_region_updt.w) + && (dirty.h == hisifd->dirty_region_updt.h)) { + return 0; + } + + dirty_region_updt = &(hisifd->dss_module.dirty_region_updt); + hisifd->dss_module.dirty_region_updt_used = 1; + dirty_region_updt->dpp_img_hrz_bef_sr = + set_bits32(dirty_region_updt->dpp_img_hrz_bef_sr, + DSS_WIDTH(dirty.w), 13, 0); + dirty_region_updt->dpp_img_vrt_bef_sr = + set_bits32(dirty_region_updt->dpp_img_vrt_bef_sr, + DSS_WIDTH(dirty.h), 13, 0); + dirty_region_updt->dpp_img_hrz_aft_sr = + set_bits32(dirty_region_updt->dpp_img_hrz_aft_sr, + DSS_WIDTH(dirty.w), 13, 0); + dirty_region_updt->dpp_img_vrt_aft_sr = + set_bits32(dirty_region_updt->dpp_img_vrt_aft_sr, + DSS_WIDTH(dirty.h), 13, 0); + + dirty_region_updt->dbuf_frm_size = + set_bits32(dirty_region_updt->dbuf_frm_size, dirty.w * dirty.h, 27, + 0); + dirty_region_updt->dbuf_frm_hsize = + set_bits32(dirty_region_updt->dbuf_frm_hsize, DSS_WIDTH(dirty.w), + 13, 0); + + return 0; +} + +void hisi_dss_dirty_region_updt_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + struct hisi_fb_panel_data *pdata = NULL; + struct hisi_panel_info *pinfo = NULL; + dirty_region_updt_t *dirty_region_updt = NULL; + struct dss_rect dirty = { 0 }; + uint32_t h_porch_pading = 0; + uint32_t v_porch_pading = 0; + dss_rect_t rect = { 0 }; + uint32_t max_latency = 0; + uint32_t bits_per_pixel = 0; + uint32_t h_front_porch_max = 0; + uint32_t h_front_porch = 0; + uint32_t h_back_porch = 0; + + BUG_ON(hisifd == NULL); + pdata = dev_get_platdata(&hisifd->pdev->dev); + BUG_ON(pdata == NULL); + pinfo = &(hisifd->panel_info); + + if ((hisifd->index != PRIMARY_PANEL_IDX) || + !pinfo->dirty_region_updt_support) + return; + + if ((!pov_req) || (pov_req->dirty_rect.w == 0) + || (pov_req->dirty_rect.h == 0)) { + dirty.x = 0; + dirty.y = 0; + dirty.w = hisifd->panel_info.xres; + dirty.h = hisifd->panel_info.yres; + } else { + dirty = pov_req->dirty_rect; + } + + if (hisifd->panel_info.xres >= dirty.w) { + h_porch_pading = hisifd->panel_info.xres - dirty.w; + } + + if (hisifd->panel_info.yres >= dirty.h) { + v_porch_pading = hisifd->panel_info.yres - dirty.h; + } + + if ((dirty.x == hisifd->dirty_region_updt.x) + && (dirty.y == hisifd->dirty_region_updt.y) + && (dirty.w == hisifd->dirty_region_updt.w) + && (dirty.h == hisifd->dirty_region_updt.h)) { + return; + } + + rect.x = 0; + rect.y = 0; + rect.w = dirty.w; + rect.h = dirty.h; + mipi_ifbc_get_rect(hisifd, &rect); + + h_front_porch = pinfo->ldi.h_front_porch; + h_back_porch = pinfo->ldi.h_back_porch; + + h_porch_pading = h_porch_pading * rect.w / dirty.w; + v_porch_pading = v_porch_pading * rect.h / dirty.h; + + if (pinfo->bpp == LCD_RGB888) + bits_per_pixel = 24; + else if (pinfo->bpp == LCD_RGB565) + bits_per_pixel = 16; + else + bits_per_pixel = 24; + + if (pinfo->pxl_clk_rate_div == 0) + pinfo->pxl_clk_rate_div = 1; + max_latency = + (rect.w * bits_per_pixel / 8 + 1 + 6) / (pinfo->mipi.lane_nums + 1); + + h_front_porch_max = + max_latency * (pinfo->pxl_clk_rate / pinfo->pxl_clk_rate_div) / + pinfo->dsi_phy_ctrl.lane_byte_clk; + HISI_FB_DEBUG("bits_per_pixel = %d\n" "data_lane_lp2hs_time = %d\n" + "max_latency = %d\n" "pxl_clk_rate = %lld\n" + "pxl_clk_rate_div = %d\n" + "dsi_phy_ctrl.lane_byte_clk = %lld\n" + "h_front_porch_max = %d\n", bits_per_pixel, + pinfo->dsi_phy_ctrl.data_lane_lp2hs_time, max_latency, + pinfo->pxl_clk_rate, pinfo->pxl_clk_rate_div, + pinfo->dsi_phy_ctrl.lane_byte_clk, h_front_porch_max); + + if (h_front_porch > h_front_porch_max) { + h_back_porch += (h_front_porch - h_front_porch_max); + h_front_porch = h_front_porch_max; + } + + dirty_region_updt = &(hisifd->dss_module.dirty_region_updt); + + dirty_region_updt->ldi_dpi0_hrz_ctrl0 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl0, + (h_front_porch) | ((h_back_porch + h_porch_pading) << + 16), 29, 0); + dirty_region_updt->ldi_dpi0_hrz_ctrl1 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl1, + DSS_WIDTH(pinfo->ldi.h_pulse_width), 13, 0); + dirty_region_updt->ldi_dpi0_hrz_ctrl2 = + set_bits32(dirty_region_updt->ldi_dpi0_hrz_ctrl2, DSS_WIDTH(rect.w), + 13, 0); + + if (is_dual_mipi_panel(hisifd)) { + dirty_region_updt->ldi_dpi1_hrz_ctrl0 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl0, + (h_back_porch + h_porch_pading) << 16, 29, 0); + dirty_region_updt->ldi_dpi1_hrz_ctrl1 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl1, + DSS_WIDTH(pinfo->ldi.h_pulse_width), 13, 0); + dirty_region_updt->ldi_dpi1_hrz_ctrl2 = + set_bits32(dirty_region_updt->ldi_dpi1_hrz_ctrl2, + DSS_WIDTH(rect.w), 13, 0); + } + + dirty_region_updt->ldi_vrt_ctrl0 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl0, + (pinfo->ldi.v_front_porch + + v_porch_pading) | ((pinfo->ldi.v_back_porch) << 16), 29, + 0); + dirty_region_updt->ldi_vrt_ctrl1 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl1, + DSS_HEIGHT(pinfo->ldi.v_pulse_width), 13, 0); + dirty_region_updt->ldi_vrt_ctrl2 = + set_bits32(dirty_region_updt->ldi_vrt_ctrl2, DSS_HEIGHT(rect.h), 13, + 0); + + dirty_region_updt->edpi_cmd_size = + set_bits32(dirty_region_updt->edpi_cmd_size, rect.w, 16, 0); + + if (pinfo->ifbc_type != IFBC_TYPE_NONE) { + if ((pinfo->ifbc_type == IFBC_TYPE_VESA2X_DUAL) || + (pinfo->ifbc_type == IFBC_TYPE_VESA3X_DUAL)) { + dirty_region_updt->ifbc_size = + set_bits32(dirty_region_updt->ifbc_size, + ((DSS_WIDTH(dirty.w / 2) << 16) | + DSS_HEIGHT(dirty.h)), 32, 0); + } else { + dirty_region_updt->ifbc_size = + set_bits32(dirty_region_updt->ifbc_size, + ((DSS_WIDTH(dirty.w) << 16) | + DSS_HEIGHT(dirty.h)), 32, 0); + } + } + + /*if (pdata && pdata->set_display_region) { + pdata->set_display_region(hisifd->pdev, &dirty); + } */ + + hisifd->dirty_region_updt = dirty; + + hisi_dss_dirty_region_updt_set_reg(hisifd, hisifd->dss_base, + &(hisifd->dss_module. + dirty_region_updt)); + + if (g_debug_dirty_region_updt) { + HISI_FB_INFO + ("dirty_region(%d,%d, %d,%d), h_porch_pading=%d, v_porch_pading=%d.\n", + dirty.x, dirty.y, dirty.w, dirty.h, h_porch_pading, + v_porch_pading); + } +} + +/******************************************************************************* + ** WCHN + */ +static uint32_t hisi_calculate_display_addr_wb(bool mmu_enable, + dss_wb_layer_t *wb_layer, + dss_rect_t aligned_rect, + dss_rect_t *ov_block_rect, + int add_type) +{ + uint32_t addr = 0; + uint32_t dst_addr = 0; + uint32_t stride = 0; + uint32_t offset = 0; + int left = 0, top = 0; + int bpp = 0; + + if (wb_layer->transform & HISI_FB_TRANSFORM_ROT_90) { + left = wb_layer->dst_rect.x; + top = + ov_block_rect->x - wb_layer->dst_rect.x + + wb_layer->dst_rect.y; + } else { + left = aligned_rect.x; + top = aligned_rect.y; + } + + if (add_type == DSS_ADDR_PLANE0) { + stride = wb_layer->dst.stride; + dst_addr = + mmu_enable ? wb_layer->dst.vir_addr : wb_layer->dst. + phy_addr; + } else if (add_type == DSS_ADDR_PLANE1) { + stride = wb_layer->dst.stride_plane1; + offset = wb_layer->dst.offset_plane1; + dst_addr = + mmu_enable ? (wb_layer->dst.vir_addr + + offset) : (wb_layer->dst.phy_addr + offset); + top /= 2; + } else { + HISI_FB_ERR("NOT SUPPORT this add_type(%d).\n", add_type); + BUG_ON(1); + } + + bpp = wb_layer->dst.bpp; + addr = dst_addr + left * bpp + top * stride; + + return addr; +} + +int hisi_dss_wdfc_config(struct hisi_fb_data_type *hisifd, + dss_wb_layer_t *layer, dss_rect_t *aligned_rect, + dss_rect_t *ov_block_rect) +{ + dss_dfc_t *dfc = NULL; + int chn_idx = 0; + dss_rect_t in_rect; + bool need_dither = false; + + int size_hrz = 0; + int size_vrt = 0; + int dfc_fmt = 0; + int dfc_pix_in_num = 0; + int aligned_line = 0; + uint32_t dfc_w = 0; + int aligned_pixel = 0; + + uint32_t left_pad = 0; + uint32_t right_pad = 0; + uint32_t top_pad = 0; + uint32_t bottom_pad = 0; + + uint32_t addr = 0; + uint32_t dst_addr = 0; + uint32_t bpp = 0; + bool mmu_enable = false; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + BUG_ON(aligned_rect == NULL); + + chn_idx = layer->chn_idx; + + dfc = &(hisifd->dss_module.dfc[chn_idx]); + hisifd->dss_module.dfc_used[chn_idx] = 1; + + dfc_fmt = hisi_pixel_format_hal2dfc(layer->dst.format); + if (dfc_fmt < 0) { + HISI_FB_ERR("layer format (%d) not support !\n", + layer->dst.format); + return -EINVAL; + } + + if (layer->need_cap & CAP_AFBCE) { + aligned_pixel = AFBC_BLOCK_ALIGN; + } else { + aligned_pixel = DMA_ALIGN_BYTES / layer->dst.bpp; + } + + need_dither = isNeedDither(dfc_fmt); + if (ov_block_rect) { + memcpy(&in_rect, ov_block_rect, sizeof(dss_rect_t)); + } else { + in_rect = layer->src_rect; + } + + size_hrz = DSS_WIDTH(in_rect.w); + size_vrt = DSS_HEIGHT(in_rect.h); + + if ((size_hrz + 1) % 2 == 1) { + size_hrz += 1; + dfc_w = 1; + } + + dfc_pix_in_num = (layer->dst.bpp <= 2) ? 0x1 : 0x0; + + if (layer->need_cap & CAP_AFBCE) { + aligned_rect->x = ALIGN_DOWN(in_rect.x, aligned_pixel); + aligned_rect->w = + ALIGN_UP(in_rect.x - aligned_rect->x + in_rect.w + dfc_w, + aligned_pixel); + aligned_rect->y = ALIGN_DOWN(in_rect.y, aligned_pixel); + aligned_rect->h = + ALIGN_UP(in_rect.y - aligned_rect->y + in_rect.h, + aligned_pixel); + + left_pad = in_rect.x - aligned_rect->x; + right_pad = + aligned_rect->w - (in_rect.x - aligned_rect->x + in_rect.w + + dfc_w); + top_pad = in_rect.y - aligned_rect->y; + bottom_pad = + aligned_rect->h - (in_rect.y - aligned_rect->y + in_rect.h); + } else if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + aligned_line = (layer->dst.bpp <= 2) ? 32 : 16; + mmu_enable = (layer->dst.mmu_enable == 1) ? true : false; + dst_addr = + mmu_enable ? layer->dst.vir_addr : layer->dst.phy_addr; + bpp = layer->dst.bpp; + addr = + dst_addr + layer->dst_rect.x * bpp + + (in_rect.x - layer->dst_rect.x + layer->dst_rect.y) * + layer->dst.stride; + + if (is_YUV_SP_420(layer->dst.format)) { + top_pad = (addr & 0x1F) / bpp; + } else { + top_pad = (addr & 0x3F) / bpp; + } + + aligned_rect->x = in_rect.x; + aligned_rect->y = in_rect.y; + aligned_rect->w = size_hrz + 1; + aligned_rect->h = ALIGN_UP(in_rect.h + top_pad, aligned_line); + + left_pad = 0; + right_pad = 0; + bottom_pad = aligned_rect->h - in_rect.h - top_pad; + } else { + aligned_rect->x = ALIGN_DOWN(in_rect.x, aligned_pixel); + aligned_rect->w = + ALIGN_UP(in_rect.x - aligned_rect->x + in_rect.w + dfc_w, + aligned_pixel); + aligned_rect->y = in_rect.y; + + if (is_YUV_SP_420(layer->dst.format)) { + aligned_rect->h = ALIGN_UP(in_rect.h, 2); + } else { + aligned_rect->h = in_rect.h; + } + + left_pad = in_rect.x - aligned_rect->x; + right_pad = aligned_rect->w - (left_pad + in_rect.w + dfc_w); + top_pad = 0; + bottom_pad = aligned_rect->h - in_rect.h; + } + + dfc->disp_size = + set_bits32(dfc->disp_size, (size_vrt | (size_hrz << 16)), 32, 0); + dfc->pix_in_num = set_bits32(dfc->pix_in_num, dfc_pix_in_num, 1, 0); + dfc->disp_fmt = set_bits32(dfc->disp_fmt, dfc_fmt, 5, 1); + dfc->clip_ctl_hrz = set_bits32(dfc->clip_ctl_hrz, 0x0, 12, 0); + dfc->clip_ctl_vrz = set_bits32(dfc->clip_ctl_vrz, 0x0, 12, 0); + dfc->ctl_clip_en = set_bits32(dfc->ctl_clip_en, 0x0, 1, 0); + dfc->icg_module = set_bits32(dfc->icg_module, 0x1, 1, 0); + if (need_dither) { + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x1, 1, 0); + } else { + dfc->dither_enable = set_bits32(dfc->dither_enable, 0x0, 1, 0); + } + + if (left_pad || right_pad || top_pad || bottom_pad) { + dfc->padding_ctl = set_bits32(dfc->padding_ctl, (left_pad | + (right_pad << 8) | (top_pad << 16) | + (bottom_pad << 24) | (0x1 << 31)), 32, 0); + } else { + dfc->padding_ctl = set_bits32(dfc->padding_ctl, 0x0, 32, 0); + } + + return 0; +} + +static void hisi_dss_wdma_init(char __iomem *wdma_base, dss_wdma_t *s_wdma) +{ + BUG_ON(wdma_base == NULL); + BUG_ON(s_wdma == NULL); + + memset(s_wdma, 0, sizeof(dss_wdma_t)); + + s_wdma->oft_x0 = inp32(wdma_base + DMA_OFT_X0); + s_wdma->oft_y0 = inp32(wdma_base + DMA_OFT_Y0); + s_wdma->oft_x1 = inp32(wdma_base + DMA_OFT_X1); + s_wdma->oft_y1 = inp32(wdma_base + DMA_OFT_Y1); + s_wdma->mask0 = inp32(wdma_base + DMA_MASK0); + s_wdma->mask1 = inp32(wdma_base + DMA_MASK1); + s_wdma->stretch_size_vrt = inp32(wdma_base + DMA_STRETCH_SIZE_VRT); + s_wdma->ctrl = inp32(wdma_base + DMA_CTRL); + s_wdma->tile_scram = inp32(wdma_base + DMA_TILE_SCRAM); + s_wdma->sw_mask_en = inp32(wdma_base + WDMA_DMA_SW_MASK_EN); + s_wdma->start_mask0 = inp32(wdma_base + WDMA_DMA_START_MASK0); + s_wdma->end_mask0 = inp32(wdma_base + WDMA_DMA_END_MASK1); + s_wdma->start_mask1 = inp32(wdma_base + WDMA_DMA_START_MASK1); + s_wdma->end_mask1 = inp32(wdma_base + WDMA_DMA_END_MASK1); + s_wdma->data_addr = inp32(wdma_base + DMA_DATA_ADDR0); + s_wdma->stride0 = inp32(wdma_base + DMA_STRIDE0); + s_wdma->data1_addr = inp32(wdma_base + DMA_DATA_ADDR1); + s_wdma->stride1 = inp32(wdma_base + DMA_STRIDE1); + s_wdma->stretch_stride = inp32(wdma_base + DMA_STRETCH_STRIDE0); + s_wdma->data_num = inp32(wdma_base + DMA_DATA_NUM0); + + s_wdma->ch_rd_shadow = inp32(wdma_base + CH_RD_SHADOW); + s_wdma->ch_ctl = inp32(wdma_base + CH_CTL); + s_wdma->ch_secu_en = inp32(wdma_base + CH_SECU_EN); + s_wdma->ch_sw_end_req = inp32(wdma_base + CH_SW_END_REQ); + + s_wdma->afbce_hreg_pic_blks = inp32(wdma_base + AFBCE_HREG_PIC_BLKS); + s_wdma->afbce_hreg_format = inp32(wdma_base + AFBCE_HREG_FORMAT); + s_wdma->afbce_hreg_hdr_ptr_lo = + inp32(wdma_base + AFBCE_HREG_HDR_PTR_LO); + s_wdma->afbce_hreg_pld_ptr_lo = + inp32(wdma_base + AFBCE_HREG_PLD_PTR_LO); + s_wdma->afbce_picture_size = inp32(wdma_base + AFBCE_PICTURE_SIZE); + s_wdma->afbce_ctl = inp32(wdma_base + AFBCE_CTL); + s_wdma->afbce_header_srtide = inp32(wdma_base + AFBCE_HEADER_SRTIDE); + s_wdma->afbce_payload_stride = inp32(wdma_base + AFBCE_PAYLOAD_STRIDE); + s_wdma->afbce_enc_os_cfg = inp32(wdma_base + AFBCE_ENC_OS_CFG); + s_wdma->afbce_mem_ctrl = inp32(wdma_base + AFBCE_MEM_CTRL); +} + +static void hisi_dss_wdma_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *wdma_base, dss_wdma_t *s_wdma) +{ + BUG_ON(hisifd == NULL); + BUG_ON(wdma_base == NULL); + BUG_ON(s_wdma == NULL); + + hisifd->set_reg(hisifd, wdma_base + CH_REG_DEFAULT, 0x1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + CH_REG_DEFAULT, 0x0, 32, 0); + + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_X0, s_wdma->oft_x0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_Y0, s_wdma->oft_y0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_X1, s_wdma->oft_x1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_OFT_Y1, s_wdma->oft_y1, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_CTRL, s_wdma->ctrl, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_TILE_SCRAM, + s_wdma->tile_scram, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_SW_MASK_EN, + s_wdma->sw_mask_en, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_START_MASK0, + s_wdma->start_mask0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + WDMA_DMA_END_MASK0, + s_wdma->end_mask0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_DATA_ADDR0, + s_wdma->data_addr, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_STRIDE0, + s_wdma->stride0, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_DATA_ADDR1, + s_wdma->data1_addr, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_STRIDE1, + s_wdma->stride1, 32, 0); + + hisifd->set_reg(hisifd, wdma_base + CH_CTL, s_wdma->ch_ctl, 32, 0); + hisifd->set_reg(hisifd, wdma_base + ROT_SIZE, s_wdma->rot_size, 32, 0); + hisifd->set_reg(hisifd, wdma_base + DMA_BUF_SIZE, + s_wdma->dma_buf_size, 32, 0); + + if (s_wdma->afbc_used == 1) { + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_PIC_BLKS, + s_wdma->afbce_hreg_pic_blks, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_FORMAT, + s_wdma->afbce_hreg_format, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_HDR_PTR_LO, + s_wdma->afbce_hreg_hdr_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HREG_PLD_PTR_LO, + s_wdma->afbce_hreg_pld_ptr_lo, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_PICTURE_SIZE, + s_wdma->afbce_picture_size, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HEADER_SRTIDE, + s_wdma->afbce_header_srtide, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_PAYLOAD_STRIDE, + s_wdma->afbce_payload_stride, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_ENC_OS_CFG, + s_wdma->afbce_enc_os_cfg, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_THRESHOLD, + s_wdma->afbce_threshold, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_SCRAMBLE_MODE, + s_wdma->afbce_scramble_mode, 32, 0); + hisifd->set_reg(hisifd, wdma_base + AFBCE_HEADER_POINTER_OFFSET, + s_wdma->afbce_header_pointer_offset, 32, 0); + } +} + +int hisi_dss_wdma_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_wb_layer_t *layer, + dss_rect_t aligned_rect, dss_rect_t *ov_block_rect, + bool last_block) +{ + dss_wdma_t *wdma = NULL; + int chn_idx = 0; + int wdma_format = 0; + int wdma_transform = 0; + uint32_t oft_x0 = 0; + uint32_t oft_x1 = 0; + uint32_t oft_y0 = 0; + uint32_t oft_y1 = 0; + uint32_t data_num = 0; + uint32_t wdma_addr = 0; + uint32_t wdma_stride = 0; + + uint32_t wdma_buf_width = 0; + uint32_t wdma_buf_height = 0; + + dss_rect_t in_rect; + int temp = 0; + int aligned_pixel = 0; + int l2t_interleave_n = 0; + bool mmu_enable = false; + + dss_rect_ltrb_t afbc_header_rect = { 0 }; + dss_rect_ltrb_t afbc_payload_rect = { 0 }; + uint32_t afbce_hreg_pic_blks; + uint32_t afbc_header_addr = 0; + uint32_t afbc_header_stride = 0; + uint32_t afbc_payload_addr = 0; + uint32_t afbc_payload_stride = 0; + int32_t afbc_header_start_pos = 0; + uint32_t afbc_header_pointer_offset = 0; + uint32_t stride_align = 0; + uint32_t addr_align = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + + wdma = &(hisifd->dss_module.wdma[chn_idx]); + hisifd->dss_module.dma_used[chn_idx] = 1; + + wdma_format = hisi_pixel_format_hal2dma(layer->dst.format); + if (wdma_format < 0) { + HISI_FB_ERR("hisi_pixel_format_hal2dma failed!\n"); + return -EINVAL; + } + + in_rect = aligned_rect; + aligned_pixel = DMA_ALIGN_BYTES / layer->dst.bpp; + + wdma_transform = hisi_transform_hal2dma(layer->transform, chn_idx); + if (wdma_transform < 0) { + HISI_FB_ERR("hisi_transform_hal2dma failed!\n"); + return -EINVAL; + } + + mmu_enable = (layer->dst.mmu_enable == 1) ? true : false; + wdma_addr = mmu_enable ? layer->dst.vir_addr : layer->dst.phy_addr; + + if (layer->need_cap & CAP_AFBCE) { + wdma->afbc_used = 1; + if ((layer->dst.width & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (layer->dst.height & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("wb_layer img width(%d) is not %d bytes aligned, or " + "img heigh(%d) is not %d bytes aligned!\n", + layer->dst.width, AFBC_HEADER_ADDR_ALIGN, + layer->dst.height, AFBC_BLOCK_ALIGN); + return -EINVAL; + } + + if ((in_rect.w < AFBC_PIC_WIDTH_MIN) + || (in_rect.w > AFBCE_IN_WIDTH_MAX) + || (in_rect.h < AFBC_PIC_HEIGHT_MIN) + || (in_rect.h > AFBC_PIC_HEIGHT_MAX) + || (in_rect.w & (AFBC_BLOCK_ALIGN - 1)) + || (in_rect.h & (AFBC_BLOCK_ALIGN - 1))) { + HISI_FB_ERR + ("afbce in_rect(%d,%d, %d,%d) is out of range!", + in_rect.x, in_rect.y, in_rect.w, in_rect.h); + return -EINVAL; + } + + afbc_header_rect.right = + ALIGN_UP(in_rect.x + in_rect.w, AFBC_HEADER_ADDR_ALIGN) - 1; + afbc_header_rect.bottom = + ALIGN_UP(in_rect.y + in_rect.h, AFBC_BLOCK_ALIGN) - 1; + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + afbc_header_rect.left = + ALIGN_DOWN(layer->dst_rect.x, + AFBC_HEADER_ADDR_ALIGN); + afbc_header_rect.top = + ALIGN_DOWN(layer->dst_rect.y + + (ov_block_rect->x - layer->dst_rect.x), + AFBC_BLOCK_ALIGN); + + afbc_payload_rect.left = + ALIGN_DOWN(layer->dst_rect.x, AFBC_BLOCK_ALIGN); + afbc_payload_rect.top = afbc_header_rect.top; + + afbc_header_start_pos = + (layer->dst_rect.x - + afbc_header_rect.left) / AFBC_BLOCK_ALIGN; + } else { + afbc_header_rect.left = + ALIGN_DOWN(in_rect.x, AFBC_HEADER_ADDR_ALIGN); + afbc_header_rect.top = + ALIGN_DOWN(in_rect.y, AFBC_BLOCK_ALIGN); + + afbc_payload_rect.left = + ALIGN_DOWN(in_rect.x, AFBC_BLOCK_ALIGN); + afbc_payload_rect.top = afbc_header_rect.top; + + afbc_header_start_pos = + (in_rect.x - + afbc_header_rect.left) / AFBC_BLOCK_ALIGN; + } + + if (afbc_header_start_pos < 0) { + HISI_FB_ERR("afbc_header_start_pos(%d) is invalid!\n", + afbc_header_start_pos); + return -EINVAL; + } + + afbce_hreg_pic_blks = + (in_rect.w / AFBC_BLOCK_ALIGN) * (in_rect.h / + AFBC_BLOCK_ALIGN) - 1; + + afbc_header_stride = + (layer->dst.width / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + + afbc_header_pointer_offset = + (afbc_header_rect.top / AFBC_BLOCK_ALIGN) * + afbc_header_stride + + (afbc_header_rect.left / AFBC_BLOCK_ALIGN) * + AFBC_HEADER_STRIDE_BLOCK; + + afbc_header_addr = + layer->dst.afbc_header_addr + afbc_header_pointer_offset; + + if ((afbc_header_addr & (AFBC_HEADER_ADDR_ALIGN - 1)) || + (afbc_header_stride & (AFBC_HEADER_STRIDE_ALIGN - 1))) { + HISI_FB_ERR + ("wb_layer afbc_header_addr(0x%x) is not %d bytes aligned, or " + "afbc_header_stride(0x%x) is not %d bytes aligned!\n", + afbc_header_addr, AFBC_HEADER_ADDR_ALIGN, + afbc_header_stride, AFBC_HEADER_STRIDE_ALIGN); + return -EINVAL; + } + + if (layer->dst.bpp == 4) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_32; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_32; + } else if (layer->dst.bpp == 2) { + stride_align = AFBC_PAYLOAD_STRIDE_ALIGN_16; + addr_align = AFBC_PAYLOAD_ADDR_ALIGN_16; + } else { + HISI_FB_ERR("bpp(%d) not supported!\n", layer->dst.bpp); + return -EINVAL; + } + + afbc_payload_stride = layer->dst.afbc_payload_stride; + if (layer->dst.afbc_scramble_mode != DSS_AFBC_SCRAMBLE_MODE2) { + afbc_payload_stride = + (layer->dst.width / AFBC_BLOCK_ALIGN) * + stride_align; + } + afbc_payload_addr = layer->dst.afbc_payload_addr + + (afbc_payload_rect.top / AFBC_BLOCK_ALIGN) * + afbc_payload_stride + + (afbc_payload_rect.left / AFBC_BLOCK_ALIGN) * stride_align; + + if ((afbc_payload_addr & (addr_align - 1)) || + (afbc_payload_stride & (stride_align - 1))) { + HISI_FB_ERR + ("afbc_payload_addr(0x%x) is not %d bytes aligned, or " + "afbc_payload_stride(0x%x) is not %d bytes aligned!\n", + afbc_payload_addr, addr_align, afbc_payload_stride, + stride_align); + return -EINVAL; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("aligned_rect(%d,%d,%d,%d), afbc_rect(%d,%d,%d,%d)!\n", + in_rect.x, in_rect.y, + DSS_WIDTH(in_rect.x + in_rect.w), + DSS_WIDTH(in_rect.y + in_rect.h), + afbc_payload_rect.left, afbc_payload_rect.top, + afbc_payload_rect.right, afbc_payload_rect.bottom); + } + + wdma->ctrl = set_bits32(wdma->ctrl, wdma_format, 5, 3); + wdma->ctrl = + set_bits32(wdma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + wdma->ctrl = set_bits32(wdma->ctrl, wdma_transform, 3, 9); + if (last_block) { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0x1d, 5, 0); + } else { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0xd, 5, 0); + } + + wdma->rot_size = set_bits32(wdma->rot_size, + (DSS_WIDTH(in_rect.w) | + (DSS_HEIGHT(in_rect.h) << 16)), 32, 0); + + wdma->afbce_hreg_pic_blks = + set_bits32(wdma->afbce_hreg_pic_blks, + afbce_hreg_pic_blks, 24, 0); + + wdma->afbce_hreg_format = + set_bits32(wdma->afbce_hreg_format, + (isYUVPackage(layer->dst.format) ? 0x0 : 0x1), 1, 21); + + wdma->afbce_hreg_hdr_ptr_lo = + set_bits32(wdma->afbce_hreg_hdr_ptr_lo, + afbc_header_addr, 32, 0); + + wdma->afbce_hreg_pld_ptr_lo = + set_bits32(wdma->afbce_hreg_pld_ptr_lo, + afbc_payload_addr, 32, 0); + + wdma->afbce_picture_size = + set_bits32(wdma->afbce_picture_size, + ((DSS_WIDTH(in_rect.w) << 16) | + DSS_HEIGHT(in_rect.h)), 32, 0); + + wdma->afbce_header_srtide = + set_bits32(wdma->afbce_header_srtide, + ((afbc_header_start_pos << 14) | + afbc_header_stride), 16, 0); + + wdma->afbce_payload_stride = + set_bits32(wdma->afbce_payload_stride, afbc_payload_stride, 20, 0); + + wdma->afbce_enc_os_cfg = + set_bits32(wdma->afbce_enc_os_cfg, + DSS_AFBCE_ENC_OS_CFG_DEFAULT_VAL, 3, 0); + + wdma->afbce_mem_ctrl = + set_bits32(wdma->afbce_mem_ctrl, 0x0, 12, 0); + wdma->afbce_threshold = + set_bits32(wdma->afbce_threshold, 0x2, 32, 0); + wdma->afbce_header_pointer_offset = + set_bits32(wdma->afbce_header_pointer_offset, + afbc_header_pointer_offset, 32, 0); + wdma->afbce_scramble_mode = + set_bits32(wdma->afbce_scramble_mode, + layer->dst.afbc_scramble_mode, 2, 0); + + return 0; + } + + if (layer->need_cap & CAP_TILE) { + l2t_interleave_n = + hisi_get_rdma_tile_interleave(layer->dst.stride); + if (l2t_interleave_n < MIN_INTERLEAVE) { + HISI_FB_ERR + ("tile stride should be 256*2^n, error stride:%d!\n", + layer->dst.stride); + return -EINVAL; + } + + if (wdma_addr & (TILE_DMA_ADDR_ALIGN - 1)) { + HISI_FB_ERR + ("tile wdma_addr(0x%x) is not %d bytes aligned.\n", + wdma_addr, TILE_DMA_ADDR_ALIGN); + return -EINVAL; + } + } + + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + temp = in_rect.w; + in_rect.w = in_rect.h; + in_rect.h = temp; + + oft_x0 = 0; + oft_x1 = DSS_WIDTH(in_rect.w) / aligned_pixel; + oft_y0 = 0; + oft_y1 = DSS_HEIGHT(ov_block_rect->w); + } else { + oft_x0 = in_rect.x / aligned_pixel; + oft_x1 = DSS_WIDTH(in_rect.x + in_rect.w) / aligned_pixel; + oft_y0 = in_rect.y; + oft_y1 = DSS_HEIGHT(in_rect.y + in_rect.h); + } + + wdma_addr = + hisi_calculate_display_addr_wb(mmu_enable, layer, in_rect, + ov_block_rect, DSS_ADDR_PLANE0); + wdma_stride = layer->dst.stride / DMA_ALIGN_BYTES; + + data_num = (oft_x1 - oft_x0 + 1) * (oft_y1 - oft_y0 + 1); + if (layer->transform & HISI_FB_TRANSFORM_ROT_90) { + wdma->rot_size = set_bits32(wdma->rot_size, + (DSS_WIDTH(ov_block_rect->w) | + (DSS_HEIGHT(aligned_rect.h) << 16)), 32, 0); + + if (ov_block_rect) { + wdma_buf_width = DSS_HEIGHT(ov_block_rect->h); + wdma_buf_height = DSS_WIDTH(ov_block_rect->w); + } else { + wdma_buf_width = DSS_HEIGHT(layer->src_rect.h); + wdma_buf_height = DSS_WIDTH(layer->src_rect.w); + } + } else { + if (ov_block_rect) { + wdma_buf_width = DSS_WIDTH(ov_block_rect->w); + wdma_buf_height = DSS_HEIGHT(ov_block_rect->h); + } else { + wdma_buf_width = DSS_WIDTH(layer->src_rect.w); + wdma_buf_height = DSS_HEIGHT(layer->src_rect.h); + } + } + + wdma->oft_x0 = set_bits32(wdma->oft_x0, oft_x0, 12, 0); + wdma->oft_y0 = set_bits32(wdma->oft_y0, oft_y0, 16, 0); + wdma->oft_x1 = set_bits32(wdma->oft_x1, oft_x1, 12, 0); + wdma->oft_y1 = set_bits32(wdma->oft_y1, oft_y1, 16, 0); + + wdma->ctrl = set_bits32(wdma->ctrl, wdma_format, 5, 3); + wdma->ctrl = set_bits32(wdma->ctrl, wdma_transform, 3, 9); + wdma->ctrl = set_bits32(wdma->ctrl, (mmu_enable ? 0x1 : 0x0), 1, 8); + wdma->data_num = set_bits32(wdma->data_num, data_num, 30, 0); + + wdma->ctrl = + set_bits32(wdma->ctrl, ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), + 1, 1); + wdma->tile_scram = + set_bits32(wdma->tile_scram, + ((layer->need_cap & CAP_TILE) ? 0x1 : 0x0), 1, 0); + + wdma->data_addr = set_bits32(wdma->data_addr, wdma_addr, 32, 0); + wdma->stride0 = + set_bits32(wdma->stride0, wdma_stride | (l2t_interleave_n << 16), + 20, 0); + + if (is_YUV_SP_420(layer->dst.format)) { + wdma_addr = + hisi_calculate_display_addr_wb(mmu_enable, layer, in_rect, + ov_block_rect, DSS_ADDR_PLANE1); + + wdma_stride = layer->dst.stride_plane1 / DMA_ALIGN_BYTES; + wdma->data1_addr = + set_bits32(wdma->data1_addr, wdma_addr, 32, 0); + wdma->stride1 = set_bits32(wdma->stride1, wdma_stride, 13, 0); + } + + if (last_block) { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 4); + } else { + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 0, 1, 4); + } + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 3); + wdma->ch_ctl = set_bits32(wdma->ch_ctl, 1, 1, 0); + + wdma->dma_buf_size = set_bits32(wdma->dma_buf_size, + wdma_buf_width | (wdma_buf_height << 16), 32, 0); + + return 0; +} + +/******************************************************************************* + ** DSS GLOBAL + */ +int hisi_dss_module_init(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + memcpy(&(hisifd->dss_module), &(hisifd->dss_module_default), + sizeof(dss_module_reg_t)); + + return 0; +} + +int hisi_dss_module_default(struct hisi_fb_data_type *hisifd) +{ + dss_module_reg_t *dss_module = NULL; + uint32_t module_base = 0; + char __iomem *dss_base = NULL; + int i = 0; + + BUG_ON(hisifd == NULL); + dss_base = hisifd->dss_base; + BUG_ON(dss_base == NULL); + + dss_module = &(hisifd->dss_module_default); + memset(dss_module, 0, sizeof(dss_module_reg_t)); + + for (i = 0; i < DSS_MCTL_IDX_MAX; i++) { + module_base = g_dss_module_ovl_base[i][MODULE_MCTL_BASE]; + if (module_base != 0) { + dss_module->mctl_base[i] = dss_base + module_base; + hisi_dss_mctl_init(dss_module->mctl_base[i], + &(dss_module->mctl[i])); + } + } + + for (i = 0; i < DSS_OVL_IDX_MAX; i++) { + module_base = g_dss_module_ovl_base[i][MODULE_OVL_BASE]; + if (module_base != 0) { + dss_module->ov_base[i] = dss_base + module_base; + hisi_dss_ovl_init(dss_module->ov_base[i], + &(dss_module->ov[i]), i); + } + } + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + module_base = g_dss_module_base[i][MODULE_AIF0_CHN]; + if (module_base != 0) { + dss_module->aif_ch_base[i] = dss_base + module_base; + hisi_dss_aif_init(dss_module->aif_ch_base[i], + &(dss_module->aif[i])); + } + + module_base = g_dss_module_base[i][MODULE_AIF1_CHN]; + if (module_base != 0) { + dss_module->aif1_ch_base[i] = dss_base + module_base; + hisi_dss_aif_init(dss_module->aif1_ch_base[i], + &(dss_module->aif1[i])); + } + + module_base = g_dss_module_base[i][MODULE_MIF_CHN]; + if (module_base != 0) { + dss_module->mif_ch_base[i] = dss_base + module_base; + hisi_dss_mif_init(dss_module->mif_ch_base[i], + &(dss_module->mif[i]), i); + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_MUTEX]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_mutex_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_FLUSH_EN]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_flush_en_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_OV_OEN]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_ov_en_base = + dss_base + module_base; + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_STARTY]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_starty_base = + dss_base + module_base; + hisi_dss_mctl_ch_starty_init( + dss_module->mctl_ch_base[i].chn_starty_base, + &(dss_module->mctl_ch[i])); + } + + module_base = g_dss_module_base[i][MODULE_MCTL_CHN_MOD_DBG]; + if (module_base != 0) { + dss_module->mctl_ch_base[i].chn_mod_dbg_base = + dss_base + module_base; + hisi_dss_mctl_ch_mod_dbg_init( + dss_module->mctl_ch_base[i].chn_mod_dbg_base, + &(dss_module->mctl_ch[i])); + } + + module_base = g_dss_module_base[i][MODULE_DMA]; + if (module_base != 0) { + dss_module->dma_base[i] = dss_base + module_base; + if (i < DSS_WCHN_W0 || i == DSS_RCHN_V2) { + hisi_dss_rdma_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + } else { + hisi_dss_wdma_init(dss_module->dma_base[i], + &(dss_module->wdma[i])); + } + + if ((i == DSS_RCHN_V0) || (i == DSS_RCHN_V1) + || (i == DSS_RCHN_V2)) { + hisi_dss_rdma_u_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + hisi_dss_rdma_v_init(dss_module->dma_base[i], + &(dss_module->rdma[i])); + } + } + + module_base = g_dss_module_base[i][MODULE_DFC]; + if (module_base != 0) { + dss_module->dfc_base[i] = dss_base + module_base; + hisi_dss_dfc_init(dss_module->dfc_base[i], + &(dss_module->dfc[i])); + } + + module_base = g_dss_module_base[i][MODULE_SCL]; + if (module_base != 0) { + dss_module->scl_base[i] = dss_base + module_base; + hisi_dss_scl_init(dss_module->scl_base[i], + &(dss_module->scl[i])); + } + + module_base = DSS_POST_SCF_OFFSET; + if (module_base != 0) { + dss_module->post_scf_base = dss_base + module_base; + hisi_dss_post_scf_init(dss_module->post_scf_base, + &(dss_module->post_scf)); + } + module_base = g_dss_module_base[i][MODULE_PCSC]; + if (module_base != 0) { + dss_module->pcsc_base[i] = dss_base + module_base; + hisi_dss_csc_init(dss_module->pcsc_base[i], + &(dss_module->pcsc[i])); + } + + module_base = g_dss_module_base[i][MODULE_ARSR2P]; + if (module_base != 0) { + dss_module->arsr2p_base[i] = dss_base + module_base; + hisi_dss_arsr2p_init(dss_module->arsr2p_base[i], + &(dss_module->arsr2p[i])); + } + module_base = g_dss_module_base[i][MODULE_POST_CLIP]; + if (module_base != 0) { + dss_module->post_clip_base[i] = dss_base + module_base; + hisi_dss_post_clip_init(dss_module->post_clip_base[i], + &(dss_module->post_clip[i])); + } + + module_base = g_dss_module_base[i][MODULE_CSC]; + if (module_base != 0) { + dss_module->csc_base[i] = dss_base + module_base; + hisi_dss_csc_init(dss_module->csc_base[i], + &(dss_module->csc[i])); + } + } + + module_base = DSS_MCTRL_SYS_OFFSET; + if (module_base != 0) { + dss_module->mctl_sys_base = dss_base + module_base; + hisi_dss_mctl_sys_init(dss_module->mctl_sys_base, + &(dss_module->mctl_sys)); + } + + module_base = DSS_SMMU_OFFSET; + if (module_base != 0) { + dss_module->smmu_base = dss_base + module_base; + hisi_dss_smmu_init(dss_module->smmu_base, &(dss_module->smmu)); + } + + return 0; +} + +int hisi_dss_ch_module_set_regs(struct hisi_fb_data_type *hisifd, + int32_t mctl_idx, int chn_idx, uint32_t wb_type, + bool enable_cmdlist) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + int ret = 0; + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((chn_idx < 0) || (chn_idx >= DSS_CHN_MAX_DEFINE)); + + dss_module = &(hisifd->dss_module); + i = chn_idx; + + if (enable_cmdlist) { + if (chn_idx == DSS_RCHN_V2) { + tmp = (0x1 << DSS_CMDLIST_V2); + hisifd->cmdlist_idx = DSS_CMDLIST_V2; + } else if (chn_idx == DSS_WCHN_W2) { + tmp = (0x1 << DSS_CMDLIST_W2); + hisifd->cmdlist_idx = DSS_CMDLIST_W2; + } else { + tmp = (0x1 << chn_idx); + hisifd->cmdlist_idx = chn_idx; + } + + ret = + hisi_cmdlist_add_new_node(hisifd, tmp, 0, 0, 0, 0, wb_type); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + if (dss_module->mctl_ch_used[i] == 1) { + hisi_dss_mctl_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[i]), + &(dss_module->mctl_ch[i]), mctl_idx); + } + + if (dss_module->smmu_used == 1) { + hisi_dss_smmu_ch_set_reg(hisifd, dss_module->smmu_base, + &(dss_module->smmu), i); + } + + if (dss_module->dma_used[i] == 1) { + if (i < DSS_WCHN_W0 || i == DSS_RCHN_V2) { + hisi_dss_rdma_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + } else { + hisi_dss_wdma_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->wdma[i])); + } + + if ((i == DSS_RCHN_V0) || (i == DSS_RCHN_V1) + || (i == DSS_RCHN_V2)) { + hisi_dss_rdma_u_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + hisi_dss_rdma_v_set_reg(hisifd, dss_module->dma_base[i], + &(dss_module->rdma[i])); + } + } + + if (dss_module->aif_ch_used[i] == 1) { + hisi_dss_aif_ch_set_reg(hisifd, dss_module->aif_ch_base[i], + &(dss_module->aif[i])); + } + + if (dss_module->aif1_ch_used[i] == 1) { + hisi_dss_aif_ch_set_reg(hisifd, dss_module->aif1_ch_base[i], + &(dss_module->aif1[i])); + } + + if (dss_module->mif_used[i] == 1) { + hisi_dss_mif_set_reg(hisifd, dss_module->mif_ch_base[i], + &(dss_module->mif[i]), i); + } + + if (dss_module->dfc_used[i] == 1) { + hisi_dss_dfc_set_reg(hisifd, dss_module->dfc_base[i], + &(dss_module->dfc[i])); + } + + if (dss_module->scl_used[i] == 1) { + hisi_dss_chn_scl_load_filter_coef_set_reg(hisifd, false, + chn_idx, + dss_module->scl[i].fmt); + hisi_dss_scl_set_reg(hisifd, dss_module->scl_base[i], + &(dss_module->scl[i])); + } + if (hisifd->dss_module.post_cilp_used[i]) { + hisi_dss_post_clip_set_reg(hisifd, + dss_module->post_clip_base[i], + &(dss_module->post_clip[i])); + } + if (dss_module->pcsc_used[i] == 1) { + hisi_dss_csc_set_reg(hisifd, dss_module->pcsc_base[i], + &(dss_module->pcsc[i])); + } + + if (dss_module->arsr2p_used[i] == 1) { + hisi_dss_arsr2p_set_reg(hisifd, dss_module->arsr2p_base[i], + &(dss_module->arsr2p[i])); + } + + if (dss_module->csc_used[i] == 1) { + hisi_dss_csc_set_reg(hisifd, dss_module->csc_base[i], + &(dss_module->csc[i])); + } + + if (dss_module->mctl_ch_used[i] == 1) { + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[i]), + &(dss_module->mctl_ch[i]), i, true); + } + + return 0; + + err_return: + return ret; +} + +int hisi_dss_ov_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, + bool enable_cmdlist, int task_end, int last, + bool is_first_ov_block) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + int ret = 0; + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + + if (pov_req && pov_req->wb_layer_infos[0].chn_idx == DSS_WCHN_W2) { + return 0; + } + + dss_module = &(hisifd->dss_module); + i = ovl_idx; + + if (enable_cmdlist) { + tmp = (0x1 << (DSS_CMDLIST_OV0 + ovl_idx)); + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + ret = + hisi_cmdlist_add_new_node(hisifd, tmp, 0, task_end, 0, last, + 0); + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + if (dss_module->mctl_used[i] == 1) { + hisi_dss_mctl_ov_set_reg(hisifd, dss_module->mctl_base[i], + &(dss_module->mctl[i]), ovl_idx, + enable_cmdlist); + } + + if (is_first_ov_block) { + if (dss_module->dirty_region_updt_used == 1) + hisi_dss_dirty_region_dbuf_set_reg(hisifd, + hisifd->dss_base, + &(dss_module-> + dirty_region_updt)); + } + + if (dss_module->ov_used[i] == 1) { + hisi_dss_ovl_set_reg(hisifd, dss_module->ov_base[i], + &(dss_module->ov[i]), ovl_idx); + } + + if (hisifd->dss_module.post_scf_used == 1) { + hisi_dss_post_scf_set_reg(hisifd, + hisifd->dss_module.post_scf_base, + &(hisifd->dss_module.post_scf)); + } + + if (dss_module->mctl_sys_used == 1) { + hisi_dss_mctl_sys_set_reg(hisifd, dss_module->mctl_sys_base, + &(dss_module->mctl_sys), ovl_idx); + } + + return 0; + + err_return: + return ret; +} + +int hisi_dss_prev_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_pre_idxs, + bool enable_cmdlist, bool *use_comm_mmbuf) +{ + dss_module_reg_t *dss_module = NULL; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + int32_t ovl_idx = 0; + int32_t layer_idx = 0; + int32_t mctl_idx = 0; + int chn_idx = 0; + int i = 0; + int j = 0; + int k = 0; + int m = 0; + bool has_base = false; + int ret = 0; + uint32_t tmp = 0; + uint32_t cmdlist_idxs_temp = 0; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_mmbuf_t offline_mmbuf[DSS_CHN_MAX_DEFINE]; + bool has_rot = false; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + ovl_idx = pov_req->ovl_idx; + dss_module = &(hisifd->dss_module); + + if (enable_cmdlist) { + if (pov_req->wb_enable) { + ret = + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, + 0, 1, 1, 1, 0); + } else { + ret = + hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, + 0, 0, 0, 0, 0); + } + if (ret != 0) { + HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n", + hisifd->index, ret); + goto err_return; + } + } + + memset(offline_mmbuf, 0x0, sizeof(offline_mmbuf)); + cmdlist_idxs_temp = cmdlist_pre_idxs; + pov_h_block_infos = (dss_overlay_block_t *) pov_req->ov_block_infos_ptr; + for (m = 0; m < pov_req->ov_block_nums; m++) { + pov_h_block = &(pov_h_block_infos[m]); + + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &(pov_h_block->layer_infos[i]); + chn_idx = layer->chn_idx; + layer_idx = layer->layer_idx; + + if (chn_idx == DSS_RCHN_V2) { + mctl_idx = DSS_MCTL5; + } else { + mctl_idx = ovl_idx; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) { + if (layer->need_cap & CAP_BASE) + has_base = true; + + continue; + } + + if (ovl_idx == DSS_OVL0) { + if ((layer->need_cap & CAP_AFBCD) + && (layer->dst_rect.y >= + pov_h_block->ov_block_rect.y)) { + if (j < DSS_CHN_MAX_DEFINE) { + g_pre_online_mmbuf[j].addr = + layer->img.mmbuf_base; + g_pre_online_mmbuf[j].size = + layer->img.mmbuf_size; + j++; + } + } + } + + if (ovl_idx == DSS_OVL2) { + if (layer->need_cap & CAP_AFBCD) { + if (j < DSS_CHN_MAX_DEFINE) { + offline_mmbuf[j].addr = + layer->img.mmbuf_base; + offline_mmbuf[j].size = + layer->img.mmbuf_size; + j++; + } + } + } + + if (chn_idx == DSS_RCHN_V2) { + tmp = (0x1 << DSS_CMDLIST_V2); + hisifd->cmdlist_idx = DSS_CMDLIST_V2; + } else { + tmp = (0x1 << chn_idx); + hisifd->cmdlist_idx = chn_idx; + } + + if ((cmdlist_idxs_temp & tmp) != tmp) { + continue; + } else { + cmdlist_idxs_temp &= (~tmp); + } + + hisi_dss_chn_set_reg_default_value(hisifd, + dss_module->dma_base[chn_idx]); + hisi_dss_smmu_ch_set_reg(hisifd, dss_module->smmu_base, + &(dss_module->smmu), chn_idx); + hisi_dss_mif_set_reg(hisifd, + dss_module->mif_ch_base[chn_idx], + &(dss_module->mif[chn_idx]), chn_idx); + hisi_dss_aif_ch_set_reg(hisifd, + dss_module->aif_ch_base[chn_idx], + &(dss_module->aif[chn_idx])); + + dss_module->mctl_ch[chn_idx].chn_mutex = + set_bits32(dss_module->mctl_ch[chn_idx].chn_mutex, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_flush_en = + set_bits32(dss_module->mctl_ch[chn_idx].chn_flush_en, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_ov_oen = + set_bits32(dss_module->mctl_ch[chn_idx].chn_ov_oen, + 0x0, 32, 0); + dss_module->mctl_ch_used[chn_idx] = 1; + + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[chn_idx]), + &(dss_module->mctl_ch[chn_idx]), + chn_idx, false); + } + } + + if (g_debug_dump_mmbuf) { + if (ovl_idx == DSS_OVL0) { + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + HISI_FB_INFO + ("g_pre_online_mmbuf[%d].addr=%d, size=%d, j=%d\n", + i, g_pre_online_mmbuf[i].addr, + g_pre_online_mmbuf[i].size, j); + } + } + } + + if (pov_req->wb_enable + && ((ovl_idx > DSS_OVL1) || (mctl_idx == DSS_MCTL5))) { + if (mctl_idx != DSS_MCTL5) { + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + + hisi_dss_ov_set_reg_default_value(hisifd, + dss_module->ov_base[ovl_idx], + ovl_idx); + } + + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + chn_idx = wb_layer->chn_idx; + if (wb_layer->transform & HISI_FB_TRANSFORM_ROT_90) + has_rot = true; + + if (chn_idx == DSS_WCHN_W2) { + hisifd->cmdlist_idx = DSS_CMDLIST_W2; + } else { + hisifd->cmdlist_idx = chn_idx; + } + + hisi_dss_chn_set_reg_default_value(hisifd, + dss_module->dma_base[chn_idx]); + hisi_dss_mif_set_reg(hisifd, + dss_module->mif_ch_base[chn_idx], + &(dss_module->mif[chn_idx]), chn_idx); + hisi_dss_aif_ch_set_reg(hisifd, + dss_module->aif_ch_base[chn_idx], + &(dss_module->aif[chn_idx])); + + dss_module->mctl_ch[chn_idx].chn_mutex = + set_bits32(dss_module->mctl_ch[chn_idx].chn_mutex, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_flush_en = + set_bits32(dss_module->mctl_ch[chn_idx].chn_flush_en, + 0x1, 1, 0); + dss_module->mctl_ch[chn_idx].chn_ov_oen = + set_bits32(dss_module->mctl_ch[chn_idx].chn_ov_oen, + 0x0, 32, 0); + dss_module->mctl_ch_used[chn_idx] = 1; + + hisi_dss_mctl_sys_ch_set_reg(hisifd, + &(dss_module->mctl_ch_base[chn_idx]), + &(dss_module->mctl_ch[chn_idx]), + chn_idx, false); + } + + if (mctl_idx != DSS_MCTL5) { + hisifd->cmdlist_idx = DSS_CMDLIST_OV0 + ovl_idx; + + dss_module->mctl_sys.chn_ov_sel_used[ovl_idx] = 1; + dss_module->mctl_sys.wch_ov_sel_used[ovl_idx - + DSS_OVL2] = 1; + dss_module->mctl_sys.ov_flush_en_used[ovl_idx] = 1; + dss_module->mctl_sys.ov_flush_en[ovl_idx] = + set_bits32(dss_module->mctl_sys.ov_flush_en[ovl_idx], + 0x1, 1, 0); + hisi_dss_mctl_sys_set_reg(hisifd, + dss_module->mctl_sys_base, + &(dss_module->mctl_sys), ovl_idx); + } + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + for (k = 0; k < DSS_CHN_MAX_DEFINE; k++) { + if ((((offline_mmbuf[i].addr < + g_pre_online_mmbuf[k].addr + g_pre_online_mmbuf[k].size) + && (offline_mmbuf[i].addr >= + g_pre_online_mmbuf[k].addr)) + || + ((g_pre_online_mmbuf[k].addr < + offline_mmbuf[i].addr + offline_mmbuf[i].size) + && (g_pre_online_mmbuf[k].addr >= + offline_mmbuf[i].addr))) + && offline_mmbuf[i].size) { + if (use_comm_mmbuf) { + *use_comm_mmbuf = true; + break; + } + } + } + } + + if (g_debug_dump_mmbuf) { + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + HISI_FB_INFO + ("offline_mmbuf[%d].addr=%d, size=%d, use_comm_mmbuf=%d, j=%d\n", + i, offline_mmbuf[i].addr, + offline_mmbuf[i].size, *use_comm_mmbuf, j); + } + } + + if (!has_rot) { + memset(g_pre_online_mmbuf, 0x0, + sizeof(g_pre_online_mmbuf)); + } + } + + return 0; + + err_return: + return ret; +} + +void hisi_dss_unflow_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, bool unmask) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + if (pov_req->ovl_idx == DSS_OVL0) { + tmp = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + if (unmask) { + tmp &= ~BIT_LDI_UNFLOW; + } else { + tmp |= BIT_LDI_UNFLOW; + } + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, + tmp); + + } else if (pov_req->ovl_idx == DSS_OVL1) { + tmp = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + if (unmask) { + tmp &= ~BIT_LDI_UNFLOW; + } else { + tmp |= BIT_LDI_UNFLOW; + } + outp32(hisifd->dss_base + DSS_LDI1_OFFSET + LDI_CPU_ITF_INT_MSK, + tmp); + } else { + ; + } +} + +/******************************************************************************* + ** compose handler + */ +int hisi_ov_compose_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_rect_t *wb_ov_block_rect, + dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, + bool *rdma_stretch_enable, + bool *has_base, + bool csc_needed, bool enable_cmdlist) +{ + int ret = 0; + int32_t mctl_idx = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_h_block == NULL); + BUG_ON(layer == NULL); + BUG_ON(clip_rect == NULL); + BUG_ON(aligned_rect == NULL); + BUG_ON(rdma_stretch_enable == NULL); + + ret = hisi_dss_check_layer_par(hisifd, layer); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_check_layer_par failed! ret = %d\n", ret); + goto err_return; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) { + if (layer->need_cap & CAP_BASE) + *has_base = true; + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, + wb_ov_block_rect, *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_ovl_config failed! need_cap=0x%x, ret=%d\n", + layer->need_cap, ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + return ret; + } + + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("layer->dst_rect.y=%d, pov_h_block->ov_block_rect.y=%d," + "layer->chn_idx=%d, layer->layer_idx=%d\n", + layer->dst_rect.y, pov_h_block->ov_block_rect.y, + layer->chn_idx, layer->layer_idx); + } + + if (layer->dst_rect.y < pov_h_block->ov_block_rect.y) { + if (g_debug_ovl_block_composer) { + HISI_FB_INFO + ("layer->dst_rect.y=%d, pov_h_block->ov_block_rect.y=%d," + "layer->chn_idx=%d, layer->layer_idx=%d!!!!\n", + layer->dst_rect.y, pov_h_block->ov_block_rect.y, + layer->chn_idx, layer->layer_idx); + } + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, + wb_ov_block_rect, *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_ovl_config failed, ret = %d\n", + ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR + ("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + return ret; + } + + ret = hisi_dss_smmu_ch_config(hisifd, layer, NULL); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_smmu_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdma input, src_rect(%d,%d,%d,%d), " + "src_rect_mask(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h, + layer->src_rect_mask.x, layer->src_rect_mask.y, + layer->src_rect_mask.w, layer->src_rect_mask.h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = hisi_dss_rdma_config(hisifd, pov_req->ovl_idx, layer, + clip_rect, aligned_rect, + rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_rdma_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdma output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = + hisi_dss_aif_ch_config(hisifd, pov_req, layer, wb_dst_rect, NULL, + pov_req->ovl_idx); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_aif_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_aif1_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_aif1_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_mif_config(hisifd, layer, NULL, *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_mif_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_rdfc_config(hisifd, layer, aligned_rect, *clip_rect); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_rdfc_config failed! ret = %d\n", ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, rdfc output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + ret = + hisi_dss_scl_config(hisifd, layer, aligned_rect, + *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_scl_config failed! ret = %d\n", ret); + goto err_return; + } + ret = + hisi_dss_arsr2p_config(hisifd, layer, aligned_rect, + *rdma_stretch_enable); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_arsr2p_config failed! ret = %d\n", ret); + goto err_return; + } + + ret = hisi_dss_post_clip_config(hisifd, layer); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_post_clip_config failed! ret = %d\n", + ret); + goto err_return; + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, scf output, clip_rect(%d,%d,%d,%d), " + "aligned_rect(%d,%d,%d,%d), dst_rect(%d,%d,%d,%d).\n", + hisifd->index, clip_rect->left, clip_rect->right, + clip_rect->top, clip_rect->bottom, aligned_rect->x, + aligned_rect->y, aligned_rect->w, aligned_rect->h, + layer->dst_rect.x, layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h); + } + + if (csc_needed) { + ret = hisi_dss_csc_config(hisifd, layer, NULL); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_csc_config failed! ret = %d\n", + ret); + goto err_return; + } + } + + ret = + hisi_dss_ovl_layer_config(hisifd, pov_req, layer, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_ovl_config failed, ret = %d\n", ret); + goto err_return; + } + + ret = + hisi_dss_mctl_ch_config(hisifd, pov_req, layer, NULL, + pov_req->ovl_idx, wb_ov_block_rect, + *has_base); + if (ret != 0) { + HISI_FB_ERR("hisi_dss_mctl_ch_config failed! ret = %d\n", ret); + goto err_return; + } + + if (layer->chn_idx == DSS_RCHN_V2) { + mctl_idx = DSS_MCTL5; + } else { + mctl_idx = pov_req->ovl_idx; + } + + ret = + hisi_dss_ch_module_set_regs(hisifd, mctl_idx, layer->chn_idx, 0, + enable_cmdlist); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_ch_module_set_regs failed! ret = %d\n", + hisifd->index, ret); + goto err_return; + } + + return 0; + + err_return: + return ret; +} + +/******************************************************************************* + ** + */ +DEFINE_SEMAPHORE(hisi_dss_mmbuf_sem); +static int mmbuf_refcount = 0; +static int dss_sr_refcount = 0; + +struct hisifb_mmbuf { + struct list_head list_node; + uint32_t addr; + uint32_t size; +}; + +static struct list_head *g_mmbuf_list = NULL; + +static void hisifb_dss_on(struct hisi_fb_data_type *hisifd, int enable_cmdlist) +{ + int prev_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + + prev_refcount = dss_sr_refcount++; + if (!prev_refcount) { + hisi_dss_qos_on(hisifd); + hisi_dss_mmbuf_on(hisifd); + hisi_dss_mif_on(hisifd); + hisi_dss_smmu_on(hisifd); + hisi_dss_scl_coef_on(hisifd, false, SCL_COEF_YUV_IDX); + + if (enable_cmdlist) { + hisi_dss_cmdlist_qos_on(hisifd); + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, dss_sr_refcount=%d.\n", hisifd->index, + dss_sr_refcount); +} + +static void hisifb_dss_off(struct hisi_fb_data_type *hisifd, bool is_lp) +{ + struct hisifb_mmbuf *node, *_node_; + int new_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + new_refcount = --dss_sr_refcount; + WARN_ON(new_refcount < 0); + + if (is_lp) { + if (!new_refcount) { + hisifd->ldi_data_gate_en = 0; + + memset(&(hisifd->ov_block_infos_prev_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev_prev, 0, + sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + } + } + + if (!g_mmbuf_list || is_lp) { + up(&hisi_dss_mmbuf_sem); + return; + } + + if (!new_refcount) { + list_for_each_entry_safe(node, _node_, g_mmbuf_list, list_node) { + if ((node->addr > 0) && (node->size > 0)) { + gen_pool_free(hisifd->mmbuf_gen_pool, + node->addr, node->size); + HISI_FB_DEBUG + ("hisi_dss_mmbuf_free, addr=0x%x, size=%d.\n", + node->addr, node->size); + } + + list_del(&node->list_node); + kfree(node); + } + } + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, dss_sr_refcount=%d.\n", hisifd->index, + dss_sr_refcount); +} + +void *hisi_dss_mmbuf_init(struct hisi_fb_data_type *hisifd) +{ + struct gen_pool *pool = NULL; + int order = 3; + size_t size = MMBUF_SIZE_MAX; + uint32_t addr = MMBUF_BASE; + int prev_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + down(&hisi_dss_mmbuf_sem); + + prev_refcount = mmbuf_refcount++; + if (!prev_refcount) { + pool = gen_pool_create(order, 0); + if (pool == NULL) { + HISI_FB_ERR("fb%d, gen_pool_create failed!", + hisifd->index); + goto err_out; + } + + if (gen_pool_add(pool, addr, size, 0) != 0) { + gen_pool_destroy(pool); + HISI_FB_ERR("fb%d, gen_pool_add failed!", + hisifd->index); + goto err_out; + } + + g_mmbuf_gen_pool = pool; + + if (!g_mmbuf_list) { + g_mmbuf_list = + kzalloc(sizeof(struct list_head), GFP_KERNEL); + BUG_ON(g_mmbuf_list == NULL); + INIT_LIST_HEAD(g_mmbuf_list); + } +#ifdef CONFIG_SMMU_RWERRADDR_USED + if (!g_smmu_rwerraddr_virt) { + g_smmu_rwerraddr_virt = + kmalloc(SMMU_RW_ERR_ADDR_SIZE, + GFP_KERNEL | __GFP_DMA); + if (g_smmu_rwerraddr_virt) { + memset(g_smmu_rwerraddr_virt, 0, + SMMU_RW_ERR_ADDR_SIZE); + } else { + HISI_FB_ERR + ("kmalloc g_smmu_rwerraddr_virt fail.\n"); + } + } +#endif + } + + hisifd->mmbuf_gen_pool = g_mmbuf_gen_pool; + hisifd->mmbuf_list = g_mmbuf_list; + + err_out: + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, mmbuf_refcount=%d.\n", hisifd->index, + mmbuf_refcount); + + return pool; +} + +void hisi_dss_mmbuf_deinit(struct hisi_fb_data_type *hisifd) +{ + int new_refcount = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +.\n", hisifd->index); + + hisifb_dss_off(hisifd, false); + + down(&hisi_dss_mmbuf_sem); + new_refcount = --mmbuf_refcount; + WARN_ON(new_refcount < 0); + + if (!new_refcount) { + if (g_mmbuf_gen_pool) { + gen_pool_destroy(g_mmbuf_gen_pool); + g_mmbuf_gen_pool = NULL; + } + + if (g_mmbuf_list) { + kfree(g_mmbuf_list); + g_mmbuf_list = NULL; + } +#ifdef CONFIG_SMMU_RWERRADDR_USED + if (g_smmu_rwerraddr_virt) { + kfree(g_smmu_rwerraddr_virt); + g_smmu_rwerraddr_virt = NULL; + } +#endif + } + + hisifd->mmbuf_gen_pool = NULL; + hisifd->mmbuf_list = NULL; + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("fb%d, -, mmbuf_refcount=%d.\n", hisifd->index, + mmbuf_refcount); +} + +uint32_t hisi_dss_mmbuf_alloc(void *handle, uint32_t size) +{ + uint32_t addr = 0; + struct hisifb_mmbuf *node = NULL; + struct hisifb_mmbuf *mmbuf_node, *_node_; + + if (NULL == handle) { + HISI_FB_ERR("handle is NULL!\n"); + return addr; + } + + if (NULL == g_mmbuf_list) { + HISI_FB_ERR("g_mmbuf_list is NULL!\n"); + return addr; + } + + if (size <= 0 || size > MMBUF_SIZE_MAX) { + HISI_FB_ERR("mmbuf size is invalid, size=%d!\n", size); + return addr; + } + + down(&hisi_dss_mmbuf_sem); + + addr = gen_pool_alloc(handle, size); + if (addr <= 0) { + HISI_FB_INFO("note: mmbuf not enough,addr=0x%x\n", addr); + } else { + node = kzalloc(sizeof(struct hisifb_mmbuf), GFP_KERNEL); + if (node) { + node->addr = addr; + node->size = size; + list_add_tail(&node->list_node, g_mmbuf_list); + } else { + HISI_FB_ERR("kzalloc struct hisifb_mmbuf fail!\n"); + } + + if ((addr & (MMBUF_ADDR_ALIGN - 1)) + || (size & (MMBUF_ADDR_ALIGN - 1))) { + HISI_FB_ERR + ("addr(0x%x) is not %d bytes aligned, " + "or size(0x%x) is not %d bytes" + "aligned!\n", addr, MMBUF_ADDR_ALIGN, size, + MMBUF_ADDR_ALIGN); + + list_for_each_entry_safe(mmbuf_node, _node_, + g_mmbuf_list, list_node) { + HISI_FB_ERR + ("mmbuf_node_addr(0x%x), mmbuf_node_size(0x%x)!\n", + mmbuf_node->addr, mmbuf_node->size); + } + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("addr=0x%x, size=%d.\n", addr, size); + + return addr; +} + +void hisi_dss_mmbuf_free(void *handle, uint32_t addr, uint32_t size) +{ + struct hisifb_mmbuf *node, *_node_; + + if (NULL == handle) { + HISI_FB_ERR("handle is NULL!\n"); + return; + } + + if (NULL == g_mmbuf_list) { + HISI_FB_ERR("g_mmbuf_list is NULL!\n"); + return; + } + + down(&hisi_dss_mmbuf_sem); + + list_for_each_entry_safe(node, _node_, g_mmbuf_list, list_node) { + if ((node->addr == addr) && (node->size == size)) { + gen_pool_free(handle, addr, size); + list_del(&node->list_node); + kfree(node); + } + } + + up(&hisi_dss_mmbuf_sem); + + HISI_FB_DEBUG("addr=0x%x, size=%d.\n", addr, size); +} + +void hisi_dss_mmbuf_info_clear(struct hisi_fb_data_type *hisifd, int idx) +{ + int i = 0; + dss_mmbuf_info_t *mmbuf_info = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON((idx < 0) || (idx >= HISI_DSS_CMDLIST_DATA_MAX)); + + mmbuf_info = &(hisifd->mmbuf_infos[idx]); + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (mmbuf_info->mm_used[i] == 1) { + hisi_dss_mmbuf_free(g_mmbuf_gen_pool, + mmbuf_info->mm_base[i], + mmbuf_info->mm_size[i]); + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO("fb%d, mm_base(0x%x, %d).\n", + hisifd->index, + mmbuf_info->mm_base[i], + mmbuf_info->mm_size[i]); + } + + mmbuf_info->mm_base[i] = 0; + mmbuf_info->mm_size[i] = 0; + mmbuf_info->mm_used[i] = 0; + } + } +} + +void hisi_mmbuf_info_get_online(struct hisi_fb_data_type *hisifd) +{ + int tmp = 0; + + BUG_ON(hisifd == NULL); + + tmp = (hisifd->frame_count + 1) % HISI_DSS_CMDLIST_DATA_MAX; + hisi_dss_mmbuf_info_clear(hisifd, tmp); + + tmp = hisifd->frame_count % HISI_DSS_CMDLIST_DATA_MAX; + hisifd->mmbuf_info = &(hisifd->mmbuf_infos[tmp]); +} + +/******************************************************************************* + ** + */ +void hisi_dss_mmbuf_on(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); +#if 0 + outp32(hisifd->mmbuf_crg_base + SMC_LOCK, 0x5A5A5A5A); + outp32(hisifd->mmbuf_crg_base + SMC_MEM_LP, 0x00000712); +#endif +} + +static int hisi_overlay_fastboot(struct hisi_fb_data_type *hisifd) +{ + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_block_t *pov_h_block_infos = NULL; + dss_overlay_block_t *pov_h_block = NULL; + dss_layer_t *layer = NULL; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + pov_req_prev = &(hisifd->ov_req_prev); + memset(pov_req_prev, 0, sizeof(dss_overlay_t)); + pov_req_prev->ov_block_infos_ptr = + (uint64_t) (&(hisifd->ov_block_infos_prev)); + pov_req_prev->ov_block_nums = 1; + pov_req_prev->ovl_idx = DSS_OVL0; + + pov_h_block_infos = + (dss_overlay_block_t *) pov_req_prev->ov_block_infos_ptr; + pov_h_block = &(pov_h_block_infos[0]); + pov_h_block->layer_nums = 1; + + layer = &(pov_h_block->layer_infos[0]); + layer->img.mmu_enable = 0; + layer->layer_idx = 0x0; + layer->chn_idx = DSS_RCHN_D0; + layer->need_cap = 0; + + memcpy(&(hisifd->dss_module_default.rdma[DSS_RCHN_D0]), + &(hisifd->dss_module_default.rdma[DSS_RCHN_D3]), + sizeof(dss_rdma_t)); + memcpy(&(hisifd->dss_module_default.dfc[DSS_RCHN_D0]), + &(hisifd->dss_module_default.dfc[DSS_RCHN_D3]), + sizeof(dss_dfc_t)); + memcpy(&(hisifd->dss_module_default.ov[DSS_OVL0].ovl_layer[0]), + &(hisifd->dss_module_default.ov[DSS_OVL0].ovl_layer[1]), + sizeof(dss_ovl_layer_t)); + + memset(&(hisifd->dss_module_default.mctl_ch[DSS_RCHN_D0]), 0, + sizeof(dss_mctl_ch_t)); + memset(&(hisifd->dss_module_default.mctl[DSS_OVL0]), 0, + sizeof(dss_mctl_t)); + + hisifd->dss_module_default.mctl_sys.chn_ov_sel[DSS_OVL0] = + 0xFFFFFFFF; + hisifd->dss_module_default.mctl_sys.ov_flush_en[DSS_OVL0] = 0x0; + + if (is_mipi_cmd_panel(hisifd)) { + if (hisifd->vactive0_start_flag == 0) { + hisifd->vactive0_start_flag = 1; + hisifd->vactive0_end_flag = 1; + } + } + } + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +int hisi_overlay_on(struct hisi_fb_data_type *hisifd, bool fastboot_enable) +{ + int ret = 0; + int ovl_idx = 0; + int mctl_idx = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + + BUG_ON(hisifd == NULL); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + memset(&(hisifd->sbl), 0, sizeof(dss_sbl_t)); + hisifd->sbl_enable = 0; + hisifd->sbl_lsensor_value = 0; + hisifd->sbl_level = 0; + + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + hisifd->crc_flag = 0; + + hisifd->dirty_region_updt.x = 0; + hisifd->dirty_region_updt.y = 0; + hisifd->dirty_region_updt.w = hisifd->panel_info.xres; + hisifd->dirty_region_updt.h = hisifd->panel_info.yres; + + hisifd->resolution_rect.x = 0; + hisifd->resolution_rect.y = 0; + hisifd->resolution_rect.w = hisifd->panel_info.xres; + hisifd->resolution_rect.h = hisifd->panel_info.yres; + + hisifd->res_updt_rect.x = 0; + hisifd->res_updt_rect.y = 0; + hisifd->res_updt_rect.w = hisifd->panel_info.xres; + hisifd->res_updt_rect.h = hisifd->panel_info.yres; + + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + hisifd->ov_req.frame_no = 0xFFFFFFFF; + + g_offline_cmdlist_idxs = 0; + +#if 0 + if (g_dss_module_resource_initialized == 0) { + hisi_dss_module_default(hisifd); + g_dss_module_resource_initialized = 1; + hisifd->dss_module_resource_initialized = true; + } + + if (!hisifd->dss_module_resource_initialized) { + if (hisifd->index != PRIMARY_PANEL_IDX) { + memcpy(&(hisifd->dss_module_default), + &(hisifd_list[PRIMARY_PANEL_IDX]-> + dss_module_default), sizeof(dss_module_reg_t)); + } + hisifd->dss_module_resource_initialized = true; + } +#else + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + hisifb_activate_vsync(hisifd); + } + + if (g_dss_module_resource_initialized == 0) { + hisi_dss_module_default(hisifd); + g_dss_module_resource_initialized = 1; + hisifd->dss_module_resource_initialized = true; + } else { + if (!hisifd->dss_module_resource_initialized) { + if (hisifd->index != PRIMARY_PANEL_IDX) { + if (hisifd_list[PRIMARY_PANEL_IDX]) { + memcpy(&(hisifd->dss_module_default), + &(hisifd_list + [PRIMARY_PANEL_IDX]-> + dss_module_default), + sizeof(dss_module_reg_t)); + } + } + hisifd->dss_module_resource_initialized = true; + } + } +#endif + + enable_cmdlist = g_enable_ovl_cmdlist_online; + hisifb_dss_on(hisifd, enable_cmdlist); + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + if (hisifd->index == PRIMARY_PANEL_IDX) { + ovl_idx = DSS_OVL0; + mctl_idx = DSS_MCTL0; + } else { + ovl_idx = DSS_OVL1; + mctl_idx = DSS_MCTL1; + } + + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + ldi_data_gate(hisifd, true); + + hisi_dss_mctl_on(hisifd, mctl_idx, enable_cmdlist, + fastboot_enable); + + if (fastboot_enable) { + hisi_overlay_fastboot(hisifd); + } else { + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_init! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + cmdlist_idxs = + (0x1 << (ovl_idx + DSS_CMDLIST_OV0)); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, + 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, ovl_idx); + } + + hisifd->ov_req_prev.ovl_idx = ovl_idx; + + ret = + hisi_dss_ovl_base_config(hisifd, NULL, NULL, NULL, + ovl_idx, 0); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_ovl_base_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, NULL, ovl_idx, + false, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_mctl_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, NULL, ovl_idx, + enable_cmdlist, 1, 0, + true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_config! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisi_cmdlist_flush_cache(hisifd, + hisifd->ion_client, + cmdlist_idxs); + hisi_cmdlist_config_start(hisifd, mctl_idx, + cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, ovl_idx); + } + + single_frame_update(hisifd); + enable_ldi(hisifd); + hisifb_frame_updated(hisifd); + hisifd->frame_count++; + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + } + err_out: + hisifb_deactivate_vsync(hisifd); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + enable_cmdlist = g_enable_ovl_cmdlist_offline; + + hisi_dss_mctl_on(hisifd, DSS_MCTL2, enable_cmdlist, 0); + hisi_dss_mctl_on(hisifd, DSS_MCTL3, enable_cmdlist, 0); + hisi_dss_mctl_on(hisifd, DSS_MCTL5, enable_cmdlist, 0); + } else { + HISI_FB_ERR("fb%d, not supported!", hisifd->index); + } + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +int hisi_overlay_off(struct hisi_fb_data_type *hisifd) +{ + int ret = 0; + int ovl_idx = 0; + uint32_t cmdlist_pre_idxs = 0; + uint32_t cmdlist_idxs = 0; + int enable_cmdlist = 0; + dss_overlay_t *pov_req_prev = NULL; + + BUG_ON(hisifd == NULL); + + pov_req_prev = &(hisifd->ov_req_prev); + + HISI_FB_DEBUG("fb%d, +\n", hisifd->index); + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX)) { + hisifb_activate_vsync(hisifd); + + ret = hisi_vactive0_start_config(hisifd, pov_req_prev); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_vactive0_start_config failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (hisifd->aod_function == 1) { + HISI_FB_INFO("fb%d, aod mode\n", hisifd->index); + goto err_out; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + ovl_idx = DSS_OVL0; + } else { + ovl_idx = DSS_OVL1; + } + + enable_cmdlist = g_enable_ovl_cmdlist_online; + if ((hisifd->index == EXTERNAL_PANEL_IDX) + && hisifd->panel_info.fake_hdmi) + enable_cmdlist = 0; + + ret = hisi_dss_module_init(hisifd); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_init! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + + hisi_cmdlist_data_get_online(hisifd); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_pre_idxs, + NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + cmdlist_idxs = (1 << (DSS_CMDLIST_OV0 + ovl_idx)); + cmdlist_pre_idxs &= (~(cmdlist_idxs)); + + hisi_cmdlist_add_nop_node(hisifd, cmdlist_pre_idxs, 0, + 0); + hisi_cmdlist_add_nop_node(hisifd, cmdlist_idxs, 0, 0); + } else { + hisifd->set_reg = hisifb_set_reg; + + hisi_dss_mctl_mutex_lock(hisifd, ovl_idx); + cmdlist_pre_idxs = ~0; + } + + hisi_dss_prev_module_set_regs(hisifd, pov_req_prev, + cmdlist_pre_idxs, enable_cmdlist, + NULL); + + ret = + hisi_dss_ovl_base_config(hisifd, NULL, NULL, NULL, ovl_idx, + 0); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_ovl_base_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_mctl_ov_config(hisifd, NULL, ovl_idx, false, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, faile to hisi_dss_mctl_config! ret=%d\n", + hisifd->index, ret); + goto err_out; + } + + ret = hisi_dss_dirty_region_dbuf_config(hisifd, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_dss_dirty_region_dbuf_config failed! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + ret = + hisi_dss_ov_module_set_regs(hisifd, NULL, ovl_idx, + enable_cmdlist, 1, 0, true); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, failed to hisi_dss_module_config! ret = %d\n", + hisifd->index, ret); + goto err_out; + } + + if (enable_cmdlist) { + hisi_cmdlist_config_stop(hisifd, cmdlist_pre_idxs); + + cmdlist_idxs |= cmdlist_pre_idxs; + hisi_cmdlist_flush_cache(hisifd, hisifd->ion_client, + cmdlist_idxs); + + if (g_debug_ovl_cmdlist) { + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + } + + hisi_cmdlist_config_start(hisifd, ovl_idx, cmdlist_idxs, 0); + } else { + hisi_dss_mctl_mutex_unlock(hisifd, ovl_idx); + } + + if (hisifd->panel_info.dirty_region_updt_support) { + hisi_dss_dirty_region_updt_config(hisifd, NULL); + } + + ldi_data_gate(hisifd, true); + + single_frame_update(hisifd); + hisifb_frame_updated(hisifd); + + if (!hisi_dss_check_reg_reload_status(hisifd)) { + mdelay(20); + } + + ldi_data_gate(hisifd, false); + + if (is_mipi_cmd_panel(hisifd)) { + hisifd->ldi_data_gate_en = 1; + } + + hisifd->frame_count++; + err_out: + hisifb_deactivate_vsync(hisifd); + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + ; + } else { + HISI_FB_ERR("fb%d, not support !\n", hisifd->index); + BUG_ON(1); + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifb_dss_off(hisifd, true); + } else { + hisifb_dss_off(hisifd, false); + } + + hisifd->ldi_data_gate_en = 0; + + memset(&(hisifd->ov_block_infos_prev_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req_prev, 0, sizeof(dss_overlay_t)); + memset(&(hisifd->ov_block_infos), 0, + HISI_DSS_OV_BLOCK_NUMS * sizeof(dss_overlay_block_t)); + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + + HISI_FB_DEBUG("fb%d, -\n", hisifd->index); + + return 0; +} + +bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd) +{ + mdelay(50); + + return true; +} + +bool hisi_dss_check_crg_sctrl_status(struct hisi_fb_data_type *hisifd) +{ + uint32_t crg_state_check = 0; + uint32_t sctrl_mmbuf_dss_check = 0; + + BUG_ON(hisifd == NULL); + + crg_state_check = inp32(hisifd->peri_crg_base + PERCLKEN3); + if ((crg_state_check & 0x23000) != 0x23000) { + HISI_FB_ERR + ("dss crg_clk_enable failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + PERRSTSTAT3); + if ((crg_state_check | 0xfffff3ff) != 0xfffff3ff) { + HISI_FB_ERR("dss crg_reset failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + ISOSTAT); + if ((crg_state_check | 0xffffffbf) != 0xffffffbf) { + HISI_FB_ERR("dss iso_disable failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + crg_state_check = inp32(hisifd->peri_crg_base + PERPWRSTAT); + if ((crg_state_check & 0x20) != 0x20) { + HISI_FB_ERR + ("dss subsys regulator_enabel failed, crg_state_check = 0x%x\n", + crg_state_check); + return false; + } + + sctrl_mmbuf_dss_check = inp32(hisifd->sctrl_base + SCPERCLKEN1); + if ((sctrl_mmbuf_dss_check & 0x1000000) != 0x1000000) { + HISI_FB_ERR + ("dss subsys mmbuf_dss_clk_enable failed, sctrl_mmbuf_dss_check = 0x%x\n", + sctrl_mmbuf_dss_check); + return false; + } + + return true; +} + +int hisi_overlay_ioctl_handler(struct hisi_fb_data_type *hisifd, + uint32_t cmd, void __user *argp) +{ + int ret = 0; + uint32_t timediff = 0; + struct timeval tv0; + struct timeval tv1; + struct hisi_panel_info *pinfo = NULL; + + if (NULL == hisifd) { + HISI_FB_ERR("NULL Pointer\n"); + return -EINVAL; + } + pinfo = &(hisifd->panel_info); + + switch (cmd) { + case HISIFB_OV_ONLINE_PLAY: + if (hisifd->ov_online_play) { + if (g_debug_ovl_online_composer_timediff & 0x1) + hisifb_get_timestamp(&tv0); + + down(&hisifd->blank_sem); + ret = hisifd->ov_online_play(hisifd, argp); + if (ret != 0) { + HISI_FB_ERR("fb%d ov_online_play failed!\n", + hisifd->index); + } + up(&hisifd->blank_sem); + + if (g_debug_ovl_online_composer_timediff & 0x1) { + hisifb_get_timestamp(&tv1); + timediff = hisifb_timestamp_diff(&tv0, &tv1); + if (timediff >= + g_debug_ovl_online_composer_time_threshold) + HISI_FB_ERR + ("ONLING_IOCTL_TIMEDIFF is %u us!\n", + timediff); + } + + if (ret == 0) { + if (hisifd->bl_update) { + hisifd->bl_update(hisifd); + } + } + } + break; + default: + break; + } + + return ret; +} + +int hisi_overlay_init(struct hisi_fb_data_type *hisifd) +{ + char wq_name[128] = { 0 }; + + BUG_ON(hisifd == NULL); + BUG_ON(hisifd->dss_base == NULL); + + hisifd->dss_module_resource_initialized = false; + + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + init_waitqueue_head(&hisifd->vactive0_start_wq); + hisifd->ldi_data_gate_en = 0; + + hisifd->crc_flag = 0; + + hisifd->frame_update_flag = 0; + + memset(&hisifd->ov_req, 0, sizeof(dss_overlay_t)); + memset(&hisifd->dss_module, 0, sizeof(dss_module_reg_t)); + memset(&hisifd->dss_module_default, 0, sizeof(dss_module_reg_t)); + + hisifd->dirty_region_updt.x = 0; + hisifd->dirty_region_updt.y = 0; + hisifd->dirty_region_updt.w = hisifd->panel_info.xres; + hisifd->dirty_region_updt.h = hisifd->panel_info.yres; + + hisifd->resolution_rect.x = 0; + hisifd->resolution_rect.y = 0; + hisifd->resolution_rect.w = hisifd->panel_info.xres; + hisifd->resolution_rect.h = hisifd->panel_info.yres; + + hisifd->res_updt_rect.x = 0; + hisifd->res_updt_rect.y = 0; + hisifd->res_updt_rect.w = hisifd->panel_info.xres; + hisifd->res_updt_rect.h = hisifd->panel_info.yres; + + hisifd->pan_display_fnc = hisi_overlay_pan_display; + hisifd->ov_ioctl_handler = hisi_overlay_ioctl_handler; + + hisifd->dss_debug_wq = NULL; + hisifd->ldi_underflow_wq = NULL; + hisifd->rch2_ce_end_wq = NULL; + hisifd->rch4_ce_end_wq = NULL; + hisifd->dpp_ce_end_wq = NULL; + hisifd->hiace_end_wq = NULL; + + if ((hisifd->index == PRIMARY_PANEL_IDX) || + (hisifd->index == EXTERNAL_PANEL_IDX + && !hisifd->panel_info.fake_hdmi)) { + snprintf(wq_name, 128, "fb%d_dss_debug", hisifd->index); + hisifd->dss_debug_wq = create_singlethread_workqueue(wq_name); + if (!hisifd->dss_debug_wq) { + HISI_FB_ERR + ("fb%d, create dss debug workqueue failed!\n", + hisifd->index); + return -EINVAL; + } + INIT_WORK(&hisifd->dss_debug_work, hisi_dss_debug_func); + + snprintf(wq_name, 128, "fb%d_ldi_underflow", hisifd->index); + hisifd->ldi_underflow_wq = + create_singlethread_workqueue(wq_name); + if (!hisifd->ldi_underflow_wq) { + HISI_FB_ERR + ("fb%d, create ldi underflow workqueue failed!\n", + hisifd->index); + return -EINVAL; + } + INIT_WORK(&hisifd->ldi_underflow_work, + hisi_ldi_underflow_handle_func); + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisifd->ov_online_play = hisi_ov_online_play; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = + hisi_vactive0_start_isr_handler; + + hisifd->crc_isr_handler = NULL; + + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + hisifd->set_reg = hisifb_set_reg; + hisifd->ov_online_play = hisi_ov_online_play; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = + hisi_vactive0_start_isr_handler; + + hisifd->crc_isr_handler = NULL; + } else if (hisifd->index == AUXILIARY_PANEL_IDX) { + hisifd->set_reg = hisi_cmdlist_set_reg; + hisifd->ov_online_play = NULL; + hisifd->ov_wb_isr_handler = NULL; + hisifd->ov_vactive0_start_isr_handler = NULL; + + hisifd->crc_isr_handler = NULL; + } else { + HISI_FB_ERR("fb%d not support this device!\n", hisifd->index); + return -EINVAL; + } + + hisi_cmdlist_init(hisifd); + + hisi_dss_mmbuf_init(hisifd); + + return 0; +} + +int hisi_overlay_deinit(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + } + + if (hisifd->rch4_ce_end_wq) { + destroy_workqueue(hisifd->rch4_ce_end_wq); + hisifd->rch4_ce_end_wq = NULL; + } + + if (hisifd->rch2_ce_end_wq) { + destroy_workqueue(hisifd->rch2_ce_end_wq); + hisifd->rch2_ce_end_wq = NULL; + } + + if (hisifd->dpp_ce_end_wq) { + destroy_workqueue(hisifd->dpp_ce_end_wq); + hisifd->dpp_ce_end_wq = NULL; + } + + if (hisifd->hiace_end_wq) { + destroy_workqueue(hisifd->hiace_end_wq); + hisifd->hiace_end_wq = NULL; + } + + if (hisifd->dss_debug_wq) { + destroy_workqueue(hisifd->dss_debug_wq); + hisifd->dss_debug_wq = NULL; + } + + if (hisifd->ldi_underflow_wq) { + destroy_workqueue(hisifd->ldi_underflow_wq); + hisifd->ldi_underflow_wq = NULL; + } + + hisi_cmdlist_deinit(hisifd); + + hisi_dss_mmbuf_deinit(hisifd); + + return 0; +} + +void hisi_vactive0_start_isr_handler(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + if (is_mipi_cmd_panel(hisifd) && (hisifd->frame_update_flag == 0)) { + hisifd->vactive0_start_flag = 1; + } else { + hisifd->vactive0_start_flag++; + } + + wake_up_interruptible_all(&hisifd->vactive0_start_wq); +} + +int hisi_vactive0_start_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + int ret = 0; + int ret1 = 0; + int times = 0; + uint32_t prev_vactive0_start = 0; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + uint32_t isr_s2_mask = 0; + char __iomem *ldi_base = NULL; + struct timeval tv0; + struct timeval tv1; + dss_overlay_t *pov_req_dump = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_t *pov_req_prev_prev = NULL; + uint32_t cmdlist_idxs = 0; + uint32_t cmdlist_idxs_prev = 0; + uint32_t cmdlist_idxs_prev_prev = 0; + uint32_t read_value[4] = { 0 }; + uint32_t ldi_vstate = 0; + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + pov_req_prev = &(hisifd->ov_req_prev); + pov_req_prev_prev = &(hisifd->ov_req_prev_prev); + if (is_mipi_cmd_panel(hisifd) && (hisifd->frame_update_flag == 0)) { + pov_req_dump = &(hisifd->ov_req_prev_prev); + if (hisifd->vactive0_start_flag == 1) { + hisifd->vactive0_start_flag = 0; + single_frame_update(hisifd); + } + + if (hisifd->vactive0_start_flag == 0) { + hisifb_get_timestamp(&tv0); + + REDO_0: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + hisifd->vactive0_start_flag, + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_0; + } + } + times = 0; + + if (ret <= 0) { + hisifb_get_timestamp(&tv1); + + ret1 = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, + &cmdlist_idxs_prev, + NULL); + if (ret1 != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret1); + } + + ret1 = + hisi_cmdlist_get_cmdlist_idxs + (pov_req_prev_prev, &cmdlist_idxs_prev_prev, + NULL); + if (ret1 != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev_prev failed! ret = %d\n", + hisifd->index, ret1); + } + + cmdlist_idxs = + cmdlist_idxs_prev | cmdlist_idxs_prev_prev; + + HISI_FB_ERR + ("fb%d, 1wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, pre_pre_frame_no=%u, " + "frame_no=%u, TIMESTAMP_DIFF is %u us, " + "cmdlist_idxs_prev=0x%x, cmdlist_idxs_prev_prev=0x%x, " + "cmdlist_idxs=0x%x, itf0_ints=0x%x\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no, pov_req->frame_no, + hisifb_timestamp_diff(&tv0, &tv1), + cmdlist_idxs_prev, cmdlist_idxs_prev_prev, + cmdlist_idxs, + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INTS) + ); + + if (g_debug_ovl_online_composer_hold) { + dumpDssOverlay(hisifd, pov_req_dump, + (g_debug_need_save_file + == 1)); + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + mdelay(HISI_DSS_COMPOSER_HOLD_TIME); + } + + if (g_debug_ldi_underflow_clear + && g_ldi_data_gate_en) { +#if 1 + hisi_cmdlist_config_reset(hisifd, + pov_req_dump, + cmdlist_idxs); + + ldi_data_gate(hisifd, false); + mdelay(10); +#else + if (hisifd->ldi_underflow_wq) { + queue_work(hisifd-> + ldi_underflow_wq, + &hisifd-> + ldi_underflow_work); + } +#endif + + mipi_panel_check_reg(hisifd, + read_value); + ldi_vstate = + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + LDI_VSTATE); + HISI_FB_ERR("fb%d, " + "Number of the Errors on DSI : 0x05 = 0x%x\n" + "Display Power Mode : 0x0A = 0x%x\n" + "Display Signal Mode : 0x0E = 0x%x\n" + "Display Self-Diagnostic Result : 0x0F = 0x%x\n" + "LDI vstate : 0x%x, LDI dpi0_hstate : 0x%x\n", + hisifd->index, + read_value[0], + read_value[1], + read_value[2], + read_value[3], ldi_vstate, + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + + LDI_DPI0_HSTATE)); + + memset(&(hisifd->ov_block_infos_prev), 0, + HISI_DSS_OV_BLOCK_NUMS * + sizeof(dss_overlay_block_t)); + + memset(&(hisifd->ov_req_prev), 0, + sizeof(dss_overlay_t)); + + if (LDI_VSTATE_V_WAIT_TE0 == ldi_vstate) { + vactive_timeout_count++; + if ((vactive_timeout_count >= 3) + && hisifd->panel_info.esd_enable) { + hisifd->esd_recover_state = + ESD_RECOVER_STATE_START; + if (hisifd->esd_ctrl.esd_check_wq) { + queue_work(hisifd->esd_ctrl.esd_check_wq, + &(hisifd->esd_ctrl.esd_check_work)); + } + } + } + return 0; + } + + ldi_data_gate(hisifd, false); + mipi_panel_check_reg(hisifd, read_value); + ldi_vstate = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_VSTATE); + HISI_FB_ERR("fb%d, " + "Number of the Errors on DSI : 0x05 = 0x%x\n" + "Display Power Mode : 0x0A = 0x%x\n" + "Display Signal Mode : 0x0E = 0x%x\n" + "Display Self-Diagnostic Result : 0x0F = 0x%x\n" + "LDI vstate : 0x%x, LDI dpi0_hstate : 0x%x \n", + hisifd->index, read_value[0], + read_value[1], read_value[2], + read_value[3], ldi_vstate, + inp32(hisifd->dss_base + + DSS_LDI0_OFFSET + + LDI_DPI0_HSTATE)); + + REDO_1: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + hisifd->vactive0_start_flag, + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_1; + } + } + times = 0; + + if (ret <= 0) { + HISI_FB_ERR + ("fb%d, 2wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, frame_no=%u.\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no); + + ldi_data_gate(hisifd, false); + ret = -ETIMEDOUT; + if (LDI_VSTATE_V_WAIT_TE0 == ldi_vstate) { + vactive_timeout_count++; + if ((vactive_timeout_count >= 1) + && hisifd->panel_info.esd_enable) { + hisifd->esd_recover_state = + ESD_RECOVER_STATE_START; + if (hisifd->esd_ctrl.esd_check_wq) { + queue_work(hisifd->esd_ctrl.esd_check_wq, + &(hisifd->esd_ctrl.esd_check_work)); + } + ret = 0; + } + } + } else { + ldi_data_gate(hisifd, true); + ret = 0; + } + } else { + ldi_data_gate(hisifd, true); + ret = 0; + } + } + + ldi_data_gate(hisifd, true); + hisifd->vactive0_start_flag = 0; + hisifd->vactive0_end_flag = 0; + if (ret >= 0) { + vactive_timeout_count = 0; + } + } else { + pov_req_dump = &(hisifd->ov_req_prev); + + hisifb_get_timestamp(&tv0); + ldi_data_gate(hisifd, false); + prev_vactive0_start = hisifd->vactive0_start_flag; + + REDO_2: + ret = + wait_event_interruptible_timeout(hisifd->vactive0_start_wq, + (prev_vactive0_start != + hisifd->vactive0_start_flag), + msecs_to_jiffies + (DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC)); + if (ret == -ERESTARTSYS) { + if (times < 50) { + times++; + mdelay(10); + goto REDO_2; + } + } + + if (ret <= 0) { + hisifb_get_timestamp(&tv1); + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_dump, + &cmdlist_idxs, NULL); + if (ret != 0) { + HISI_FB_INFO + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + } + + HISI_FB_ERR + ("fb%d, 1wait_for vactive0_start_flag timeout!ret=%d, " + "vactive0_start_flag=%d, frame_no=%u, " + "TIMESTAMP_DIFF is %u us, cmdlist_idxs=0x%x!\n", + hisifd->index, ret, + hisifd->vactive0_start_flag, + pov_req_dump->frame_no, + hisifb_timestamp_diff(&tv0, &tv1), + cmdlist_idxs); + + if (g_debug_ovl_online_composer_hold) { + dumpDssOverlay(hisifd, pov_req_dump, + (g_debug_need_save_file == 1)); + hisi_cmdlist_dump_all_node(hisifd, NULL, + cmdlist_idxs); + mdelay(HISI_DSS_COMPOSER_HOLD_TIME); + } + mipi_dsi_reset(hisifd); + + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } + + if (ret == -ETIMEDOUT) { + if (pov_req_dump && pov_req_dump->ovl_idx == DSS_OVL0) { + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2_mask = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INT_MSK); + isr_s2 = + inp32(hisifd->dss_base + DSS_LDI0_OFFSET + + LDI_CPU_ITF_INTS); + ldi_base = hisifd->dss_base + DSS_LDI0_OFFSET; + } else if (pov_req_dump && pov_req_dump->ovl_idx == DSS_OVL1) { + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_SDP_INTS); + isr_s2_mask = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INT_MSK); + isr_s2 = + inp32(hisifd->dss_base + DSS_LDI1_OFFSET + + LDI_CPU_ITF_INTS); + ldi_base = hisifd->dss_base + DSS_LDI1_OFFSET; + } else { + ; + } + + HISI_FB_ERR("fb%d, isr_s1=0x%x, isr_s2_mask=0x%x, isr_s2=0x%x, " + "LDI_CTRL(0x%x), LDI_FRM_MSK(0x%x).\n", + hisifd->index, isr_s1, isr_s2_mask, isr_s2, + inp32(ldi_base + LDI_CTRL), + inp32(ldi_base + LDI_FRM_MSK)); + } + + return ret; +} + +int hisi_crc_enable(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (g_enable_crc_debug == 0) + return 0; + + if (pov_req->crc_enable_status <= 0) + return 0; + + if (hisifd->index == PRIMARY_PANEL_IDX) { + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV0_EN, 0x1); + + tmp &= ~BIT_CRC_OV0_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + + tmp &= ~BIT_CRC_ITF0_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_EN, 0x1); + + tmp &= ~BIT_CRC_SUM_INT; + } + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV1_EN, 0x1); + + tmp &= ~BIT_CRC_OV1_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + outp32(hisifd->dss_base + GLB_CRC_LDI1_EN, 0x1); + + tmp &= ~BIT_CRC_ITF1_INT; + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_EN, 0x1); + + tmp &= ~BIT_CRC_SUM_INT; + } + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +static int hisi_crc_disable(struct hisi_fb_data_type *hisifd) +{ + uint32_t tmp = 0; + + BUG_ON(hisifd == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_OV0_EN, 0x0); + + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_SUM_EN, 0x0); + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + tmp |= (BIT_CRC_OV0_INT | BIT_CRC_ITF0_INT | BIT_CRC_SUM_INT); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_OV1_EN, 0x0); + outp32(hisifd->dss_base + GLB_CRC_LDI1_EN, 0x0); + outp32(hisifd->dss_base + DSS_DBG_OFFSET + DBG_CRC_SUM_EN, 0x0); + tmp = inp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK); + tmp |= (BIT_CRC_OV1_INT | BIT_CRC_ITF1_INT | BIT_CRC_SUM_INT); + outp32(hisifd->dss_base + DSS_DPP_OFFSET + DPP_INT_MSK, tmp); + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +static int hisi_crc_get_result(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req) +{ + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + pov_req->crc_info.crc_ov_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_OV0); + pov_req->crc_info.crc_ov_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV0_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + GLB_CRC_DBG_LDI0); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + GLB_CRC_LDI0_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_SUM); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_FRM); + } + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + if (pov_req->crc_enable_status == DSS_CRC_OV_EN) { + pov_req->crc_info.crc_ov_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_OV1); + pov_req->crc_info.crc_ov_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_OV1_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_LDI_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + GLB_CRC_DBG_LDI1); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + GLB_CRC_LDI1_FRM); + } else if (pov_req->crc_enable_status == DSS_CRC_SUM_EN) { + pov_req->crc_info.crc_ldi_result = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_DBG_SUM); + pov_req->crc_info.crc_ldi_frm = + inp32(hisifd->dss_base + DSS_DBG_OFFSET + + DBG_CRC_SUM_FRM); + } + } else { + HISI_FB_ERR("fb%d, not support!", hisifd->index); + return -EINVAL; + } + + return 0; +} + +void hisi_crc_isr_handler(struct hisi_fb_data_type *hisifd) +{ + BUG_ON(hisifd == NULL); + + hisi_crc_disable(hisifd); + + hisifd->crc_flag++; + wake_up_interruptible_all(&hisifd->crc_wq); +} + +int hisi_crc_config(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req) +{ + int ret = 0; + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + + if (g_enable_crc_debug == 0) + return 0; + + if (pov_req->crc_enable_status <= 0) + return 0; + +#if 1 + mdelay(100); + hisi_crc_get_result(hisifd, pov_req); + hisi_crc_disable(hisifd); +#else + prev_crc_flag = hisifd->crc_flag; + ret = wait_event_interruptible_timeout(hisifd->crc_wq, + (prev_crc_flag != + hisifd->crc_flag), 1 * HZ); + if (ret == -ERESTARTSYS) { + HISI_FB_DEBUG + ("fb%d, wait_for crc_flag, " + "Returns -ERESTARTSYS if interrupted by a signal!\n", + hisifd->index); + ret = + wait_event_interruptible_timeout(hisifd->crc_wq, + (prev_crc_flag != + hisifd->crc_flag), 1 * HZ); + } + + if (ret <= 0) { + HISI_FB_ERR("fb%d, wait_for crc_flag timeout!ret=%d, " + "prev_crc_flag=%d, crc_flag=%d\n", + hisifd->index, ret, prev_crc_flag, + hisifd->crc_flag); + ret = -ETIMEDOUT; + } else { + ret = 0; + + hisi_crc_get_result(hisifd, pov_req); + } +#endif + + return ret; +} + +void hisi_dss_debug_func(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + + hisifd = container_of(work, struct hisi_fb_data_type, dss_debug_work); + BUG_ON(hisifd == NULL); + + dumpDssOverlay(hisifd, &hisifd->ov_req, true); +} + +void hisi_ldi_underflow_handle_func(struct work_struct *work) +{ + struct hisi_fb_data_type *hisifd = NULL; + dss_overlay_t *pov_req_prev = NULL; + dss_overlay_t *pov_req_prev_prev = NULL; + uint32_t cmdlist_idxs_prev = 0; + uint32_t cmdlist_idxs_prev_prev = 0; + int ret = 0; + uint32_t tmp = 0; + uint32_t isr_s1 = 0; + uint32_t isr_s2 = 0; + + hisifd = + container_of(work, struct hisi_fb_data_type, ldi_underflow_work); + BUG_ON(hisifd == NULL); + + HISI_FB_INFO("fb%d, +.\n", hisifd->index); + + down(&hisifd->blank_sem0); + if (!hisifd->panel_power_on) { + HISI_FB_INFO("fb%d, panel is power off!", hisifd->index); + up(&hisifd->blank_sem0); + return; + } + hisifb_activate_vsync(hisifd); + + pov_req_prev = &(hisifd->ov_req_prev); + pov_req_prev_prev = &(hisifd->ov_req_prev_prev); + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev, &cmdlist_idxs_prev, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev failed! ret = %d\n", + hisifd->index, ret); + } + + ret = + hisi_cmdlist_get_cmdlist_idxs(pov_req_prev_prev, + &cmdlist_idxs_prev_prev, NULL); + if (ret != 0) { + HISI_FB_ERR + ("fb%d, hisi_cmdlist_get_cmdlist_idxs " + "pov_req_prev_prev failed! ret = %d\n", + hisifd->index, ret); + } + + hisi_cmdlist_config_reset(hisifd, pov_req_prev, + cmdlist_idxs_prev | cmdlist_idxs_prev_prev); + + enable_ldi(hisifd); + isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS); + isr_s2 = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS); + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INTS, isr_s2); + outp32(hisifd->dss_base + GLB_CPU_PDP_INTS, isr_s1); + + tmp = inp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK); + tmp &= ~BIT_LDI_UNFLOW; + outp32(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CPU_ITF_INT_MSK, tmp); + + hisifb_deactivate_vsync(hisifd); + + up(&hisifd->blank_sem0); + + HISI_FB_INFO + ("fb%d, -. cmdlist_idxs_prev = 0x%x, cmdlist_idxs_prev_prev = 0x%x\n", + hisifd->index, cmdlist_idxs_prev, cmdlist_idxs_prev_prev); +} + +/*lint +e778 +e732*/ diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h new file mode 100755 index 000000000000..31088fbe2c73 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils.h @@ -0,0 +1,269 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef HISI_OVERLAY_UTILS_H +#define HISI_OVERLAY_UTILS_H + +#include "hisi_fb.h" + +/******************************************************************************* + ** + */ +extern uint32_t g_dss_module_base[DSS_CHN_MAX_DEFINE][MODULE_CHN_MAX]; +extern uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX]; +extern uint32_t g_dss_module_cap[DSS_CHN_MAX_DEFINE][MODULE_CAP_MAX]; +extern uint32_t g_dss_mif_sid_map[DSS_CHN_MAX_DEFINE]; +extern uint32_t g_dss_smmu_smrx_idx[DSS_CHN_MAX_DEFINE]; +extern int g_scf_lut_chn_coef_idx[DSS_CHN_MAX_DEFINE]; +extern unsigned int g_dss_smmu_outstanding; +extern void *g_smmu_rwerraddr_virt; + +#define DSS_COMPOSER_TIMEOUT_THRESHOLD_FPGA (10000) +#define DSS_COMPOSER_TIMEOUT_THRESHOLD_ASIC (300) + +enum ENUM_LDI_VSTATE { + LDI_VSTATE_IDLE = 0x1, + LDI_VSTATE_VSW = 0x2, + LDI_VSTATE_VBP = 0x4, + LDI_VSTATE_VACTIVE0 = 0x8, + LDI_VSTATE_VACTIVE_SPACE = 0x10, + LDI_VSTATE_VACTIVE1 = 0x20, + LDI_VSTATE_VFP = 0x40, + LDI_VSTATE_V_WAIT_TE0 = 0x80, + LDI_VSTATE_V_WAIT_TE1 = 0x100, + LDI_VSTATE_V_WAIT_TE_EN = 0x200, +}; + +void dumpDssOverlay(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req, + bool isNeedSaveFile); + +int hisi_get_hal_format(struct fb_info *info); +int hisi_overlay_init(struct hisi_fb_data_type *hisifd); +int hisi_overlay_deinit(struct hisi_fb_data_type *hisifd); +int hisi_overlay_on(struct hisi_fb_data_type *hisifd, bool fastboot_enable); +int hisi_overlay_off(struct hisi_fb_data_type *hisifd); +bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd); +bool hisi_dss_check_crg_sctrl_status(struct hisi_fb_data_type *hisifd); + +void hisifb_adjust_block_rect(int block_num, dss_rect_t *ov_block_rects[], + dss_wb_layer_t *wb_layer); +void hisifb_disreset_dss(struct hisi_fb_data_type *hisifd); + +void hisi_vactive0_start_isr_handler(struct hisi_fb_data_type *hisifd); +int hisi_vactive0_start_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_dss_dirty_region_dbuf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_dss_dirty_region_updt_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_dss_handle_cur_ovl_req(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); + +int hisi_ov_compose_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_rect_t *wb_ov_block_rect, + dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, + bool *rdma_stretch_enable, + bool *has_base, + bool csc_needed, bool enable_cmdlist); + +void hisi_dss_qos_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_mmbuf_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_mif_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_smmu_on(struct hisi_fb_data_type *hisifd); +void hisi_dss_smmu_init(char __iomem *smmu_base, dss_smmu_t *s_smmu); +void hisi_dss_smmu_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu, + int chn_idx); +void hisi_dss_smmu_ov_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu); +int hisi_dss_scl_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist, + int coef_lut_idx); + +int hisi_overlay_pan_display(struct hisi_fb_data_type *hisifd); +int hisi_ov_online_play(struct hisi_fb_data_type *hisifd, void __user *argp); +int hisi_overlay_ioctl_handler(struct hisi_fb_data_type *hisifd, + uint32_t cmd, void __user *argp); + +void hisi_dss_unflow_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, bool unmask); + +void hisi_dss_chn_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *dma_base); +void hisi_dss_ov_set_reg_default_value(struct hisi_fb_data_type *hisifd, + char __iomem *ovl_base, int ovl_idx); +int hisi_dss_prev_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + uint32_t cmdlist_pre_idxs, + bool enable_cmdlist, bool *use_comm_mmbuf); + +int hisi_dss_check_pure_layer(struct hisi_fb_data_type *hisifd, + dss_overlay_block_t *pov_h_block, + void __user *argp); + +int hisi_dss_check_userdata(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block_infos); +int hisi_dss_check_layer_par(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); + +int hisi_dss_aif_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block); +void hisi_dss_aif_init(char __iomem *aif_ch_base, dss_aif_t *s_aif); +void hisi_dss_aif_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *aif_ch_base, dss_aif_t *s_aif); +int hisi_dss_aif_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_dst_rect, dss_wb_layer_t *wb_layer, + int ovl_idx); + +int hisi_dss_aif1_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx); + +int hisi_dss_mif_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer, + bool rdma_stretch_enable); + +int hisi_dss_smmu_ch_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer); + +int hisi_dss_rdma_config(struct hisi_fb_data_type *hisifd, int ovl_idx, + dss_layer_t *layer, dss_rect_ltrb_t *clip_rect, + dss_rect_t *aligned_rect, bool *rdma_stretch_enable); +int hisi_dss_wdma_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_wb_layer_t *layer, + dss_rect_t aligned_rect, dss_rect_t *ov_block_rect, + bool last_block); +int hisi_dss_rdfc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, dss_rect_ltrb_t clip_rect); +int hisi_dss_wdfc_config(struct hisi_fb_data_type *hisifd, + dss_wb_layer_t *layer, dss_rect_t *aligned_rect, + dss_rect_t *ov_block_rect); + +void hisi_dss_scl_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *scl_base, dss_scl_t *s_scl); +int hisi_dss_chn_scl_load_filter_coef_set_reg(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, int chn_idx, + uint32_t format); +int hisi_dss_post_scl_load_filter_coef(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *scl_lut_base, + int coef_lut_idx); +int hisi_dss_scl_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_rect_t *aligned_rect, bool rdma_stretch_enable); + +int hisi_dss_post_scf_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_dss_csc_init(char __iomem *csc_base, dss_csc_t *s_csc); +void hisi_dss_csc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *csc_base, dss_csc_t *s_csc); +int hisi_dss_csc_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer, + dss_wb_layer_t *wb_layer); + +int hisi_dss_ovl_base_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block, + dss_rect_t *wb_ov_block_rect, int ovl_idx, + int ov_h_block_idx); +int hisi_dss_ovl_layer_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_ov_block_rect, bool has_base); + +void hisi_dss_mctl_mutex_lock(struct hisi_fb_data_type *hisifd, int ovl_idx); +void hisi_dss_mctl_mutex_unlock(struct hisi_fb_data_type *hisifd, int ovl_idx); +void hisi_dss_mctl_on(struct hisi_fb_data_type *hisifd, + int mctl_idx, bool enable_cmdlist, bool fastboot_enable); +int hisi_dss_mctl_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx, + dss_rect_t *wb_ov_block_rect, bool has_base); +int hisi_dss_mctl_ov_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, bool has_base, + bool is_first_ov_block); + +int hisi_dss_sharpness_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); +int hisi_dss_post_clip_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer); +int hisi_dss_ce_config(struct hisi_fb_data_type *hisifd, dss_layer_t *layer); + +int hisi_dss_module_default(struct hisi_fb_data_type *hisifd); +int hisi_dss_module_init(struct hisi_fb_data_type *hisifd); +int hisi_dss_ch_module_set_regs(struct hisi_fb_data_type *hisifd, + int32_t mctl_idx, int chn_idx, uint32_t wb_type, + bool enable_cmdlist); +int hisi_dss_ov_module_set_regs(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, int ovl_idx, + bool enable_cmdlist, int task_end, int last, + bool is_first_ov_block); + +void hisi_dss_secure_layer_check_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req); +void hisi_rch2_ce_end_handle_func(struct work_struct *work); +void hisi_rch4_ce_end_handle_func(struct work_struct *work); +void hisi_dss_dpp_acm_ce_end_handle_func(struct work_struct *work); + +void hisi_crc_isr_handler(struct hisi_fb_data_type *hisifd); +int hisi_crc_enable(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req); +int hisi_crc_config(struct hisi_fb_data_type *hisifd, dss_overlay_t *pov_req); +void hisi_dss_debug_func(struct work_struct *work); +void hisi_ldi_underflow_handle_func(struct work_struct *work); + +void *hisi_dss_mmbuf_init(struct hisi_fb_data_type *hisifd); +void hisi_dss_mmbuf_deinit(struct hisi_fb_data_type *hisifd); +uint32_t hisi_dss_mmbuf_alloc(void *handle, uint32_t size); +void hisi_dss_mmbuf_free(void *handle, uint32_t addr, uint32_t size); +void hisi_dss_mmbuf_info_clear(struct hisi_fb_data_type *hisifd, int idx); +void hisi_mmbuf_info_get_online(struct hisi_fb_data_type *hisifd); +void hisi_dss_mctl_ov_set_ctl_dbg_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, + bool enable_cmdlist); +uint32_t hisi_dss_mif_get_invalid_sel(dss_img_t *img, uint32_t transform, + int v_scaling_factor, uint8_t is_tile, + bool rdma_stretch_enable); + +bool isYUVPackage(uint32_t format); +bool isYUVSemiPlanar(uint32_t format); +bool isYUVPlanar(uint32_t format); +bool isYUV(uint32_t format); + +bool is_YUV_SP_420(uint32_t format); +bool is_YUV_SP_422(uint32_t format); +bool is_YUV_P_420(uint32_t format); +bool is_YUV_P_422(uint32_t format); +bool is_RGBX(uint32_t format); + +int hisi_dss_arsr1p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col); + +/*arsr2p interface*/ +void hisi_dss_arsr2p_init(char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p); +void hisi_dss_arsr2p_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *arsr2p_base, + dss_arsr2p_t *s_arsr2p); +void hisi_dss_arsr2p_coef_on(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist); +int hisi_dss_arsr2p_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, bool rdma_stretch_enable); +void hisi_remove_mctl_mutex(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs); + +#endif /* HISI_OVERLAY_UTILS_H */ diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c new file mode 100755 index 000000000000..fb7628e0aa3e --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.c @@ -0,0 +1,2741 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_overlay_utils.h" + +uint32_t g_dss_module_base[DSS_CHN_MAX_DEFINE][MODULE_CHN_MAX] = { + /* D0 */ + { + MIF_CH0_OFFSET, + AIF0_CH0_OFFSET, + AIF1_CH0_OFFSET, + MCTL_CTL_MUTEX_RCH0, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH0_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD0_DBG, + DSS_RCH_D0_DMA_OFFSET, + DSS_RCH_D0_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D0_CSC_OFFSET, + } + , + + /* D1 */ + { + MIF_CH1_OFFSET, + AIF0_CH1_OFFSET, + AIF1_CH1_OFFSET, + MCTL_CTL_MUTEX_RCH1, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH1_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD1_DBG, + DSS_RCH_D1_DMA_OFFSET, + DSS_RCH_D1_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D1_CSC_OFFSET, + } + , + + /* V0 */ + { + MIF_CH2_OFFSET, + AIF0_CH2_OFFSET, + AIF1_CH2_OFFSET, + MCTL_CTL_MUTEX_RCH2, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH2_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD2_DBG, + DSS_RCH_VG0_DMA_OFFSET, + DSS_RCH_VG0_DFC_OFFSET, + DSS_RCH_VG0_SCL_OFFSET, + DSS_RCH_VG0_SCL_LUT_OFFSET, + DSS_RCH_VG0_ARSR_OFFSET, + DSS_RCH_VG0_ARSR_LUT_OFFSET, + DSS_RCH_VG0_POST_CLIP_OFFSET, + DSS_RCH_VG0_PCSC_OFFSET, + DSS_RCH_VG0_CSC_OFFSET, + } + , + + /* G0 */ + { + MIF_CH3_OFFSET, + AIF0_CH3_OFFSET, + AIF1_CH3_OFFSET, + MCTL_CTL_MUTEX_RCH3, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH3_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD3_DBG, + DSS_RCH_G0_DMA_OFFSET, + DSS_RCH_G0_DFC_OFFSET, + DSS_RCH_G0_SCL_OFFSET, + 0, + 0, + 0, + DSS_RCH_G0_POST_CLIP_OFFSET, + 0, + DSS_RCH_G0_CSC_OFFSET, + } + , + + /* V1 */ + { + MIF_CH4_OFFSET, + AIF0_CH4_OFFSET, + AIF1_CH4_OFFSET, + MCTL_CTL_MUTEX_RCH4, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH4_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD4_DBG, + DSS_RCH_VG1_DMA_OFFSET, + DSS_RCH_VG1_DFC_OFFSET, + DSS_RCH_VG1_SCL_OFFSET, + DSS_RCH_VG1_SCL_LUT_OFFSET, + 0, + 0, + DSS_RCH_VG1_POST_CLIP_OFFSET, + 0, + DSS_RCH_VG1_CSC_OFFSET, + } + , + + /* G1 */ + { + MIF_CH5_OFFSET, + AIF0_CH5_OFFSET, + AIF1_CH5_OFFSET, + MCTL_CTL_MUTEX_RCH5, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH5_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD5_DBG, + DSS_RCH_G1_DMA_OFFSET, + DSS_RCH_G1_DFC_OFFSET, + DSS_RCH_G1_SCL_OFFSET, + 0, + 0, + 0, + DSS_RCH_G1_POST_CLIP_OFFSET, + 0, + DSS_RCH_G1_CSC_OFFSET, + } + , + + /* D2 */ + { + MIF_CH6_OFFSET, + AIF0_CH6_OFFSET, + AIF1_CH6_OFFSET, + MCTL_CTL_MUTEX_RCH6, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH6_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD6_DBG, + DSS_RCH_D2_DMA_OFFSET, + DSS_RCH_D2_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D2_CSC_OFFSET, + } + , + + /* D3 */ + { + MIF_CH7_OFFSET, + AIF0_CH7_OFFSET, + AIF1_CH7_OFFSET, + MCTL_CTL_MUTEX_RCH7, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_OV_OEN, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH7_STARTY, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD7_DBG, + DSS_RCH_D3_DMA_OFFSET, + DSS_RCH_D3_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_RCH_D3_CSC_OFFSET, + } + , + + /* W0 */ + { + MIF_CH8_OFFSET, + AIF0_CH8_OFFSET, + AIF1_CH8_OFFSET, + MCTL_CTL_MUTEX_WCH0, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH0_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH0_OV_IEN, + 0, + 0, + DSS_WCH0_DMA_OFFSET, + DSS_WCH0_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH0_CSC_OFFSET, + } + , + + /* W1 */ + { + MIF_CH9_OFFSET, + AIF0_CH9_OFFSET, + AIF1_CH9_OFFSET, + MCTL_CTL_MUTEX_WCH1, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH1_FLUSH_EN, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH1_OV_IEN, + 0, + 0, + DSS_WCH1_DMA_OFFSET, + DSS_WCH1_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH1_CSC_OFFSET, + } + , + + /* V2 */ + { + MIF_CH10_OFFSET, + AIF0_CH11_OFFSET, + AIF1_CH11_OFFSET, + MCTL_CTL_MUTEX_RCH8, + DSS_MCTRL_SYS_OFFSET + MCTL_RCH8_FLUSH_EN, + 0, + 0, + DSS_MCTRL_SYS_OFFSET + MCTL_MOD8_DBG, + DSS_RCH_VG2_DMA_OFFSET, + DSS_RCH_VG2_DFC_OFFSET, + DSS_RCH_VG2_SCL_OFFSET, + DSS_RCH_VG2_SCL_LUT_OFFSET, + 0, + 0, + DSS_RCH_VG2_POST_CLIP_OFFSET, + 0, + DSS_RCH_VG2_CSC_OFFSET, + } + , + /* W2 */ + { + MIF_CH11_OFFSET, + AIF0_CH12_OFFSET, + AIF1_CH12_OFFSET, + MCTL_CTL_MUTEX_WCH2, + DSS_MCTRL_SYS_OFFSET + MCTL_WCH2_FLUSH_EN, + 0, + 0, + 0, + DSS_WCH2_DMA_OFFSET, + DSS_WCH2_DFC_OFFSET, + 0, + 0, + 0, + 0, + 0, + 0, + DSS_WCH2_CSC_OFFSET, + } + , +}; + +uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX] = { + {DSS_OVL0_OFFSET, + DSS_MCTRL_CTL0_OFFSET} + , + + {DSS_OVL1_OFFSET, + DSS_MCTRL_CTL1_OFFSET} + , + + {DSS_OVL2_OFFSET, + DSS_MCTRL_CTL2_OFFSET} + , + + {DSS_OVL3_OFFSET, + DSS_MCTRL_CTL3_OFFSET} + , + + {0, + DSS_MCTRL_CTL4_OFFSET} + , + + {0, + DSS_MCTRL_CTL5_OFFSET} + , +}; + +int g_scf_lut_chn_coef_idx[DSS_CHN_MAX_DEFINE] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +uint32_t g_dss_module_cap[DSS_CHN_MAX_DEFINE][MODULE_CAP_MAX] = { + /* D2 */ + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1}, + /* D3 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + /* V0 */ + {0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1}, + /* G0 */ + {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + /* V1 */ + {0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1}, + /* G1 */ + {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + /* D0 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + /* D1 */ + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, + + /* W0 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, + /* W1 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, + + /* V2 */ + {0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1}, + /* W2 */ + {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1}, +}; + +/* number of smrx idx for each channel */ +uint32_t g_dss_chn_sid_num[DSS_CHN_MAX_DEFINE] = { + 4, 1, 4, 4, 4, 4, 1, 1, 3, 3, 3, 2 +}; + +/* start idx of each channel */ +/* smrx_idx = g_dss_smmu_smrx_idx[chn_idx] + (0 ~ g_dss_chn_sid_num[chn_idx]) */ +uint32_t g_dss_smmu_smrx_idx[DSS_CHN_MAX_DEFINE] = { + 0, 4, 5, 9, 13, 17, 21, 22, 26, 29, 23, 32 +}; + +void *g_smmu_rwerraddr_virt = NULL; +static void aif_bw_sort(dss_aif_bw_t a[], int n) +{ + int i = 0; + int j = 0; + dss_aif_bw_t tmp; + + for (; i < n; ++i) { + for (j = i; j < n - 1; ++j) { + if (a[j].bw > a[j + 1].bw) { + tmp = a[j]; + a[j] = a[j + 1]; + a[j + 1] = tmp; + } + } + } +} + +int hisi_dss_aif_handler(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_overlay_block_t *pov_h_block) +{ + int i = 0; + int k = 0; + dss_layer_t *layer = NULL; + dss_wb_layer_t *wb_layer = NULL; + int chn_idx = 0; + dss_aif_bw_t *aif_bw = NULL; + uint32_t tmp = 0; + uint32_t bw_sum = 0; + + int rch_cnt = 0; + int axi0_cnt = 0; + int axi1_cnt = 0; + dss_aif_bw_t aif_bw_tmp[DSS_CHN_MAX_DEFINE]; + + dss_aif_bw_t *aif1_bw = NULL; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON(pov_h_block == NULL); + + memset(aif_bw_tmp, 0, sizeof(aif_bw_tmp)); + + if (pov_req->wb_enable) { + for (k = 0; k < pov_req->wb_layer_nums; k++) { + wb_layer = &(pov_req->wb_layer_infos[k]); + chn_idx = wb_layer->chn_idx; + + aif_bw = &(hisifd->dss_module.aif_bw[chn_idx]); + aif_bw->bw = (uint64_t) wb_layer->dst.buf_size * + (wb_layer->src_rect.w * wb_layer->src_rect.h) / + (wb_layer->dst.width * wb_layer->dst.height); + aif_bw->chn_idx = chn_idx; + aif_bw->axi_sel = AXI_CHN1; + aif_bw->is_used = 1; + } + + if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) { + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &pov_h_block->layer_infos[i]; + chn_idx = layer->chn_idx; + aif_bw_tmp[i].chn_idx = chn_idx; + aif_bw_tmp[i].axi_sel = AXI_CHN0; + aif_bw_tmp[i].is_used = 1; + hisifd->dss_module.aif_bw[chn_idx] = + aif_bw_tmp[i]; + } + return 0; + } + } + + rch_cnt = 0; + for (i = 0; i < pov_h_block->layer_nums; i++) { + layer = &pov_h_block->layer_infos[i]; + chn_idx = layer->chn_idx; + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + continue; + + if (layer->need_cap & CAP_AFBCD) { + aif1_bw = &(hisifd->dss_module.aif1_bw[chn_idx]); + aif1_bw->is_used = 1; + aif1_bw->chn_idx = chn_idx; + if ((pov_req->ovl_idx == DSS_OVL0) || + (pov_req->ovl_idx == DSS_OVL1)) { + if ((i % 2) == 0) { + aif1_bw->axi_sel = AXI_CHN0; + } else { + aif1_bw->axi_sel = AXI_CHN1; + } + } else { + if ((i % 2) == 0) { + aif1_bw->axi_sel = AXI_CHN1; + } else { + aif1_bw->axi_sel = AXI_CHN0; + } + } + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, aif1, chn_idx=%d, axi_sel=%d.\n", + hisifd->index, chn_idx, aif1_bw->axi_sel); + } + } + + aif_bw_tmp[i].bw = (uint64_t) layer->img.buf_size * + (layer->src_rect.w * layer->src_rect.h) / + (layer->img.width * layer->img.height); + aif_bw_tmp[i].chn_idx = chn_idx; + aif_bw_tmp[i].axi_sel = AXI_CHN0; + aif_bw_tmp[i].is_used = 1; + + bw_sum += aif_bw_tmp[i].bw; + rch_cnt++; + } + + aif_bw_sort(aif_bw_tmp, rch_cnt); + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (aif_bw_tmp[i].is_used != 1) + continue; + + tmp += aif_bw_tmp[i].bw; + + if ((pov_req->ovl_idx == DSS_OVL0) + || (pov_req->ovl_idx == DSS_OVL1)) { + if (tmp <= (bw_sum / 2)) { + aif_bw_tmp[i].axi_sel = AXI_CHN0; + if (axi0_cnt >= AXI0_MAX_DSS_CHN_THRESHOLD) { + aif_bw_tmp[i - + AXI0_MAX_DSS_CHN_THRESHOLD].axi_sel + = AXI_CHN1; + axi1_cnt++; + axi0_cnt--; + } + axi0_cnt++; + } else { + aif_bw_tmp[i].axi_sel = AXI_CHN1; + axi1_cnt++; + } + } else { + if (tmp <= (bw_sum / 2)) { + aif_bw_tmp[i].axi_sel = AXI_CHN1; + if (axi1_cnt >= AXI1_MAX_DSS_CHN_THRESHOLD) { + aif_bw_tmp[i - + AXI1_MAX_DSS_CHN_THRESHOLD].axi_sel + = AXI_CHN0; + axi0_cnt++; + axi1_cnt--; + } + axi1_cnt++; + } else { + aif_bw_tmp[i].axi_sel = AXI_CHN0; + axi0_cnt++; + } + } + + chn_idx = aif_bw_tmp[i].chn_idx; + hisifd->dss_module.aif_bw[chn_idx] = aif_bw_tmp[i]; + + if (g_debug_ovl_online_composer) { + HISI_FB_INFO + ("fb%d, aif0, chn_idx=%d, axi_sel=%d, bw=%llu.\n", + hisifd->index, chn_idx, aif_bw_tmp[i].axi_sel, + aif_bw_tmp[i].bw); + } + } + + return 0; +} + +void hisi_dss_qos_on(struct hisi_fb_data_type *hisifd) +{ + outp32(hisifd->noc_dss_base + 0xc, 0x2); + outp32(hisifd->noc_dss_base + 0x8c, 0x2); + outp32(hisifd->noc_dss_base + 0x10c, 0x2); + outp32(hisifd->noc_dss_base + 0x18c, 0x2); +} + +/******************************************************************************* + ** DSS AIF + */ +static int mid_array[DSS_CHN_MAX_DEFINE] = { + 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x2, 0x1, 0x3, 0x0 +}; +#define CREDIT_STEP_LOWER_ENABLE +void hisi_dss_aif_init(char __iomem *aif_ch_base, dss_aif_t *s_aif) +{ + BUG_ON(aif_ch_base == NULL); + BUG_ON(s_aif == NULL); + + memset(s_aif, 0, sizeof(dss_aif_t)); + + s_aif->aif_ch_ctl = inp32(aif_ch_base + AIF_CH_CTL); + s_aif->aif_ch_ctl_add = inp32(aif_ch_base + AIF_CH_CTL_ADD); +} + +void hisi_dss_aif_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *aif_ch_base, dss_aif_t *s_aif) +{ + BUG_ON(hisifd == NULL); + BUG_ON(aif_ch_base == NULL); + BUG_ON(s_aif == NULL); + + hisifd->set_reg(hisifd, aif_ch_base + AIF_CH_CTL, s_aif->aif_ch_ctl, 32, + 0); + hisifd->set_reg(hisifd, aif_ch_base + AIF_CH_CTL_ADD, + s_aif->aif_ch_ctl_add, 32, 0); +} + +int hisi_dss_aif_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_rect_t *wb_dst_rect, + dss_wb_layer_t *wb_layer, int ovl_idx) +{ + dss_aif_t *aif = NULL; + dss_aif_bw_t *aif_bw = NULL; + int chn_idx = 0; + int mid = 0; + uint32_t credit_step = 0; + uint32_t credit_step_lower = 0; + uint64_t dss_core_rate = 0; + uint32_t scfd_h = 0; + uint32_t scfd_v = 0; + uint32_t online_offline_rate = 1; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + } else { + chn_idx = layer->chn_idx; + } + + aif = &(hisifd->dss_module.aif[chn_idx]); + hisifd->dss_module.aif_ch_used[chn_idx] = 1; + + aif_bw = &(hisifd->dss_module.aif_bw[chn_idx]); + BUG_ON(aif_bw->is_used != 1); + + mid = mid_array[chn_idx]; + BUG_ON(mid < 0 || mid > 0xb); + + aif->aif_ch_ctl = set_bits32(aif->aif_ch_ctl, aif_bw->axi_sel, 1, 0); + aif->aif_ch_ctl = set_bits32(aif->aif_ch_ctl, mid, 4, 4); + + if ((ovl_idx == DSS_OVL2) || (ovl_idx == DSS_OVL3) + || (layer->chn_idx == DSS_RCHN_V2)) { + if (layer && ((layer->need_cap & CAP_AFBCD) != CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) { + if (wb_dst_rect) { + online_offline_rate = + wb_dst_rect->w * wb_dst_rect->h / + (hisifd->panel_info.xres * + hisifd->panel_info.yres); + } + + if (online_offline_rate == 0) + online_offline_rate = 1; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * + online_offline_rate * 32 * scfd_h * scfd_v / + dss_core_rate / (100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } + + if (credit_step < 32) { + credit_step = 32; + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); + } else { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x1, 1, 11); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 1, 1, 11); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 2, 4, 12); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x2, 2, 8); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); +#endif + } + + if (wb_layer) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + scfd_h = 100; + scfd_v = 100; + online_offline_rate = 1; + credit_step = + hisifd->panel_info.pxl_clk_rate * + online_offline_rate * 32 * scfd_h * scfd_v / + dss_core_rate / (100 * 100); + + if (credit_step < 32) { + credit_step = 32; + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); + } else { + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x1, 1, 11); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 1, 1, 11); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, 2, 4, 12); + aif->aif_ch_ctl_add = + set_bits32(aif->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x2, 2, 8); + aif->aif_ch_ctl = + set_bits32(aif->aif_ch_ctl, 0x0, 1, 11); +#endif + } + } + return 0; +} + +int hisi_dss_aif1_ch_config(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, dss_layer_t *layer, + dss_wb_layer_t *wb_layer, int ovl_idx) +{ + dss_aif_t *aif1 = NULL; + dss_aif_bw_t *aif1_bw = NULL; + int chn_idx = 0; + uint32_t need_cap = 0; + int mid = 0; + uint32_t credit_step = 0; + uint32_t credit_step_lower = 0; + uint64_t dss_core_rate = 0; + uint32_t scfd_h = 0; + uint32_t scfd_v = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(pov_req == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + BUG_ON((ovl_idx < DSS_OVL0) || (ovl_idx >= DSS_OVL_IDX_MAX)); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + need_cap = wb_layer->need_cap; + } else { + chn_idx = layer->chn_idx; + need_cap = layer->need_cap; + } + + if (!(need_cap & CAP_AFBCD)) + return 0; + + aif1 = &(hisifd->dss_module.aif1[chn_idx]); + hisifd->dss_module.aif1_ch_used[chn_idx] = 1; + + aif1_bw = &(hisifd->dss_module.aif1_bw[chn_idx]); + BUG_ON(aif1_bw->is_used != 1); + + mid = mid_array[chn_idx]; + BUG_ON(mid < 0 || mid > 0xb); + + aif1->aif_ch_ctl = set_bits32(aif1->aif_ch_ctl, aif1_bw->axi_sel, 1, 0); + aif1->aif_ch_ctl = set_bits32(aif1->aif_ch_ctl, mid, 4, 4); + + if ((ovl_idx == DSS_OVL0) || (ovl_idx == DSS_OVL1)) { + if (layer && (layer->need_cap & CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu) is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * 32 * 150 * + scfd_h * scfd_v / dss_core_rate / (100 * 100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } + + if (credit_step < 32) { + credit_step = 32; + } + + if (credit_step > 64) { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); + } else { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x1, 1, 11); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, credit_step, 7, + 16); + } + + } + } else { + if (layer && (layer->need_cap & CAP_AFBCD)) { + dss_core_rate = hisifd->dss_clk_rate.dss_pri_clk_rate; + if (dss_core_rate == 0) { + HISI_FB_ERR + ("fb%d, dss_core_rate(%llu is invalid!", + hisifd->index, dss_core_rate); + dss_core_rate = DEFAULT_DSS_CORE_CLK_07V_RATE; + } + + credit_step_lower = + g_dss_min_bandwidth_inbusbusy * 1000000UL * 8 / + dss_core_rate; + + if ((layer->src_rect.w > layer->dst_rect.w) && + (layer->src_rect.w > get_panel_xres(hisifd))) { + scfd_h = + layer->src_rect.w * 100 / + get_panel_xres(hisifd); + } else { + scfd_h = 100; + } + + if (layer->src_rect.h > layer->dst_rect.h) { + scfd_v = + layer->src_rect.h * 100 / layer->dst_rect.h; + } else { + scfd_v = 100; + } + + credit_step = + hisifd->panel_info.pxl_clk_rate * 32 * scfd_h * + scfd_v / dss_core_rate / (100 * 100); + + if (g_debug_ovl_online_composer + || g_debug_ovl_credit_step) { + HISI_FB_INFO + ("fb%d, layer_idx(%d), chn_idx(%d), src_rect(%d,%d,%d,%d)," + "dst_rect(%d,%d,%d,%d), scfd_h=%d, " + "scfd_v=%d, credit_step=%d.\n", + hisifd->index, layer->layer_idx, + layer->chn_idx, layer->src_rect.x, + layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, layer->dst_rect.x, + layer->dst_rect.y, layer->dst_rect.w, + layer->dst_rect.h, scfd_h, scfd_v, + credit_step); + } +#ifndef CREDIT_STEP_LOWER_ENABLE + if (credit_step > 64) { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); + } else { + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x1, 1, 11); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, credit_step, 7, + 16); + } +#else + /* credit en lower */ + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, 1, 1, 11); + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, 2, 4, 12); + aif1->aif_ch_ctl_add = + set_bits32(aif1->aif_ch_ctl_add, credit_step_lower, + 7, 16); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x2, 2, 8); + aif1->aif_ch_ctl = + set_bits32(aif1->aif_ch_ctl, 0x0, 1, 11); +#endif + } + } + + return 0; +} + +/******************************************************************************* + ** DSS SMMU + */ +void hisi_dss_smmu_on(struct hisi_fb_data_type *hisifd) +{ + char __iomem *smmu_base = NULL; + int idx0 = 0; + int idx1 = 0; + int idx2 = 0; + uint32_t phy_pgd_base = 0; + struct iommu_domain_data *domain_data = NULL; + uint64_t smmu_rwerraddr_phys = 0; + + BUG_ON(hisifd == NULL); + + smmu_base = hisifd->dss_base + DSS_SMMU_OFFSET; + + set_reg(smmu_base + SMMU_SCR, 0x0, 1, 0); + set_reg(smmu_base + SMMU_SCR, 0x1, 8, 20); + set_reg(smmu_base + SMMU_SCR, g_dss_smmu_outstanding - 1, 4, 16); + set_reg(smmu_base + SMMU_SCR, 0x7, 3, 3); + set_reg(smmu_base + SMMU_LP_CTRL, 0x1, 1, 0); + + set_reg(smmu_base + SMMU_CB_TTBCR, 0x1, 1, 0); + + if (g_smmu_rwerraddr_virt) { + smmu_rwerraddr_phys = virt_to_phys(g_smmu_rwerraddr_virt); + set_reg(smmu_base + SMMU_ERR_RDADDR, + (uint32_t) (smmu_rwerraddr_phys & 0xFFFFFFFF), 32, 0); + set_reg(smmu_base + SMMU_ERR_WRADDR, + (uint32_t) (smmu_rwerraddr_phys & 0xFFFFFFFF), 32, 0); + } else { + set_reg(smmu_base + SMMU_ERR_RDADDR, 0x7FF00000, 32, 0); + set_reg(smmu_base + SMMU_ERR_WRADDR, 0x7FFF0000, 32, 0); + } + + set_reg(smmu_base + SMMU_RLD_EN0_NS, DSS_SMMU_RLD_EN0_DEFAULT_VAL, 32, + 0); + set_reg(smmu_base + SMMU_RLD_EN1_NS, DSS_SMMU_RLD_EN1_DEFAULT_VAL, 32, + 0); + + idx0 = 36; + idx1 = 37; + idx2 = 38; + + set_reg(smmu_base + SMMU_SMRx_NS + idx0 * 0x4, 0x1, 32, 0); + set_reg(smmu_base + SMMU_SMRx_NS + idx1 * 0x4, 0x1, 32, 0); + set_reg(smmu_base + SMMU_SMRx_NS + idx2 * 0x4, 0x1, 32, 0); + + domain_data = (struct iommu_domain_data *)(hisifd->hisi_domain->priv); + phy_pgd_base = (uint32_t) (domain_data->phy_pgd_base); + set_reg(smmu_base + SMMU_CB_TTBR0, phy_pgd_base, 32, 0); +} + +void hisi_dss_smmu_init(char __iomem *smmu_base, dss_smmu_t *s_smmu) +{ + BUG_ON(smmu_base == NULL); + BUG_ON(s_smmu == NULL); + + memset(s_smmu, 0, sizeof(dss_smmu_t)); +} + +void +hisi_dss_smmu_ch_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *smmu_base, dss_smmu_t *s_smmu, + int chn_idx) +{ + uint32_t idx = 0; + uint32_t i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(smmu_base == NULL); + BUG_ON(s_smmu == NULL); + + if (s_smmu->smmu_smrx_ns_used[chn_idx] == 0) + return; + + for (i = 0; i < g_dss_chn_sid_num[chn_idx]; i++) { + idx = g_dss_smmu_smrx_idx[chn_idx] + i; + BUG_ON((idx < 0) || (idx >= SMMU_SID_NUM)); + + hisifd->set_reg(hisifd, smmu_base + SMMU_SMRx_NS + idx * 0x4, + s_smmu->smmu_smrx_ns[idx], 32, 0); + } +} + +int +hisi_dss_smmu_ch_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer) +{ + dss_smmu_t *smmu = NULL; + int chn_idx = 0; + dss_img_t *img = NULL; + uint32_t idx = 0; + uint32_t i = 0; + + BUG_ON(hisifd == NULL); + BUG_ON((layer == NULL) && (wb_layer == NULL)); + + if (wb_layer) { + img = &(wb_layer->dst); + chn_idx = wb_layer->chn_idx; + } else { + img = &(layer->img); + chn_idx = layer->chn_idx; + } + + smmu = &(hisifd->dss_module.smmu); + hisifd->dss_module.smmu_used = 1; + + smmu->smmu_smrx_ns_used[chn_idx] = 1; + + for (i = 0; i < g_dss_chn_sid_num[chn_idx]; i++) { + idx = g_dss_smmu_smrx_idx[chn_idx] + i; + BUG_ON((idx < 0) || (idx >= SMMU_SID_NUM)); + + if (img->mmu_enable == 0) { + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x1, 1, 0); + } else { + /* stream config */ + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x0, 1, 0); + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x1, 1, 4); + smmu->smmu_smrx_ns[idx] = + set_bits32(smmu->smmu_smrx_ns[idx], 0x3, 7, 5); + } + } + return 0; +} + +void +hisifb_adjust_block_rect(int block_num, dss_rect_t *ov_block_rects[], + dss_wb_layer_t *wb_layer) +{ + return; +} + +/******************************************************************************* + ** DSS CSC + */ +#define CSC_ROW (3) +#define CSC_COL (5) + +/* application: mode 2 is used in rgb2yuv, mode 0 is used in yuv2rgb */ +#define CSC_MPREC_MODE_0 (0) +#define CSC_MPREC_MODE_1 (1) +#define CSC_MPREC_MODE_2 (2) + +#define CSC_MPREC_MODE_RGB2YUV (CSC_MPREC_MODE_2) +#define CSC_MPREC_MODE_YUV2RGB (CSC_MPREC_MODE_0) + +/* + ** Rec.601 for Computer + ** [ p00 p01 p02 cscidc2 cscodc2 ] + ** [ p10 p11 p12 cscidc1 cscodc1 ] + ** [ p20 p21 p22 cscidc0 cscodc0 ] + */ +static int CSC_COE_YUV2RGB601_NARROW_MPREC0[CSC_ROW][CSC_COL] = { + {0x4a8, 0x000, 0x662, 0x7f0, 0x000}, + {0x4a8, 0x1e6f, 0x1cc0, 0x77f, 0x000}, + {0x4a8, 0x812, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV601_NARROW_MPREC2[CSC_ROW][CSC_COL] = { + {0x41C, 0x811, 0x191, 0x000, 0x010}, + {0x1DA1, 0x1B58, 0x707, 0x000, 0x081}, + {0x707, 0x1A1E, 0x1EDB, 0x000, 0x081} +}; + +static int CSC_COE_YUV2RGB709_NARROW_MPREC0[CSC_ROW][CSC_COL] = { + {0x4a8, 0x000, 0x72c, 0x7f0, 0x000}, + {0x4a8, 0x1f26, 0x1dde, 0x77f, 0x000}, + {0x4a8, 0x873, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV709_NARROW_MPREC2[CSC_ROW][CSC_COL] = { + {0x2EC, 0x9D4, 0x0FE, 0x000, 0x010}, + {0x1E64, 0x1A95, 0x707, 0x000, 0x081}, + {0x707, 0x199E, 0x1F5B, 0x000, 0x081} +}; + +static int CSC_COE_YUV2RGB601_WIDE_MPREC0[CSC_ROW][CSC_COL] = { + {0x400, 0x000, 0x59c, 0x000, 0x000}, + {0x400, 0x1ea0, 0x1d25, 0x77f, 0x000}, + {0x400, 0x717, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV601_WIDE_MPREC2[CSC_ROW][CSC_COL] = { + {0x4C9, 0x964, 0x1d3, 0x000, 0x000}, + {0x1D4D, 0x1AB3, 0x800, 0x000, 0x081}, + {0x800, 0x194D, 0x1EB3, 0x000, 0x081}, +}; + +static int CSC_COE_YUV2RGB709_WIDE_MPREC0[CSC_ROW][CSC_COL] = { + {0x400, 0x000, 0x64d, 0x000, 0x000}, + {0x400, 0x1f40, 0x1e21, 0x77f, 0x000}, + {0x400, 0x76c, 0x000, 0x77f, 0x000} +}; + +static int CSC_COE_RGB2YUV709_WIDE_MPREC2[CSC_ROW][CSC_COL] = { + {0x367, 0xB71, 0x128, 0x000, 0x000}, + {0x1E2B, 0x19D5, 0x800, 0x000, 0x081}, + {0x800, 0x18BC, 0x1F44, 0x000, 0x081}, +}; + +void hisi_dss_csc_init(char __iomem *csc_base, dss_csc_t *s_csc) +{ + BUG_ON(csc_base == NULL); + BUG_ON(s_csc == NULL); + + memset(s_csc, 0, sizeof(dss_csc_t)); + + s_csc->idc0 = inp32(csc_base + CSC_IDC0); + s_csc->idc2 = inp32(csc_base + CSC_IDC2); + s_csc->odc0 = inp32(csc_base + CSC_ODC0); + s_csc->odc2 = inp32(csc_base + CSC_ODC2); + s_csc->p0 = inp32(csc_base + CSC_P0); + s_csc->p1 = inp32(csc_base + CSC_P1); + s_csc->p2 = inp32(csc_base + CSC_P2); + s_csc->p3 = inp32(csc_base + CSC_P3); + s_csc->p4 = inp32(csc_base + CSC_P4); + s_csc->icg_module = inp32(csc_base + CSC_ICG_MODULE); + s_csc->mprec = inp32(csc_base + CSC_MPREC); +} + +void +hisi_dss_csc_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *csc_base, dss_csc_t *s_csc) +{ + BUG_ON(hisifd == NULL); + BUG_ON(csc_base == NULL); + BUG_ON(s_csc == NULL); + + hisifd->set_reg(hisifd, csc_base + CSC_IDC0, s_csc->idc0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_IDC2, s_csc->idc2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ODC0, s_csc->odc0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ODC2, s_csc->odc2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P0, s_csc->p0, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P1, s_csc->p1, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P2, s_csc->p2, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P3, s_csc->p3, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_P4, s_csc->p4, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_ICG_MODULE, + s_csc->icg_module, 32, 0); + hisifd->set_reg(hisifd, csc_base + CSC_MPREC, s_csc->mprec, 32, 0); +} + +bool is_pcsc_needed(dss_layer_t *layer) +{ + if (layer->chn_idx != DSS_RCHN_V0) + return false; + + if (layer->need_cap & CAP_2D_SHARPNESS) + return true; + + /* horizental shrink is not supported by arsr2p */ + if ((layer->dst_rect.h != layer->src_rect.h) + || (layer->dst_rect.w > layer->src_rect.w)) + return true; + + return false; +} + +int +hisi_dss_csc_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_wb_layer_t *wb_layer) +{ + dss_csc_t *csc = NULL; + int chn_idx = 0; + uint32_t format = 0; + uint32_t csc_mode = 0; + int (*csc_coe_yuv2rgb)[CSC_COL]; + int (*csc_coe_rgb2yuv)[CSC_COL]; + + BUG_ON(hisifd == NULL); + + if (wb_layer) { + chn_idx = wb_layer->chn_idx; + format = wb_layer->dst.format; + csc_mode = wb_layer->dst.csc_mode; + } else { + chn_idx = layer->chn_idx; + format = layer->img.format; + csc_mode = layer->img.csc_mode; + } + + if (chn_idx != DSS_RCHN_V0) { + if (!isYUV(format)) + return 0; + hisifd->dss_module.csc_used[chn_idx] = 1; + } else if ((chn_idx == DSS_RCHN_V0) && (!isYUV(format))) { + if (!is_pcsc_needed(layer)) + return 0; + + hisifd->dss_module.csc_used[DSS_RCHN_V0] = 1; + hisifd->dss_module.pcsc_used[DSS_RCHN_V0] = 1; + } else { + hisifd->dss_module.csc_used[chn_idx] = 1; + } + + if (csc_mode == DSS_CSC_601_WIDE) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_WIDE_MPREC2; + } else if (csc_mode == DSS_CSC_601_NARROW) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_NARROW_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_NARROW_MPREC2; + } else if (csc_mode == DSS_CSC_709_WIDE) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB709_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV709_WIDE_MPREC2; + } else if (csc_mode == DSS_CSC_709_NARROW) { + csc_coe_yuv2rgb = CSC_COE_YUV2RGB709_NARROW_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV709_NARROW_MPREC2; + } else { + /* TBD add csc mprec mode 1 and mode 2 */ + HISI_FB_ERR("not support this csc_mode(%d)!\n", csc_mode); + csc_coe_yuv2rgb = CSC_COE_YUV2RGB601_WIDE_MPREC0; + csc_coe_rgb2yuv = CSC_COE_RGB2YUV601_WIDE_MPREC2; + } + + /* config rch csc */ + if (layer && hisifd->dss_module.csc_used[chn_idx]) { + csc = &(hisifd->dss_module.csc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_YUV2RGB; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_yuv2rgb[2][3]) | + (csc_coe_yuv2rgb[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_yuv2rgb[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_yuv2rgb[2][4]) | + (csc_coe_yuv2rgb[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_yuv2rgb[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_yuv2rgb[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_yuv2rgb[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_yuv2rgb[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_yuv2rgb[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_yuv2rgb[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_yuv2rgb[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_yuv2rgb[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_yuv2rgb[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_yuv2rgb[2][2], 13, 0); + } + + /* config rch pcsc */ + if (layer && hisifd->dss_module.pcsc_used[chn_idx]) { + csc = &(hisifd->dss_module.pcsc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_RGB2YUV; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_rgb2yuv[2][3]) | + (csc_coe_rgb2yuv[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_rgb2yuv[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_rgb2yuv[2][4]) | + (csc_coe_rgb2yuv[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_rgb2yuv[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_rgb2yuv[2][2], 13, 0); + } + + /* config wch csc */ + if (wb_layer) { + csc = &(hisifd->dss_module.csc[chn_idx]); + csc->mprec = CSC_MPREC_MODE_RGB2YUV; + csc->icg_module = set_bits32(csc->icg_module, 0x1, 1, 0); + + csc->idc0 = set_bits32(csc->idc0, + (csc_coe_rgb2yuv[2][3]) | + (csc_coe_rgb2yuv[1][3] << 16), 27, 0); + csc->idc2 = + set_bits32(csc->idc2, (csc_coe_rgb2yuv[0][3]), 11, 0); + + csc->odc0 = set_bits32(csc->odc0, + (csc_coe_rgb2yuv[2][4]) | + (csc_coe_rgb2yuv[1][4] << 16), 27, 0); + csc->odc2 = + set_bits32(csc->odc2, (csc_coe_rgb2yuv[0][4]), 11, 0); + + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][0], 13, 0); + csc->p0 = set_bits32(csc->p0, csc_coe_rgb2yuv[0][1], 13, 16); + + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[0][2], 13, 0); + csc->p1 = set_bits32(csc->p1, csc_coe_rgb2yuv[1][0], 13, 16); + + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][1], 13, 0); + csc->p2 = set_bits32(csc->p2, csc_coe_rgb2yuv[1][2], 13, 16); + + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][0], 13, 0); + csc->p3 = set_bits32(csc->p3, csc_coe_rgb2yuv[2][1], 13, 16); + + csc->p4 = set_bits32(csc->p4, csc_coe_rgb2yuv[2][2], 13, 0); + } + + return 0; +} + +uint32_t hisi_dss_mif_get_invalid_sel(dss_img_t *img, uint32_t transform, + int v_scaling_factor, uint8_t is_tile, + bool rdma_stretch_enable) +{ + uint32_t invalid_sel_val = 0; + uint32_t tlb_tag_org = 0; + + if (img == NULL) { + HISI_FB_ERR("img is null"); + return 0; + } + + if ((transform == (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H)) + || (transform == + (HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V))) { + transform = HISI_FB_TRANSFORM_ROT_90; + } + + tlb_tag_org = (transform & 0x7) | + ((is_tile ? 1 : 0) << 3) | ((rdma_stretch_enable ? 1 : 0) << 4); + + switch (tlb_tag_org) { + case MMU_TLB_TAG_ORG_0x0: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x1: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x2: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x3: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x4: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x7: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x8: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x9: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xA: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xB: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0xC: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0xF: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x10: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x11: + invalid_sel_val = 1; + break; + case MMU_TLB_TAG_ORG_0x12: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x13: + invalid_sel_val = 2; + break; + case MMU_TLB_TAG_ORG_0x14: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x17: + invalid_sel_val = 0; + break; + + case MMU_TLB_TAG_ORG_0x18: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x19: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1A: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1B: + invalid_sel_val = 3; + break; + case MMU_TLB_TAG_ORG_0x1C: + invalid_sel_val = 0; + break; + case MMU_TLB_TAG_ORG_0x1F: + invalid_sel_val = 0; + break; + + default: + invalid_sel_val = 0; + HISI_FB_ERR("not support this tlb_tag_org(0x%x)!\n", + tlb_tag_org); + break; + } + + return invalid_sel_val; +} + +/******************************************************************************* + ** DSS ARSR2P + */ +#define ARSR2P_PHASE_NUM (9) +#define ARSR2P_TAP4 (4) +#define ARSR2P_TAP6 (6) +#define ARSR2P_MIN_INPUT (16) +#define ARSR2P_MAX_WIDTH (2560) +#define ARSR2P_MAX_HEIGHT (8192) +#define ARSR2P_SCALE_MAX (60) + +#define ARSR2P_SCL_UP_OFFSET (0x48) +#define ARSR2P_COEF_H0_OFFSET (0x100) +#define ARSR2P_COEF_H1_OFFSET (0x200) + +static const int COEF_AUV_SCL_UP_TAP4[ARSR2P_PHASE_NUM][ARSR2P_TAP4] = { + {-3, 254, 6, -1}, + {-9, 255, 13, -3}, + {-18, 254, 27, -7}, + {-23, 245, 44, -10}, + {-27, 233, 64, -14}, + {-29, 218, 85, -18}, + {-29, 198, 108, -21}, + {-29, 177, 132, -24}, + {-27, 155, 155, -27} +}; + +static const int COEF_AUV_SCL_DOWN_TAP4[ARSR2P_PHASE_NUM][ARSR2P_TAP4] = { + {31, 194, 31, 0}, + {23, 206, 44, -17}, + {14, 203, 57, -18}, + {6, 198, 70, -18}, + {0, 190, 85, -19}, + {-5, 180, 99, -18}, + {-10, 170, 114, -18}, + {-13, 157, 129, -17}, + {-15, 143, 143, -15} +}; + +static const int COEF_Y_SCL_UP_TAP6[ARSR2P_PHASE_NUM][ARSR2P_TAP6] = { + {0, -3, 254, 6, -1, 0}, + {4, -12, 252, 15, -5, 2}, + {7, -22, 245, 31, -9, 4}, + {10, -29, 234, 49, -14, 6}, + {12, -34, 221, 68, -19, 8}, + {13, -37, 206, 88, -24, 10}, + {14, -38, 189, 108, -29, 12}, + {14, -38, 170, 130, -33, 13}, + {14, -36, 150, 150, -36, 14} +}; + +static const int COEF_Y_SCL_DOWN_TAP6[ARSR2P_PHASE_NUM][ARSR2P_TAP6] = { + {-22, 43, 214, 43, -22, 0}, + {-18, 29, 205, 53, -23, 10}, + {-16, 18, 203, 67, -25, 9}, + {-13, 9, 198, 80, -26, 8}, + {-10, 0, 191, 95, -27, 7}, + {-7, -7, 182, 109, -27, 6}, + {-5, -14, 174, 124, -27, 4}, + {-2, -18, 162, 137, -25, 2}, + {0, -22, 150, 150, -22, 0} +}; + +/******************************************************************************* + ** DSS ARSR2P + */ +int +hisi_dss_arsr1p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int coef_value = 0; + int coef_num = 0; + int i = 0; + int j = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != ARSR2P_PHASE_NUM) + || ((col != ARSR2P_TAP4) && (col != ARSR2P_TAP6))) { + HISI_FB_ERR + ("arsr1p filter coefficients is err, arsr1p_phase_num = %d, arsr1p_tap_num = %d\n", + row, col); + return -EINVAL; + } + + coef_num = (col == ARSR2P_TAP4 ? 2 : 3); + + for (j = 0; j < 2; j++) { + for (i = 0; i < row; i++) { + if (coef_num == 2) { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9); + } else { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9) | ((*((int *)p + i * col + + j * coef_num + + 2) & 0x1FF) << 18); + } + + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + 0x8 * i + j * 0x4, + coef_value, 32, 0); + } else { + set_reg(addr + 0x8 * i + j * 0x4, coef_value, + 32, 0); + } + } + } + + return 0; +} + +int +hisi_dss_post_scl_load_filter_coef(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *scl_lut_base, + int coef_lut_idx) +{ + int ret = 0; + + BUG_ON(hisifd == NULL); + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_H_Y0, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write H_Y0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_V_Y0, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + if (ret < 0) { + HISI_FB_ERR("Error to write V_Y0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_H_UV0, + (const int **)COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write H_UV0_COEF coefficients.\n"); + } + + ret = + hisi_dss_arsr1p_write_coefs(hisifd, enable_cmdlist, + scl_lut_base + ARSR1P_COEFF_V_UV0, + (const int **)COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + if (ret < 0) { + HISI_FB_ERR("Error to write V_UV0_COEF coefficients.\n"); + } + + return ret; +} + +int +hisi_dss_arsr2p_write_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, char __iomem *addr, + const int **p, int row, int col) +{ + int coef_value = 0; + int coef_num = 0; + int i = 0; + int j = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(addr == NULL); + + if ((row != ARSR2P_PHASE_NUM) + || ((col != ARSR2P_TAP4) && (col != ARSR2P_TAP6))) { + HISI_FB_ERR + ("arsr2p filter coefficients is err, arsr2p_phase_num = %d, arsr2p_tap_num = %d\n", + row, col); + return -EINVAL; + } + + coef_num = (col == ARSR2P_TAP4 ? 2 : 3); + for (i = 0; i < row; i++) { + for (j = 0; j < 2; j++) { + if (coef_num == 2) { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9); + } else { + coef_value = + (*((int *)p + i * col + j * coef_num) & + 0x1FF) | + ((*((int *)p + i * col + j * coef_num + 1) & + 0x1FF) << 9) | ((*((int *)p + i * col + + j * coef_num + + 2) & 0x1FF) << 18); + } + + if (enable_cmdlist) { + hisifd->set_reg(hisifd, + addr + 0x8 * i + j * 0x4, + coef_value, 32, 0); + } else { + set_reg(addr + 0x8 * i + j * 0x4, coef_value, + 32, 0); + } + } + } + + return 0; +} + +void +hisi_dss_arsr2p_write_config_coefs(struct hisi_fb_data_type *hisifd, + bool enable_cmdlist, + char __iomem *addr, + const int **scl_down, + const int **scl_up, int row, int col) +{ + int ret = 0; + + ret = + hisi_dss_arsr2p_write_coefs(hisifd, enable_cmdlist, addr, + scl_down, row, col); + if (ret < 0) { + HISI_FB_ERR("Error to write COEF_SCL_DOWN coefficients.\n"); + return; + } + + ret = + hisi_dss_arsr2p_write_coefs(hisifd, enable_cmdlist, + addr + ARSR2P_SCL_UP_OFFSET, scl_up, + row, col); + if (ret < 0) { + HISI_FB_ERR("Error to write COEF_SCL_UP coefficients.\n"); + return; + } + +} + +void hisi_dss_arsr2p_init(char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p) +{ + BUG_ON(arsr2p_base == NULL); + BUG_ON(s_arsr2p == NULL); + + memset(s_arsr2p, 0, sizeof(dss_arsr2p_t)); + + s_arsr2p->arsr_input_width_height = + inp32(arsr2p_base + ARSR2P_INPUT_WIDTH_HEIGHT); + s_arsr2p->arsr_output_width_height = + inp32(arsr2p_base + ARSR2P_OUTPUT_WIDTH_HEIGHT); + s_arsr2p->ihleft = inp32(arsr2p_base + ARSR2P_IHLEFT); + s_arsr2p->ihright = inp32(arsr2p_base + ARSR2P_IHRIGHT); + s_arsr2p->ivtop = inp32(arsr2p_base + ARSR2P_IVTOP); + s_arsr2p->ivbottom = inp32(arsr2p_base + ARSR2P_IVBOTTOM); + s_arsr2p->ihinc = inp32(arsr2p_base + ARSR2P_IHINC); + s_arsr2p->ivinc = inp32(arsr2p_base + ARSR2P_IVINC); + s_arsr2p->offset = inp32(arsr2p_base + ARSR2P_UV_OFFSET); + s_arsr2p->mode = inp32(arsr2p_base + ARSR2P_MODE); + s_arsr2p->arsr2p_effect.skin_thres_y = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_Y); + s_arsr2p->arsr2p_effect.skin_thres_u = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_U); + s_arsr2p->arsr2p_effect.skin_thres_v = + inp32(arsr2p_base + ARSR2P_SKIN_THRES_V); + s_arsr2p->arsr2p_effect.skin_cfg0 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG0); + s_arsr2p->arsr2p_effect.skin_cfg1 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG1); + s_arsr2p->arsr2p_effect.skin_cfg2 = + inp32(arsr2p_base + ARSR2P_SKIN_CFG2); + s_arsr2p->arsr2p_effect.shoot_cfg1 = + inp32(arsr2p_base + ARSR2P_SHOOT_CFG1); + s_arsr2p->arsr2p_effect.shoot_cfg2 = + inp32(arsr2p_base + ARSR2P_SHOOT_CFG2); + s_arsr2p->arsr2p_effect.sharp_cfg1 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG1); + s_arsr2p->arsr2p_effect.sharp_cfg2 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG2); + s_arsr2p->arsr2p_effect.sharp_cfg3 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG3); + s_arsr2p->arsr2p_effect.sharp_cfg4 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG4); + s_arsr2p->arsr2p_effect.sharp_cfg5 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG5); + s_arsr2p->arsr2p_effect.sharp_cfg6 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG6); + s_arsr2p->arsr2p_effect.sharp_cfg7 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG7); + s_arsr2p->arsr2p_effect.sharp_cfg8 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG8); + s_arsr2p->arsr2p_effect.sharp_cfg9 = + inp32(arsr2p_base + ARSR2P_SHARP_CFG9); + s_arsr2p->arsr2p_effect.texturw_analysts = + inp32(arsr2p_base + ARSR2P_TEXTURW_ANALYSTS); + s_arsr2p->arsr2p_effect.intplshootctrl = + inp32(arsr2p_base + ARSR2P_INTPLSHOOTCTRL); + + s_arsr2p->ihleft1 = inp32(arsr2p_base + ARSR2P_IHLEFT1); + s_arsr2p->ihright1 = inp32(arsr2p_base + ARSR2P_IHRIGHT1); + s_arsr2p->ivbottom1 = inp32(arsr2p_base + ARSR2P_IVBOTTOM1); +} + +void +hisi_dss_arsr2p_set_reg(struct hisi_fb_data_type *hisifd, + char __iomem *arsr2p_base, dss_arsr2p_t *s_arsr2p) +{ + BUG_ON(arsr2p_base == NULL); + BUG_ON(s_arsr2p == NULL); + + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INPUT_WIDTH_HEIGHT, + s_arsr2p->arsr_input_width_height, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_OUTPUT_WIDTH_HEIGHT, + s_arsr2p->arsr_output_width_height, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHLEFT, + s_arsr2p->ihleft, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHRIGHT, + s_arsr2p->ihright, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVTOP, + s_arsr2p->ivtop, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVBOTTOM, + s_arsr2p->ivbottom, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHINC, + s_arsr2p->ihinc, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVINC, + s_arsr2p->ivinc, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_UV_OFFSET, + s_arsr2p->offset, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_MODE, + s_arsr2p->mode, 32, 0); + + if (hisifd->dss_module.arsr2p_effect_used[DSS_RCHN_V0]) { + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_Y, + s_arsr2p->arsr2p_effect.skin_thres_y, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_U, + s_arsr2p->arsr2p_effect.skin_thres_u, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_V, + s_arsr2p->arsr2p_effect.skin_thres_v, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG0, + s_arsr2p->arsr2p_effect.skin_cfg0, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG1, + s_arsr2p->arsr2p_effect.skin_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG2, + s_arsr2p->arsr2p_effect.skin_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG1, + s_arsr2p->arsr2p_effect.shoot_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG2, + s_arsr2p->arsr2p_effect.shoot_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG1, + s_arsr2p->arsr2p_effect.sharp_cfg1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG2, + s_arsr2p->arsr2p_effect.sharp_cfg2, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG3, + s_arsr2p->arsr2p_effect.sharp_cfg3, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG4, + s_arsr2p->arsr2p_effect.sharp_cfg4, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG5, + s_arsr2p->arsr2p_effect.sharp_cfg5, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG6, + s_arsr2p->arsr2p_effect.sharp_cfg6, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG7, + s_arsr2p->arsr2p_effect.sharp_cfg7, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG8, + s_arsr2p->arsr2p_effect.sharp_cfg8, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG9, + s_arsr2p->arsr2p_effect.sharp_cfg9, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_TEXTURW_ANALYSTS, + s_arsr2p->arsr2p_effect.texturw_analysts, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INTPLSHOOTCTRL, + s_arsr2p->arsr2p_effect.intplshootctrl, 32, 0); + } + + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHLEFT1, + s_arsr2p->ihleft1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IHRIGHT1, + s_arsr2p->ihright1, 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_IVBOTTOM1, + s_arsr2p->ivbottom1, 32, 0); +} + +void +hisi_dss_arsr2p_coef_on(struct hisi_fb_data_type *hisifd, bool enable_cmdlist) +{ + uint32_t module_base = 0; + char __iomem *arsr2p_base = 0; + char __iomem *coefy_v = NULL; + char __iomem *coefa_v = NULL; + char __iomem *coefuv_v = NULL; + + BUG_ON(hisifd == NULL); + + module_base = g_dss_module_base[DSS_RCHN_V0][MODULE_ARSR2P_LUT]; + coefy_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFY_V_OFFSET; + coefa_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFA_V_OFFSET; + coefuv_v = hisifd->dss_base + module_base + ARSR2P_LUT_COEFUV_V_OFFSET; + arsr2p_base = + hisifd->dss_base + g_dss_module_base[DSS_RCHN_V0][MODULE_ARSR2P]; + + /* COEFY_V COEFY_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefy_v, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefy_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefy_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_Y_SCL_DOWN_TAP6, + (const int **)COEF_Y_SCL_UP_TAP6, + ARSR2P_PHASE_NUM, ARSR2P_TAP6); + + /* COEFA_V COEFA_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefa_v, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefa_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefa_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + + /* COEFUV_V COEFUV_H */ + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, coefuv_v, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefuv_v + ARSR2P_COEF_H0_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + hisi_dss_arsr2p_write_config_coefs(hisifd, enable_cmdlist, + coefuv_v + ARSR2P_COEF_H1_OFFSET, + (const int **) + COEF_AUV_SCL_DOWN_TAP4, + (const int **) + COEF_AUV_SCL_UP_TAP4, + ARSR2P_PHASE_NUM, ARSR2P_TAP4); + + if (enable_cmdlist) { + hisifd->set_reg = hisi_cmdlist_set_reg; + } else { + hisifd->set_reg = hisifb_set_reg; + } + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_Y, + (75 | (83 << 8) | (145 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_U, + (5 | (10 << 8) | (113 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_THRES_V, + (6 | (12 << 8) | (152 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG0, + (512 | (3 << 12)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG1, (819), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SKIN_CFG2, (682), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG1, + (512 | (20 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHOOT_CFG2, + (-16 | (0 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG1, + (2 | (6 << 8) | (48 << 16) | (64 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG2, + (8 | (24 << 8) | (24 << 16) | (40 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG3, + (1 | (1 << 8) | (2500 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG4, + (10 | (6 << 8) | (9 << 16) | (12 << 24)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG5, + (2 | (12 << 8)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG6, + (448 | (64 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG7, + (1 | (250 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG8, + (-48000), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_SHARP_CFG9, + (-32000), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_TEXTURW_ANALYSTS, + (15 | (20 << 16)), 32, 0); + hisifd->set_reg(hisifd, arsr2p_base + ARSR2P_INTPLSHOOTCTRL, + (4), 32, 0); + +} + +void hisi_dss_arsr2p_effect_config(dss_arsr2p_effect_t *arsr2p_effect) +{ + arsr2p_effect->skin_thres_y = 75 | (83 << 8) | (145 << 16); + arsr2p_effect->skin_thres_u = 5 | (10 << 8) | (113 << 16); + arsr2p_effect->skin_thres_v = 6 | (12 << 8) | (152 << 16); + arsr2p_effect->skin_cfg0 = 512 | (3 << 12); + arsr2p_effect->skin_cfg1 = 819; + arsr2p_effect->skin_cfg2 = 682; + arsr2p_effect->shoot_cfg1 = 512 | (20 << 16); + arsr2p_effect->shoot_cfg2 = -16 | (0 << 16); + arsr2p_effect->sharp_cfg1 = 2 | (6 << 8) | (48 << 16) | (64 << 24); + arsr2p_effect->sharp_cfg2 = 8 | (24 << 8) | (24 << 16) | (40 << 24); + arsr2p_effect->sharp_cfg3 = 1 | (1 << 8) | (2500 << 16); + arsr2p_effect->sharp_cfg4 = 10 | (6 << 8) | (9 << 16) | (12 << 24); + arsr2p_effect->sharp_cfg5 = 2 | (12 << 8); + arsr2p_effect->sharp_cfg6 = 448 | (64 << 16); + arsr2p_effect->sharp_cfg7 = 1 | (250 << 16); + arsr2p_effect->sharp_cfg8 = -48000; + arsr2p_effect->sharp_cfg9 = -32000; + arsr2p_effect->texturw_analysts = 15 | (20 << 16); + arsr2p_effect->intplshootctrl = 4; +} + +int +hisi_dss_arsr2p_config(struct hisi_fb_data_type *hisifd, + dss_layer_t *layer, dss_rect_t *aligned_rect, + bool rdma_stretch_enable) +{ + dss_arsr2p_t *arsr2p = NULL; + dss_rect_t src_rect; + dss_rect_t dst_rect; + uint32_t need_cap = 0; + int chn_idx = 0; + dss_block_info_t *pblock_info = NULL; + int extraw = 0, extraw_left = 0, extraw_right = 0; + + bool en_hscl = false; + bool en_vscl = false; + + /* arsr mode */ + bool imageintpl_dis = false; + bool hscldown_enabled = false; + bool nearest_en = false; + bool diintpl_en = false; + bool textureanalyhsisen_en = false; + bool skinctrl_en = false; + bool shootdetect_en = false; + bool sharpen_en = false; + bool arsr2p_bypass = true; + + bool hscldown_flag = false; + + int ih_inc = 0; + int iv_inc = 0; + int ih_left = 0; + int ih_right = 0; + int iv_top = 0; + int iv_bottom = 0; + int uv_offset = 0; + int src_width = 0; + int dst_whole_width = 0; + + int outph_left = 0; + int outph_right = 0; + int outpv_bottom = 0; + + BUG_ON(hisifd == NULL); + BUG_ON(layer == NULL); + + chn_idx = layer->chn_idx; + if (chn_idx != DSS_RCHN_V0) { + return 0; + } + + need_cap = layer->need_cap; + + src_rect = layer->src_rect; + dst_rect = layer->dst_rect; + pblock_info = &(layer->block_info); + + if (pblock_info && pblock_info->h_ratio_arsr2p) { + src_rect = pblock_info->arsr2p_in_rect; + } + + src_rect.h = aligned_rect->h; + + /* horizental scaler compute */ + do { + if (pblock_info && pblock_info->h_ratio_arsr2p) { + ih_inc = pblock_info->h_ratio_arsr2p; + src_width = src_rect.w; + dst_whole_width = pblock_info->arsr2p_dst_w; + src_rect.x = src_rect.x - pblock_info->arsr2p_src_x; + src_rect.y = src_rect.y - pblock_info->arsr2p_src_y; + dst_rect.x = dst_rect.x - pblock_info->arsr2p_dst_x; + dst_rect.y = dst_rect.y - pblock_info->arsr2p_dst_y; + + if (pblock_info->both_vscfh_arsr2p_used) { + hscldown_flag = true; + } + + if (rdma_stretch_enable) { + en_hscl = true; + } + + if (ih_inc && ih_inc != ARSR2P_INC_FACTOR) { + en_hscl = true; + } + } else { + /* horizental scaling down is not supported by arsr2p, set src_rect.w = dst_rect.w */ + if (src_rect.w > dst_rect.w) { + src_width = dst_rect.w; + hscldown_flag = true; + } else { + src_width = src_rect.w; + } + dst_whole_width = dst_rect.w; + + src_rect.x = 0; + src_rect.y = 0; + dst_rect.x = 0; + dst_rect.y = 0; + if (src_width != dst_rect.w) + en_hscl = true; + + ih_inc = + (DSS_WIDTH(src_width) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR - ih_left) / dst_rect.w; + } + + outph_left = + dst_rect.x * ih_inc - (src_rect.x * ARSR2P_INC_FACTOR); + if (outph_left < 0) + outph_left = 0; + + extraw = (8 * ARSR2P_INC_FACTOR) / ih_inc; + extraw_left = (extraw % 2) ? (extraw + 1) : (extraw); + ih_left = outph_left - extraw_left * ih_inc; + if (ih_left < 0) + ih_left = 0; + + outph_right = + (dst_rect.x + dst_rect.w - 1) * ih_inc - + (src_rect.x * ARSR2P_INC_FACTOR); + if (dst_whole_width == dst_rect.w) { + extraw = (2 * ARSR2P_INC_FACTOR) / ih_inc; + extraw_right = (extraw % 2) ? (extraw + 1) : (extraw); + ih_right = outph_right + extraw_right * ih_inc; + + /*if(ihright+(starti << 16)) >(width - 1)* ihinc); + ihright = endo*ihinc-(starti<<16); */ + extraw = + (dst_whole_width - 1) * ih_inc - + (src_rect.x * ARSR2P_INC_FACTOR); + + if (ih_right > extraw) { + ih_right = extraw; + } + } else { + ih_right = src_width * ARSR2P_INC_FACTOR - 1; + } + } while(0); + + /* vertical scaler compute */ + do { + if (src_rect.h != dst_rect.h) + en_vscl = true; + + if (src_rect.h > dst_rect.h) { + iv_inc = + (DSS_HEIGHT(src_rect.h) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR / 2 - + iv_top) / DSS_HEIGHT(dst_rect.h); + } else { + iv_inc = + (DSS_HEIGHT(src_rect.h) * ARSR2P_INC_FACTOR + + ARSR2P_INC_FACTOR - iv_top) / dst_rect.h; + } + + iv_bottom = DSS_HEIGHT(dst_rect.h) * iv_inc + iv_top; + outpv_bottom = iv_bottom; + } while(0); + + if (need_cap & CAP_2D_SHARPNESS) { + sharpen_en = true; + } + + if ((!en_hscl) && (!en_vscl)) { + if (!sharpen_en) { + /*if both scaler up and sharpness are not needed, just return */ + return 0; + } else if (!hscldown_flag) { + /*if only sharpness is needed, disable image interplo, enable textureanalyhsis */ + imageintpl_dis = true; + textureanalyhsisen_en = true; + } + } + + arsr2p = &(hisifd->dss_module.arsr2p[chn_idx]); + hisifd->dss_module.arsr2p_used[chn_idx] = 1; + + /*check arsr2p input and output width */ + if ((src_width < ARSR2P_MIN_INPUT) || (dst_rect.w < ARSR2P_MIN_INPUT) + || (src_width > ARSR2P_MAX_WIDTH) + || (dst_rect.w > ARSR2P_MAX_WIDTH)) { + HISI_FB_ERR + ("src_rect.w(%d) or dst_rect.w(%d) is smaller than 16 " + "or larger than 2560!\n", + src_width, dst_rect.w); + return -EINVAL; + } + + if ((dst_rect.w > (src_width * ARSR2P_SCALE_MAX)) + || (src_width > (dst_rect.w * ARSR2P_SCALE_MAX))) { + HISI_FB_ERR + ("width out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), dst_rect(%d, %d, %d, %d)\n", + layer->src_rect.x, layer->src_rect.y, src_width, + layer->src_rect.h, src_rect.x, src_rect.y, src_width, + src_rect.h, dst_rect.x, dst_rect.y, dst_rect.w, + dst_rect.h); + + return -EINVAL; + } + + /*check arsr2p input and output height */ + if ((src_rect.h > ARSR2P_MAX_HEIGHT) + || (dst_rect.h > ARSR2P_MAX_HEIGHT)) { + HISI_FB_ERR + ("src_rect.h(%d) or dst_rect.h(%d) is smaller than 16 " + "or larger than 8192!\n", + src_rect.h, dst_rect.h); + return -EINVAL; + } + + if ((dst_rect.h > (src_rect.h * ARSR2P_SCALE_MAX)) + || (src_rect.h > (dst_rect.h * ARSR2P_SCALE_MAX))) { + HISI_FB_ERR + ("height out of range, original_src_rec(%d, %d, %d, %d) " + "new_src_rect(%d, %d, %d, %d), dst_rect(%d, %d, %d, %d).\n", + layer->src_rect.x, layer->src_rect.y, layer->src_rect.w, + layer->src_rect.h, src_rect.x, src_rect.y, src_rect.w, + src_rect.h, dst_rect.x, dst_rect.y, dst_rect.w, + dst_rect.h); + return -EINVAL; + } + + /*if arsr2p is enabled, hbp+hfp+hsw > 20 */ + /*if (hisifd_primary && (hisifd_primary->panel_info.ldi.h_back_porch + hisifd_primary->panel_info.ldi.h_front_porch + + hisifd_primary->panel_info.ldi.h_pulse_width) <= 20) { + HISI_FB_ERR("ldi hbp+hfp+hsw is not larger than 20, return!\n"); + return -EINVAL; + } */ + + /*config arsr2p mode , start */ + arsr2p_bypass = false; + do { + if (hscldown_flag) { + hscldown_enabled = true; + break; + } + + if (!en_hscl && (iv_inc >= 2 * ARSR2P_INC_FACTOR) + && !pblock_info->h_ratio_arsr2p) { + nearest_en = true; + sharpen_en = false; + break; + } + + if ((!en_hscl) && (!en_vscl)) { + break; + } + + diintpl_en = true; + textureanalyhsisen_en = true; + } while(0); + + if (sharpen_en) { + skinctrl_en = true; + shootdetect_en = true; + } + /*config arsr2p mode , end */ + + /*if sharpness 2d is needed, config the arsr2p effect */ + hisi_dss_arsr2p_effect_config(&(arsr2p->arsr2p_effect)); + hisifd->dss_module.arsr2p_effect_used[chn_idx] = 1; + + arsr2p->arsr_input_width_height = + set_bits32(arsr2p->arsr_input_width_height, + DSS_HEIGHT(src_rect.h), 13, 0); + arsr2p->arsr_input_width_height = + set_bits32(arsr2p->arsr_input_width_height, DSS_WIDTH(src_width), + 13, 16); + arsr2p->arsr_output_width_height = + set_bits32(arsr2p->arsr_output_width_height, + DSS_HEIGHT(dst_rect.h), 13, 0); + arsr2p->arsr_output_width_height = + set_bits32(arsr2p->arsr_output_width_height, + DSS_WIDTH(dst_rect.w), 13, 16); + arsr2p->ihleft = set_bits32(arsr2p->ihleft, ih_left, 29, 0); + arsr2p->ihright = set_bits32(arsr2p->ihright, ih_right, 29, 0); + arsr2p->ivtop = set_bits32(arsr2p->ivtop, iv_top, 29, 0); + arsr2p->ivbottom = set_bits32(arsr2p->ivbottom, iv_bottom, 29, 0); + arsr2p->ihinc = set_bits32(arsr2p->ihinc, ih_inc, 22, 0); + arsr2p->ivinc = set_bits32(arsr2p->ivinc, iv_inc, 22, 0); + arsr2p->offset = set_bits32(arsr2p->offset, uv_offset, 22, 0); + arsr2p->mode = set_bits32(arsr2p->mode, arsr2p_bypass, 1, 0); + arsr2p->mode = set_bits32(arsr2p->mode, sharpen_en, 1, 1); + arsr2p->mode = set_bits32(arsr2p->mode, shootdetect_en, 1, 2); + arsr2p->mode = set_bits32(arsr2p->mode, skinctrl_en, 1, 3); + arsr2p->mode = set_bits32(arsr2p->mode, textureanalyhsisen_en, 1, 4); + arsr2p->mode = set_bits32(arsr2p->mode, diintpl_en, 1, 5); + arsr2p->mode = set_bits32(arsr2p->mode, nearest_en, 1, 6); + arsr2p->mode = set_bits32(arsr2p->mode, hscldown_enabled, 1, 7); + arsr2p->mode = set_bits32(arsr2p->mode, imageintpl_dis, 1, 8); + + arsr2p->ihleft1 = set_bits32(arsr2p->ihleft1, outph_left, 29, 0); + arsr2p->ihright1 = set_bits32(arsr2p->ihright1, outph_right, 29, 0); + arsr2p->ivbottom1 = set_bits32(arsr2p->ivbottom1, outpv_bottom, 29, 0); + + return 0; +} + +/******************************************************************************* + ** DSS remove mctl ch&ov mutex for offline + */ +void +hisi_remove_mctl_mutex(struct hisi_fb_data_type *hisifd, int mctl_idx, + uint32_t cmdlist_idxs) +{ + dss_module_reg_t *dss_module = NULL; + int i = 0; + char __iomem *chn_mutex_base = NULL; + char __iomem *cmdlist_base = NULL; + uint32_t offset = 0; + uint32_t cmdlist_idxs_temp = 0; + + BUG_ON(hisifd == NULL); + + dss_module = &(hisifd->dss_module); + cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET; + + for (i = 0; i < DSS_CHN_MAX_DEFINE; i++) { + if (dss_module->mctl_ch_used[i] == 1) { + chn_mutex_base = + dss_module->mctl_ch_base[i].chn_mutex_base + + g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE]; + BUG_ON(chn_mutex_base == NULL); + + set_reg(chn_mutex_base, 0, 32, 0); + } + } + + set_reg(dss_module->mctl_base[mctl_idx] + MCTL_CTL_MUTEX_OV, 0, 32, 0); + + offset = 0x40; + cmdlist_idxs_temp = cmdlist_idxs; + + for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) { + if ((cmdlist_idxs_temp & 0x1) == 0x1) { + set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, + 0x6, 3, 2); + } + cmdlist_idxs_temp = cmdlist_idxs_temp >> 1; + } + +} + +void +hisi_dss_mctl_ov_set_ctl_dbg_reg(struct hisi_fb_data_type *hisifd, + char __iomem *mctl_base, bool enable_cmdlist) +{ + if (hisifd == NULL) { + HISI_FB_ERR("hisifd is null"); + return; + } + + if (enable_cmdlist) { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB03A20, 32, 0); + set_reg(mctl_base + MCTL_CTL_TOP, 0x1, 32, 0); + } else { + set_reg(mctl_base + MCTL_CTL_DBG, 0xB13A00, 32, 0); + if (hisifd->index == PRIMARY_PANEL_IDX) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x2, 32, 0); + } else if (hisifd->index == EXTERNAL_PANEL_IDX) { + set_reg(mctl_base + MCTL_CTL_TOP, 0x3, 32, 0); + } else { + ; + } + } +} + +int +hisi_dss_check_userdata(struct hisi_fb_data_type *hisifd, + dss_overlay_t *pov_req, + dss_overlay_block_t *pov_h_block_infos) +{ + int i = 0; + dss_wb_layer_t *wb_layer = NULL; + + if (hisifd == NULL) { + HISI_FB_ERR("invalid hisifd!"); + return -EINVAL; + } + + if (pov_req == NULL) { + HISI_FB_ERR("fb%d, invalid pov_req!", hisifd->index); + return -EINVAL; + } + + if (pov_h_block_infos == NULL) { + HISI_FB_ERR("fb%d, invalid pov_h_block_infos!", hisifd->index); + return -EINVAL; + } + + if ((pov_req->ov_block_nums <= 0) || + (pov_req->ov_block_nums > HISI_DSS_OV_BLOCK_NUMS)) { + HISI_FB_ERR("fb%d, invalid ov_block_nums=%d!", + hisifd->index, pov_req->ov_block_nums); + return -EINVAL; + } + + if ((pov_h_block_infos->layer_nums <= 0) + || (pov_h_block_infos->layer_nums > MAX_DSS_SRC_NUM)) { + HISI_FB_ERR("fb%d, invalid layer_nums=%d!", + hisifd->index, pov_h_block_infos->layer_nums); + return -EINVAL; + } + + if ((pov_req->ovl_idx < 0) || pov_req->ovl_idx >= DSS_OVL_IDX_MAX) { + HISI_FB_ERR("fb%d, invalid ovl_idx=%d!", + hisifd->index, pov_req->ovl_idx); + return -EINVAL; + } + + if (hisifd->index == PRIMARY_PANEL_IDX) { + if (hisifd->panel_info.dirty_region_updt_support) { + if (pov_req->dirty_rect.x < 0 + || pov_req->dirty_rect.y < 0 + || pov_req->dirty_rect.w < 0 + || pov_req->dirty_rect.h < 0) { + HISI_FB_ERR + ("dirty_rect(%d, %d, %d, %d) is out of range!\n", + pov_req->dirty_rect.x, + pov_req->dirty_rect.y, + pov_req->dirty_rect.w, + pov_req->dirty_rect.h); + return -EINVAL; + } + } + } + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + if (pov_req->wb_enable != 1) { + HISI_FB_ERR("pov_req->wb_enable=%u is invalid!\n", + pov_req->wb_enable); + return -EINVAL; + } + + if ((pov_req->wb_layer_nums <= 0) || + (pov_req->wb_layer_nums > MAX_DSS_DST_NUM)) { + HISI_FB_ERR("fb%d, invalid wb_layer_nums=%d!", + hisifd->index, pov_req->wb_layer_nums); + return -EINVAL; + } + + if (pov_req->wb_ov_rect.x < 0 || pov_req->wb_ov_rect.y < 0) { + HISI_FB_ERR("wb_ov_rect(%d, %d) is out of range!\n", + pov_req->wb_ov_rect.x, + pov_req->wb_ov_rect.y); + return -EINVAL; + } + + if (pov_req->wb_compose_type >= DSS_WB_COMPOSE_TYPE_MAX) { + HISI_FB_ERR("wb_compose_type=%u is invalid!\n", + pov_req->wb_compose_type); + return -EINVAL; + } + + for (i = 0; i < pov_req->wb_layer_nums; i++) { + wb_layer = &(pov_req->wb_layer_infos[i]); + + if (wb_layer->chn_idx != DSS_WCHN_W2) { + if (wb_layer->chn_idx < DSS_WCHN_W0 + || wb_layer->chn_idx > DSS_WCHN_W1) { + HISI_FB_ERR + ("fb%d, wchn_idx=%d is invalid!", + hisifd->index, wb_layer->chn_idx); + return -EINVAL; + } + } + + if (wb_layer->dst.format >= HISI_FB_PIXEL_FORMAT_MAX) { + HISI_FB_ERR("fb%d, format=%d is invalid!", + hisifd->index, + wb_layer->dst.format); + return -EINVAL; + } + + if ((wb_layer->dst.bpp == 0) + || (wb_layer->dst.width == 0) + || (wb_layer->dst.height == 0) + || (wb_layer->dst.stride == 0)) { + HISI_FB_ERR + ("fb%d, bpp=%d, width=%d, height=%d, stride=%d is invalid!", + hisifd->index, wb_layer->dst.bpp, + wb_layer->dst.width, wb_layer->dst.height, + wb_layer->dst.stride); + return -EINVAL; + } +#if 0 + if (wb_layer->dst.mmu_enable) { + if (wb_layer->dst.buf_size == 0) { + HISI_FB_ERR + ("fb%d, buf_size=%d is invalid!", + hisifd->index, + wb_layer->dst.buf_size); + return -EINVAL; + } + } + + if (isYUVSemiPlanar(wb_layer->dst.format) + || isYUVPlanar(wb_layer->dst.format)) { + if ((wb_layer->dst.stride_plane1 == 0) + || (wb_layer->dst.offset_plane1 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane1=%d, offset_plane1=%d is invalid!", + hisifd->index, + wb_layer->dst.stride_plane1, + wb_layer->dst.offset_plane1); + return -EINVAL; + } + } + + if (isYUVPlanar(wb_layer->dst.format)) { + if ((wb_layer->dst.stride_plane2 == 0) + || (wb_layer->dst.offset_plane2 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane2=%d, offset_plane2=%d is invalid!", + hisifd->index, + wb_layer->dst.stride_plane2, + wb_layer->dst.offset_plane2); + return -EINVAL; + } + } +#endif + + if (wb_layer->need_cap & CAP_AFBCE) { + if ((wb_layer->dst.afbc_header_stride == 0) + || (wb_layer->dst.afbc_payload_stride == 0)) { + HISI_FB_ERR + ("fb%d, afbc_header_stride=%d, afbc_payload_stride=%d is invalid!", + hisifd->index, + wb_layer->dst.afbc_header_stride, + wb_layer->dst.afbc_payload_stride); + return -EINVAL; + } + } + + if (wb_layer->dst.csc_mode >= DSS_CSC_MOD_MAX) { + HISI_FB_ERR("fb%d, csc_mode=%d is invalid!", + hisifd->index, + wb_layer->dst.csc_mode); + return -EINVAL; + } + + if (wb_layer->dst.afbc_scramble_mode >= + DSS_AFBC_SCRAMBLE_MODE_MAX) { + HISI_FB_ERR + ("fb%d, afbc_scramble_mode=%d is invalid!", + hisifd->index, + wb_layer->dst.afbc_scramble_mode); + return -EINVAL; + } + + if (wb_layer->src_rect.x < 0 || wb_layer->src_rect.y < 0 + || wb_layer->src_rect.w <= 0 + || wb_layer->src_rect.h <= 0) { + HISI_FB_ERR + ("src_rect(%d, %d, %d, %d) is out of range!\n", + wb_layer->src_rect.x, wb_layer->src_rect.y, + wb_layer->src_rect.w, + wb_layer->src_rect.h); + return -EINVAL; + } + + if (wb_layer->dst_rect.x < 0 || wb_layer->dst_rect.y < 0 + || wb_layer->dst_rect.w <= 0 + || wb_layer->dst_rect.h <= 0) { + HISI_FB_ERR + ("dst_rect(%d, %d, %d, %d) is out of range!\n", + wb_layer->dst_rect.x, wb_layer->dst_rect.y, + wb_layer->dst_rect.w, + wb_layer->dst_rect.h); + return -EINVAL; + } + } + } else { + ; + } + + return 0; +} + +int +hisi_dss_check_layer_par(struct hisi_fb_data_type *hisifd, dss_layer_t *layer) +{ + if (hisifd == NULL) { + HISI_FB_ERR("hisifd is NULL, return!"); + return -EINVAL; + } + + if (layer == NULL) { + HISI_FB_ERR("layer is NULL, return!"); + return -EINVAL; + } + + if (layer->layer_idx < 0 || layer->layer_idx >= MAX_DSS_SRC_NUM) { + HISI_FB_ERR("fb%d, layer_idx=%d is invalid!", hisifd->index, + layer->layer_idx); + return -EINVAL; + } + + if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR)) + return 0; + + if (hisifd->index == AUXILIARY_PANEL_IDX) { + if (layer->chn_idx != DSS_RCHN_V2) { + if (layer->chn_idx < 0 || layer->chn_idx >= DSS_WCHN_W0) { + HISI_FB_ERR("fb%d, rchn_idx=%d is invalid!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } + + if (layer->chn_idx == DSS_RCHN_D2) { + HISI_FB_ERR + ("fb%d, chn_idx[%d] does not used by offline play!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } else { + if (layer->chn_idx < 0 || layer->chn_idx >= DSS_WCHN_W0) { + HISI_FB_ERR("fb%d, rchn_idx=%d is invalid!", + hisifd->index, layer->chn_idx); + return -EINVAL; + } + } + + if (layer->blending < 0 || layer->blending >= HISI_FB_BLENDING_MAX) { + HISI_FB_ERR("fb%d, blending=%d is invalid!", hisifd->index, + layer->blending); + return -EINVAL; + } + + if (layer->img.format >= HISI_FB_PIXEL_FORMAT_MAX) { + HISI_FB_ERR("fb%d, format=%d is invalid!", hisifd->index, + layer->img.format); + return -EINVAL; + } + + if ((layer->img.bpp == 0) || (layer->img.width == 0) + || (layer->img.height == 0) || (layer->img.stride == 0)) { + HISI_FB_ERR + ("fb%d, bpp=%d, width=%d, height=%d, stride=%d is invalid!", + hisifd->index, layer->img.bpp, layer->img.width, + layer->img.height, layer->img.stride); + return -EINVAL; + } +#if 0 + if (layer->img.mmu_enable) { + if (layer->img.buf_size == 0) { + HISI_FB_ERR("fb%d, buf_size=%d is invalid!", + hisifd->index, layer->img.buf_size); + return -EINVAL; + } + } + + if (isYUVSemiPlanar(layer->img.format) + || isYUVPlanar(layer->img.format)) { + if ((layer->img.stride_plane1 == 0) + || (layer->img.offset_plane1 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane1=%d, offset_plane1=%d is invalid!", + hisifd->index, layer->img.stride_plane1, + layer->img.offset_plane1); + return -EINVAL; + } + } + + if (isYUVPlanar(layer->img.format)) { + if ((layer->img.stride_plane2 == 0) + || (layer->img.offset_plane2 == 0)) { + HISI_FB_ERR + ("fb%d, stride_plane2=%d, offset_plane2=%d is invalid!", + hisifd->index, layer->img.stride_plane2, + layer->img.offset_plane2); + return -EINVAL; + } + } +#endif + + if (layer->need_cap & CAP_AFBCD) { + if ((layer->img.afbc_header_stride == 0) + || (layer->img.afbc_payload_stride == 0) + || (layer->img.mmbuf_size == 0)) { + HISI_FB_ERR + ("fb%d, afbc_header_stride=%d, afbc_payload_stride=%d, " + "mmbuf_size=%d is invalid!", + hisifd->index, layer->img.afbc_header_stride, + layer->img.afbc_payload_stride, + layer->img.mmbuf_size); + return -EINVAL; + } + } + + if (layer->img.csc_mode >= DSS_CSC_MOD_MAX) { + HISI_FB_ERR("fb%d, csc_mode=%d is invalid!", hisifd->index, + layer->img.csc_mode); + return -EINVAL; + } + + if (layer->img.afbc_scramble_mode >= DSS_AFBC_SCRAMBLE_MODE_MAX) { + HISI_FB_ERR("fb%d, afbc_scramble_mode=%d is invalid!", + hisifd->index, layer->img.afbc_scramble_mode); + return -EINVAL; + } + + if ((layer->layer_idx != 0) && (layer->need_cap & CAP_BASE)) { + HISI_FB_ERR("fb%d, layer%d is not base!", hisifd->index, + layer->layer_idx); + return -EINVAL; + } + + if (layer->src_rect.x < 0 || layer->src_rect.y < 0 || + layer->src_rect.w <= 0 || layer->src_rect.h <= 0) { + HISI_FB_ERR("src_rect(%d, %d, %d, %d) is out of range!\n", + layer->src_rect.x, layer->src_rect.y, + layer->src_rect.w, layer->src_rect.h); + return -EINVAL; + } + + if (layer->src_rect_mask.x < 0 || layer->src_rect_mask.y < 0 || + layer->src_rect_mask.w < 0 || layer->src_rect_mask.h < 0) { + HISI_FB_ERR("src_rect_mask(%d, %d, %d, %d) is out of range!\n", + layer->src_rect_mask.x, layer->src_rect_mask.y, + layer->src_rect_mask.w, layer->src_rect_mask.h); + return -EINVAL; + } + + if (layer->dst_rect.x < 0 || layer->dst_rect.y < 0 || + layer->dst_rect.w <= 0 || layer->dst_rect.h <= 0) { + HISI_FB_ERR("dst_rect(%d, %d, %d, %d) is out of range!\n", + layer->dst_rect.x, layer->dst_rect.y, + layer->dst_rect.w, layer->dst_rect.h); + return -EINVAL; + } + + return 0; +} + +void hisifb_disreset_dss(struct hisi_fb_data_type *hisifd) +{ +} diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h new file mode 100755 index 000000000000..1d5b1fc0cc92 --- /dev/null +++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_utils_hi3660.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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. + * + */ +#ifndef _HISI_OVERLAY_UTILS_PLATFORM_H_ +#define _HISI_OVERLAY_UTILS_PLATFORM_H_ + +#define HISI_DSS_VERSION_V400 + +#define GPIO_LCD_POWER_1V2 (54) +#define GPIO_LCD_STANDBY (67) +#define GPIO_LCD_RESETN (65) +#define GPIO_LCD_GATING (60) +#define GPIO_LCD_PCLK_GATING (58) +#define GPIO_LCD_REFCLK_GATING (59) +#define GPIO_LCD_SPICS (168) +#define GPIO_LCD_DRV_EN (73) + +#define GPIO_PG_SEL_A (72) +#define GPIO_TX_RX_A (74) +#define GPIO_PG_SEL_B (76) +#define GPIO_TX_RX_B (78) + +/******************************************************************************* + ** + */ +#define CRGPERI_PLL0_CLK_RATE (1600000000UL) +#define CRGPERI_PLL2_CLK_RATE (960000000UL) +#define CRGPERI_PLL3_CLK_RATE (1600000000UL) + +#define DEFAULT_DSS_CORE_CLK_08V_RATE (535000000UL) +#define DEFAULT_DSS_CORE_CLK_07V_RATE (400000000UL) +#define DEFAULT_PCLK_DSS_RATE (114000000UL) +#define DEFAULT_PCLK_PCTRL_RATE (80000000UL) +#define DSS_MAX_PXL0_CLK_288M (288000000UL) + +#define MMBUF_SIZE_MAX (288 * 1024) +#define HISI_DSS_CMDLIST_MAX (16) +#define HISI_DSS_CMDLIST_IDXS_MAX (0xFFFF) +#define HISI_DSS_COPYBIT_CMDLIST_IDXS (0xC000) +#define HISI_DSS_DPP_MAX_SUPPORT_BIT (0x7ff) +#define HISIFB_DSS_PLATFORM_TYPE (FB_ACCEL_HI366x | FB_ACCEL_PLATFORM_TYPE_ASIC) + +#define DSS_MIF_SMMU_SMRX_IDX_STEP (16) +#define CRG_PERI_DIS3_DEFAULT_VAL (0x0002F000) +#define SCF_LINE_BUF (2560) +#define DSS_GLB_MODULE_CLK_SEL_DEFAULT_VAL (0xF0000008) +#define DSS_LDI_CLK_SEL_DEFAULT_VAL (0x00000004) +#define DSS_DBUF_MEM_CTRL_DEFAULT_VAL (0x00000008) +#define DSS_SMMU_RLD_EN0_DEFAULT_VAL (0xffffffff) +#define DSS_SMMU_RLD_EN1_DEFAULT_VAL (0xffffff8f) +#define DSS_SMMU_OUTSTANDING_VAL (0xf) +#define DSS_MIF_CTRL2_INVAL_SEL3_STRIDE_MASK (0xc) +#define DSS_AFBCE_ENC_OS_CFG_DEFAULT_VAL (0x7) +#define TUI_SEC_RCH (DSS_RCHN_V0) +#define DSS_CHN_MAX_DEFINE (DSS_COPYBIT_MAX) + +/* perf stat */ +#define DSS_DEVMEM_PERF_BASE (0xFDF10000) +#define CRG_PERIPH_APB_PERRSTSTAT0_REG (0x68) +#define CRG_PERIPH_APB_IP_RST_PERF_STAT_BIT (18) +#define PERF_SAMPSTOP_REG (0x10) +#define DEVMEM_PERF_SIZE (0x100) + +#endif -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 8/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei @ 2017-02-07 2:35 ` cailiwei -1 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) mode change 100644 => 100755 arch/arm64/boot/dts/hisilicon/hi3660.dtsi diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi old mode 100644 new mode 100755 index 5389799ff371..2ad11800dd67 --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi @@ -132,6 +132,54 @@ clock-frequency = <1920000>; }; + /* display start */ + framebuffer@E8600000 { + #address-cells = <2>; + #size-cells = <2>; + compatible = "hisilicon,hisifb"; + fastboot_enable_flag = <0>; + fake_lcd_flag = <0>; + dss_base_phy = <0xE8600000>; + // DSS, PERI_CRG, SCTRL, PCTRL, NOC_DSS_Service_Target, MMBUF_CFG + reg = <0 0xE8600000 0 0x80000>, <0 0xFFF35000 0 0x1000>, <0 0xFFF0A000 0 0x1000>, <0 0xE8A09000 0 0x1000>, + <0 0xE86C0000 0 0x10000>, <0 0xFFF02000 0 0x1000>, <0 0xFFF31000 0 0x1000>; + // dss-pdp, dss-sdp, dss-adp, dss-dsi0, dss-dsi1 irq + interrupts = <0 245 4>, <0 246 4>, <0 247 4>, <0 251 4>, <0 252 4>; + //regulator_dsssubsys-supply = <&dsssubsys>; + //regulator_mmbuf-supply = <&mmbuf>; + clocks = <&crg_ctrl HI3660_ACLK_GATE_DSS>, <&crg_ctrl HI3660_PCLK_GATE_DSS>, <&crg_ctrl HI3660_CLK_GATE_EDC0>, + <&crg_ctrl HI3660_CLK_GATE_LDI0>, <&crg_ctrl HI3660_CLK_GATE_LDI1>, <&sctrl HI3660_CLK_GATE_DSS_AXI_MM>, + <&sctrl HI3660_PCLK_GATE_MMBUF>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY0_REF>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY1_REF>, + <&crg_ctrl HI3660_CLK_GATE_TXDPHY0_CFG>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY1_CFG>, <&crg_ctrl HI3660_PCLK_GATE_DSI0>, + <&crg_ctrl HI3660_PCLK_GATE_DSI1>;//, <&crg_ctrl HI3660_PCLK_GATE_PCTRL>; + clock-names = "aclk_dss", "pclk_dss", "clk_edc0", "clk_ldi0", "clk_ldi1", + "clk_dss_axi_mm", "pclk_mmbuf", + "clk_txdphy0_ref", "clk_txdphy1_ref", "clk_txdphy0_cfg", "clk_txdphy1_cfg", + "pclk_dsi0", "pclk_dsi1";//, "pclk_pctrl"; + status = "ok"; + fpga_flag = <0>; + + /*iommu_info { + start-addr = <0x8000>; + size = <0xbfff8000>; + };*/ + }; + + panel_lcd_hikey { + #address-cells = <2>; + #size-cells = <2>; + compatible = "hisilicon,mipi_hikey"; + lcd-bl-type = <0>; + lcd-display-type = <8>; + //vdd-supply = <&ldo3>; + lcd-ifbc-type = <0>; + gpios = <&gpio27 0 0>, <&gpio27 2 0>, <&gpio22 6 0>, <&gpio2 4 0>; + gpio_nums = <216 218 182 20>; + fpga_flag = <0>; + status = "disabled"; + }; + /* display end */ + soc { compatible = "simple-bus"; #address-cells = <2>; -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 8/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-07 2:35 ` cailiwei 0 siblings, 0 replies; 15+ messages in thread From: cailiwei @ 2017-02-07 2:35 UTC (permalink / raw) To: linux-fbdev, linux-kernel, b.zolnierkie, guodong.xu Cc: suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan, cailiwei From: Levy-Cai <cailiwei@hisilicon.com> Add framebuffer driver for hi3660 SoC, this driver include lcd driver & Hdmi adv7533/adv7535 driver, support lcd display at 1080p@60 and hdmi display at 1080p@60. Signed-off-by: cailiwei <cailiwei@hisilicon.com> --- arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) mode change 100644 => 100755 arch/arm64/boot/dts/hisilicon/hi3660.dtsi diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi old mode 100644 new mode 100755 index 5389799ff371..2ad11800dd67 --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi @@ -132,6 +132,54 @@ clock-frequency = <1920000>; }; + /* display start */ + framebuffer@E8600000 { + #address-cells = <2>; + #size-cells = <2>; + compatible = "hisilicon,hisifb"; + fastboot_enable_flag = <0>; + fake_lcd_flag = <0>; + dss_base_phy = <0xE8600000>; + // DSS, PERI_CRG, SCTRL, PCTRL, NOC_DSS_Service_Target, MMBUF_CFG + reg = <0 0xE8600000 0 0x80000>, <0 0xFFF35000 0 0x1000>, <0 0xFFF0A000 0 0x1000>, <0 0xE8A09000 0 0x1000>, + <0 0xE86C0000 0 0x10000>, <0 0xFFF02000 0 0x1000>, <0 0xFFF31000 0 0x1000>; + // dss-pdp, dss-sdp, dss-adp, dss-dsi0, dss-dsi1 irq + interrupts = <0 245 4>, <0 246 4>, <0 247 4>, <0 251 4>, <0 252 4>; + //regulator_dsssubsys-supply = <&dsssubsys>; + //regulator_mmbuf-supply = <&mmbuf>; + clocks = <&crg_ctrl HI3660_ACLK_GATE_DSS>, <&crg_ctrl HI3660_PCLK_GATE_DSS>, <&crg_ctrl HI3660_CLK_GATE_EDC0>, + <&crg_ctrl HI3660_CLK_GATE_LDI0>, <&crg_ctrl HI3660_CLK_GATE_LDI1>, <&sctrl HI3660_CLK_GATE_DSS_AXI_MM>, + <&sctrl HI3660_PCLK_GATE_MMBUF>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY0_REF>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY1_REF>, + <&crg_ctrl HI3660_CLK_GATE_TXDPHY0_CFG>, <&crg_ctrl HI3660_CLK_GATE_TXDPHY1_CFG>, <&crg_ctrl HI3660_PCLK_GATE_DSI0>, + <&crg_ctrl HI3660_PCLK_GATE_DSI1>;//, <&crg_ctrl HI3660_PCLK_GATE_PCTRL>; + clock-names = "aclk_dss", "pclk_dss", "clk_edc0", "clk_ldi0", "clk_ldi1", + "clk_dss_axi_mm", "pclk_mmbuf", + "clk_txdphy0_ref", "clk_txdphy1_ref", "clk_txdphy0_cfg", "clk_txdphy1_cfg", + "pclk_dsi0", "pclk_dsi1";//, "pclk_pctrl"; + status = "ok"; + fpga_flag = <0>; + + /*iommu_info { + start-addr = <0x8000>; + size = <0xbfff8000>; + };*/ + }; + + panel_lcd_hikey { + #address-cells = <2>; + #size-cells = <2>; + compatible = "hisilicon,mipi_hikey"; + lcd-bl-type = <0>; + lcd-display-type = <8>; + //vdd-supply = <&ldo3>; + lcd-ifbc-type = <0>; + gpios = <&gpio27 0 0>, <&gpio27 2 0>, <&gpio22 6 0>, <&gpio2 4 0>; + gpio_nums = <216 218 182 20>; + fpga_flag = <0>; + status = "disabled"; + }; + /* display end */ + soc { compatible = "simple-bus"; #address-cells = <2>; -- 2.12.0-rc0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC 2017-02-07 2:35 ` cailiwei @ 2017-02-08 16:07 ` Bartlomiej Zolnierkiewicz -1 siblings, 0 replies; 15+ messages in thread From: Bartlomiej Zolnierkiewicz @ 2017-02-08 16:07 UTC (permalink / raw) To: cailiwei Cc: linux-fbdev, linux-kernel, guodong.xu, suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan Hi, I cannot merge this upstream as it was collectively decided that there should be no new fbdev drivers (DRM subsystem should be used instead). [ You may consider submitting this driver to staging subsystem to make hardware usable by kernel while proper DRM driver is being developed. ] Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics On Tuesday, February 07, 2017 10:35:52 AM cailiwei wrote: > From: Levy-Cai <cailiwei@hisilicon.com> > > Add framebuffer driver for hi3660 SoC, this driver include lcd > driver & Hdmi adv7533/adv7535 driver, support lcd display at > 1080p@60 and hdmi display at 1080p@60. > > Signed-off-by: cailiwei <cailiwei@hisilicon.com> > --- > drivers/video/fbdev/Kconfig | 11 ++++++++++ > drivers/video/fbdev/Makefile | 1 + > drivers/video/fbdev/hisi/Kconfig | 6 +++++ > drivers/video/fbdev/hisi/dss/Makefile | 41 +++++++++++++++++++++++++++++++++++ > 4 files changed, 59 insertions(+) > mode change 100644 => 100755 drivers/video/fbdev/Kconfig > mode change 100644 => 100755 drivers/video/fbdev/Makefile > create mode 100755 drivers/video/fbdev/hisi/Kconfig > create mode 100755 drivers/video/fbdev/hisi/dss/Makefile > > diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig > old mode 100644 > new mode 100755 > index 5d3b0db5ce0a..85c46cc75908 > --- a/drivers/video/fbdev/Kconfig > +++ b/drivers/video/fbdev/Kconfig > @@ -2429,6 +2429,16 @@ config FB_HYPERV > help > This framebuffer driver supports Microsoft Hyper-V Synthetic Video. > > +config FB_HISI > + tristate "Hisilicon Framebuffer support" > + depends on FB > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + select REGMAP > + help > + This framebuffer driver supports Hisilicon FB. > + > config FB_SIMPLE > bool "Simple framebuffer support" > depends on (FB = y) > @@ -2448,6 +2458,7 @@ config FB_SIMPLE > source "drivers/video/fbdev/omap/Kconfig" > source "drivers/video/fbdev/omap2/Kconfig" > source "drivers/video/fbdev/mmp/Kconfig" > +source "drivers/video/fbdev/hisi/Kconfig" > > config FB_SH_MOBILE_MERAM > tristate "SuperH Mobile MERAM read ahead support" > diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile > old mode 100644 > new mode 100755 > index ee8c81405a7f..a10d3d2793e3 > --- a/drivers/video/fbdev/Makefile > +++ b/drivers/video/fbdev/Makefile > @@ -23,6 +23,7 @@ obj-$(CONFIG_FB_I740) += i740fb.o > obj-$(CONFIG_FB_MATROX) += matrox/ > obj-$(CONFIG_FB_RIVA) += riva/ > obj-$(CONFIG_FB_NVIDIA) += nvidia/ > +obj-$(CONFIG_FB_HISI) += hisi/dss/ > obj-$(CONFIG_FB_ATY) += aty/ macmodes.o > obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o > obj-$(CONFIG_FB_RADEON) += aty/ > diff --git a/drivers/video/fbdev/hisi/Kconfig b/drivers/video/fbdev/hisi/Kconfig > new file mode 100755 > index 000000000000..c30747d52a38 > --- /dev/null > +++ b/drivers/video/fbdev/hisi/Kconfig > @@ -0,0 +1,6 @@ > +config HISI_FB_KIRIN960 > + tristate "HISI FB KIRIN960 Framebuffer support" > + depends on FB_HISI > + > + help > + This framebuffer driver supports KIRIN960 FB. > diff --git a/drivers/video/fbdev/hisi/dss/Makefile b/drivers/video/fbdev/hisi/dss/Makefile > new file mode 100755 > index 000000000000..60004880dd80 > --- /dev/null > +++ b/drivers/video/fbdev/hisi/dss/Makefile > @@ -0,0 +1,41 @@ > +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) > +obj-$(CONFIG_HISI_FB_KIRIN960) := hisifb.o > +endif > + > +hisifb-objs := \ > + hisi_mipi_dsi_host.o \ > + hisi_mipi_dsi.o \ > + hisi_dpe.o \ > + hisi_fb_panel.o \ > + hisi_fb_isr.o \ > + hisi_fb_vsync.o \ > + hisi_fb_buf_sync.o \ > + hisi_fb_bl.o \ > + hisi_fb_utils.o \ > + hisi_fb.o \ > + hisi_overlay_utils.o \ > + hisi_block_algorithm.o \ > + hisi_overlay_online.o \ > + hisi_overlay_cmdlist_utils.o > + > +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) > +hisifb-objs += \ > + hisi_dpe_utils_hi3660.o \ > + hisi_overlay_utils_hi3660.o \ > + panel/mipi_hikey_nte300nts.o \ > + hdmi/adv75xx.o \ > + hdmi/mipi_adi_hdmi.o > +endif > + > +EXTRA_CFLAGS += -Idrivers/video/hisi/dss \ > + -Idrivers/video/hisi/panel \ > + -Idrivers/video/hisi \ > + -Iinclude \ > + -Idrivers/staging/android > + > +ifeq ($(CONFIG_HISI_PERIDVFS),y) > +EXTRA_CFLAGS += -Idrivers/clk/hisi/peri_dvfs > +endif > + > +clean: > + rm *.o .*cmd ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC @ 2017-02-08 16:07 ` Bartlomiej Zolnierkiewicz 0 siblings, 0 replies; 15+ messages in thread From: Bartlomiej Zolnierkiewicz @ 2017-02-08 16:07 UTC (permalink / raw) To: cailiwei Cc: linux-fbdev, linux-kernel, guodong.xu, suzhuangluan, dengqingshan, xuhongtao8, zhengwanchun, shizongxuan Hi, I cannot merge this upstream as it was collectively decided that there should be no new fbdev drivers (DRM subsystem should be used instead). [ You may consider submitting this driver to staging subsystem to make hardware usable by kernel while proper DRM driver is being developed. ] Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics On Tuesday, February 07, 2017 10:35:52 AM cailiwei wrote: > From: Levy-Cai <cailiwei@hisilicon.com> > > Add framebuffer driver for hi3660 SoC, this driver include lcd > driver & Hdmi adv7533/adv7535 driver, support lcd display at > 1080p@60 and hdmi display at 1080p@60. > > Signed-off-by: cailiwei <cailiwei@hisilicon.com> > --- > drivers/video/fbdev/Kconfig | 11 ++++++++++ > drivers/video/fbdev/Makefile | 1 + > drivers/video/fbdev/hisi/Kconfig | 6 +++++ > drivers/video/fbdev/hisi/dss/Makefile | 41 +++++++++++++++++++++++++++++++++++ > 4 files changed, 59 insertions(+) > mode change 100644 => 100755 drivers/video/fbdev/Kconfig > mode change 100644 => 100755 drivers/video/fbdev/Makefile > create mode 100755 drivers/video/fbdev/hisi/Kconfig > create mode 100755 drivers/video/fbdev/hisi/dss/Makefile > > diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig > old mode 100644 > new mode 100755 > index 5d3b0db5ce0a..85c46cc75908 > --- a/drivers/video/fbdev/Kconfig > +++ b/drivers/video/fbdev/Kconfig > @@ -2429,6 +2429,16 @@ config FB_HYPERV > help > This framebuffer driver supports Microsoft Hyper-V Synthetic Video. > > +config FB_HISI > + tristate "Hisilicon Framebuffer support" > + depends on FB > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + select REGMAP > + help > + This framebuffer driver supports Hisilicon FB. > + > config FB_SIMPLE > bool "Simple framebuffer support" > depends on (FB = y) > @@ -2448,6 +2458,7 @@ config FB_SIMPLE > source "drivers/video/fbdev/omap/Kconfig" > source "drivers/video/fbdev/omap2/Kconfig" > source "drivers/video/fbdev/mmp/Kconfig" > +source "drivers/video/fbdev/hisi/Kconfig" > > config FB_SH_MOBILE_MERAM > tristate "SuperH Mobile MERAM read ahead support" > diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile > old mode 100644 > new mode 100755 > index ee8c81405a7f..a10d3d2793e3 > --- a/drivers/video/fbdev/Makefile > +++ b/drivers/video/fbdev/Makefile > @@ -23,6 +23,7 @@ obj-$(CONFIG_FB_I740) += i740fb.o > obj-$(CONFIG_FB_MATROX) += matrox/ > obj-$(CONFIG_FB_RIVA) += riva/ > obj-$(CONFIG_FB_NVIDIA) += nvidia/ > +obj-$(CONFIG_FB_HISI) += hisi/dss/ > obj-$(CONFIG_FB_ATY) += aty/ macmodes.o > obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o > obj-$(CONFIG_FB_RADEON) += aty/ > diff --git a/drivers/video/fbdev/hisi/Kconfig b/drivers/video/fbdev/hisi/Kconfig > new file mode 100755 > index 000000000000..c30747d52a38 > --- /dev/null > +++ b/drivers/video/fbdev/hisi/Kconfig > @@ -0,0 +1,6 @@ > +config HISI_FB_KIRIN960 > + tristate "HISI FB KIRIN960 Framebuffer support" > + depends on FB_HISI > + > + help > + This framebuffer driver supports KIRIN960 FB. > diff --git a/drivers/video/fbdev/hisi/dss/Makefile b/drivers/video/fbdev/hisi/dss/Makefile > new file mode 100755 > index 000000000000..60004880dd80 > --- /dev/null > +++ b/drivers/video/fbdev/hisi/dss/Makefile > @@ -0,0 +1,41 @@ > +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) > +obj-$(CONFIG_HISI_FB_KIRIN960) := hisifb.o > +endif > + > +hisifb-objs := \ > + hisi_mipi_dsi_host.o \ > + hisi_mipi_dsi.o \ > + hisi_dpe.o \ > + hisi_fb_panel.o \ > + hisi_fb_isr.o \ > + hisi_fb_vsync.o \ > + hisi_fb_buf_sync.o \ > + hisi_fb_bl.o \ > + hisi_fb_utils.o \ > + hisi_fb.o \ > + hisi_overlay_utils.o \ > + hisi_block_algorithm.o \ > + hisi_overlay_online.o \ > + hisi_overlay_cmdlist_utils.o > + > +ifeq ($(CONFIG_HISI_FB_KIRIN960),y) > +hisifb-objs += \ > + hisi_dpe_utils_hi3660.o \ > + hisi_overlay_utils_hi3660.o \ > + panel/mipi_hikey_nte300nts.o \ > + hdmi/adv75xx.o \ > + hdmi/mipi_adi_hdmi.o > +endif > + > +EXTRA_CFLAGS += -Idrivers/video/hisi/dss \ > + -Idrivers/video/hisi/panel \ > + -Idrivers/video/hisi \ > + -Iinclude \ > + -Idrivers/staging/android > + > +ifeq ($(CONFIG_HISI_PERIDVFS),y) > +EXTRA_CFLAGS += -Idrivers/clk/hisi/peri_dvfs > +endif > + > +clean: > + rm *.o .*cmd ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2017-02-08 16:41 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <CGME20170207024027epcas5p2528e797ee0c34cb60d97f0b659f4acbf@epcas5p2.samsung.com> 2017-02-07 2:35 ` [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC cailiwei 2017-02-07 2:35 ` cailiwei 2017-02-07 2:35 ` [PATCH 2/8] " cailiwei 2017-02-07 2:35 ` cailiwei 2017-02-07 2:35 ` [PATCH 3/8] " cailiwei 2017-02-07 2:35 ` [PATCH 4/8] " cailiwei 2017-02-07 2:35 ` [PATCH 5/8] " cailiwei 2017-02-07 2:35 ` cailiwei 2017-02-07 2:35 ` [PATCH 6/8] " cailiwei 2017-02-07 2:35 ` cailiwei 2017-02-07 2:35 ` [PATCH 7/8] " cailiwei 2017-02-07 2:35 ` [PATCH 8/8] " cailiwei 2017-02-07 2:35 ` cailiwei 2017-02-08 16:07 ` [PATCH 1/8] " Bartlomiej Zolnierkiewicz 2017-02-08 16:07 ` Bartlomiej Zolnierkiewicz
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.