diff options
Diffstat (limited to 'drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c new file mode 100644 index 000000000000..82a3d311e164 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -0,0 +1,210 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * Freescale DCU drm device driver + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/regmap.h> + +#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +#include "fsl_dcu_drm_crtc.h" +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_plane.h" + +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ +} + +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + return 0; +} + +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ +} + +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + int ret; + + ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_OFF)); + if (ret) + dev_err(fsl_dev->dev, "Disable CRTC failed\n"); + ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, + DCU_UPDATE_MODE_READREG); + if (ret) + dev_err(fsl_dev->dev, "Enable CRTC failed\n"); +} + +static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + int ret; + + ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); + if (ret) + dev_err(fsl_dev->dev, "Enable CRTC failed\n"); + ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, + DCU_UPDATE_MODE_READREG); + if (ret) + dev_err(fsl_dev->dev, "Enable CRTC failed\n"); +} + +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + struct drm_display_mode *mode = &crtc->state->mode; + unsigned int hbp, hfp, hsw, vbp, vfp, vsw, div, index; + unsigned long dcuclk; + int ret; + + index = drm_crtc_index(crtc); + dcuclk = clk_get_rate(fsl_dev->clk); + div = dcuclk / mode->clock / 1000; + + /* Configure timings: */ + hbp = mode->htotal - mode->hsync_end; + hfp = mode->hsync_start - mode->hdisplay; + hsw = mode->hsync_end - mode->hsync_start; + vbp = mode->vtotal - mode->vsync_end; + vfp = mode->vsync_start - mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + + ret = regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, + DCU_HSYN_PARA_BP(hbp) | + DCU_HSYN_PARA_PW(hsw) | + DCU_HSYN_PARA_FP(hfp)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, + DCU_VSYN_PARA_BP(vbp) | + DCU_VSYN_PARA_PW(vsw) | + DCU_VSYN_PARA_FP(vfp)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, + DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | + DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_SYN_POL, + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | + DCU_BGND_G(0) | DCU_BGND_B(0)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_THRESHOLD, + DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | + DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | + DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, + DCU_UPDATE_MODE_READREG); + if (ret) + goto set_failed; + return; +set_failed: + dev_err(dev->dev, "set DCU register failed\n"); +} + +static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { + .atomic_begin = fsl_dcu_drm_crtc_atomic_begin, + .atomic_check = fsl_dcu_drm_crtc_atomic_check, + .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, + .disable = fsl_dcu_drm_disable_crtc, + .enable = fsl_dcu_drm_crtc_enable, + .mode_fixup = fsl_dcu_drm_crtc_mode_fixup, + .mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb, +}; + +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = { + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .destroy = drm_crtc_cleanup, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .set_config = drm_atomic_helper_set_config, +}; + +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) +{ + struct drm_plane *primary; + struct drm_crtc *crtc = &fsl_dev->crtc; + unsigned int i, j, reg_num; + int ret; + + primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm); + ret = drm_crtc_init_with_planes(fsl_dev->drm, crtc, primary, NULL, + &fsl_dcu_drm_crtc_funcs); + if (ret < 0) + return ret; + + drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); + + if (!strcmp(fsl_dev->soc->name, "ls1021a")) + reg_num = LS1021A_LAYER_REG_NUM; + else + reg_num = VF610_LAYER_REG_NUM; + for (i = 0; i <= fsl_dev->soc->total_layer; i++) { + for (j = 0; j < reg_num; j++) { + ret = regmap_write(fsl_dev->regmap, + DCU_CTRLDESCLN(i, j), 0); + if (ret) + goto init_failed; + } + } + ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_OFF)); + if (ret) + goto init_failed; + ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, + DCU_UPDATE_MODE_READREG); + if (ret) + goto init_failed; + + return 0; +init_failed: + dev_err(fsl_dev->dev, "init DCU register failed\n"); + return ret; +} |