162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Based on sun4i_backend.c, which is:
662306a36Sopenharmony_ci *   Copyright (C) 2015 Free Electrons
762306a36Sopenharmony_ci *   Copyright (C) 2015 NextThing Co
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/component.h>
1162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_device.h>
1562306a36Sopenharmony_ci#include <linux/of_graph.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/reset.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
2062306a36Sopenharmony_ci#include <drm/drm_crtc.h>
2162306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
2262306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h>
2362306a36Sopenharmony_ci#include <drm/drm_probe_helper.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "sun4i_drv.h"
2662306a36Sopenharmony_ci#include "sun8i_mixer.h"
2762306a36Sopenharmony_ci#include "sun8i_ui_layer.h"
2862306a36Sopenharmony_ci#include "sun8i_vi_layer.h"
2962306a36Sopenharmony_ci#include "sunxi_engine.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct de2_fmt_info {
3262306a36Sopenharmony_ci	u32	drm_fmt;
3362306a36Sopenharmony_ci	u32	de2_fmt;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const struct de2_fmt_info de2_formats[] = {
3762306a36Sopenharmony_ci	{
3862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ARGB8888,
3962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
4062306a36Sopenharmony_ci	},
4162306a36Sopenharmony_ci	{
4262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ABGR8888,
4362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
4462306a36Sopenharmony_ci	},
4562306a36Sopenharmony_ci	{
4662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBA8888,
4762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
4862306a36Sopenharmony_ci	},
4962306a36Sopenharmony_ci	{
5062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRA8888,
5162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
5262306a36Sopenharmony_ci	},
5362306a36Sopenharmony_ci	{
5462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XRGB8888,
5562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
5662306a36Sopenharmony_ci	},
5762306a36Sopenharmony_ci	{
5862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XBGR8888,
5962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
6062306a36Sopenharmony_ci	},
6162306a36Sopenharmony_ci	{
6262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBX8888,
6362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
6462306a36Sopenharmony_ci	},
6562306a36Sopenharmony_ci	{
6662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRX8888,
6762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
6862306a36Sopenharmony_ci	},
6962306a36Sopenharmony_ci	{
7062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGB888,
7162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
7262306a36Sopenharmony_ci	},
7362306a36Sopenharmony_ci	{
7462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGR888,
7562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci	{
7862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGB565,
7962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
8062306a36Sopenharmony_ci	},
8162306a36Sopenharmony_ci	{
8262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGR565,
8362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
8462306a36Sopenharmony_ci	},
8562306a36Sopenharmony_ci	{
8662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ARGB4444,
8762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
8862306a36Sopenharmony_ci	},
8962306a36Sopenharmony_ci	{
9062306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
9162306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XRGB4444,
9262306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
9362306a36Sopenharmony_ci	},
9462306a36Sopenharmony_ci	{
9562306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ABGR4444,
9662306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
9762306a36Sopenharmony_ci	},
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
10062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XBGR4444,
10162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
10262306a36Sopenharmony_ci	},
10362306a36Sopenharmony_ci	{
10462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBA4444,
10562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
10662306a36Sopenharmony_ci	},
10762306a36Sopenharmony_ci	{
10862306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
10962306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBX4444,
11062306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
11162306a36Sopenharmony_ci	},
11262306a36Sopenharmony_ci	{
11362306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRA4444,
11462306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
11562306a36Sopenharmony_ci	},
11662306a36Sopenharmony_ci	{
11762306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
11862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRX4444,
11962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
12062306a36Sopenharmony_ci	},
12162306a36Sopenharmony_ci	{
12262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ARGB1555,
12362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
12462306a36Sopenharmony_ci	},
12562306a36Sopenharmony_ci	{
12662306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
12762306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XRGB1555,
12862306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
12962306a36Sopenharmony_ci	},
13062306a36Sopenharmony_ci	{
13162306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ABGR1555,
13262306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
13362306a36Sopenharmony_ci	},
13462306a36Sopenharmony_ci	{
13562306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
13662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_XBGR1555,
13762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
13862306a36Sopenharmony_ci	},
13962306a36Sopenharmony_ci	{
14062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBA5551,
14162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
14262306a36Sopenharmony_ci	},
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
14562306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBX5551,
14662306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
14762306a36Sopenharmony_ci	},
14862306a36Sopenharmony_ci	{
14962306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRA5551,
15062306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	{
15362306a36Sopenharmony_ci		/* for DE2 VI layer which ignores alpha */
15462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRX5551,
15562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
15662306a36Sopenharmony_ci	},
15762306a36Sopenharmony_ci	{
15862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ARGB2101010,
15962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
16062306a36Sopenharmony_ci	},
16162306a36Sopenharmony_ci	{
16262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_ABGR2101010,
16362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
16462306a36Sopenharmony_ci	},
16562306a36Sopenharmony_ci	{
16662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_RGBA1010102,
16762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
16862306a36Sopenharmony_ci	},
16962306a36Sopenharmony_ci	{
17062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_BGRA1010102,
17162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
17262306a36Sopenharmony_ci	},
17362306a36Sopenharmony_ci	{
17462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_UYVY,
17562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
17662306a36Sopenharmony_ci	},
17762306a36Sopenharmony_ci	{
17862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_VYUY,
17962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
18062306a36Sopenharmony_ci	},
18162306a36Sopenharmony_ci	{
18262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YUYV,
18362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
18462306a36Sopenharmony_ci	},
18562306a36Sopenharmony_ci	{
18662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YVYU,
18762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
18862306a36Sopenharmony_ci	},
18962306a36Sopenharmony_ci	{
19062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_NV16,
19162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_NV16,
19262306a36Sopenharmony_ci	},
19362306a36Sopenharmony_ci	{
19462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_NV61,
19562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_NV61,
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci	{
19862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_NV12,
19962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_NV12,
20062306a36Sopenharmony_ci	},
20162306a36Sopenharmony_ci	{
20262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_NV21,
20362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_NV21,
20462306a36Sopenharmony_ci	},
20562306a36Sopenharmony_ci	{
20662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YUV422,
20762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
20862306a36Sopenharmony_ci	},
20962306a36Sopenharmony_ci	{
21062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YUV420,
21162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
21262306a36Sopenharmony_ci	},
21362306a36Sopenharmony_ci	{
21462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YUV411,
21562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
21662306a36Sopenharmony_ci	},
21762306a36Sopenharmony_ci	{
21862306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YVU422,
21962306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
22062306a36Sopenharmony_ci	},
22162306a36Sopenharmony_ci	{
22262306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YVU420,
22362306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
22462306a36Sopenharmony_ci	},
22562306a36Sopenharmony_ci	{
22662306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_YVU411,
22762306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
22862306a36Sopenharmony_ci	},
22962306a36Sopenharmony_ci	{
23062306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_P010,
23162306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
23262306a36Sopenharmony_ci	},
23362306a36Sopenharmony_ci	{
23462306a36Sopenharmony_ci		.drm_fmt = DRM_FORMAT_P210,
23562306a36Sopenharmony_ci		.de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
23662306a36Sopenharmony_ci	},
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	unsigned int i;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
24462306a36Sopenharmony_ci		if (de2_formats[i].drm_fmt == format) {
24562306a36Sopenharmony_ci			*hw_format = de2_formats[i].de2_fmt;
24662306a36Sopenharmony_ci			return 0;
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return -EINVAL;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void sun8i_mixer_commit(struct sunxi_engine *engine)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("Committing changes\n");
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
25762306a36Sopenharmony_ci		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic struct drm_plane **sun8i_layers_init(struct drm_device *drm,
26162306a36Sopenharmony_ci					    struct sunxi_engine *engine)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct drm_plane **planes;
26462306a36Sopenharmony_ci	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
26562306a36Sopenharmony_ci	int i;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	planes = devm_kcalloc(drm->dev,
26862306a36Sopenharmony_ci			      mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
26962306a36Sopenharmony_ci			      sizeof(*planes), GFP_KERNEL);
27062306a36Sopenharmony_ci	if (!planes)
27162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	for (i = 0; i < mixer->cfg->vi_num; i++) {
27462306a36Sopenharmony_ci		struct sun8i_vi_layer *layer;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		layer = sun8i_vi_layer_init_one(drm, mixer, i);
27762306a36Sopenharmony_ci		if (IS_ERR(layer)) {
27862306a36Sopenharmony_ci			dev_err(drm->dev,
27962306a36Sopenharmony_ci				"Couldn't initialize overlay plane\n");
28062306a36Sopenharmony_ci			return ERR_CAST(layer);
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		planes[i] = &layer->plane;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	for (i = 0; i < mixer->cfg->ui_num; i++) {
28762306a36Sopenharmony_ci		struct sun8i_ui_layer *layer;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		layer = sun8i_ui_layer_init_one(drm, mixer, i);
29062306a36Sopenharmony_ci		if (IS_ERR(layer)) {
29162306a36Sopenharmony_ci			dev_err(drm->dev, "Couldn't initialize %s plane\n",
29262306a36Sopenharmony_ci				i ? "overlay" : "primary");
29362306a36Sopenharmony_ci			return ERR_CAST(layer);
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		planes[mixer->cfg->vi_num + i] = &layer->plane;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return planes;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void sun8i_mixer_mode_set(struct sunxi_engine *engine,
30362306a36Sopenharmony_ci				 const struct drm_display_mode *mode)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
30662306a36Sopenharmony_ci	u32 bld_base, size, val;
30762306a36Sopenharmony_ci	bool interlaced;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	bld_base = sun8i_blender_base(mixer);
31062306a36Sopenharmony_ci	interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
31162306a36Sopenharmony_ci	size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
31462306a36Sopenharmony_ci			 mode->hdisplay, mode->vdisplay);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
31762306a36Sopenharmony_ci	regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (interlaced)
32062306a36Sopenharmony_ci		val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
32162306a36Sopenharmony_ci	else
32262306a36Sopenharmony_ci		val = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
32562306a36Sopenharmony_ci			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
32862306a36Sopenharmony_ci			 interlaced ? "on" : "off");
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic const struct sunxi_engine_ops sun8i_engine_ops = {
33262306a36Sopenharmony_ci	.commit		= sun8i_mixer_commit,
33362306a36Sopenharmony_ci	.layers_init	= sun8i_layers_init,
33462306a36Sopenharmony_ci	.mode_set	= sun8i_mixer_mode_set,
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic const struct regmap_config sun8i_mixer_regmap_config = {
33862306a36Sopenharmony_ci	.reg_bits	= 32,
33962306a36Sopenharmony_ci	.val_bits	= 32,
34062306a36Sopenharmony_ci	.reg_stride	= 4,
34162306a36Sopenharmony_ci	.max_register	= 0xffffc, /* guessed */
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int sun8i_mixer_of_get_id(struct device_node *node)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct device_node *ep, *remote;
34762306a36Sopenharmony_ci	struct of_endpoint of_ep;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Output port is 1, and we want the first endpoint. */
35062306a36Sopenharmony_ci	ep = of_graph_get_endpoint_by_regs(node, 1, -1);
35162306a36Sopenharmony_ci	if (!ep)
35262306a36Sopenharmony_ci		return -EINVAL;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	remote = of_graph_get_remote_endpoint(ep);
35562306a36Sopenharmony_ci	of_node_put(ep);
35662306a36Sopenharmony_ci	if (!remote)
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	of_graph_parse_endpoint(remote, &of_ep);
36062306a36Sopenharmony_ci	of_node_put(remote);
36162306a36Sopenharmony_ci	return of_ep.id;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int sun8i_mixer_bind(struct device *dev, struct device *master,
36562306a36Sopenharmony_ci			      void *data)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
36862306a36Sopenharmony_ci	struct drm_device *drm = data;
36962306a36Sopenharmony_ci	struct sun4i_drv *drv = drm->dev_private;
37062306a36Sopenharmony_ci	struct sun8i_mixer *mixer;
37162306a36Sopenharmony_ci	void __iomem *regs;
37262306a36Sopenharmony_ci	unsigned int base;
37362306a36Sopenharmony_ci	int plane_cnt;
37462306a36Sopenharmony_ci	int i, ret;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/*
37762306a36Sopenharmony_ci	 * The mixer uses single 32-bit register to store memory
37862306a36Sopenharmony_ci	 * addresses, so that it cannot deal with 64-bit memory
37962306a36Sopenharmony_ci	 * addresses.
38062306a36Sopenharmony_ci	 * Restrict the DMA mask so that the mixer won't be
38162306a36Sopenharmony_ci	 * allocated some memory that is too high.
38262306a36Sopenharmony_ci	 */
38362306a36Sopenharmony_ci	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
38462306a36Sopenharmony_ci	if (ret) {
38562306a36Sopenharmony_ci		dev_err(dev, "Cannot do 32-bit DMA.\n");
38662306a36Sopenharmony_ci		return ret;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
39062306a36Sopenharmony_ci	if (!mixer)
39162306a36Sopenharmony_ci		return -ENOMEM;
39262306a36Sopenharmony_ci	dev_set_drvdata(dev, mixer);
39362306a36Sopenharmony_ci	mixer->engine.ops = &sun8i_engine_ops;
39462306a36Sopenharmony_ci	mixer->engine.node = dev->of_node;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (of_property_present(dev->of_node, "iommus")) {
39762306a36Sopenharmony_ci		/*
39862306a36Sopenharmony_ci		 * This assume we have the same DMA constraints for
39962306a36Sopenharmony_ci		 * all our the mixers in our pipeline. This sounds
40062306a36Sopenharmony_ci		 * bad, but it has always been the case for us, and
40162306a36Sopenharmony_ci		 * DRM doesn't do per-device allocation either, so we
40262306a36Sopenharmony_ci		 * would need to fix DRM first...
40362306a36Sopenharmony_ci		 */
40462306a36Sopenharmony_ci		ret = of_dma_configure(drm->dev, dev->of_node, true);
40562306a36Sopenharmony_ci		if (ret)
40662306a36Sopenharmony_ci			return ret;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * While this function can fail, we shouldn't do anything
41162306a36Sopenharmony_ci	 * if this happens. Some early DE2 DT entries don't provide
41262306a36Sopenharmony_ci	 * mixer id but work nevertheless because matching between
41362306a36Sopenharmony_ci	 * TCON and mixer is done by comparing node pointers (old
41462306a36Sopenharmony_ci	 * way) instead comparing ids. If this function fails and
41562306a36Sopenharmony_ci	 * id is needed, it will fail during id matching anyway.
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci	mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	mixer->cfg = of_device_get_match_data(dev);
42062306a36Sopenharmony_ci	if (!mixer->cfg)
42162306a36Sopenharmony_ci		return -EINVAL;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	regs = devm_platform_ioremap_resource(pdev, 0);
42462306a36Sopenharmony_ci	if (IS_ERR(regs))
42562306a36Sopenharmony_ci		return PTR_ERR(regs);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
42862306a36Sopenharmony_ci						   &sun8i_mixer_regmap_config);
42962306a36Sopenharmony_ci	if (IS_ERR(mixer->engine.regs)) {
43062306a36Sopenharmony_ci		dev_err(dev, "Couldn't create the mixer regmap\n");
43162306a36Sopenharmony_ci		return PTR_ERR(mixer->engine.regs);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	mixer->reset = devm_reset_control_get(dev, NULL);
43562306a36Sopenharmony_ci	if (IS_ERR(mixer->reset)) {
43662306a36Sopenharmony_ci		dev_err(dev, "Couldn't get our reset line\n");
43762306a36Sopenharmony_ci		return PTR_ERR(mixer->reset);
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret = reset_control_deassert(mixer->reset);
44162306a36Sopenharmony_ci	if (ret) {
44262306a36Sopenharmony_ci		dev_err(dev, "Couldn't deassert our reset line\n");
44362306a36Sopenharmony_ci		return ret;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mixer->bus_clk = devm_clk_get(dev, "bus");
44762306a36Sopenharmony_ci	if (IS_ERR(mixer->bus_clk)) {
44862306a36Sopenharmony_ci		dev_err(dev, "Couldn't get the mixer bus clock\n");
44962306a36Sopenharmony_ci		ret = PTR_ERR(mixer->bus_clk);
45062306a36Sopenharmony_ci		goto err_assert_reset;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	clk_prepare_enable(mixer->bus_clk);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	mixer->mod_clk = devm_clk_get(dev, "mod");
45562306a36Sopenharmony_ci	if (IS_ERR(mixer->mod_clk)) {
45662306a36Sopenharmony_ci		dev_err(dev, "Couldn't get the mixer module clock\n");
45762306a36Sopenharmony_ci		ret = PTR_ERR(mixer->mod_clk);
45862306a36Sopenharmony_ci		goto err_disable_bus_clk;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/*
46262306a36Sopenharmony_ci	 * It seems that we need to enforce that rate for whatever
46362306a36Sopenharmony_ci	 * reason for the mixer to be functional. Make sure it's the
46462306a36Sopenharmony_ci	 * case.
46562306a36Sopenharmony_ci	 */
46662306a36Sopenharmony_ci	if (mixer->cfg->mod_rate)
46762306a36Sopenharmony_ci		clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	clk_prepare_enable(mixer->mod_clk);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	list_add_tail(&mixer->engine.list, &drv->engine_list);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	base = sun8i_blender_base(mixer);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Reset registers and disable unused sub-engines */
47662306a36Sopenharmony_ci	if (mixer->cfg->is_de3) {
47762306a36Sopenharmony_ci		for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
47862306a36Sopenharmony_ci			regmap_write(mixer->engine.regs, i, 0);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
48162306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
48262306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
48362306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
48462306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
48562306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
48662306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
48762306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
48862306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
48962306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
49062306a36Sopenharmony_ci	} else {
49162306a36Sopenharmony_ci		for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
49262306a36Sopenharmony_ci			regmap_write(mixer->engine.regs, i, 0);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
49562306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
49662306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
49762306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
49862306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
49962306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
50062306a36Sopenharmony_ci		regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Enable the mixer */
50462306a36Sopenharmony_ci	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
50562306a36Sopenharmony_ci		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* Set background color to black */
50862306a36Sopenharmony_ci	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
50962306a36Sopenharmony_ci		     SUN8I_MIXER_BLEND_COLOR_BLACK);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/*
51262306a36Sopenharmony_ci	 * Set fill color of bottom plane to black. Generally not needed
51362306a36Sopenharmony_ci	 * except when VI plane is at bottom (zpos = 0) and enabled.
51462306a36Sopenharmony_ci	 */
51562306a36Sopenharmony_ci	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
51662306a36Sopenharmony_ci		     SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
51762306a36Sopenharmony_ci	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
51862306a36Sopenharmony_ci		     SUN8I_MIXER_BLEND_COLOR_BLACK);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
52162306a36Sopenharmony_ci	for (i = 0; i < plane_cnt; i++)
52262306a36Sopenharmony_ci		regmap_write(mixer->engine.regs,
52362306a36Sopenharmony_ci			     SUN8I_MIXER_BLEND_MODE(base, i),
52462306a36Sopenharmony_ci			     SUN8I_MIXER_BLEND_MODE_DEF);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
52762306a36Sopenharmony_ci			   SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	return 0;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cierr_disable_bus_clk:
53262306a36Sopenharmony_ci	clk_disable_unprepare(mixer->bus_clk);
53362306a36Sopenharmony_cierr_assert_reset:
53462306a36Sopenharmony_ci	reset_control_assert(mixer->reset);
53562306a36Sopenharmony_ci	return ret;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void sun8i_mixer_unbind(struct device *dev, struct device *master,
53962306a36Sopenharmony_ci				 void *data)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	list_del(&mixer->engine.list);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	clk_disable_unprepare(mixer->mod_clk);
54662306a36Sopenharmony_ci	clk_disable_unprepare(mixer->bus_clk);
54762306a36Sopenharmony_ci	reset_control_assert(mixer->reset);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic const struct component_ops sun8i_mixer_ops = {
55162306a36Sopenharmony_ci	.bind	= sun8i_mixer_bind,
55262306a36Sopenharmony_ci	.unbind	= sun8i_mixer_unbind,
55362306a36Sopenharmony_ci};
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int sun8i_mixer_probe(struct platform_device *pdev)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	return component_add(&pdev->dev, &sun8i_mixer_ops);
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void sun8i_mixer_remove(struct platform_device *pdev)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	component_del(&pdev->dev, &sun8i_mixer_ops);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
56662306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER0_LAYOUT,
56762306a36Sopenharmony_ci	.scaler_mask	= 0xf,
56862306a36Sopenharmony_ci	.scanline_yuv	= 2048,
56962306a36Sopenharmony_ci	.ui_num		= 3,
57062306a36Sopenharmony_ci	.vi_num		= 1,
57162306a36Sopenharmony_ci};
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
57462306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER1_LAYOUT,
57562306a36Sopenharmony_ci	.scaler_mask	= 0x3,
57662306a36Sopenharmony_ci	.scanline_yuv	= 2048,
57762306a36Sopenharmony_ci	.ui_num		= 1,
57862306a36Sopenharmony_ci	.vi_num		= 1,
57962306a36Sopenharmony_ci};
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
58262306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER0_LAYOUT,
58362306a36Sopenharmony_ci	.mod_rate	= 432000000,
58462306a36Sopenharmony_ci	.scaler_mask	= 0xf,
58562306a36Sopenharmony_ci	.scanline_yuv	= 2048,
58662306a36Sopenharmony_ci	.ui_num		= 3,
58762306a36Sopenharmony_ci	.vi_num		= 1,
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
59162306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER0_LAYOUT,
59262306a36Sopenharmony_ci	.mod_rate	= 297000000,
59362306a36Sopenharmony_ci	.scaler_mask	= 0xf,
59462306a36Sopenharmony_ci	.scanline_yuv	= 2048,
59562306a36Sopenharmony_ci	.ui_num		= 3,
59662306a36Sopenharmony_ci	.vi_num		= 1,
59762306a36Sopenharmony_ci};
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
60062306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER1_LAYOUT,
60162306a36Sopenharmony_ci	.mod_rate	= 297000000,
60262306a36Sopenharmony_ci	.scaler_mask	= 0x3,
60362306a36Sopenharmony_ci	.scanline_yuv	= 2048,
60462306a36Sopenharmony_ci	.ui_num		= 1,
60562306a36Sopenharmony_ci	.vi_num		= 1,
60662306a36Sopenharmony_ci};
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
60962306a36Sopenharmony_ci	.vi_num = 2,
61062306a36Sopenharmony_ci	.ui_num = 1,
61162306a36Sopenharmony_ci	.scaler_mask = 0x3,
61262306a36Sopenharmony_ci	.scanline_yuv = 2048,
61362306a36Sopenharmony_ci	.ccsc = CCSC_MIXER0_LAYOUT,
61462306a36Sopenharmony_ci	.mod_rate = 150000000,
61562306a36Sopenharmony_ci};
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
61862306a36Sopenharmony_ci	.ccsc		= CCSC_D1_MIXER0_LAYOUT,
61962306a36Sopenharmony_ci	.mod_rate	= 297000000,
62062306a36Sopenharmony_ci	.scaler_mask	= 0x3,
62162306a36Sopenharmony_ci	.scanline_yuv	= 2048,
62262306a36Sopenharmony_ci	.ui_num		= 1,
62362306a36Sopenharmony_ci	.vi_num		= 1,
62462306a36Sopenharmony_ci};
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
62762306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER1_LAYOUT,
62862306a36Sopenharmony_ci	.mod_rate	= 297000000,
62962306a36Sopenharmony_ci	.scaler_mask	= 0x1,
63062306a36Sopenharmony_ci	.scanline_yuv	= 1024,
63162306a36Sopenharmony_ci	.ui_num		= 0,
63262306a36Sopenharmony_ci	.vi_num		= 1,
63362306a36Sopenharmony_ci};
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
63662306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER0_LAYOUT,
63762306a36Sopenharmony_ci	.mod_rate	= 297000000,
63862306a36Sopenharmony_ci	.scaler_mask	= 0xf,
63962306a36Sopenharmony_ci	.scanline_yuv	= 4096,
64062306a36Sopenharmony_ci	.ui_num		= 3,
64162306a36Sopenharmony_ci	.vi_num		= 1,
64262306a36Sopenharmony_ci};
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
64562306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER1_LAYOUT,
64662306a36Sopenharmony_ci	.mod_rate	= 297000000,
64762306a36Sopenharmony_ci	.scaler_mask	= 0x3,
64862306a36Sopenharmony_ci	.scanline_yuv	= 2048,
64962306a36Sopenharmony_ci	.ui_num		= 1,
65062306a36Sopenharmony_ci	.vi_num		= 1,
65162306a36Sopenharmony_ci};
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
65462306a36Sopenharmony_ci	.ccsc		= CCSC_MIXER0_LAYOUT,
65562306a36Sopenharmony_ci	.is_de3		= true,
65662306a36Sopenharmony_ci	.mod_rate	= 600000000,
65762306a36Sopenharmony_ci	.scaler_mask	= 0xf,
65862306a36Sopenharmony_ci	.scanline_yuv	= 4096,
65962306a36Sopenharmony_ci	.ui_num		= 3,
66062306a36Sopenharmony_ci	.vi_num		= 1,
66162306a36Sopenharmony_ci};
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic const struct of_device_id sun8i_mixer_of_table[] = {
66462306a36Sopenharmony_ci	{
66562306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
66662306a36Sopenharmony_ci		.data = &sun8i_a83t_mixer0_cfg,
66762306a36Sopenharmony_ci	},
66862306a36Sopenharmony_ci	{
66962306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-a83t-de2-mixer-1",
67062306a36Sopenharmony_ci		.data = &sun8i_a83t_mixer1_cfg,
67162306a36Sopenharmony_ci	},
67262306a36Sopenharmony_ci	{
67362306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-h3-de2-mixer-0",
67462306a36Sopenharmony_ci		.data = &sun8i_h3_mixer0_cfg,
67562306a36Sopenharmony_ci	},
67662306a36Sopenharmony_ci	{
67762306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-r40-de2-mixer-0",
67862306a36Sopenharmony_ci		.data = &sun8i_r40_mixer0_cfg,
67962306a36Sopenharmony_ci	},
68062306a36Sopenharmony_ci	{
68162306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-r40-de2-mixer-1",
68262306a36Sopenharmony_ci		.data = &sun8i_r40_mixer1_cfg,
68362306a36Sopenharmony_ci	},
68462306a36Sopenharmony_ci	{
68562306a36Sopenharmony_ci		.compatible = "allwinner,sun8i-v3s-de2-mixer",
68662306a36Sopenharmony_ci		.data = &sun8i_v3s_mixer_cfg,
68762306a36Sopenharmony_ci	},
68862306a36Sopenharmony_ci	{
68962306a36Sopenharmony_ci		.compatible = "allwinner,sun20i-d1-de2-mixer-0",
69062306a36Sopenharmony_ci		.data = &sun20i_d1_mixer0_cfg,
69162306a36Sopenharmony_ci	},
69262306a36Sopenharmony_ci	{
69362306a36Sopenharmony_ci		.compatible = "allwinner,sun20i-d1-de2-mixer-1",
69462306a36Sopenharmony_ci		.data = &sun20i_d1_mixer1_cfg,
69562306a36Sopenharmony_ci	},
69662306a36Sopenharmony_ci	{
69762306a36Sopenharmony_ci		.compatible = "allwinner,sun50i-a64-de2-mixer-0",
69862306a36Sopenharmony_ci		.data = &sun50i_a64_mixer0_cfg,
69962306a36Sopenharmony_ci	},
70062306a36Sopenharmony_ci	{
70162306a36Sopenharmony_ci		.compatible = "allwinner,sun50i-a64-de2-mixer-1",
70262306a36Sopenharmony_ci		.data = &sun50i_a64_mixer1_cfg,
70362306a36Sopenharmony_ci	},
70462306a36Sopenharmony_ci	{
70562306a36Sopenharmony_ci		.compatible = "allwinner,sun50i-h6-de3-mixer-0",
70662306a36Sopenharmony_ci		.data = &sun50i_h6_mixer0_cfg,
70762306a36Sopenharmony_ci	},
70862306a36Sopenharmony_ci	{ }
70962306a36Sopenharmony_ci};
71062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic struct platform_driver sun8i_mixer_platform_driver = {
71362306a36Sopenharmony_ci	.probe		= sun8i_mixer_probe,
71462306a36Sopenharmony_ci	.remove_new	= sun8i_mixer_remove,
71562306a36Sopenharmony_ci	.driver		= {
71662306a36Sopenharmony_ci		.name		= "sun8i-mixer",
71762306a36Sopenharmony_ci		.of_match_table	= sun8i_mixer_of_table,
71862306a36Sopenharmony_ci	},
71962306a36Sopenharmony_ci};
72062306a36Sopenharmony_cimodule_platform_driver(sun8i_mixer_platform_driver);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ciMODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
72362306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
72462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
725