brintos

brintos / linux-shallow public Read only

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