Skip to content

Commit

Permalink
drm/imx: Introduce i.MX8qm/qxp DPU DRM
Browse files Browse the repository at this point in the history
This patch introduces i.MX8qm/qxp Display Processing Unit(DPU) DRM support.

DPU is comprised of two main components that include a blit engine for
2D graphics accelerations(with composition support) and a display controller
for display output processing, as well as a command sequencer.  Outside of
DPU, optional prefetch engines, a.k.a, Prefetch Resolve Gasket(PRG) and
Display Prefetch Resolve(DPR), can fetch data from memory prior to some DPU
fetchunits of blit engine and display controller.  The prefetch engines
support reading linear formats and resolving Vivante GPU tile formats.

This patch adds kernel modesetting support for the display controller part.
The driver supports two CRTCs per display controller, planes backed by
four fetchunits(decode0/1, fetchlayer, fetchwarp), fetchunit allocation
logic for the two CRTCs, prefetch engines(with tile resolving supported),
plane upscaling/deinterlacing/yuv2rgb CSC/alpha blending and CRTC gamma
correction.  The registers of the controller is accessed without command
sequencer involved, instead just by using CPU.

Reference manual can be found at:
https://www.nxp.com/webapp/Download?colCode=IMX8DQXPRM

Signed-off-by: Liu Ying <victor.liu@nxp.com>
  • Loading branch information
Liu Ying authored and intel-lab-lkp committed Dec 3, 2020
1 parent bf259fa commit 9782ac2
Show file tree
Hide file tree
Showing 34 changed files with 9,445 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/imx/Kconfig
Expand Up @@ -41,3 +41,4 @@ config DRM_IMX_HDMI
Choose this if you want to use HDMI on i.MX6.

source "drivers/gpu/drm/imx/dcss/Kconfig"
source "drivers/gpu/drm/imx/dpu/Kconfig"
1 change: 1 addition & 0 deletions drivers/gpu/drm/imx/Makefile
Expand Up @@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o

obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
obj-$(CONFIG_DRM_IMX_DPU) += dpu/
10 changes: 10 additions & 0 deletions drivers/gpu/drm/imx/dpu/Kconfig
@@ -0,0 +1,10 @@
config DRM_IMX_DPU
tristate "DRM support for Freescale i.MX DPU Graphics"
select DRM_KMS_HELPER
select VIDEOMODE_HELPERS
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
depends on DRM && OF && IMX_SCU && ARCH_MXC
depends on COMMON_CLK
help
enable Freescale i.MX DPU graphics support
10 changes: 10 additions & 0 deletions drivers/gpu/drm/imx/dpu/Makefile
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0

imx-dpu-drm-objs := dpu-constframe.o dpu-core.o dpu-crtc.o \
dpu-disengcfg.o dpu-dprc.o dpu-drv.o dpu-extdst.o \
dpu-fetchdecode.o dpu-fetcheco.o dpu-fetchlayer.o \
dpu-fetchwarp.o dpu-fetchunit.o dpu-framegen.o \
dpu-gammacor.o dpu-hscaler.o dpu-kms.o dpu-layerblend.o \
dpu-plane.o dpu-prg.o dpu-tcon.o dpu-vscaler.o

obj-$(CONFIG_DRM_IMX_DPU) += imx-dpu-drm.o
170 changes: 170 additions & 0 deletions drivers/gpu/drm/imx/dpu/dpu-constframe.c
@@ -0,0 +1,170 @@
// SPDX-License-Identifier: GPL-2.0+

/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017-2020 NXP
*/

#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/sizes.h>

#include "dpu-prv.h"

#define STATICCONTROL 0x8

#define FRAMEDIMENSIONS 0xc
#define WIDTH(w) (((w) - 1) & 0x3fff)
#define HEIGHT(h) ((((h) - 1) & 0x3fff) << 16)

#define CONSTANTCOLOR 0x10
#define RED(r) (((r) & 0xff) << 24)
#define GREEN(g) (((g) & 0xff) << 16)
#define BLUE(b) (((b) & 0xff) << 8)
#define ALPHA(a) ((a) & 0xff)

