This patch add support for Two Dimensional Animation and Compositing Engine (2D-ACE) on Freescale SoCs. 2D-ACE is a Freescale display controller. It provide an hardware cursor. This is a simplified version, only a primary plane, a fb created for fbdev, a crtc, a connector for TFT LCD panel, an encoder, and the encoder is not in use. Signed-off-by: Alison Wang <b18965@xxxxxxxxxxxxx> Signed-off-by: Xiubo Li <lixiubo@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Jianwei Wang <b52261@xxxxxxxxxxxxx> --- Changed in v2: - Add atomic support - Modify bindings file - Rename node for compatibility - Move platform related code out for compatibility Added in v1: - Add support for DCU display controller on the Freescale LS102x SoCs. - Create a primary plane, a fb created for fbdev, a crtc, a connector for TFT LCD panel, an encoder. arch/arm/mach-imx/mach-ls1021a.c | 36 ++++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/fsl/Kconfig | 17 ++ drivers/gpu/drm/fsl/Makefile | 8 + drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c | 203 ++++++++++++++++++++ drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h | 28 +++ drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c | 164 ++++++++++++++++ drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h | 26 +++ drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c | 288 ++++++++++++++++++++++++++++ drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h | 168 ++++++++++++++++ drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c | 26 +++ drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c | 42 ++++ drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h | 17 ++ drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c | 187 ++++++++++++++++++ drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h | 23 +++ include/linux/fsl/dcu.h | 22 +++ 17 files changed, 1258 insertions(+) create mode 100644 drivers/gpu/drm/fsl/Kconfig create mode 100644 drivers/gpu/drm/fsl/Makefile create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h create mode 100644 include/linux/fsl/dcu.h diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c index b89c858..4fb346d 100644 --- a/arch/arm/mach-imx/mach-ls1021a.c +++ b/arch/arm/mach-imx/mach-ls1021a.c @@ -8,9 +8,44 @@ */ #include <asm/mach/arch.h> +#include <linux/of_platform.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/fsl/dcu.h> #include "common.h" +void dcu_pixclk_disable(void) +{ + struct regmap *scfg_regmap; + + scfg_regmap = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg"); + if (IS_ERR(scfg_regmap)) { + pr_err("No syscfg phandle specified\n"); + return; + } + + regmap_write(scfg_regmap, SCFG_PIXCLKCR, PXCK_DISABLE); +} + +void dcu_pixclk_enable(void) +{ + struct regmap *scfg_regmap; + + scfg_regmap = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg"); + if (IS_ERR(scfg_regmap)) { + pr_err("No syscfg phandle specified\n"); + return; + } + + regmap_write(scfg_regmap, SCFG_PIXCLKCR, PXCK_ENABLE); +} + +static void __init ls1021a_init_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + dcu_pixclk_enable(); +} static const char * const ls1021a_dt_compat[] __initconst = { "fsl,ls1021a", NULL, @@ -18,5 +53,6 @@ static const char * const ls1021a_dt_compat[] __initconst = { DT_MACHINE_START(LS1021A, "Freescale LS1021A") .smp = smp_ops(ls1021a_smp_ops), + .init_machine = ls1021a_init_machine, .dt_compat = ls1021a_dt_compat, MACHINE_END diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 151a050..a6957aa 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig" source "drivers/gpu/drm/msm/Kconfig" +source "drivers/gpu/drm/fsl/Kconfig" + source "drivers/gpu/drm/tegra/Kconfig" source "drivers/gpu/drm/panel/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 2c239b9..ab5b9ef 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_AST) += ast/ obj-$(CONFIG_DRM_ARMADA) += armada/ obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ +obj-$(CONFIG_DRM_FSL_DCU) += fsl/ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ diff --git a/drivers/gpu/drm/fsl/Kconfig b/drivers/gpu/drm/fsl/Kconfig new file mode 100644 index 0000000..e4f8df0 --- /dev/null +++ b/drivers/gpu/drm/fsl/Kconfig @@ -0,0 +1,17 @@ +config DRM_FSL_DCU + tristate "DRM Support for Freescale DCU" + depends on DRM && OF && ARM + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select VIDEOMODE_HELPERS + select BACKLIGHT_CLASS_DEVICE + select BACKLIGHT_LCD_SUPPORT + select REGMAP_MMIO + select DRM_KMS_FB_HELPER + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + help + Choose this option if you have an Freescale DCU chipset. + If M is selected the module will be called fsl-dcu-drm. diff --git a/drivers/gpu/drm/fsl/Makefile b/drivers/gpu/drm/fsl/Makefile new file mode 100644 index 0000000..5f74aee --- /dev/null +++ b/drivers/gpu/drm/fsl/Makefile @@ -0,0 +1,8 @@ +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \ + fsl_dcu_drm_kms.o \ + fsl_dcu_drm_connector.o \ + fsl_dcu_drm_plane.o \ + fsl_dcu_drm_crtc.o \ + fsl_dcu_drm_fbdev.o \ + +obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu-drm.o diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c new file mode 100644 index 0000000..178d647 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c @@ -0,0 +1,203 @@ +/* + * 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/backlight.h> + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <video/of_display_timing.h> + +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_connector.h" + +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +} + +/* Disable the encoders as the first thing we do. */ +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder *encoder) +{ +} + +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ +} + +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder *encoder) +{ +} + +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder) +{ +} + +static int +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + return 0; +} + +static bool +fsl_dcu_drm_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .dpms = fsl_dcu_drm_encoder_dpms, + .prepare = fsl_dcu_drm_encoder_mode_prepare, + .commit = fsl_dcu_drm_encoder_mode_commit, + .mode_set = fsl_dcu_drm_encoder_mode_set, + .disable = fsl_dcu_drm_encoder_disable, + .atomic_check = fsl_dcu_drm_encoder_atomic_check, + .mode_fixup = fsl_dcu_drm_encoder_mode_fixup, +}; + +static const struct drm_encoder_funcs encoder_funcs = { + .destroy = fsl_dcu_drm_encoder_destroy, +}; + +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev) +{ + struct drm_encoder *encoder = &fsl_dev->encoder; + int ret; + + encoder->possible_crtcs = 1; + + ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs, + DRM_MODE_ENCODER_LVDS); + if (ret < 0) + return ret; + + drm_encoder_helper_add(encoder, &encoder_helper_funcs); + + return 0; +} + +#define to_fsl_dcu_connector(connector) \ + container_of(connector, struct fsl_dcu_drm_connector, connector) + +static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct device_node *display_np, *np = dev->dev->of_node; + struct drm_display_mode *mode = drm_mode_create(connector->dev); + int num_modes = 0; + + if (np) { + display_np = of_parse_phandle(np, "display", 0); + if (!display_np) { + dev_err(dev->dev, "failed to find display phandle\n"); + return num_modes; + } + of_get_drm_display_mode(display_np, mode, OF_USE_NATIVE_MODE); + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + drm_mode_probed_add(connector, mode); + num_modes++; + } + + return num_modes; +} + +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static struct drm_encoder * +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector) +{ + struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); + + return fsl_con->encoder; +} + +static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .reset = drm_atomic_helper_connector_reset, + .detect = fsl_dcu_drm_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = fsl_dcu_drm_connector_destroy, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = fsl_dcu_drm_connector_get_modes, + .mode_valid = fsl_dcu_drm_connector_mode_valid, + .best_encoder = fsl_dcu_drm_connector_best_encoder, +}; + +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, + struct drm_encoder *encoder) +{ + struct drm_connector *connector = &fsl_dev->connector.connector; + int ret; + + fsl_dev->connector.encoder = encoder; + + connector->display_info.width_mm = 0; + connector->display_info.height_mm = 0; + + ret = drm_connector_init(fsl_dev->ddev, connector, + &fsl_dcu_drm_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret < 0) + return ret; + + connector->dpms = DRM_MODE_DPMS_OFF; + drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_connector_register(connector); + if (ret < 0) + goto err_cleanup; + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret < 0) + goto err_sysfs; + + connector->encoder = encoder; + + drm_object_property_set_value + (&connector->base, fsl_dev->ddev->mode_config.dpms_property, + DRM_MODE_DPMS_OFF); + + return 0; + +err_sysfs: + drm_connector_unregister(connector); +err_cleanup: + drm_connector_cleanup(connector); + return ret; +} diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h new file mode 100644 index 0000000..afe44ab --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_DRM_CONNECTOR_H__ +#define __FSL_DCU_DRM_CONNECTOR_H__ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> + +struct fsl_dcu_drm_device; +struct fsl_dcu_drm_connector { + struct drm_connector connector; + struct drm_encoder *encoder; +}; + +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev); +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, + struct drm_encoder *encoder); + +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c new file mode 100644 index 0000000..a43e7ce --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c @@ -0,0 +1,164 @@ +/* + * 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/regmap.h> +#include <linux/clk.h> + +#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> + +#include "fsl_dcu_drm_crtc.h" +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_plane.h" + +#define to_fsl_dcu_crtc(c) container_of(c, struct fsl_dcu_drm_crtc, crtc) + +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc) +{ +} + +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; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index; + + DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + mode->base.id, mode->name, + mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, + mode->type, mode->flags); + + index = drm_crtc_index(crtc); + div = (uint32_t)clk_get_rate(fsl_dev->clk) / 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; + + regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, + DCU_HSYN_PARA_BP(hbp) | + DCU_HSYN_PARA_PW(hsw) | + DCU_HSYN_PARA_FP(hfp)); + regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, + DCU_VSYN_PARA_BP(vbp) | + DCU_VSYN_PARA_PW(vsw) | + DCU_VSYN_PARA_FP(vfp)); + regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, + DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | + DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); + regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div); + regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); +} + +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_prepare(struct drm_crtc *crtc) +{ +} + +/* Now enable the clocks, plane, pipe, and connectors that we set up. */ +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc) +{ +} + +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_begin(struct drm_crtc *crtc) +{ +} + +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc) +{ +} + +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) +{ +} + +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = { + .page_flip = drm_atomic_helper_page_flip, + .set_config = drm_crtc_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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +} + +static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { + .disable = fsl_dcu_drm_disable_crtc, + .mode_fixup = fsl_dcu_drm_crtc_mode_fixup, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, + .prepare = fsl_dcu_drm_crtc_prepare, + .commit = fsl_dcu_drm_crtc_mode_commit, + .atomic_check = fsl_dcu_drm_crtc_atomic_check, + .atomic_begin = fsl_dcu_drm_crtc_atomic_begin, + .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, + .dpms = fsl_dcu_drm_crtc_dpms, +}; + +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) +{ + struct drm_plane *primary; + struct drm_crtc *crtc = &fsl_dev->crtc.crtc; + int ret; + + fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF; + + primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev); + ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary, NULL, + &fsl_dcu_drm_crtc_funcs); + if (ret < 0) + return ret; + + drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); + + regmap_write(fsl_dev->regmap, DCU_SYN_POL, + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW); + regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | + DCU_BGND_G(0) | DCU_BGND_B(0)); + regmap_write(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); + 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)); + regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); + regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); + return 0; +} diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h new file mode 100644 index 0000000..d44b564 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_DRM_CRTC_H__ +#define __FSL_DCU_DRM_CRTC_H__ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> + +struct fsl_dcu_drm_device; +struct fsl_dcu_drm_crtc { + struct drm_crtc crtc; + int dpms; +}; + +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev); + +#endif /* __FSL_DCU_DRM_CRTC_H__ */ diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c new file mode 100644 index 0000000..10975ee --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c @@ -0,0 +1,288 @@ +/* + * 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/io.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <drm/drmP.h> +#include <linux/fsl/dcu.h> + +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_kms.h" + +static int fsl_dcu_unload(struct drm_device *dev) +{ + drm_mode_config_cleanup(dev); + drm_vblank_cleanup(dev); + drm_irq_uninstall(dev); + + dev->dev_private = NULL; + + return 0; +} + +static struct regmap_config fsl_dcu_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev, + struct device_node *np) +{ + struct device_node *tcon_np; + struct platform_device *pdev; + struct clk *tcon_clk; + struct resource *res; + void __iomem *base; + + tcon_np = of_parse_phandle(np, "tcon-controller", 0); + if (!tcon_np) + return -EINVAL; + + pdev = of_find_device_by_node(tcon_np); + if (!pdev) + return -EINVAL; + + tcon_clk = devm_clk_get(&pdev->dev, "tcon"); + if (IS_ERR(tcon_clk)) + return PTR_ERR(tcon_clk); + clk_prepare_enable(tcon_clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "tcon", base, &fsl_dcu_regmap_config); + if (IS_ERR(fsl_dev->tcon_regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + return PTR_ERR(fsl_dev->tcon_regmap); + } + + regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1, TCON_BYPASS_ENABLE); + return 0; +} + +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags) +{ + struct platform_device *pdev = dev->platformdev; + struct fsl_dcu_drm_device *fsl_dev; + struct resource *res; + void __iomem *base; + int ret; + + fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev), GFP_KERNEL); + if (!fsl_dev) + return -ENOMEM; + + fsl_dev->dev = &pdev->dev; + fsl_dev->ddev = dev; + dev->dev_private = fsl_dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + return ret; + } + + fsl_dev->regmap = devm_regmap_init_mmio(&pdev->dev, + base, &fsl_dcu_regmap_config); + if (IS_ERR(fsl_dev->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + return PTR_ERR(fsl_dev->regmap); + } + + ret = fsl_dcu_drm_modeset_init(fsl_dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to initialize mode setting\n"); + return ret; + } + + ret = drm_vblank_init(dev, 1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to initialize vblank\n"); + goto done; + } + + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); + if (ret < 0) { + dev_err(&pdev->dev, "failed to install IRQ handler\n"); + goto done; + } + + /* Put TCON in bypass mode, so the input signals from DCU are passed + * through TCON unchanged */ + fsl_dcu_bypass_tcon(fsl_dev, pdev->dev.of_node); + + fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu"); + if (IS_ERR(fsl_dev->clk)) { + ret = PTR_ERR(fsl_dev->clk); + dev_err(&pdev->dev, "could not get clock\n"); + return ret; + } + clk_prepare_enable(fsl_dev->clk); + + dev_set_drvdata(dev->dev, fsl_dev); + + fsl_dcu_fbdev_init(dev); + + return 0; +done: + if (ret) + fsl_dcu_unload(dev); + + return ret; +} + +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct drm_file *file) +{ + ; +} + +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg) +{ + return IRQ_HANDLED; +} + +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc) +{ + return 0; +} + +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc) +{ + ; +} + +static const struct file_operations fsl_dcu_drm_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .mmap = drm_gem_cma_mmap, +}; + +static struct drm_driver fsl_dcu_drm_driver = { + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET + | DRIVER_PRIME, + .load = fsl_dcu_load, + .unload = fsl_dcu_unload, + .preclose = fsl_dcu_drm_preclose, + .irq_handler = fsl_dcu_drm_irq, + .get_vblank_counter = drm_vblank_count, + .enable_vblank = fsl_dcu_drm_enable_vblank, + .disable_vblank = fsl_dcu_drm_disable_vblank, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .fops = &fsl_dcu_drm_fops, + .name = "fsl-dcu-drm", + .desc = "Freescale DCU DRM", + .date = "20150213", + .major = 1, + .minor = 0, +}; + +#ifdef CONFIG_PM_SLEEP +static int fsl_dcu_drm_pm_suspend(struct device *dev) +{ + struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); + + dcu_pixclk_disable(); + drm_kms_helper_poll_disable(fsl_dev->ddev); + fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc); + + return 0; +} + +static int fsl_dcu_drm_pm_resume(struct device *dev) +{ + struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); + + drm_modeset_lock_all(fsl_dev->ddev); + fsl_dcu_drm_crtc_resume(&fsl_dev->crtc); + drm_modeset_unlock_all(fsl_dev->ddev); + drm_kms_helper_poll_enable(fsl_dev->ddev); + dcu_pixclk_enable(); + return 0; +} +#endif + +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume) +}; + +static int fsl_dcu_drm_probe(struct platform_device *pdev) +{ + return drm_platform_init(&fsl_dcu_drm_driver, pdev); +} + +static int fsl_dcu_drm_remove(struct platform_device *pdev) +{ + struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); + + drm_put_dev(fsl_dev->ddev); + + return 0; +} + +static const struct of_device_id fsl_dcu_of_match[] = { + { .compatible = "fsl,dcu", }, + { }, +}; +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match); + +static struct platform_driver fsl_dcu_drm_platform_driver = { + .probe = fsl_dcu_drm_probe, + .remove = fsl_dcu_drm_remove, + .driver = { + .owner = THIS_MODULE, + .name = "fsl,dcu", + .pm = &fsl_dcu_drm_pm_ops, + .of_match_table = fsl_dcu_of_match, + }, +}; + +module_platform_driver(fsl_dcu_drm_platform_driver); + +MODULE_ALIAS("platform:fsl-dcu-drm"); +MODULE_DESCRIPTION("Freescale DCU DRM Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h new file mode 100644 index 0000000..cbdfefc --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h @@ -0,0 +1,168 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_DRM_DRV_H__ +#define __FSL_DCU_DRM_DRV_H__ + +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <stddef.h> +#include <drm/drm.h> +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fb_cma_helper.h> + +#include "fsl_dcu_drm_crtc.h" +#include "fsl_dcu_drm_plane.h" +#include "fsl_dcu_drm_connector.h" +#define DRIVER_NAME "fsl-dcu-fb" + +#define DCU_DCU_MODE 0x0010 +#define DCU_MODE_BLEND_ITER(x) ((x) << 20) +#define DCU_MODE_RASTER_EN BIT(14) +#define DCU_MODE_DCU_MODE(x) (x) +#define DCU_MODE_DCU_MODE_MASK 0x03 +#define DCU_MODE_OFF 0 +#define DCU_MODE_NORMAL 1 +#define DCU_MODE_TEST 2 +#define DCU_MODE_COLORBAR 3 + +#define DCU_BGND 0x0014 +#define DCU_BGND_R(x) ((x) << 16) +#define DCU_BGND_G(x) ((x) << 8) +#define DCU_BGND_B(x) (x) + +#define DCU_DISP_SIZE 0x0018 +#define DCU_DISP_SIZE_DELTA_Y(x) ((x) << 16) +/*Regisiter value 1/16 of horizontal resolution*/ +#define DCU_DISP_SIZE_DELTA_X(x) ((x) >> 4) + +#define DCU_HSYN_PARA 0x001c +#define DCU_HSYN_PARA_BP(x) ((x) << 22) +#define DCU_HSYN_PARA_PW(x) ((x) << 11) +#define DCU_HSYN_PARA_FP(x) (x) + +#define DCU_VSYN_PARA 0x0020 +#define DCU_VSYN_PARA_BP(x) ((x) << 22) +#define DCU_VSYN_PARA_PW(x) ((x) << 11) +#define DCU_VSYN_PARA_FP(x) (x) + +#define DCU_SYN_POL 0x0024 +#define DCU_SYN_POL_INV_PXCK_FALL (0 << 6) +#define DCU_SYN_POL_NEG_REMAIN (0 << 5) +#define DCU_SYN_POL_INV_VS_LOW BIT(1) +#define DCU_SYN_POL_INV_HS_LOW (1) + +#define DCU_THRESHOLD 0x0028 +#define DCU_THRESHOLD_LS_BF_VS(x) ((x) << 16) +#define DCU_THRESHOLD_OUT_BUF_HIGH(x) ((x) << 8) +#define DCU_THRESHOLD_OUT_BUF_LOW(x) (x) +#define BF_VS_VAL 0x03 +#define BUF_MAX_VAL 0x78 +#define BUF_MIN_VAL 0x0a + +#define DCU_INT_STATUS 0x002C +#define DCU_INT_STATUS_UNDRUN BIT(1) + +#define DCU_INT_MASK 0x0030 +#define DCU_INT_MASK_UNDRUN BIT(1) +#define DCU_INT_MASK_VBLANK BIT(3) + +#define DCU_DIV_RATIO 0x0054 + +#define DCU_UPDATE_MODE 0x00cc +#define DCU_UPDATE_MODE_MODE BIT(31) +#define DCU_UPDATE_MODE_READREG BIT(30) + +#define DCU_DCFB_MAX 0x300 + +#define DCU_CTRLDESCLN_1(x) (0x200 + (x) * 0x40) +#define DCU_CTRLDESCLN_1_HEIGHT(x) ((x) << 16) +#define DCU_CTRLDESCLN_1_WIDTH(x) (x) + +#define DCU_CTRLDESCLN_2(x) (0x204 + (x) * 0x40) +#define DCU_CTRLDESCLN_2_POSY(x) ((x) << 16) +#define DCU_CTRLDESCLN_2_POSX(x) (x) + +#define DCU_CTRLDESCLN_3(x) (0x208 + (x) * 0x40) + +#define DCU_CTRLDESCLN_4(x) (0x20c + (x) * 0x40) +#define DCU_CTRLDESCLN_4_EN BIT(31) +#define DCU_CTRLDESCLN_4_TILE_EN BIT(30) +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT BIT(29) +#define DCU_CTRLDESCLN_4_SAFETY_EN BIT(28) +#define DCU_CTRLDESCLN_4_TRANS(x) ((x) << 20) +#define DCU_CTRLDESCLN_4_BPP(x) ((x) << 16) +#define DCU_CTRLDESCLN_4_RLE_EN BIT(15) +#define DCU_CTRLDESCLN_4_LUOFFS(x) ((x) << 4) +#define DCU_CTRLDESCLN_4_BB_ON BIT(2) +#define DCU_CTRLDESCLN_4_AB(x) (x) + +#define DCU_CTRLDESCLN_5(x) (0x210 + (x) * 0x40) +#define DCU_CTRLDESCLN_5_CKMAX_R(x) ((x) << 16) +#define DCU_CTRLDESCLN_5_CKMAX_G(x) ((x) << 8) +#define DCU_CTRLDESCLN_5_CKMAX_B(x) (x) + +#define DCU_CTRLDESCLN_6(x) (0x214 + (x) * 0x40) +#define DCU_CTRLDESCLN_6_CKMIN_R(x) ((x) << 16) +#define DCU_CTRLDESCLN_6_CKMIN_G(x) ((x) << 8) +#define DCU_CTRLDESCLN_6_CKMIN_B(x) (x) + +#define DCU_CTRLDESCLN_7(x) (0x218 + (x) * 0x40) +#define DCU_CTRLDESCLN_7_TILE_VER(x) ((x) << 16) +#define DCU_CTRLDESCLN_7_TILE_HOR(x) (x) + +#define DCU_CTRLDESCLN_8(x) (0x21c + (x) * 0x40) +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x) (x) + +#define DCU_CTRLDESCLN_9(x) (0x220 + (x) * 0x40) +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x) (x) + +#define DCU_CTRLDESCLN_10(x) (0x224 + (x) * 0x40) +#define DCU_CTRLDESCLN_10_POST_SKIP(x) ((x) << 16) +#define DCU_CTRLDESCLN_10_PRE_SKIP(x) (x) + +#define FSL_DCU_RGB565 4 +#define FSL_DCU_RGB888 5 +#define FSL_DCU_ARGB8888 6 +#define FSL_DCU_ARGB1555 11 +#define FSL_DCU_ARGB4444 12 +#define FSL_DCU_YUV422 14 + +#define TCON_CTRL1 0x0000 +#define TCON_BYPASS_ENABLE BIT(29) + +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) + +struct clk; +struct device; +struct drm_device; + +struct fsl_dcu_drm_device { + struct device *dev; + struct regmap *regmap; + struct regmap *tcon_regmap; + unsigned int irq; + struct clk *clk; + /*protects hardware register*/ + spinlock_t irq_lock; + struct drm_device *ddev; + struct drm_fbdev_cma *fbdev; + struct fsl_dcu_drm_crtc crtc; + struct drm_encoder encoder; + struct fsl_dcu_drm_connector connector; +}; + +void fsl_dcu_fbdev_init(struct drm_device *dev); + +#endif /* __FSL_DCU_DRM_DRV_H__ */ diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c new file mode 100644 index 0000000..f8ef0e1 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c @@ -0,0 +1,26 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <drm/drmP.h> +#include <drm/drm_fb_cma_helper.h> + +#include "fsl_dcu_drm_drv.h" + +/* initialize fbdev helper */ +void fsl_dcu_fbdev_init(struct drm_device *dev) +{ + struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev); + + fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1); +} diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c new file mode 100644 index 0000000..4a840fb --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c @@ -0,0 +1,42 @@ +/* + * 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 <drm/drmP.h> +#include <drm/drm_atomic_helper.h> + +#include "fsl_dcu_drm_crtc.h" +#include "fsl_dcu_drm_connector.h" +#include "fsl_dcu_drm_drv.h" + +static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev) +{ + drm_mode_config_init(fsl_dev->ddev); + + fsl_dev->ddev->mode_config.min_width = 0; + fsl_dev->ddev->mode_config.min_height = 0; + fsl_dev->ddev->mode_config.max_width = 2031; + fsl_dev->ddev->mode_config.max_height = 2047; + fsl_dev->ddev->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs; + + drm_kms_helper_poll_init(fsl_dev->ddev); + fsl_dcu_drm_crtc_create(fsl_dev); + fsl_dcu_drm_encoder_create(fsl_dev); + fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); + drm_mode_config_reset(fsl_dev->ddev); + + return 0; +} diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h new file mode 100644 index 0000000..b9bd299 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h @@ -0,0 +1,17 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_DRM_KMS_H__ +#define __FSL_DCU_DRM_KMS_H__ + +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev); + +#endif /* __FSL_DCU_DRM_KMS_H__ */ diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c new file mode 100644 index 0000000..b7b4405 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c @@ -0,0 +1,187 @@ +/* + * 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 <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <linux/regmap.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_atomic_helper.h> + +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_kms.h" +#include "fsl_dcu_drm_plane.h" + +#define to_fsl_dcu_plane(plane) \ + container_of(plane, struct fsl_dcu_drm_plane, plane) + +static int +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) +{ + return 0; +} + +static void +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) +{ +} + +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + return 0; +} + +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ +} + +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = plane->state->fb; + u32 index, alpha, bpp; + struct drm_gem_cma_object *gem; + struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane); + + index = fsl_plane->index; + gem = drm_fb_cma_get_gem_obj(fb, 0); + + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + bpp = FSL_DCU_RGB565; + alpha = 0xff; + break; + case DRM_FORMAT_RGB888: + bpp = FSL_DCU_RGB888; + alpha = 0xff; + break; + case DRM_FORMAT_ARGB8888: + bpp = FSL_DCU_ARGB8888; + alpha = 0xff; + break; + case DRM_FORMAT_BGRA4444: + bpp = FSL_DCU_ARGB4444; + alpha = 0xff; + break; + case DRM_FORMAT_ARGB1555: + bpp = FSL_DCU_ARGB1555; + alpha = 0xff; + break; + case DRM_FORMAT_YUV422: + bpp = FSL_DCU_YUV422; + alpha = 0xff; + break; + default: + return; + } + + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index), + DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) | + DCU_CTRLDESCLN_1_WIDTH(state->crtc_w)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index), + DCU_CTRLDESCLN_2_POSY(state->crtc_y) | + DCU_CTRLDESCLN_2_POSX(state->crtc_x)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem->paddr); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index), + DCU_CTRLDESCLN_4_EN | + DCU_CTRLDESCLN_4_TRANS(alpha) | + DCU_CTRLDESCLN_4_BPP(bpp) | + DCU_CTRLDESCLN_4_AB(2)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index), + DCU_CTRLDESCLN_5_CKMAX_R(0xFF) | + DCU_CTRLDESCLN_5_CKMAX_G(0xFF) | + DCU_CTRLDESCLN_5_CKMAX_B(0xFF)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index), + DCU_CTRLDESCLN_6_CKMIN_R(0) | + DCU_CTRLDESCLN_6_CKMIN_G(0) | + DCU_CTRLDESCLN_6_CKMIN_B(0)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index), + DCU_CTRLDESCLN_8_FG_FCOLOR(0)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index), + DCU_CTRLDESCLN_9_BG_BCOLOR(0)); + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index), + DCU_CTRLDESCLN_10_POST_SKIP(0) | + DCU_CTRLDESCLN_10_PRE_SKIP(0)); + regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); +} + +int fsl_dcu_drm_plane_disable(struct drm_plane *plane) +{ + return 0; +} + +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane) +{ + fsl_dcu_drm_plane_disable(plane); + drm_plane_cleanup(plane); +} + +static const uint32_t fsl_dcu_drm_plane_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_YUV422, +}; + +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = { + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, + .destroy = fsl_dcu_drm_plane_destroy, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .reset = drm_atomic_helper_plane_reset, +}; + +static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = { + .prepare_fb = fsl_dcu_drm_plane_prepare_fb, + .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb, + .atomic_check = fsl_dcu_drm_plane_atomic_check, + .atomic_update = fsl_dcu_drm_plane_atomic_update, + .atomic_disable = fsl_dcu_drm_plane_atomic_disable, +}; + +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev) +{ + struct drm_plane *primary; + int ret; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (!primary) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + /* possible_crtc's will be filled in later by crtc_init */ + ret = drm_universal_plane_init(dev, primary, 0, + &fsl_dcu_drm_plane_funcs, + fsl_dcu_drm_plane_formats, + ARRAY_SIZE(fsl_dcu_drm_plane_formats), + DRM_PLANE_TYPE_PRIMARY); + if (ret) { + kfree(primary); + primary = NULL; + } + drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs); + + return primary; +} diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h new file mode 100644 index 0000000..ccbfa61 --- /dev/null +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_DRM_PLANE_H__ +#define __FSL_DCU_DRM_PLANE_H__ + +struct fsl_dcu_drm_device; +struct fsl_dcu_drm_plane { + struct drm_plane plane; + unsigned int index; +}; + +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev); + +#endif /* __FSL_DCU_DRM_PLANE_H__ */ diff --git a/include/linux/fsl/dcu.h b/include/linux/fsl/dcu.h new file mode 100644 index 0000000..1873057 --- /dev/null +++ b/include/linux/fsl/dcu.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#ifndef __FSL_DCU_H__ +#define __FSL_DCU_H__ + +#define SCFG_PIXCLKCR 0x28 +#define PXCK_ENABLE BIT(31) +#define PXCK_DISABLE 0 + +void dcu_pixclk_enable(void); +void dcu_pixclk_disable(void); + +#endif /* __FSL_DCU_H__ */ -- 2.1.0.27.g96db324
_______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel