summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFancy Fang <chen.fang@nxp.com>2018-08-07 18:04:54 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:59:22 +0800
commit5757e468fcee4a499d57e9fcb83075f15ae5fa26 (patch)
tree535815276eb1566584b540affca8db81c93aa251
parente662645ff44fc640ed0354702873975428a0fffa (diff)
MLK-19152-1 gpu: imx: lcdif: realize fb horizontal crop via Pigeon Mode
According to the LCDIF specification, the Legacy Mode does not support cropping function in the horizontal direction, so add Pigeon Mode which can support this kind of function. And when enable this mode, the legacy horizontal timings configuration should use stride value but not the active width, and related pigeon configuration should use the active width but not the stride value. Signed-off-by: Fancy Fang <chen.fang@nxp.com> (cherry picked from commit e6da9542693dd585972897f62748a101f5726a74)
-rw-r--r--drivers/gpu/imx/lcdif/lcdif-common.c58
-rw-r--r--drivers/gpu/imx/lcdif/lcdif-regs.h16
-rw-r--r--include/video/imx-lcdif.h2
3 files changed, 76 insertions, 0 deletions
diff --git a/drivers/gpu/imx/lcdif/lcdif-common.c b/drivers/gpu/imx/lcdif/lcdif-common.c
index a5f4e8bc58c1..af3ad161413d 100644
--- a/drivers/gpu/imx/lcdif/lcdif-common.c
+++ b/drivers/gpu/imx/lcdif/lcdif-common.c
@@ -377,6 +377,64 @@ void lcdif_set_fb_addr(struct lcdif_soc *lcdif, int id, u32 addr)
}
EXPORT_SYMBOL(lcdif_set_fb_addr);
+void lcdif_set_fb_hcrop(struct lcdif_soc *lcdif, u32 src_w,
+ u32 fb_w, bool crop)
+{
+ u32 mask_cnt, htotal, hcount;
+ u32 vdctrl2, vdctrl3, vdctrl4, transfer_count;
+ u32 pigeon_12_0, pigeon_12_1, pigeon_12_2;
+
+ if (!crop) {
+ writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_0);
+ writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+ return;
+ }
+
+ /* transfer_count's hcount, vdctrl2's htotal and vdctrl4's
+ * H_VALID_DATA_CNT should use fb width instead of hactive
+ * when requires cropping.
+ * */
+ transfer_count = readl(lcdif->base + LCDIF_TRANSFER_COUNT);
+ hcount = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+
+ transfer_count &= ~TRANSFER_COUNT_SET_HCOUNT(0xffff);
+ transfer_count |= TRANSFER_COUNT_SET_HCOUNT(fb_w);
+ writel(transfer_count, lcdif->base + LCDIF_TRANSFER_COUNT);
+
+ vdctrl2 = readl(lcdif->base + LCDIF_VDCTRL2);
+ htotal = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2);
+ htotal += fb_w - hcount;
+ vdctrl2 &= ~VDCTRL2_SET_HSYNC_PERIOD(0x3ffff);
+ vdctrl2 |= VDCTRL2_SET_HSYNC_PERIOD(htotal);
+ writel(vdctrl2, lcdif->base + LCDIF_VDCTRL2);
+
+ vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+ vdctrl4 &= ~SET_DOTCLK_H_VALID_DATA_CNT(0x3ffff);
+ vdctrl4 |= SET_DOTCLK_H_VALID_DATA_CNT(fb_w);
+ writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+
+ /* configure related pigeon registers */
+ vdctrl3 = readl(lcdif->base + LCDIF_VDCTRL3);
+ mask_cnt = GET_HOR_WAIT_CNT(vdctrl3) - 5;
+
+ pigeon_12_0 = PIGEON_12_0_SET_STATE_MASK(0x24) |
+ PIGEON_12_0_SET_MASK_CNT(mask_cnt) |
+ PIGEON_12_0_SET_MASK_CNT_SEL(0x6) |
+ PIGEON_12_0_POL_ACTIVE_LOW |
+ PIGEON_12_0_EN;
+ writel(pigeon_12_0, lcdif->base + HW_EPDC_PIGEON_12_0);
+
+ pigeon_12_1 = PIGEON_12_1_SET_CLR_CNT(src_w) |
+ PIGEON_12_1_SET_SET_CNT(0x0);
+ writel(pigeon_12_1, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+ pigeon_12_2 = 0x0;
+ writel(pigeon_12_2, lcdif->base + HW_EPDC_PIGEON_12_2);
+}
+EXPORT_SYMBOL(lcdif_set_fb_hcrop);
+
+
void lcdif_set_mode(struct lcdif_soc *lcdif, struct videomode *vmode)
{
const struct of_device_id *of_id =
diff --git a/drivers/gpu/imx/lcdif/lcdif-regs.h b/drivers/gpu/imx/lcdif/lcdif-regs.h
index 0cfec71d6af1..de2f1c55591c 100644
--- a/drivers/gpu/imx/lcdif/lcdif-regs.h
+++ b/drivers/gpu/imx/lcdif/lcdif-regs.h
@@ -32,6 +32,11 @@
#define LCDIF_VDCTRL3 0xa0
#define LCDIF_VDCTRL4 0xb0
+/* pigeon registers for crop */
+#define HW_EPDC_PIGEON_12_0 0xb00
+#define HW_EPDC_PIGEON_12_1 0xb10
+#define HW_EPDC_PIGEON_12_2 0xb20
+
/* reg bit manipulation */
#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
@@ -115,6 +120,17 @@
#define VDCTRL4_SYNC_SIGNALS_ON BIT(18)
#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+#define PIGEON_12_0_SET_STATE_MASK(x) REG_PUT((x), 31, 24)
+#define PIGEON_12_0_SET_MASK_CNT(x) REG_PUT((x), 23, 12)
+#define PIGEON_12_0_SET_MASK_CNT_SEL(x) REG_PUT((x), 11, 8)
+#define PIGEON_12_0_SET_OFFSET(x) REG_PUT((x), 7, 4)
+#define PIGEON_12_0_SET_INC_SEL(x) REG_PUT((x), 3, 2)
+#define PIGEON_12_0_POL_ACTIVE_LOW BIT(1)
+#define PIGEON_12_0_EN BIT(0)
+
+#define PIGEON_12_1_SET_CLR_CNT(x) REG_PUT((x), 31, 16)
+#define PIGEON_12_1_SET_SET_CNT(x) REG_PUT((x), 15, 0)
+
#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */
#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
diff --git a/include/video/imx-lcdif.h b/include/video/imx-lcdif.h
index ed43e80bdd2b..6597e46d5ca1 100644
--- a/include/video/imx-lcdif.h
+++ b/include/video/imx-lcdif.h
@@ -32,6 +32,8 @@ int lcdif_get_bus_fmt_from_pix_fmt(struct lcdif_soc *lcdif,
int lcdif_set_pix_fmt(struct lcdif_soc *lcdif, u32 format);
void lcdif_set_fb_addr(struct lcdif_soc *lcdif, int id, u32 addr);
void lcdif_set_mode(struct lcdif_soc *lcdif, struct videomode *vmode);
+void lcdif_set_fb_hcrop(struct lcdif_soc *lcdif, u32 src_w,
+ u32 fb_w, bool crop);
void lcdif_enable_controller(struct lcdif_soc *lcdif);
void lcdif_disable_controller(struct lcdif_soc *lcdif);
void lcdif_dump_registers(struct lcdif_soc *lcdif);