Add crtc funcs and helper funcs for DE. Signed-off-by: lijianhua <jueying0518@xxxxxxxxx> --- 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel