[PATCH 3/7] drm/hisilicon:Add crtc for DE
lijianhua
jueying0518 at gmail.com
Mon Feb 29 00:58:37 UTC 2016
Add crtc funcs and helper funcs for DE.
Signed-off-by: lijianhua <jueying0518 at 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
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
--
1.9.1
More information about the dri-devel
mailing list