struct dpu_constframe {
void __iomem *pec_base;
void __iomem *base;
struct mutex mutex;
unsigned int id;
unsigned int index;
enum dpu_link_id link_id;
bool inuse;
struct dpu_soc *dpu;
};

static const enum dpu_link_id
dpu_cf_link_id[] = {LINK_ID_CONSTFRAME0, LINK_ID_CONSTFRAME1,
LINK_ID_CONSTFRAME4, LINK_ID_CONSTFRAME5};

static inline void dpu_cf_write(struct dpu_constframe *cf,
unsigned int offset, u32 value)
{
writel(value, cf->base + offset);
}

static void dpu_cf_enable_shden(struct dpu_constframe *cf)
{
dpu_cf_write(cf, STATICCONTROL, SHDEN);
}

enum dpu_link_id dpu_cf_get_link_id(struct dpu_constframe *cf)
{
return cf->link_id;
}

void dpu_cf_framedimensions(struct dpu_constframe *cf, unsigned int w,
unsigned int h)
{
dpu_cf_write(cf, FRAMEDIMENSIONS, WIDTH(w) | HEIGHT(h));
}

void dpu_cf_constantcolor_black(struct dpu_constframe *cf)
{
dpu_cf_write(cf, CONSTANTCOLOR, 0);
}

void dpu_cf_constantcolor_blue(struct dpu_constframe *cf)
{
dpu_cf_write(cf, CONSTANTCOLOR, BLUE(0xff));
}

static struct dpu_constframe *dpu_cf_get(struct dpu_soc *dpu, unsigned int id)
{
struct dpu_constframe *cf;
int i;

for (i = 0; i < ARRAY_SIZE(dpu->cf_priv); i++) {
cf = dpu->cf_priv[i];
if (cf->id == id)
break;
}

if (i == ARRAY_SIZE(dpu->cf_priv))
return ERR_PTR(-EINVAL);

mutex_lock(&cf->mutex);

if (cf->inuse) {
mutex_unlock(&cf->mutex);
return ERR_PTR(-EBUSY);
}

cf->inuse = true;

mutex_unlock(&cf->mutex);

return cf;
}

static void dpu_cf_put(struct dpu_constframe *cf)
{
mutex_lock(&cf->mutex);

cf->inuse = false;

mutex_unlock(&cf->mutex);
}

/* ConstFrame for safety stream */
struct dpu_constframe *dpu_cf_safe_get(struct dpu_soc *dpu,
unsigned int stream_id)
{
return dpu_cf_get(dpu, stream_id + DPU_SAFETY_STREAM_OFFSET);
}

void dpu_cf_safe_put(struct dpu_constframe *cf)
{
return dpu_cf_put(cf);
}

/* ConstFrame for content stream */
struct dpu_constframe *dpu_cf_cont_get(struct dpu_soc *dpu,
unsigned int stream_id)
{
return dpu_cf_get(dpu, stream_id);
}

void dpu_cf_cont_put(struct dpu_constframe *cf)
{
return dpu_cf_put(cf);
}

void dpu_cf_hw_init(struct dpu_soc *dpu, unsigned int index)
{
struct dpu_constframe *cf = dpu->cf_priv[index];

dpu_cf_enable_shden(cf);
}

int dpu_cf_init(struct dpu_soc *dpu, unsigned int index,
unsigned int id, enum dpu_unit_type type,
unsigned long pec_base, unsigned long base)
{
struct dpu_constframe *cf;

cf = devm_kzalloc(dpu->dev, sizeof(*cf), GFP_KERNEL);
if (!cf)
return -ENOMEM;

dpu->cf_priv[index] = cf;

cf->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
if (!cf->pec_base)
return -ENOMEM;

cf->base = devm_ioremap(dpu->dev, base, SZ_32);
if (!cf->base)
return -ENOMEM;

cf->dpu = dpu;
cf->id = id;
cf->index = index;
cf->link_id = dpu_cf_link_id[index];

mutex_init(&cf->mutex);

return 0;
}

0 comments on commit 9782ac2

Please sign in to comment.