cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sun8i_mixer.c (17968B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
      4 *
      5 * Based on sun4i_backend.c, which is:
      6 *   Copyright (C) 2015 Free Electrons
      7 *   Copyright (C) 2015 NextThing Co
      8 */
      9
     10#include <linux/component.h>
     11#include <linux/dma-mapping.h>
     12#include <linux/module.h>
     13#include <linux/of_device.h>
     14#include <linux/of_graph.h>
     15#include <linux/reset.h>
     16
     17#include <drm/drm_atomic_helper.h>
     18#include <drm/drm_crtc.h>
     19#include <drm/drm_fb_cma_helper.h>
     20#include <drm/drm_gem_cma_helper.h>
     21#include <drm/drm_plane_helper.h>
     22#include <drm/drm_probe_helper.h>
     23
     24#include "sun4i_drv.h"
     25#include "sun8i_mixer.h"
     26#include "sun8i_ui_layer.h"
     27#include "sun8i_vi_layer.h"
     28#include "sunxi_engine.h"
     29
     30struct de2_fmt_info {
     31	u32	drm_fmt;
     32	u32	de2_fmt;
     33};
     34
     35static const struct de2_fmt_info de2_formats[] = {
     36	{
     37		.drm_fmt = DRM_FORMAT_ARGB8888,
     38		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
     39	},
     40	{
     41		.drm_fmt = DRM_FORMAT_ABGR8888,
     42		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
     43	},
     44	{
     45		.drm_fmt = DRM_FORMAT_RGBA8888,
     46		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
     47	},
     48	{
     49		.drm_fmt = DRM_FORMAT_BGRA8888,
     50		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
     51	},
     52	{
     53		.drm_fmt = DRM_FORMAT_XRGB8888,
     54		.de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
     55	},
     56	{
     57		.drm_fmt = DRM_FORMAT_XBGR8888,
     58		.de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
     59	},
     60	{
     61		.drm_fmt = DRM_FORMAT_RGBX8888,
     62		.de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
     63	},
     64	{
     65		.drm_fmt = DRM_FORMAT_BGRX8888,
     66		.de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
     67	},
     68	{
     69		.drm_fmt = DRM_FORMAT_RGB888,
     70		.de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
     71	},
     72	{
     73		.drm_fmt = DRM_FORMAT_BGR888,
     74		.de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
     75	},
     76	{
     77		.drm_fmt = DRM_FORMAT_RGB565,
     78		.de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
     79	},
     80	{
     81		.drm_fmt = DRM_FORMAT_BGR565,
     82		.de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
     83	},
     84	{
     85		.drm_fmt = DRM_FORMAT_ARGB4444,
     86		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
     87	},
     88	{
     89		/* for DE2 VI layer which ignores alpha */
     90		.drm_fmt = DRM_FORMAT_XRGB4444,
     91		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
     92	},
     93	{
     94		.drm_fmt = DRM_FORMAT_ABGR4444,
     95		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
     96	},
     97	{
     98		/* for DE2 VI layer which ignores alpha */
     99		.drm_fmt = DRM_FORMAT_XBGR4444,
    100		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
    101	},
    102	{
    103		.drm_fmt = DRM_FORMAT_RGBA4444,
    104		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
    105	},
    106	{
    107		/* for DE2 VI layer which ignores alpha */
    108		.drm_fmt = DRM_FORMAT_RGBX4444,
    109		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
    110	},
    111	{
    112		.drm_fmt = DRM_FORMAT_BGRA4444,
    113		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
    114	},
    115	{
    116		/* for DE2 VI layer which ignores alpha */
    117		.drm_fmt = DRM_FORMAT_BGRX4444,
    118		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
    119	},
    120	{
    121		.drm_fmt = DRM_FORMAT_ARGB1555,
    122		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
    123	},
    124	{
    125		/* for DE2 VI layer which ignores alpha */
    126		.drm_fmt = DRM_FORMAT_XRGB1555,
    127		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
    128	},
    129	{
    130		.drm_fmt = DRM_FORMAT_ABGR1555,
    131		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
    132	},
    133	{
    134		/* for DE2 VI layer which ignores alpha */
    135		.drm_fmt = DRM_FORMAT_XBGR1555,
    136		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
    137	},
    138	{
    139		.drm_fmt = DRM_FORMAT_RGBA5551,
    140		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
    141	},
    142	{
    143		/* for DE2 VI layer which ignores alpha */
    144		.drm_fmt = DRM_FORMAT_RGBX5551,
    145		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
    146	},
    147	{
    148		.drm_fmt = DRM_FORMAT_BGRA5551,
    149		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
    150	},
    151	{
    152		/* for DE2 VI layer which ignores alpha */
    153		.drm_fmt = DRM_FORMAT_BGRX5551,
    154		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
    155	},
    156	{
    157		.drm_fmt = DRM_FORMAT_ARGB2101010,
    158		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
    159	},
    160	{
    161		.drm_fmt = DRM_FORMAT_ABGR2101010,
    162		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
    163	},
    164	{
    165		.drm_fmt = DRM_FORMAT_RGBA1010102,
    166		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
    167	},
    168	{
    169		.drm_fmt = DRM_FORMAT_BGRA1010102,
    170		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
    171	},
    172	{
    173		.drm_fmt = DRM_FORMAT_UYVY,
    174		.de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
    175	},
    176	{
    177		.drm_fmt = DRM_FORMAT_VYUY,
    178		.de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
    179	},
    180	{
    181		.drm_fmt = DRM_FORMAT_YUYV,
    182		.de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
    183	},
    184	{
    185		.drm_fmt = DRM_FORMAT_YVYU,
    186		.de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
    187	},
    188	{
    189		.drm_fmt = DRM_FORMAT_NV16,
    190		.de2_fmt = SUN8I_MIXER_FBFMT_NV16,
    191	},
    192	{
    193		.drm_fmt = DRM_FORMAT_NV61,
    194		.de2_fmt = SUN8I_MIXER_FBFMT_NV61,
    195	},
    196	{
    197		.drm_fmt = DRM_FORMAT_NV12,
    198		.de2_fmt = SUN8I_MIXER_FBFMT_NV12,
    199	},
    200	{
    201		.drm_fmt = DRM_FORMAT_NV21,
    202		.de2_fmt = SUN8I_MIXER_FBFMT_NV21,
    203	},
    204	{
    205		.drm_fmt = DRM_FORMAT_YUV422,
    206		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
    207	},
    208	{
    209		.drm_fmt = DRM_FORMAT_YUV420,
    210		.de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
    211	},
    212	{
    213		.drm_fmt = DRM_FORMAT_YUV411,
    214		.de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
    215	},
    216	{
    217		.drm_fmt = DRM_FORMAT_YVU422,
    218		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
    219	},
    220	{
    221		.drm_fmt = DRM_FORMAT_YVU420,
    222		.de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
    223	},
    224	{
    225		.drm_fmt = DRM_FORMAT_YVU411,
    226		.de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
    227	},
    228	{
    229		.drm_fmt = DRM_FORMAT_P010,
    230		.de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
    231	},
    232	{
    233		.drm_fmt = DRM_FORMAT_P210,
    234		.de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
    235	},
    236};
    237
    238int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
    239{
    240	unsigned int i;
    241
    242	for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
    243		if (de2_formats[i].drm_fmt == format) {
    244			*hw_format = de2_formats[i].de2_fmt;
    245			return 0;
    246		}
    247
    248	return -EINVAL;
    249}
    250
    251static void sun8i_mixer_commit(struct sunxi_engine *engine)
    252{
    253	DRM_DEBUG_DRIVER("Committing changes\n");
    254
    255	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
    256		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
    257}
    258
    259static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
    260					    struct sunxi_engine *engine)
    261{
    262	struct drm_plane **planes;
    263	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
    264	int i;
    265
    266	planes = devm_kcalloc(drm->dev,
    267			      mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
    268			      sizeof(*planes), GFP_KERNEL);
    269	if (!planes)
    270		return ERR_PTR(-ENOMEM);
    271
    272	for (i = 0; i < mixer->cfg->vi_num; i++) {
    273		struct sun8i_vi_layer *layer;
    274
    275		layer = sun8i_vi_layer_init_one(drm, mixer, i);
    276		if (IS_ERR(layer)) {
    277			dev_err(drm->dev,
    278				"Couldn't initialize overlay plane\n");
    279			return ERR_CAST(layer);
    280		}
    281
    282		planes[i] = &layer->plane;
    283	}
    284
    285	for (i = 0; i < mixer->cfg->ui_num; i++) {
    286		struct sun8i_ui_layer *layer;
    287
    288		layer = sun8i_ui_layer_init_one(drm, mixer, i);
    289		if (IS_ERR(layer)) {
    290			dev_err(drm->dev, "Couldn't initialize %s plane\n",
    291				i ? "overlay" : "primary");
    292			return ERR_CAST(layer);
    293		}
    294
    295		planes[mixer->cfg->vi_num + i] = &layer->plane;
    296	}
    297
    298	return planes;
    299}
    300
    301static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
    302				 const struct drm_display_mode *mode)
    303{
    304	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
    305	u32 bld_base, size, val;
    306	bool interlaced;
    307
    308	bld_base = sun8i_blender_base(mixer);
    309	interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
    310	size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
    311
    312	DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
    313			 mode->hdisplay, mode->vdisplay);
    314
    315	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
    316	regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
    317
    318	if (interlaced)
    319		val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
    320	else
    321		val = 0;
    322
    323	regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
    324			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
    325
    326	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
    327			 interlaced ? "on" : "off");
    328}
    329
    330static const struct sunxi_engine_ops sun8i_engine_ops = {
    331	.commit		= sun8i_mixer_commit,
    332	.layers_init	= sun8i_layers_init,
    333	.mode_set	= sun8i_mixer_mode_set,
    334};
    335
    336static const struct regmap_config sun8i_mixer_regmap_config = {
    337	.reg_bits	= 32,
    338	.val_bits	= 32,
    339	.reg_stride	= 4,
    340	.max_register	= 0xffffc, /* guessed */
    341};
    342
    343static int sun8i_mixer_of_get_id(struct device_node *node)
    344{
    345	struct device_node *ep, *remote;
    346	struct of_endpoint of_ep;
    347
    348	/* Output port is 1, and we want the first endpoint. */
    349	ep = of_graph_get_endpoint_by_regs(node, 1, -1);
    350	if (!ep)
    351		return -EINVAL;
    352
    353	remote = of_graph_get_remote_endpoint(ep);
    354	of_node_put(ep);
    355	if (!remote)
    356		return -EINVAL;
    357
    358	of_graph_parse_endpoint(remote, &of_ep);
    359	of_node_put(remote);
    360	return of_ep.id;
    361}
    362
    363static int sun8i_mixer_bind(struct device *dev, struct device *master,
    364			      void *data)
    365{
    366	struct platform_device *pdev = to_platform_device(dev);
    367	struct drm_device *drm = data;
    368	struct sun4i_drv *drv = drm->dev_private;
    369	struct sun8i_mixer *mixer;
    370	void __iomem *regs;
    371	unsigned int base;
    372	int plane_cnt;
    373	int i, ret;
    374
    375	/*
    376	 * The mixer uses single 32-bit register to store memory
    377	 * addresses, so that it cannot deal with 64-bit memory
    378	 * addresses.
    379	 * Restrict the DMA mask so that the mixer won't be
    380	 * allocated some memory that is too high.
    381	 */
    382	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
    383	if (ret) {
    384		dev_err(dev, "Cannot do 32-bit DMA.\n");
    385		return ret;
    386	}
    387
    388	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
    389	if (!mixer)
    390		return -ENOMEM;
    391	dev_set_drvdata(dev, mixer);
    392	mixer->engine.ops = &sun8i_engine_ops;
    393	mixer->engine.node = dev->of_node;
    394
    395	if (of_find_property(dev->of_node, "iommus", NULL)) {
    396		/*
    397		 * This assume we have the same DMA constraints for
    398		 * all our the mixers in our pipeline. This sounds
    399		 * bad, but it has always been the case for us, and
    400		 * DRM doesn't do per-device allocation either, so we
    401		 * would need to fix DRM first...
    402		 */
    403		ret = of_dma_configure(drm->dev, dev->of_node, true);
    404		if (ret)
    405			return ret;
    406	}
    407
    408	/*
    409	 * While this function can fail, we shouldn't do anything
    410	 * if this happens. Some early DE2 DT entries don't provide
    411	 * mixer id but work nevertheless because matching between
    412	 * TCON and mixer is done by comparing node pointers (old
    413	 * way) instead comparing ids. If this function fails and
    414	 * id is needed, it will fail during id matching anyway.
    415	 */
    416	mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
    417
    418	mixer->cfg = of_device_get_match_data(dev);
    419	if (!mixer->cfg)
    420		return -EINVAL;
    421
    422	regs = devm_platform_ioremap_resource(pdev, 0);
    423	if (IS_ERR(regs))
    424		return PTR_ERR(regs);
    425
    426	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
    427						   &sun8i_mixer_regmap_config);
    428	if (IS_ERR(mixer->engine.regs)) {
    429		dev_err(dev, "Couldn't create the mixer regmap\n");
    430		return PTR_ERR(mixer->engine.regs);
    431	}
    432
    433	mixer->reset = devm_reset_control_get(dev, NULL);
    434	if (IS_ERR(mixer->reset)) {
    435		dev_err(dev, "Couldn't get our reset line\n");
    436		return PTR_ERR(mixer->reset);
    437	}
    438
    439	ret = reset_control_deassert(mixer->reset);
    440	if (ret) {
    441		dev_err(dev, "Couldn't deassert our reset line\n");
    442		return ret;
    443	}
    444
    445	mixer->bus_clk = devm_clk_get(dev, "bus");
    446	if (IS_ERR(mixer->bus_clk)) {
    447		dev_err(dev, "Couldn't get the mixer bus clock\n");
    448		ret = PTR_ERR(mixer->bus_clk);
    449		goto err_assert_reset;
    450	}
    451	clk_prepare_enable(mixer->bus_clk);
    452
    453	mixer->mod_clk = devm_clk_get(dev, "mod");
    454	if (IS_ERR(mixer->mod_clk)) {
    455		dev_err(dev, "Couldn't get the mixer module clock\n");
    456		ret = PTR_ERR(mixer->mod_clk);
    457		goto err_disable_bus_clk;
    458	}
    459
    460	/*
    461	 * It seems that we need to enforce that rate for whatever
    462	 * reason for the mixer to be functional. Make sure it's the
    463	 * case.
    464	 */
    465	if (mixer->cfg->mod_rate)
    466		clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
    467
    468	clk_prepare_enable(mixer->mod_clk);
    469
    470	list_add_tail(&mixer->engine.list, &drv->engine_list);
    471
    472	base = sun8i_blender_base(mixer);
    473
    474	/* Reset registers and disable unused sub-engines */
    475	if (mixer->cfg->is_de3) {
    476		for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
    477			regmap_write(mixer->engine.regs, i, 0);
    478
    479		regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
    480		regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
    481		regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
    482		regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
    483		regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
    484		regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
    485		regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
    486		regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
    487		regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
    488		regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
    489	} else {
    490		for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
    491			regmap_write(mixer->engine.regs, i, 0);
    492
    493		regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
    494		regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
    495		regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
    496		regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
    497		regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
    498		regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
    499		regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
    500	}
    501
    502	/* Enable the mixer */
    503	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
    504		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
    505
    506	/* Set background color to black */
    507	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
    508		     SUN8I_MIXER_BLEND_COLOR_BLACK);
    509
    510	/*
    511	 * Set fill color of bottom plane to black. Generally not needed
    512	 * except when VI plane is at bottom (zpos = 0) and enabled.
    513	 */
    514	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
    515		     SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
    516	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
    517		     SUN8I_MIXER_BLEND_COLOR_BLACK);
    518
    519	plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
    520	for (i = 0; i < plane_cnt; i++)
    521		regmap_write(mixer->engine.regs,
    522			     SUN8I_MIXER_BLEND_MODE(base, i),
    523			     SUN8I_MIXER_BLEND_MODE_DEF);
    524
    525	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
    526			   SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
    527
    528	return 0;
    529
    530err_disable_bus_clk:
    531	clk_disable_unprepare(mixer->bus_clk);
    532err_assert_reset:
    533	reset_control_assert(mixer->reset);
    534	return ret;
    535}
    536
    537static void sun8i_mixer_unbind(struct device *dev, struct device *master,
    538				 void *data)
    539{
    540	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
    541
    542	list_del(&mixer->engine.list);
    543
    544	clk_disable_unprepare(mixer->mod_clk);
    545	clk_disable_unprepare(mixer->bus_clk);
    546	reset_control_assert(mixer->reset);
    547}
    548
    549static const struct component_ops sun8i_mixer_ops = {
    550	.bind	= sun8i_mixer_bind,
    551	.unbind	= sun8i_mixer_unbind,
    552};
    553
    554static int sun8i_mixer_probe(struct platform_device *pdev)
    555{
    556	return component_add(&pdev->dev, &sun8i_mixer_ops);
    557}
    558
    559static int sun8i_mixer_remove(struct platform_device *pdev)
    560{
    561	component_del(&pdev->dev, &sun8i_mixer_ops);
    562
    563	return 0;
    564}
    565
    566static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
    567	.ccsc		= CCSC_MIXER0_LAYOUT,
    568	.scaler_mask	= 0xf,
    569	.scanline_yuv	= 2048,
    570	.ui_num		= 3,
    571	.vi_num		= 1,
    572};
    573
    574static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
    575	.ccsc		= CCSC_MIXER1_LAYOUT,
    576	.scaler_mask	= 0x3,
    577	.scanline_yuv	= 2048,
    578	.ui_num		= 1,
    579	.vi_num		= 1,
    580};
    581
    582static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
    583	.ccsc		= CCSC_MIXER0_LAYOUT,
    584	.mod_rate	= 432000000,
    585	.scaler_mask	= 0xf,
    586	.scanline_yuv	= 2048,
    587	.ui_num		= 3,
    588	.vi_num		= 1,
    589};
    590
    591static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
    592	.ccsc		= CCSC_MIXER0_LAYOUT,
    593	.mod_rate	= 297000000,
    594	.scaler_mask	= 0xf,
    595	.scanline_yuv	= 2048,
    596	.ui_num		= 3,
    597	.vi_num		= 1,
    598};
    599
    600static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
    601	.ccsc		= CCSC_MIXER1_LAYOUT,
    602	.mod_rate	= 297000000,
    603	.scaler_mask	= 0x3,
    604	.scanline_yuv	= 2048,
    605	.ui_num		= 1,
    606	.vi_num		= 1,
    607};
    608
    609static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
    610	.vi_num = 2,
    611	.ui_num = 1,
    612	.scaler_mask = 0x3,
    613	.scanline_yuv = 2048,
    614	.ccsc = CCSC_MIXER0_LAYOUT,
    615	.mod_rate = 150000000,
    616};
    617
    618static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
    619	.ccsc		= CCSC_D1_MIXER0_LAYOUT,
    620	.mod_rate	= 297000000,
    621	.scaler_mask	= 0x3,
    622	.scanline_yuv	= 2048,
    623	.ui_num		= 1,
    624	.vi_num		= 1,
    625};
    626
    627static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
    628	.ccsc		= CCSC_MIXER1_LAYOUT,
    629	.mod_rate	= 297000000,
    630	.scaler_mask	= 0x1,
    631	.scanline_yuv	= 1024,
    632	.ui_num		= 0,
    633	.vi_num		= 1,
    634};
    635
    636static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
    637	.ccsc		= CCSC_MIXER0_LAYOUT,
    638	.mod_rate	= 297000000,
    639	.scaler_mask	= 0xf,
    640	.scanline_yuv	= 4096,
    641	.ui_num		= 3,
    642	.vi_num		= 1,
    643};
    644
    645static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
    646	.ccsc		= CCSC_MIXER1_LAYOUT,
    647	.mod_rate	= 297000000,
    648	.scaler_mask	= 0x3,
    649	.scanline_yuv	= 2048,
    650	.ui_num		= 1,
    651	.vi_num		= 1,
    652};
    653
    654static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
    655	.ccsc		= CCSC_MIXER0_LAYOUT,
    656	.is_de3		= true,
    657	.mod_rate	= 600000000,
    658	.scaler_mask	= 0xf,
    659	.scanline_yuv	= 4096,
    660	.ui_num		= 3,
    661	.vi_num		= 1,
    662};
    663
    664static const struct of_device_id sun8i_mixer_of_table[] = {
    665	{
    666		.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
    667		.data = &sun8i_a83t_mixer0_cfg,
    668	},
    669	{
    670		.compatible = "allwinner,sun8i-a83t-de2-mixer-1",
    671		.data = &sun8i_a83t_mixer1_cfg,
    672	},
    673	{
    674		.compatible = "allwinner,sun8i-h3-de2-mixer-0",
    675		.data = &sun8i_h3_mixer0_cfg,
    676	},
    677	{
    678		.compatible = "allwinner,sun8i-r40-de2-mixer-0",
    679		.data = &sun8i_r40_mixer0_cfg,
    680	},
    681	{
    682		.compatible = "allwinner,sun8i-r40-de2-mixer-1",
    683		.data = &sun8i_r40_mixer1_cfg,
    684	},
    685	{
    686		.compatible = "allwinner,sun8i-v3s-de2-mixer",
    687		.data = &sun8i_v3s_mixer_cfg,
    688	},
    689	{
    690		.compatible = "allwinner,sun20i-d1-de2-mixer-0",
    691		.data = &sun20i_d1_mixer0_cfg,
    692	},
    693	{
    694		.compatible = "allwinner,sun20i-d1-de2-mixer-1",
    695		.data = &sun20i_d1_mixer1_cfg,
    696	},
    697	{
    698		.compatible = "allwinner,sun50i-a64-de2-mixer-0",
    699		.data = &sun50i_a64_mixer0_cfg,
    700	},
    701	{
    702		.compatible = "allwinner,sun50i-a64-de2-mixer-1",
    703		.data = &sun50i_a64_mixer1_cfg,
    704	},
    705	{
    706		.compatible = "allwinner,sun50i-h6-de3-mixer-0",
    707		.data = &sun50i_h6_mixer0_cfg,
    708	},
    709	{ }
    710};
    711MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
    712
    713static struct platform_driver sun8i_mixer_platform_driver = {
    714	.probe		= sun8i_mixer_probe,
    715	.remove		= sun8i_mixer_remove,
    716	.driver		= {
    717		.name		= "sun8i-mixer",
    718		.of_match_table	= sun8i_mixer_of_table,
    719	},
    720};
    721module_platform_driver(sun8i_mixer_platform_driver);
    722
    723MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
    724MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
    725MODULE_LICENSE("GPL");