root/drivers/gpu/drm/sun4i/sun8i_mixer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun8i_mixer_format_info
  2. sun8i_mixer_commit
  3. sun8i_layers_init
  4. sun8i_mixer_of_get_id
  5. sun8i_mixer_bind
  6. sun8i_mixer_unbind
  7. sun8i_mixer_probe
  8. sun8i_mixer_remove

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

/* [<][>][^][v][top][bottom][index][help] */