blob: f76a5576c0e625c1df8b91fd1f1f15a86ff047b3 [file] [log] [blame]
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +08001/*
2 * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
3 *
4 * Based on sun4i_backend.c, which is:
5 * Copyright (C) 2015 Free Electrons
6 * Copyright (C) 2015 NextThing Co
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 */
13
14#include <drm/drmP.h>
15#include <drm/drm_atomic_helper.h>
16#include <drm/drm_crtc.h>
17#include <drm/drm_crtc_helper.h>
18#include <drm/drm_fb_cma_helper.h>
19#include <drm/drm_gem_cma_helper.h>
20#include <drm/drm_plane_helper.h>
21
22#include <linux/component.h>
23#include <linux/dma-mapping.h>
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +080024#include <linux/of_device.h>
Jernej Skrabec7da9b2e2018-07-11 13:27:06 +020025#include <linux/of_graph.h>
Jernej Skrabece0f56782018-07-10 22:35:02 +020026#include <linux/reset.h>
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +080027
28#include "sun4i_drv.h"
29#include "sun8i_mixer.h"
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +010030#include "sun8i_ui_layer.h"
Jernej Skrabec7480ba42017-12-01 07:05:42 +010031#include "sun8i_vi_layer.h"
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +080032#include "sunxi_engine.h"
33
Jernej Skrabecfba49552017-12-01 07:05:40 +010034static const struct de2_fmt_info de2_formats[] = {
35 {
36 .drm_fmt = DRM_FORMAT_ARGB8888,
37 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010038 .rgb = true,
39 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010040 },
41 {
42 .drm_fmt = DRM_FORMAT_ABGR8888,
43 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010044 .rgb = true,
45 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010046 },
47 {
48 .drm_fmt = DRM_FORMAT_RGBA8888,
49 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010050 .rgb = true,
51 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010052 },
53 {
54 .drm_fmt = DRM_FORMAT_BGRA8888,
55 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010056 .rgb = true,
57 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010058 },
59 {
60 .drm_fmt = DRM_FORMAT_XRGB8888,
61 .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010062 .rgb = true,
63 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010064 },
65 {
66 .drm_fmt = DRM_FORMAT_XBGR8888,
67 .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010068 .rgb = true,
69 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010070 },
71 {
72 .drm_fmt = DRM_FORMAT_RGBX8888,
73 .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010074 .rgb = true,
75 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010076 },
77 {
78 .drm_fmt = DRM_FORMAT_BGRX8888,
79 .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010080 .rgb = true,
81 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010082 },
83 {
84 .drm_fmt = DRM_FORMAT_RGB888,
85 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010086 .rgb = true,
87 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010088 },
89 {
90 .drm_fmt = DRM_FORMAT_BGR888,
91 .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010092 .rgb = true,
93 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +010094 },
95 {
96 .drm_fmt = DRM_FORMAT_RGB565,
97 .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +010098 .rgb = true,
99 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100100 },
101 {
102 .drm_fmt = DRM_FORMAT_BGR565,
103 .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100104 .rgb = true,
105 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100106 },
107 {
108 .drm_fmt = DRM_FORMAT_ARGB4444,
109 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100110 .rgb = true,
111 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100112 },
113 {
114 .drm_fmt = DRM_FORMAT_ABGR4444,
115 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100116 .rgb = true,
117 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100118 },
119 {
120 .drm_fmt = DRM_FORMAT_RGBA4444,
121 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100122 .rgb = true,
123 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100124 },
125 {
126 .drm_fmt = DRM_FORMAT_BGRA4444,
127 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100128 .rgb = true,
129 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100130 },
131 {
132 .drm_fmt = DRM_FORMAT_ARGB1555,
133 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100134 .rgb = true,
135 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100136 },
137 {
138 .drm_fmt = DRM_FORMAT_ABGR1555,
139 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100140 .rgb = true,
141 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100142 },
143 {
144 .drm_fmt = DRM_FORMAT_RGBA5551,
145 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100146 .rgb = true,
147 .csc = SUN8I_CSC_MODE_OFF,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100148 },
149 {
150 .drm_fmt = DRM_FORMAT_BGRA5551,
151 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
Jernej Skrabec60a3dcf2017-12-01 07:05:47 +0100152 .rgb = true,
153 .csc = SUN8I_CSC_MODE_OFF,
154 },
155 {
156 .drm_fmt = DRM_FORMAT_UYVY,
157 .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
158 .rgb = false,
159 .csc = SUN8I_CSC_MODE_YUV2RGB,
160 },
161 {
162 .drm_fmt = DRM_FORMAT_VYUY,
163 .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
164 .rgb = false,
165 .csc = SUN8I_CSC_MODE_YUV2RGB,
166 },
167 {
168 .drm_fmt = DRM_FORMAT_YUYV,
169 .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
170 .rgb = false,
171 .csc = SUN8I_CSC_MODE_YUV2RGB,
172 },
173 {
174 .drm_fmt = DRM_FORMAT_YVYU,
175 .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
176 .rgb = false,
177 .csc = SUN8I_CSC_MODE_YUV2RGB,
178 },
179 {
180 .drm_fmt = DRM_FORMAT_NV16,
181 .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
182 .rgb = false,
183 .csc = SUN8I_CSC_MODE_YUV2RGB,
184 },
185 {
186 .drm_fmt = DRM_FORMAT_NV61,
187 .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
188 .rgb = false,
189 .csc = SUN8I_CSC_MODE_YUV2RGB,
190 },
191 {
192 .drm_fmt = DRM_FORMAT_NV12,
193 .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
194 .rgb = false,
195 .csc = SUN8I_CSC_MODE_YUV2RGB,
196 },
197 {
198 .drm_fmt = DRM_FORMAT_NV21,
199 .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
200 .rgb = false,
201 .csc = SUN8I_CSC_MODE_YUV2RGB,
202 },
203 {
204 .drm_fmt = DRM_FORMAT_YUV444,
205 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
206 .rgb = true,
207 .csc = SUN8I_CSC_MODE_YUV2RGB,
208 },
209 {
210 .drm_fmt = DRM_FORMAT_YUV422,
211 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
212 .rgb = false,
213 .csc = SUN8I_CSC_MODE_YUV2RGB,
214 },
215 {
216 .drm_fmt = DRM_FORMAT_YUV420,
217 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
218 .rgb = false,
219 .csc = SUN8I_CSC_MODE_YUV2RGB,
220 },
221 {
222 .drm_fmt = DRM_FORMAT_YUV411,
223 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
224 .rgb = false,
225 .csc = SUN8I_CSC_MODE_YUV2RGB,
226 },
227 {
228 .drm_fmt = DRM_FORMAT_YVU444,
229 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
230 .rgb = true,
231 .csc = SUN8I_CSC_MODE_YVU2RGB,
232 },
233 {
234 .drm_fmt = DRM_FORMAT_YVU422,
235 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
236 .rgb = false,
237 .csc = SUN8I_CSC_MODE_YVU2RGB,
238 },
239 {
240 .drm_fmt = DRM_FORMAT_YVU420,
241 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
242 .rgb = false,
243 .csc = SUN8I_CSC_MODE_YVU2RGB,
244 },
245 {
246 .drm_fmt = DRM_FORMAT_YVU411,
247 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
248 .rgb = false,
249 .csc = SUN8I_CSC_MODE_YVU2RGB,
Jernej Skrabecfba49552017-12-01 07:05:40 +0100250 },
251};
252
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100253const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
Jernej Skrabecfba49552017-12-01 07:05:40 +0100254{
255 unsigned int i;
256
257 for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
258 if (de2_formats[i].drm_fmt == format)
259 return &de2_formats[i];
260
261 return NULL;
262}
263
Jernej Skrabecf88c5ee2018-07-06 18:47:32 +0200264static void sun8i_mixer_atomic_begin(struct sunxi_engine *engine,
265 struct drm_crtc_state *old_state)
266{
267 /*
268 * Disable all pipes at the beginning. They will be enabled
269 * again if needed in plane update callback.
270 */
271 regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL,
272 SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
273}
274
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800275static void sun8i_mixer_commit(struct sunxi_engine *engine)
276{
277 DRM_DEBUG_DRIVER("Committing changes\n");
278
279 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
280 SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
281}
282
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100283static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
284 struct sunxi_engine *engine)
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800285{
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100286 struct drm_plane **planes;
287 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
288 int i;
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800289
Jernej Skrabec7480ba42017-12-01 07:05:42 +0100290 planes = devm_kcalloc(drm->dev,
291 mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100292 sizeof(*planes), GFP_KERNEL);
293 if (!planes)
294 return ERR_PTR(-ENOMEM);
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800295
Jernej Skrabec7480ba42017-12-01 07:05:42 +0100296 for (i = 0; i < mixer->cfg->vi_num; i++) {
297 struct sun8i_vi_layer *layer;
298
299 layer = sun8i_vi_layer_init_one(drm, mixer, i);
300 if (IS_ERR(layer)) {
301 dev_err(drm->dev,
302 "Couldn't initialize overlay plane\n");
303 return ERR_CAST(layer);
304 };
305
306 planes[i] = &layer->plane;
307 };
308
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100309 for (i = 0; i < mixer->cfg->ui_num; i++) {
310 struct sun8i_ui_layer *layer;
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800311
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100312 layer = sun8i_ui_layer_init_one(drm, mixer, i);
313 if (IS_ERR(layer)) {
314 dev_err(drm->dev, "Couldn't initialize %s plane\n",
315 i ? "overlay" : "primary");
316 return ERR_CAST(layer);
317 };
Jernej Skrabec26264ce2017-12-01 07:05:32 +0100318
Jernej Skrabec7480ba42017-12-01 07:05:42 +0100319 planes[mixer->cfg->vi_num + i] = &layer->plane;
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100320 };
Jernej Skrabec26264ce2017-12-01 07:05:32 +0100321
Jernej Skrabec5bb5f5d2017-12-01 07:05:41 +0100322 return planes;
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800323}
324
325static const struct sunxi_engine_ops sun8i_engine_ops = {
Jernej Skrabecf88c5ee2018-07-06 18:47:32 +0200326 .atomic_begin = sun8i_mixer_atomic_begin,
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800327 .commit = sun8i_mixer_commit,
328 .layers_init = sun8i_layers_init,
329};
330
331static struct regmap_config sun8i_mixer_regmap_config = {
332 .reg_bits = 32,
333 .val_bits = 32,
334 .reg_stride = 4,
335 .max_register = 0xbfffc, /* guessed */
336};
337
Jernej Skrabec7da9b2e2018-07-11 13:27:06 +0200338static int sun8i_mixer_of_get_id(struct device_node *node)
339{
340 struct device_node *port, *ep;
341 int ret = -EINVAL;
342
343 /* output is port 1 */
344 port = of_graph_get_port_by_id(node, 1);
345 if (!port)
346 return -EINVAL;
347
348 /* try to find downstream endpoint */
349 for_each_available_child_of_node(port, ep) {
350 struct device_node *remote;
351 u32 reg;
352
353 remote = of_graph_get_remote_endpoint(ep);
354 if (!remote)
355 continue;
356
357 ret = of_property_read_u32(remote, "reg", &reg);
358 if (!ret) {
359 of_node_put(remote);
360 of_node_put(ep);
361 of_node_put(port);
362
363 return reg;
364 }
365
366 of_node_put(remote);
367 }
368
369 of_node_put(port);
370
371 return ret;
372}
373
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800374static int sun8i_mixer_bind(struct device *dev, struct device *master,
375 void *data)
376{
377 struct platform_device *pdev = to_platform_device(dev);
378 struct drm_device *drm = data;
379 struct sun4i_drv *drv = drm->dev_private;
380 struct sun8i_mixer *mixer;
381 struct resource *res;
382 void __iomem *regs;
Jernej Skrabec7a744a72017-12-01 07:05:30 +0100383 int plane_cnt;
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800384 int i, ret;
385
386 /*
387 * The mixer uses single 32-bit register to store memory
388 * addresses, so that it cannot deal with 64-bit memory
389 * addresses.
390 * Restrict the DMA mask so that the mixer won't be
391 * allocated some memory that is too high.
392 */
393 ret = dma_set_mask(dev, DMA_BIT_MASK(32));
394 if (ret) {
395 dev_err(dev, "Cannot do 32-bit DMA.\n");
396 return ret;
397 }
398
399 mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
400 if (!mixer)
401 return -ENOMEM;
402 dev_set_drvdata(dev, mixer);
403 mixer->engine.ops = &sun8i_engine_ops;
404 mixer->engine.node = dev->of_node;
Jernej Skrabec7da9b2e2018-07-11 13:27:06 +0200405
406 /*
407 * While this function can fail, we shouldn't do anything
408 * if this happens. Some early DE2 DT entries don't provide
409 * mixer id but work nevertheless because matching between
410 * TCON and mixer is done by comparing node pointers (old
411 * way) instead comparing ids. If this function fails and
412 * id is needed, it will fail during id matching anyway.
413 */
414 mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800415
416 mixer->cfg = of_device_get_match_data(dev);
417 if (!mixer->cfg)
418 return -EINVAL;
419
420 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
421 regs = devm_ioremap_resource(dev, res);
422 if (IS_ERR(regs))
423 return PTR_ERR(regs);
424
425 mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
426 &sun8i_mixer_regmap_config);
427 if (IS_ERR(mixer->engine.regs)) {
428 dev_err(dev, "Couldn't create the mixer regmap\n");
429 return PTR_ERR(mixer->engine.regs);
430 }
431
432 mixer->reset = devm_reset_control_get(dev, NULL);
433 if (IS_ERR(mixer->reset)) {
434 dev_err(dev, "Couldn't get our reset line\n");
435 return PTR_ERR(mixer->reset);
436 }
437
438 ret = reset_control_deassert(mixer->reset);
439 if (ret) {
440 dev_err(dev, "Couldn't deassert our reset line\n");
441 return ret;
442 }
443
444 mixer->bus_clk = devm_clk_get(dev, "bus");
445 if (IS_ERR(mixer->bus_clk)) {
446 dev_err(dev, "Couldn't get the mixer bus clock\n");
447 ret = PTR_ERR(mixer->bus_clk);
448 goto err_assert_reset;
449 }
450 clk_prepare_enable(mixer->bus_clk);
451
452 mixer->mod_clk = devm_clk_get(dev, "mod");
453 if (IS_ERR(mixer->mod_clk)) {
454 dev_err(dev, "Couldn't get the mixer module clock\n");
455 ret = PTR_ERR(mixer->mod_clk);
456 goto err_disable_bus_clk;
457 }
Maxime Ripardedea3722017-12-21 12:02:31 +0100458
459 /*
460 * It seems that we need to enforce that rate for whatever
461 * reason for the mixer to be functional. Make sure it's the
462 * case.
463 */
464 if (mixer->cfg->mod_rate)
465 clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
466
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800467 clk_prepare_enable(mixer->mod_clk);
468
469 list_add_tail(&mixer->engine.list, &drv->engine_list);
470
471 /* Reset the registers */
472 for (i = 0x0; i < 0x20000; i += 4)
473 regmap_write(mixer->engine.regs, i, 0);
474
475 /* Enable the mixer */
476 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
477 SUN8I_MIXER_GLOBAL_CTL_RT_EN);
478
Jernej Skrabec2f4cffe2017-12-01 07:05:29 +0100479 /* Set background color to black */
480 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
481 SUN8I_MIXER_BLEND_COLOR_BLACK);
482
Jernej Skrabec26264ce2017-12-01 07:05:32 +0100483 /*
484 * Set fill color of bottom plane to black. Generally not needed
485 * except when VI plane is at bottom (zpos = 0) and enabled.
486 */
Jernej Skrabecbb940be2017-12-01 07:05:31 +0100487 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
Jernej Skrabecbb940be2017-12-01 07:05:31 +0100488 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
Jernej Skrabec26264ce2017-12-01 07:05:32 +0100489 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
Jernej Skrabec2f4cffe2017-12-01 07:05:29 +0100490 SUN8I_MIXER_BLEND_COLOR_BLACK);
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800491
Jernej Skrabec7a744a72017-12-01 07:05:30 +0100492 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
493 for (i = 0; i < plane_cnt; i++)
494 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
495 SUN8I_MIXER_BLEND_MODE_DEF);
496
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800497 return 0;
498
499err_disable_bus_clk:
500 clk_disable_unprepare(mixer->bus_clk);
501err_assert_reset:
502 reset_control_assert(mixer->reset);
503 return ret;
504}
505
506static void sun8i_mixer_unbind(struct device *dev, struct device *master,
507 void *data)
508{
509 struct sun8i_mixer *mixer = dev_get_drvdata(dev);
510
511 list_del(&mixer->engine.list);
512
513 clk_disable_unprepare(mixer->mod_clk);
514 clk_disable_unprepare(mixer->bus_clk);
515 reset_control_assert(mixer->reset);
516}
517
518static const struct component_ops sun8i_mixer_ops = {
519 .bind = sun8i_mixer_bind,
520 .unbind = sun8i_mixer_unbind,
521};
522
523static int sun8i_mixer_probe(struct platform_device *pdev)
524{
525 return component_add(&pdev->dev, &sun8i_mixer_ops);
526}
527
528static int sun8i_mixer_remove(struct platform_device *pdev)
529{
530 component_del(&pdev->dev, &sun8i_mixer_ops);
531
532 return 0;
533}
534
Maxime Ripard2f0d7bb2017-12-21 12:02:34 +0100535static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
536 .ccsc = 0,
537 .scaler_mask = 0xf,
538 .ui_num = 3,
539 .vi_num = 1,
540};
541
Jernej Skrabec47095e12018-02-14 21:09:03 +0100542static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
543 .ccsc = 1,
544 .scaler_mask = 0x3,
545 .ui_num = 1,
546 .vi_num = 1,
547};
548
Jernej Skrabece679f4a2018-03-01 22:34:34 +0100549static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
550 .ccsc = 0,
551 .mod_rate = 432000000,
552 .scaler_mask = 0xf,
553 .ui_num = 3,
554 .vi_num = 1,
555};
556
Jernej Skrabec07408452018-06-25 14:02:54 +0200557static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
558 .ccsc = 0,
559 .mod_rate = 297000000,
560 .scaler_mask = 0xf,
561 .ui_num = 3,
562 .vi_num = 1,
563};
564
565static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
566 .ccsc = 1,
567 .mod_rate = 297000000,
568 .scaler_mask = 0x3,
569 .ui_num = 1,
570 .vi_num = 1,
571};
572
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800573static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
574 .vi_num = 2,
575 .ui_num = 1,
Jernej Skrabec5b1f8362017-12-01 07:05:43 +0100576 .scaler_mask = 0x3,
Jernej Skrabecbd3bcb92017-12-01 07:05:45 +0100577 .ccsc = 0,
Maxime Ripardedea3722017-12-21 12:02:31 +0100578 .mod_rate = 150000000,
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800579};
580
581static const struct of_device_id sun8i_mixer_of_table[] = {
582 {
Maxime Ripard2f0d7bb2017-12-21 12:02:34 +0100583 .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
584 .data = &sun8i_a83t_mixer0_cfg,
585 },
586 {
Jernej Skrabec47095e12018-02-14 21:09:03 +0100587 .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
588 .data = &sun8i_a83t_mixer1_cfg,
589 },
590 {
Jernej Skrabece679f4a2018-03-01 22:34:34 +0100591 .compatible = "allwinner,sun8i-h3-de2-mixer-0",
592 .data = &sun8i_h3_mixer0_cfg,
593 },
594 {
Jernej Skrabec07408452018-06-25 14:02:54 +0200595 .compatible = "allwinner,sun8i-r40-de2-mixer-0",
596 .data = &sun8i_r40_mixer0_cfg,
597 },
598 {
599 .compatible = "allwinner,sun8i-r40-de2-mixer-1",
600 .data = &sun8i_r40_mixer1_cfg,
601 },
602 {
Icenowy Zheng9d75b8c2017-05-17 22:47:20 +0800603 .compatible = "allwinner,sun8i-v3s-de2-mixer",
604 .data = &sun8i_v3s_mixer_cfg,
605 },
606 { }
607};
608MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
609
610static struct platform_driver sun8i_mixer_platform_driver = {
611 .probe = sun8i_mixer_probe,
612 .remove = sun8i_mixer_remove,
613 .driver = {
614 .name = "sun8i-mixer",
615 .of_match_table = sun8i_mixer_of_table,
616 },
617};
618module_platform_driver(sun8i_mixer_platform_driver);
619
620MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
621MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
622MODULE_LICENSE("GPL");