[3/7] drm/hisilicon:Add crtc for DE

Submitted by lijianhua on Feb. 29, 2016, 12:58 a.m.

Details

Message ID 1456707521-59036-4-git-send-email-jueying0518@gmail.com
State New
Headers show
Series "Add DRM driver for Hisilicon hi1710" ( rev: 1 ) in DRI devel

Not browsing as part of any series.

Commit Message

lijianhua Feb. 29, 2016, 12:58 a.m.
Add crtc funcs and helper funcs for DE.

Signed-off-by: lijianhua <jueying0518@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 279 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  20 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   1 +
 4 files changed, 306 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index 35a675c..5d3ed66 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -18,6 +18,7 @@ 
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_hw.h"
+#include "hibmc_drm_de.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -156,3 +157,281 @@  int hibmc_plane_init(struct drm_device *dev)
 	return 0;
 }
 
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	/* power mode 0 is default. */
+	set_power_mode(POWER_MODE_CTRL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = PEEK32(CURRENT_GATE);
+	reg = FIELD_SET(reg, CURRENT_GATE, DISPLAY, ON);
+	reg = FIELD_SET(reg, CURRENT_GATE, LOCALMEM, ON);
+	set_current_gate(reg);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+
+	set_power_mode(POWER_MODE_CTRL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = PEEK32(CURRENT_GATE);
+	reg = FIELD_SET(reg, CURRENT_GATE, DISPLAY, OFF);
+	reg = FIELD_SET(reg, CURRENT_GATE, LOCALMEM, OFF);
+	set_current_gate(reg);
+}
+
+int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
+			    struct drm_crtc_state *state)
+{
+	return 0;
+}
+
+unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct panel_pll pll = {0};
+
+	/* Note that all PLL's have the same format. Here,
+     * we just use Panel PLL parameter to work out the bit
+     * fields in the register.On returning a 32 bit number, the value can
+     * be applied to any PLL in the calling function.
+     */
+	pllreg = FIELD_SET(0, PANEL_PLL_CTRL, BYPASS, OFF) |
+	FIELD_SET(0, PANEL_PLL_CTRL, POWER,  ON) |
+	FIELD_SET(0, PANEL_PLL_CTRL, INPUT,  OSC) |
+	FIELD_VALUE(0, PANEL_PLL_CTRL, POD,    pll.POD) |
+	FIELD_VALUE(0, PANEL_PLL_CTRL, OD,     pll.OD) |
+	FIELD_VALUE(0, PANEL_PLL_CTRL, N,      pll.N) |
+	FIELD_VALUE(0, PANEL_PLL_CTRL, M,      pll.M);
+
+	return pllreg;
+}
+
+void set_vclock_hisilicon(unsigned long pll)
+{
+	unsigned long tmp0, tmp1;
+
+    /* 1. outer_bypass_n=0 */
+	tmp0 = PEEK32(CRT_PLL1_HS);
+	tmp0 &= 0xBFFFFFFF;
+	POKE32(CRT_PLL1_HS, tmp0);
+
+	/* 2. pll_pd=1?inter_bypass=1 */
+	POKE32(CRT_PLL1_HS, 0x21000000);
+
+	/* 3. config pll */
+	POKE32(CRT_PLL1_HS, pll);
+
+	/* 4. delay  */
+	mdelay(1);
+
+	/* 5. pll_pd =0 */
+	tmp1 = pll & ~0x01000000;
+	POKE32(CRT_PLL1_HS, tmp1);
+
+	/* 6. delay  */
+	mdelay(1);
+
+	/* 7. inter_bypass=0 */
+	tmp1 &= ~0x20000000;
+	POKE32(CRT_PLL1_HS, tmp1);
+
+	/* 8. delay  */
+	mdelay(1);
+
+	/* 9. outer_bypass_n=1 */
+	tmp1 |= 0x40000000;
+	POKE32(CRT_PLL1_HS, tmp1);
+}
+
+/* This function takes care the extra registers and bit fields required to
+*setup a mode in board.
+*Explanation about Display Control register:
+*FPGA only supports 7 predefined pixel clocks, and clock select is
+*in bit 4:0 of new register 0x802a8.
+*/
+unsigned int display_ctrl_adjust(struct drm_display_mode *mode,
+				 unsigned int ctrl)
+{
+	unsigned long x, y;
+	unsigned long pll1; /* bit[31:0] of PLL */
+	unsigned long pll2; /* bit[63:32] of PLL */
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	/* Hisilicon has to set up a new register for PLL control
+	 *(CRT_PLL1_HS & CRT_PLL2_HS).
+	 */
+	if (x == 800 && y == 600) {
+		pll1 = CRT_PLL1_HS_40MHZ;
+		pll2 = CRT_PLL2_HS_40MHZ;
+	} else if (x == 1024 && y == 768) {
+		pll1 = CRT_PLL1_HS_65MHZ;
+		pll2 = CRT_PLL2_HS_65MHZ;
+	} else if (x == 1152 && y == 864) {
+		pll1 = CRT_PLL1_HS_80MHZ_1152;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 768) {
+		pll1 = CRT_PLL1_HS_80MHZ;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 720) {
+		pll1 = CRT_PLL1_HS_74MHZ;
+		pll2 = CRT_PLL2_HS_74MHZ;
+	} else if (x == 1280 && y == 960) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1280 && y == 1024) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1600 && y == 1200) {
+		pll1 = CRT_PLL1_HS_162MHZ;
+		pll2 = CRT_PLL2_HS_162MHZ;
+	} else if (x == 1920 && y == 1080) {
+		pll1 = CRT_PLL1_HS_148MHZ;
+		pll2 = CRT_PLL2_HS_148MHZ;
+	} else if (x == 1920 && y == 1200) {
+		pll1 = CRT_PLL1_HS_193MHZ;
+		pll2 = CRT_PLL2_HS_193MHZ;
+	} else /* default to VGA clock */ {
+		pll1 = CRT_PLL1_HS_25MHZ;
+		pll2 = CRT_PLL2_HS_25MHZ;
+	}
+
+	POKE32(CRT_PLL2_HS, pll2);
+	set_vclock_hisilicon(pll1);
+
+	/* Hisilicon has to set up the top-left and bottom-right
+	 * registers as well.
+	 * Note that normal chip only use those two register for
+	 * auto-centering mode.
+	 */
+	POKE32(CRT_AUTO_CENTERING_TL,
+	       FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0)
+	       | FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0));
+
+	POKE32(CRT_AUTO_CENTERING_BR,
+	       FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y - 1)
+	       | FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x - 1));
+
+	/* Assume common fields in ctrl have been properly set before
+	 * calling this function.
+	 * This function only sets the extra fields in ctrl.
+	 */
+
+	/* Set bit 25 of display controller: Select CRT or VGA clock */
+	ctrl = FIELD_SET(ctrl, CRT_DISPLAY_CTRL, CRTSELECT, CRT);
+
+	/* Set bit 14 of display controller */
+	ctrl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLOCK_PHASE);
+
+	/* clock_phase_polarity is 0 */
+	ctrl = FIELD_SET(ctrl, CRT_DISPLAY_CTRL,
+			 CLOCK_PHASE, ACTIVE_HIGH);
+
+	POKE32(CRT_DISPLAY_CTRL, ctrl);
+
+	return ctrl;
+}
+
+static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	unsigned int val;
+	struct drm_display_mode *mode = &crtc->state->mode;
+
+	POKE32(CRT_PLL_CTRL, format_pll_reg());
+	POKE32(CRT_HORIZONTAL_TOTAL,
+	       FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL,
+			   TOTAL, mode->htotal - 1) |
+	       FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL,
+			   DISPLAY_END, mode->hdisplay - 1));
+
+	POKE32(CRT_HORIZONTAL_SYNC,
+	       FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH,
+			   mode->hsync_end - mode->hsync_start) |
+	       FIELD_VALUE(0, CRT_HORIZONTAL_SYNC,
+			   START, mode->hsync_start - 1));
+
+	POKE32(CRT_VERTICAL_TOTAL,
+	       FIELD_VALUE(0, CRT_VERTICAL_TOTAL,
+			   TOTAL, mode->vtotal - 1) |
+	       FIELD_VALUE(0, CRT_VERTICAL_TOTAL,
+			   DISPLAY_END, mode->vdisplay - 1));
+
+	POKE32(CRT_VERTICAL_SYNC,
+	       FIELD_VALUE(0, CRT_VERTICAL_SYNC,
+			   HEIGHT, mode->vsync_end - mode->vsync_start) |
+	       FIELD_VALUE(0, CRT_VERTICAL_SYNC,
+			   START, mode->vsync_start - 1));
+
+	val = FIELD_VALUE(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, 0) |
+			  FIELD_VALUE(0, CRT_DISPLAY_CTRL, HSYNC_PHASE, 0) |
+			  FIELD_SET(0, CRT_DISPLAY_CTRL, TIMING, ENABLE) |
+			  FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE);
+
+	display_ctrl_adjust(mode, val);
+}
+
+static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	unsigned int reg;
+
+	set_power_mode(POWER_MODE_CTRL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = PEEK32(CURRENT_GATE);
+	reg = FIELD_SET(reg, CURRENT_GATE, DISPLAY, ON);
+	reg = FIELD_SET(reg, CURRENT_GATE, LOCALMEM, ON);
+	set_current_gate(reg);
+
+	/* We can add more initialization as needed. */
+}
+
+static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+
+{
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs hibmc_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
+	.enable		= hibmc_crtc_enable,
+	.disable	= hibmc_crtc_disable,
+	.mode_set_nofb	= hibmc_crtc_mode_set_nofb,
+	.atomic_check	= hibmc_crtc_atomic_check,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_crtc_init(struct drm_device *dev)
+{
+	struct hibmc_private *hiprivate = dev->dev_private;
+	struct drm_crtc *crtc = &hiprivate->crtc;
+	struct drm_plane *plane = &hiprivate->plane;
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_mode_crtc_set_gamma_size(crtc, 256);
+	drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
new file mode 100644
index 0000000..b7b9d2b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
@@ -0,0 +1,20 @@ 
+/*
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+ #ifndef HIBMC_DRM_DE_H
+#define HIBMC_DRM_DE_H
+
+struct panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index d7e03c5..732836d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -131,6 +131,12 @@  int hibmc_kms_init(struct hibmc_private *hiprivate)
 		return ret;
 	}
 
+	ret = hibmc_crtc_init(hiprivate->dev);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 08c82ae..7b4cb5e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -47,5 +47,6 @@  struct hibmc_private {
 };
 
 int hibmc_plane_init(struct drm_device *dev);
+int hibmc_crtc_init(struct drm_device *dev);
 
 #endif