0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/component.h>
0011 #include <linux/dma-mapping.h>
0012 #include <linux/module.h>
0013 #include <linux/of_device.h>
0014 #include <linux/of_graph.h>
0015 #include <linux/reset.h>
0016
0017 #include <drm/drm_atomic_helper.h>
0018 #include <drm/drm_crtc.h>
0019 #include <drm/drm_fb_cma_helper.h>
0020 #include <drm/drm_framebuffer.h>
0021 #include <drm/drm_gem_cma_helper.h>
0022 #include <drm/drm_plane_helper.h>
0023 #include <drm/drm_probe_helper.h>
0024
0025 #include "sun4i_drv.h"
0026 #include "sun8i_mixer.h"
0027 #include "sun8i_ui_layer.h"
0028 #include "sun8i_vi_layer.h"
0029 #include "sunxi_engine.h"
0030
0031 struct de2_fmt_info {
0032 u32 drm_fmt;
0033 u32 de2_fmt;
0034 };
0035
0036 static const struct de2_fmt_info de2_formats[] = {
0037 {
0038 .drm_fmt = DRM_FORMAT_ARGB8888,
0039 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
0040 },
0041 {
0042 .drm_fmt = DRM_FORMAT_ABGR8888,
0043 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
0044 },
0045 {
0046 .drm_fmt = DRM_FORMAT_RGBA8888,
0047 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
0048 },
0049 {
0050 .drm_fmt = DRM_FORMAT_BGRA8888,
0051 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
0052 },
0053 {
0054 .drm_fmt = DRM_FORMAT_XRGB8888,
0055 .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
0056 },
0057 {
0058 .drm_fmt = DRM_FORMAT_XBGR8888,
0059 .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
0060 },
0061 {
0062 .drm_fmt = DRM_FORMAT_RGBX8888,
0063 .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
0064 },
0065 {
0066 .drm_fmt = DRM_FORMAT_BGRX8888,
0067 .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
0068 },
0069 {
0070 .drm_fmt = DRM_FORMAT_RGB888,
0071 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
0072 },
0073 {
0074 .drm_fmt = DRM_FORMAT_BGR888,
0075 .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
0076 },
0077 {
0078 .drm_fmt = DRM_FORMAT_RGB565,
0079 .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
0080 },
0081 {
0082 .drm_fmt = DRM_FORMAT_BGR565,
0083 .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
0084 },
0085 {
0086 .drm_fmt = DRM_FORMAT_ARGB4444,
0087 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
0088 },
0089 {
0090
0091 .drm_fmt = DRM_FORMAT_XRGB4444,
0092 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
0093 },
0094 {
0095 .drm_fmt = DRM_FORMAT_ABGR4444,
0096 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
0097 },
0098 {
0099
0100 .drm_fmt = DRM_FORMAT_XBGR4444,
0101 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
0102 },
0103 {
0104 .drm_fmt = DRM_FORMAT_RGBA4444,
0105 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
0106 },
0107 {
0108
0109 .drm_fmt = DRM_FORMAT_RGBX4444,
0110 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
0111 },
0112 {
0113 .drm_fmt = DRM_FORMAT_BGRA4444,
0114 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
0115 },
0116 {
0117
0118 .drm_fmt = DRM_FORMAT_BGRX4444,
0119 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
0120 },
0121 {
0122 .drm_fmt = DRM_FORMAT_ARGB1555,
0123 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
0124 },
0125 {
0126
0127 .drm_fmt = DRM_FORMAT_XRGB1555,
0128 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
0129 },
0130 {
0131 .drm_fmt = DRM_FORMAT_ABGR1555,
0132 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
0133 },
0134 {
0135
0136 .drm_fmt = DRM_FORMAT_XBGR1555,
0137 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
0138 },
0139 {
0140 .drm_fmt = DRM_FORMAT_RGBA5551,
0141 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
0142 },
0143 {
0144
0145 .drm_fmt = DRM_FORMAT_RGBX5551,
0146 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
0147 },
0148 {
0149 .drm_fmt = DRM_FORMAT_BGRA5551,
0150 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
0151 },
0152 {
0153
0154 .drm_fmt = DRM_FORMAT_BGRX5551,
0155 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
0156 },
0157 {
0158 .drm_fmt = DRM_FORMAT_ARGB2101010,
0159 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
0160 },
0161 {
0162 .drm_fmt = DRM_FORMAT_ABGR2101010,
0163 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
0164 },
0165 {
0166 .drm_fmt = DRM_FORMAT_RGBA1010102,
0167 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
0168 },
0169 {
0170 .drm_fmt = DRM_FORMAT_BGRA1010102,
0171 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
0172 },
0173 {
0174 .drm_fmt = DRM_FORMAT_UYVY,
0175 .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
0176 },
0177 {
0178 .drm_fmt = DRM_FORMAT_VYUY,
0179 .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
0180 },
0181 {
0182 .drm_fmt = DRM_FORMAT_YUYV,
0183 .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
0184 },
0185 {
0186 .drm_fmt = DRM_FORMAT_YVYU,
0187 .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
0188 },
0189 {
0190 .drm_fmt = DRM_FORMAT_NV16,
0191 .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
0192 },
0193 {
0194 .drm_fmt = DRM_FORMAT_NV61,
0195 .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
0196 },
0197 {
0198 .drm_fmt = DRM_FORMAT_NV12,
0199 .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
0200 },
0201 {
0202 .drm_fmt = DRM_FORMAT_NV21,
0203 .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
0204 },
0205 {
0206 .drm_fmt = DRM_FORMAT_YUV422,
0207 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
0208 },
0209 {
0210 .drm_fmt = DRM_FORMAT_YUV420,
0211 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
0212 },
0213 {
0214 .drm_fmt = DRM_FORMAT_YUV411,
0215 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
0216 },
0217 {
0218 .drm_fmt = DRM_FORMAT_YVU422,
0219 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
0220 },
0221 {
0222 .drm_fmt = DRM_FORMAT_YVU420,
0223 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
0224 },
0225 {
0226 .drm_fmt = DRM_FORMAT_YVU411,
0227 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
0228 },
0229 {
0230 .drm_fmt = DRM_FORMAT_P010,
0231 .de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
0232 },
0233 {
0234 .drm_fmt = DRM_FORMAT_P210,
0235 .de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
0236 },
0237 };
0238
0239 int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
0240 {
0241 unsigned int i;
0242
0243 for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
0244 if (de2_formats[i].drm_fmt == format) {
0245 *hw_format = de2_formats[i].de2_fmt;
0246 return 0;
0247 }
0248
0249 return -EINVAL;
0250 }
0251
0252 static void sun8i_mixer_commit(struct sunxi_engine *engine)
0253 {
0254 DRM_DEBUG_DRIVER("Committing changes\n");
0255
0256 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
0257 SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
0258 }
0259
0260 static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
0261 struct sunxi_engine *engine)
0262 {
0263 struct drm_plane **planes;
0264 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
0265 int i;
0266
0267 planes = devm_kcalloc(drm->dev,
0268 mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
0269 sizeof(*planes), GFP_KERNEL);
0270 if (!planes)
0271 return ERR_PTR(-ENOMEM);
0272
0273 for (i = 0; i < mixer->cfg->vi_num; i++) {
0274 struct sun8i_vi_layer *layer;
0275
0276 layer = sun8i_vi_layer_init_one(drm, mixer, i);
0277 if (IS_ERR(layer)) {
0278 dev_err(drm->dev,
0279 "Couldn't initialize overlay plane\n");
0280 return ERR_CAST(layer);
0281 }
0282
0283 planes[i] = &layer->plane;
0284 }
0285
0286 for (i = 0; i < mixer->cfg->ui_num; i++) {
0287 struct sun8i_ui_layer *layer;
0288
0289 layer = sun8i_ui_layer_init_one(drm, mixer, i);
0290 if (IS_ERR(layer)) {
0291 dev_err(drm->dev, "Couldn't initialize %s plane\n",
0292 i ? "overlay" : "primary");
0293 return ERR_CAST(layer);
0294 }
0295
0296 planes[mixer->cfg->vi_num + i] = &layer->plane;
0297 }
0298
0299 return planes;
0300 }
0301
0302 static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
0303 const struct drm_display_mode *mode)
0304 {
0305 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
0306 u32 bld_base, size, val;
0307 bool interlaced;
0308
0309 bld_base = sun8i_blender_base(mixer);
0310 interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
0311 size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
0312
0313 DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
0314 mode->hdisplay, mode->vdisplay);
0315
0316 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
0317 regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
0318
0319 if (interlaced)
0320 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
0321 else
0322 val = 0;
0323
0324 regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
0325 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
0326
0327 DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
0328 interlaced ? "on" : "off");
0329 }
0330
0331 static const struct sunxi_engine_ops sun8i_engine_ops = {
0332 .commit = sun8i_mixer_commit,
0333 .layers_init = sun8i_layers_init,
0334 .mode_set = sun8i_mixer_mode_set,
0335 };
0336
0337 static const struct regmap_config sun8i_mixer_regmap_config = {
0338 .reg_bits = 32,
0339 .val_bits = 32,
0340 .reg_stride = 4,
0341 .max_register = 0xffffc,
0342 };
0343
0344 static int sun8i_mixer_of_get_id(struct device_node *node)
0345 {
0346 struct device_node *ep, *remote;
0347 struct of_endpoint of_ep;
0348
0349
0350 ep = of_graph_get_endpoint_by_regs(node, 1, -1);
0351 if (!ep)
0352 return -EINVAL;
0353
0354 remote = of_graph_get_remote_endpoint(ep);
0355 of_node_put(ep);
0356 if (!remote)
0357 return -EINVAL;
0358
0359 of_graph_parse_endpoint(remote, &of_ep);
0360 of_node_put(remote);
0361 return of_ep.id;
0362 }
0363
0364 static int sun8i_mixer_bind(struct device *dev, struct device *master,
0365 void *data)
0366 {
0367 struct platform_device *pdev = to_platform_device(dev);
0368 struct drm_device *drm = data;
0369 struct sun4i_drv *drv = drm->dev_private;
0370 struct sun8i_mixer *mixer;
0371 void __iomem *regs;
0372 unsigned int base;
0373 int plane_cnt;
0374 int i, ret;
0375
0376
0377
0378
0379
0380
0381
0382
0383 ret = dma_set_mask(dev, DMA_BIT_MASK(32));
0384 if (ret) {
0385 dev_err(dev, "Cannot do 32-bit DMA.\n");
0386 return ret;
0387 }
0388
0389 mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
0390 if (!mixer)
0391 return -ENOMEM;
0392 dev_set_drvdata(dev, mixer);
0393 mixer->engine.ops = &sun8i_engine_ops;
0394 mixer->engine.node = dev->of_node;
0395
0396 if (of_find_property(dev->of_node, "iommus", NULL)) {
0397
0398
0399
0400
0401
0402
0403
0404 ret = of_dma_configure(drm->dev, dev->of_node, true);
0405 if (ret)
0406 return ret;
0407 }
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417 mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node);
0418
0419 mixer->cfg = of_device_get_match_data(dev);
0420 if (!mixer->cfg)
0421 return -EINVAL;
0422
0423 regs = devm_platform_ioremap_resource(pdev, 0);
0424 if (IS_ERR(regs))
0425 return PTR_ERR(regs);
0426
0427 mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
0428 &sun8i_mixer_regmap_config);
0429 if (IS_ERR(mixer->engine.regs)) {
0430 dev_err(dev, "Couldn't create the mixer regmap\n");
0431 return PTR_ERR(mixer->engine.regs);
0432 }
0433
0434 mixer->reset = devm_reset_control_get(dev, NULL);
0435 if (IS_ERR(mixer->reset)) {
0436 dev_err(dev, "Couldn't get our reset line\n");
0437 return PTR_ERR(mixer->reset);
0438 }
0439
0440 ret = reset_control_deassert(mixer->reset);
0441 if (ret) {
0442 dev_err(dev, "Couldn't deassert our reset line\n");
0443 return ret;
0444 }
0445
0446 mixer->bus_clk = devm_clk_get(dev, "bus");
0447 if (IS_ERR(mixer->bus_clk)) {
0448 dev_err(dev, "Couldn't get the mixer bus clock\n");
0449 ret = PTR_ERR(mixer->bus_clk);
0450 goto err_assert_reset;
0451 }
0452 clk_prepare_enable(mixer->bus_clk);
0453
0454 mixer->mod_clk = devm_clk_get(dev, "mod");
0455 if (IS_ERR(mixer->mod_clk)) {
0456 dev_err(dev, "Couldn't get the mixer module clock\n");
0457 ret = PTR_ERR(mixer->mod_clk);
0458 goto err_disable_bus_clk;
0459 }
0460
0461
0462
0463
0464
0465
0466 if (mixer->cfg->mod_rate)
0467 clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
0468
0469 clk_prepare_enable(mixer->mod_clk);
0470
0471 list_add_tail(&mixer->engine.list, &drv->engine_list);
0472
0473 base = sun8i_blender_base(mixer);
0474
0475
0476 if (mixer->cfg->is_de3) {
0477 for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
0478 regmap_write(mixer->engine.regs, i, 0);
0479
0480 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
0481 regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
0482 regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
0483 regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
0484 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
0485 regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
0486 regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
0487 regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
0488 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
0489 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
0490 } else {
0491 for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
0492 regmap_write(mixer->engine.regs, i, 0);
0493
0494 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
0495 regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
0496 regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
0497 regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
0498 regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
0499 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
0500 regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
0501 }
0502
0503
0504 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
0505 SUN8I_MIXER_GLOBAL_CTL_RT_EN);
0506
0507
0508 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
0509 SUN8I_MIXER_BLEND_COLOR_BLACK);
0510
0511
0512
0513
0514
0515 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
0516 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
0517 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
0518 SUN8I_MIXER_BLEND_COLOR_BLACK);
0519
0520 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
0521 for (i = 0; i < plane_cnt; i++)
0522 regmap_write(mixer->engine.regs,
0523 SUN8I_MIXER_BLEND_MODE(base, i),
0524 SUN8I_MIXER_BLEND_MODE_DEF);
0525
0526 regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
0527 SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
0528
0529 return 0;
0530
0531 err_disable_bus_clk:
0532 clk_disable_unprepare(mixer->bus_clk);
0533 err_assert_reset:
0534 reset_control_assert(mixer->reset);
0535 return ret;
0536 }
0537
0538 static void sun8i_mixer_unbind(struct device *dev, struct device *master,
0539 void *data)
0540 {
0541 struct sun8i_mixer *mixer = dev_get_drvdata(dev);
0542
0543 list_del(&mixer->engine.list);
0544
0545 clk_disable_unprepare(mixer->mod_clk);
0546 clk_disable_unprepare(mixer->bus_clk);
0547 reset_control_assert(mixer->reset);
0548 }
0549
0550 static const struct component_ops sun8i_mixer_ops = {
0551 .bind = sun8i_mixer_bind,
0552 .unbind = sun8i_mixer_unbind,
0553 };
0554
0555 static int sun8i_mixer_probe(struct platform_device *pdev)
0556 {
0557 return component_add(&pdev->dev, &sun8i_mixer_ops);
0558 }
0559
0560 static int sun8i_mixer_remove(struct platform_device *pdev)
0561 {
0562 component_del(&pdev->dev, &sun8i_mixer_ops);
0563
0564 return 0;
0565 }
0566
0567 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
0568 .ccsc = CCSC_MIXER0_LAYOUT,
0569 .scaler_mask = 0xf,
0570 .scanline_yuv = 2048,
0571 .ui_num = 3,
0572 .vi_num = 1,
0573 };
0574
0575 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
0576 .ccsc = CCSC_MIXER1_LAYOUT,
0577 .scaler_mask = 0x3,
0578 .scanline_yuv = 2048,
0579 .ui_num = 1,
0580 .vi_num = 1,
0581 };
0582
0583 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
0584 .ccsc = CCSC_MIXER0_LAYOUT,
0585 .mod_rate = 432000000,
0586 .scaler_mask = 0xf,
0587 .scanline_yuv = 2048,
0588 .ui_num = 3,
0589 .vi_num = 1,
0590 };
0591
0592 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
0593 .ccsc = CCSC_MIXER0_LAYOUT,
0594 .mod_rate = 297000000,
0595 .scaler_mask = 0xf,
0596 .scanline_yuv = 2048,
0597 .ui_num = 3,
0598 .vi_num = 1,
0599 };
0600
0601 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
0602 .ccsc = CCSC_MIXER1_LAYOUT,
0603 .mod_rate = 297000000,
0604 .scaler_mask = 0x3,
0605 .scanline_yuv = 2048,
0606 .ui_num = 1,
0607 .vi_num = 1,
0608 };
0609
0610 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
0611 .vi_num = 2,
0612 .ui_num = 1,
0613 .scaler_mask = 0x3,
0614 .scanline_yuv = 2048,
0615 .ccsc = CCSC_MIXER0_LAYOUT,
0616 .mod_rate = 150000000,
0617 };
0618
0619 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
0620 .ccsc = CCSC_D1_MIXER0_LAYOUT,
0621 .mod_rate = 297000000,
0622 .scaler_mask = 0x3,
0623 .scanline_yuv = 2048,
0624 .ui_num = 1,
0625 .vi_num = 1,
0626 };
0627
0628 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
0629 .ccsc = CCSC_MIXER1_LAYOUT,
0630 .mod_rate = 297000000,
0631 .scaler_mask = 0x1,
0632 .scanline_yuv = 1024,
0633 .ui_num = 0,
0634 .vi_num = 1,
0635 };
0636
0637 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
0638 .ccsc = CCSC_MIXER0_LAYOUT,
0639 .mod_rate = 297000000,
0640 .scaler_mask = 0xf,
0641 .scanline_yuv = 4096,
0642 .ui_num = 3,
0643 .vi_num = 1,
0644 };
0645
0646 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
0647 .ccsc = CCSC_MIXER1_LAYOUT,
0648 .mod_rate = 297000000,
0649 .scaler_mask = 0x3,
0650 .scanline_yuv = 2048,
0651 .ui_num = 1,
0652 .vi_num = 1,
0653 };
0654
0655 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
0656 .ccsc = CCSC_MIXER0_LAYOUT,
0657 .is_de3 = true,
0658 .mod_rate = 600000000,
0659 .scaler_mask = 0xf,
0660 .scanline_yuv = 4096,
0661 .ui_num = 3,
0662 .vi_num = 1,
0663 };
0664
0665 static const struct of_device_id sun8i_mixer_of_table[] = {
0666 {
0667 .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
0668 .data = &sun8i_a83t_mixer0_cfg,
0669 },
0670 {
0671 .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
0672 .data = &sun8i_a83t_mixer1_cfg,
0673 },
0674 {
0675 .compatible = "allwinner,sun8i-h3-de2-mixer-0",
0676 .data = &sun8i_h3_mixer0_cfg,
0677 },
0678 {
0679 .compatible = "allwinner,sun8i-r40-de2-mixer-0",
0680 .data = &sun8i_r40_mixer0_cfg,
0681 },
0682 {
0683 .compatible = "allwinner,sun8i-r40-de2-mixer-1",
0684 .data = &sun8i_r40_mixer1_cfg,
0685 },
0686 {
0687 .compatible = "allwinner,sun8i-v3s-de2-mixer",
0688 .data = &sun8i_v3s_mixer_cfg,
0689 },
0690 {
0691 .compatible = "allwinner,sun20i-d1-de2-mixer-0",
0692 .data = &sun20i_d1_mixer0_cfg,
0693 },
0694 {
0695 .compatible = "allwinner,sun20i-d1-de2-mixer-1",
0696 .data = &sun20i_d1_mixer1_cfg,
0697 },
0698 {
0699 .compatible = "allwinner,sun50i-a64-de2-mixer-0",
0700 .data = &sun50i_a64_mixer0_cfg,
0701 },
0702 {
0703 .compatible = "allwinner,sun50i-a64-de2-mixer-1",
0704 .data = &sun50i_a64_mixer1_cfg,
0705 },
0706 {
0707 .compatible = "allwinner,sun50i-h6-de3-mixer-0",
0708 .data = &sun50i_h6_mixer0_cfg,
0709 },
0710 { }
0711 };
0712 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
0713
0714 static struct platform_driver sun8i_mixer_platform_driver = {
0715 .probe = sun8i_mixer_probe,
0716 .remove = sun8i_mixer_remove,
0717 .driver = {
0718 .name = "sun8i-mixer",
0719 .of_match_table = sun8i_mixer_of_table,
0720 },
0721 };
0722 module_platform_driver(sun8i_mixer_platform_driver);
0723
0724 MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
0725 MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
0726 MODULE_LICENSE("GPL");