]> Git Repo - linux.git/blob - drivers/gpu/drm/sun4i/sun8i_mixer.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / sun4i / sun8i_mixer.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017 Icenowy Zheng <[email protected]>
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.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
32 struct de2_fmt_info {
33         u32     drm_fmt;
34         u32     de2_fmt;
35 };
36
37 static 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
240 int 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
253 static 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
271 static 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 clear
304                  * 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
324 static 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
366 static 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         else
386                 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
395 static 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
401 static 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
408 static 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
428 static 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 memory
442          * addresses, so that it cannot deal with 64-bit memory
443          * addresses.
444          * Restrict the DMA mask so that the mixer won't be
445          * 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 for
463                  * all our the mixers in our pipeline. This sounds
464                  * bad, but it has always been the case for us, and
465                  * DRM doesn't do per-device allocation either, so we
466                  * 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 anything
475          * if this happens. Some early DE2 DT entries don't provide
476          * mixer id but work nevertheless because matching between
477          * TCON and mixer is done by comparing node pointers (old
478          * way) instead comparing ids. If this function fails and
479          * 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 whatever
527          * reason for the mixer to be functional. Make sure it's the
528          * 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 needed
577          * 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
595 err_disable_bus_clk:
596         clk_disable_unprepare(mixer->bus_clk);
597 err_assert_reset:
598         reset_control_assert(mixer->reset);
599         return ret;
600 }
601
602 static 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
614 static const struct component_ops sun8i_mixer_ops = {
615         .bind   = sun8i_mixer_bind,
616         .unbind = sun8i_mixer_unbind,
617 };
618
619 static int sun8i_mixer_probe(struct platform_device *pdev)
620 {
621         return component_add(&pdev->dev, &sun8i_mixer_ops);
622 }
623
624 static void sun8i_mixer_remove(struct platform_device *pdev)
625 {
626         component_del(&pdev->dev, &sun8i_mixer_ops);
627 }
628
629 static 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
637 static 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
645 static 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
654 static 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
663 static 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
672 static 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
681 static 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
690 static 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
699 static 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
708 static 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
717 static 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
727 static 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 };
774 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
775
776 static struct platform_driver sun8i_mixer_platform_driver = {
777         .probe          = sun8i_mixer_probe,
778         .remove         = sun8i_mixer_remove,
779         .driver         = {
780                 .name           = "sun8i-mixer",
781                 .of_match_table = sun8i_mixer_of_table,
782         },
783 };
784 module_platform_driver(sun8i_mixer_platform_driver);
785
786 MODULE_AUTHOR("Icenowy Zheng <[email protected]>");
787 MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
788 MODULE_LICENSE("GPL");
This page took 0.079922 seconds and 4 git commands to generate.