Skip to content

Commit

Permalink
drm/layerscape: Add Freescale DCU DRM driver
Browse files Browse the repository at this point in the history
This patch add support for Two Dimensional Animation and Compositing
Engine (2D-ACE) on the Freescale SoCs.

2D-ACE is a Freescale display controller. 2D-ACE describes
the functionality of the module extremely well its name is a value
that cannot be used as a token in programming languages.
Instead the valid token "DCU" is used to tag the register names and
function names.

The Display Controller Unit (DCU) module is a system master that
fetches graphics stored in internal or external memory and displays
them on a TFT LCD panel. A wide range of panel sizes is supported
and the timing of the interface signals is highly configurable.
Graphics are read directly from memory and then blended in real-time,
which allows for dynamic content creation with minimal CPU
intervention.

The features:
(1) Full RGB888 output to TFT LCD panel.
(2) Blending of each pixel using up to 4 source layers
dependent
on size of panel.
(3) Each graphic layer can be placed with one pixel resolution
in either axis.
(4) Each graphic layer support RGB565 and RGB888 direct colors
without alpha channel and BGRA8888 BGRA4444 ARGB1555 direct
colors
with an alpha channel and YUV422 format.
(5) Each graphic layer support alpha blending with 8-bit
resolution.
This is a simplified version, only one primary plane, one
framebuffer, one crtc, one connector and one encoder for TFT
LCD panel.

Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
Signed-off-by: Jianwei Wang <jianwei.wang.chn@gmail.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Jianwei Wang committed Aug 20, 2015
1 parent 294947a commit 109eee2
Show file tree
Hide file tree
Showing 15 changed files with 1,439 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Documentation/devicetree/bindings/video/fsl,dcu.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Device Tree bindings for Freescale DCU DRM Driver

Required properties:
- compatible: Should be one of
* "fsl,ls1021a-dcu".
* "fsl,vf610-dcu".

- reg: Address and length of the register set for dcu.
- clocks: From common clock binding: handle to dcu clock.
- clock-names: From common clock binding: Shall be "dcu".
- big-endian Boolean property, LS1021A DCU registers are big-endian.
- fsl,panel: The phandle to panel node.

Examples:
dcu: dcu@2ce0000 {
compatible = "fsl,ls1021a-dcu";
reg = <0x0 0x2ce0000 0x0 0x10000>;
clocks = <&platform_clk 0>;
clock-names = "dcu";
big-endian;
fsl,panel = <&panel>;
};
2 changes: 2 additions & 0 deletions drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ source "drivers/gpu/drm/virtio/Kconfig"

source "drivers/gpu/drm/msm/Kconfig"

source "drivers/gpu/drm/fsl-dcu/Kconfig"

source "drivers/gpu/drm/tegra/Kconfig"

source "drivers/gpu/drm/panel/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ obj-$(CONFIG_DRM_IMX) += imx/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
18 changes: 18 additions & 0 deletions drivers/gpu/drm/fsl-dcu/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
config DRM_FSL_DCU
tristate "DRM Support for Freescale DCU"
depends on DRM && OF && ARM
select BACKLIGHT_CLASS_DEVICE
select BACKLIGHT_LCD_SUPPORT
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_KMS_FB_HELPER
select DRM_PANEL
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select REGMAP_MMIO
select VIDEOMODE_HELPERS
help
Choose this option if you have an Freescale DCU chipset.
If M is selected the module will be called fsl-dcu-drm.
7 changes: 7 additions & 0 deletions drivers/gpu/drm/fsl-dcu/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
fsl_dcu_drm_kms.o \
fsl_dcu_drm_rgb.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
210 changes: 210 additions & 0 deletions drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
Original file line number Diff line number Diff line change
@@ -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;
}
19 changes: 19 additions & 0 deletions drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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__

struct fsl_dcu_drm_device;

int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);

#endif /* __FSL_DCU_DRM_CRTC_H__ */
Loading

0 comments on commit 109eee2

Please sign in to comment.