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