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.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_print.h> 25 #include <drm/drm_probe_helper.h> 26 27 #include "sun4i_drv.h" 28 #include "sun8i_mixer.h" 29 #include "sun8i_ui_layer.h" 30 #include "sun8i_vi_layer.h" 31 #include "sunxi_engine.h" 32 33 struct de2_fmt_info { 34 u32 drm_fmt; 35 u32 de2_fmt; 36 }; 37 38 static const struct de2_fmt_info de2_formats[] = { 39 { 40 .drm_fmt = DRM_FORMAT_ARGB8888, 41 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888, 42 }, 43 { 44 .drm_fmt = DRM_FORMAT_ABGR8888, 45 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888, 46 }, 47 { 48 .drm_fmt = DRM_FORMAT_RGBA8888, 49 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888, 50 }, 51 { 52 .drm_fmt = DRM_FORMAT_BGRA8888, 53 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888, 54 }, 55 { 56 .drm_fmt = DRM_FORMAT_XRGB8888, 57 .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888, 58 }, 59 { 60 .drm_fmt = DRM_FORMAT_XBGR8888, 61 .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888, 62 }, 63 { 64 .drm_fmt = DRM_FORMAT_RGBX8888, 65 .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888, 66 }, 67 { 68 .drm_fmt = DRM_FORMAT_BGRX8888, 69 .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888, 70 }, 71 { 72 .drm_fmt = DRM_FORMAT_RGB888, 73 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888, 74 }, 75 { 76 .drm_fmt = DRM_FORMAT_BGR888, 77 .de2_fmt = SUN8I_MIXER_FBFMT_BGR888, 78 }, 79 { 80 .drm_fmt = DRM_FORMAT_RGB565, 81 .de2_fmt = SUN8I_MIXER_FBFMT_RGB565, 82 }, 83 { 84 .drm_fmt = DRM_FORMAT_BGR565, 85 .de2_fmt = SUN8I_MIXER_FBFMT_BGR565, 86 }, 87 { 88 .drm_fmt = DRM_FORMAT_ARGB4444, 89 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444, 90 }, 91 { 92 /* for DE2 VI layer which ignores alpha */ 93 .drm_fmt = DRM_FORMAT_XRGB4444, 94 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444, 95 }, 96 { 97 .drm_fmt = DRM_FORMAT_ABGR4444, 98 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444, 99 }, 100 { 101 /* for DE2 VI layer which ignores alpha */ 102 .drm_fmt = DRM_FORMAT_XBGR4444, 103 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444, 104 }, 105 { 106 .drm_fmt = DRM_FORMAT_RGBA4444, 107 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444, 108 }, 109 { 110 /* for DE2 VI layer which ignores alpha */ 111 .drm_fmt = DRM_FORMAT_RGBX4444, 112 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444, 113 }, 114 { 115 .drm_fmt = DRM_FORMAT_BGRA4444, 116 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444, 117 }, 118 { 119 /* for DE2 VI layer which ignores alpha */ 120 .drm_fmt = DRM_FORMAT_BGRX4444, 121 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444, 122 }, 123 { 124 .drm_fmt = DRM_FORMAT_ARGB1555, 125 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555, 126 }, 127 { 128 /* for DE2 VI layer which ignores alpha */ 129 .drm_fmt = DRM_FORMAT_XRGB1555, 130 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555, 131 }, 132 { 133 .drm_fmt = DRM_FORMAT_ABGR1555, 134 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555, 135 }, 136 { 137 /* for DE2 VI layer which ignores alpha */ 138 .drm_fmt = DRM_FORMAT_XBGR1555, 139 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555, 140 }, 141 { 142 .drm_fmt = DRM_FORMAT_RGBA5551, 143 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551, 144 }, 145 { 146 /* for DE2 VI layer which ignores alpha */ 147 .drm_fmt = DRM_FORMAT_RGBX5551, 148 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551, 149 }, 150 { 151 .drm_fmt = DRM_FORMAT_BGRA5551, 152 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551, 153 }, 154 { 155 /* for DE2 VI layer which ignores alpha */ 156 .drm_fmt = DRM_FORMAT_BGRX5551, 157 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551, 158 }, 159 { 160 .drm_fmt = DRM_FORMAT_ARGB2101010, 161 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010, 162 }, 163 { 164 .drm_fmt = DRM_FORMAT_ABGR2101010, 165 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010, 166 }, 167 { 168 .drm_fmt = DRM_FORMAT_RGBA1010102, 169 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102, 170 }, 171 { 172 .drm_fmt = DRM_FORMAT_BGRA1010102, 173 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102, 174 }, 175 { 176 .drm_fmt = DRM_FORMAT_UYVY, 177 .de2_fmt = SUN8I_MIXER_FBFMT_UYVY, 178 }, 179 { 180 .drm_fmt = DRM_FORMAT_VYUY, 181 .de2_fmt = SUN8I_MIXER_FBFMT_VYUY, 182 }, 183 { 184 .drm_fmt = DRM_FORMAT_YUYV, 185 .de2_fmt = SUN8I_MIXER_FBFMT_YUYV, 186 }, 187 { 188 .drm_fmt = DRM_FORMAT_YVYU, 189 .de2_fmt = SUN8I_MIXER_FBFMT_YVYU, 190 }, 191 { 192 .drm_fmt = DRM_FORMAT_NV16, 193 .de2_fmt = SUN8I_MIXER_FBFMT_NV16, 194 }, 195 { 196 .drm_fmt = DRM_FORMAT_NV61, 197 .de2_fmt = SUN8I_MIXER_FBFMT_NV61, 198 }, 199 { 200 .drm_fmt = DRM_FORMAT_NV12, 201 .de2_fmt = SUN8I_MIXER_FBFMT_NV12, 202 }, 203 { 204 .drm_fmt = DRM_FORMAT_NV21, 205 .de2_fmt = SUN8I_MIXER_FBFMT_NV21, 206 }, 207 { 208 .drm_fmt = DRM_FORMAT_YUV422, 209 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422, 210 }, 211 { 212 .drm_fmt = DRM_FORMAT_YUV420, 213 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420, 214 }, 215 { 216 .drm_fmt = DRM_FORMAT_YUV411, 217 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411, 218 }, 219 { 220 .drm_fmt = DRM_FORMAT_YVU422, 221 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422, 222 }, 223 { 224 .drm_fmt = DRM_FORMAT_YVU420, 225 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420, 226 }, 227 { 228 .drm_fmt = DRM_FORMAT_YVU411, 229 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411, 230 }, 231 { 232 .drm_fmt = DRM_FORMAT_P010, 233 .de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV, 234 }, 235 { 236 .drm_fmt = DRM_FORMAT_P210, 237 .de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV, 238 }, 239 }; 240 241 int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format) 242 { 243 unsigned int i; 244 245 for (i = 0; i < ARRAY_SIZE(de2_formats); ++i) 246 if (de2_formats[i].drm_fmt == format) { 247 *hw_format = de2_formats[i].de2_fmt; 248 return 0; 249 } 250 251 return -EINVAL; 252 } 253 254 static void sun8i_mixer_commit(struct sunxi_engine *engine, 255 struct drm_crtc *crtc, 256 struct drm_atomic_state *state) 257 { 258 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine); 259 u32 bld_base = sun8i_blender_base(mixer); 260 struct regmap *bld_regs = sun8i_blender_regmap(mixer); 261 struct drm_plane_state *plane_state; 262 struct drm_plane *plane; 263 u32 route = 0, pipe_en = 0; 264 265 DRM_DEBUG_DRIVER("Committing changes\n"); 266 267 drm_for_each_plane(plane, state->dev) { 268 struct sun8i_layer *layer = plane_to_sun8i_layer(plane); 269 int w, h, x, y, zpos; 270 bool enable; 271 272 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) 273 continue; 274 275 plane_state = drm_atomic_get_new_plane_state(state, plane); 276 if (!plane_state) 277 plane_state = plane->state; 278 279 enable = plane_state->crtc && plane_state->visible; 280 zpos = plane_state->normalized_zpos; 281 x = plane_state->dst.x1; 282 y = plane_state->dst.y1; 283 w = drm_rect_width(&plane_state->dst); 284 h = drm_rect_height(&plane_state->dst); 285 286 DRM_DEBUG_DRIVER(" plane %d: chan=%d ovl=%d en=%d zpos=%d x=%d y=%d w=%d h=%d\n", 287 plane->base.id, layer->index, layer->overlay, 288 enable, zpos, x, y, w, h); 289 290 if (!enable) 291 continue; 292 293 /* Route layer to pipe based on zpos */ 294 route |= layer->index << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 295 pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 296 297 regmap_write(bld_regs, 298 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos), 299 SUN8I_MIXER_COORD(x, y)); 300 regmap_write(bld_regs, 301 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos), 302 SUN8I_MIXER_SIZE(w, h)); 303 } 304 305 regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route); 306 regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), 307 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0)); 308 309 if (mixer->cfg->de_type != SUN8I_MIXER_DE33) 310 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF, 311 SUN8I_MIXER_GLOBAL_DBUFF_ENABLE); 312 } 313 314 static struct drm_plane **sun8i_layers_init(struct drm_device *drm, 315 struct sunxi_engine *engine) 316 { 317 struct drm_plane **planes; 318 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine); 319 int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; 320 enum drm_plane_type type; 321 unsigned int phy_index; 322 int i; 323 324 planes = devm_kcalloc(drm->dev, plane_cnt + 1, sizeof(*planes), GFP_KERNEL); 325 if (!planes) 326 return ERR_PTR(-ENOMEM); 327 328 for (i = 0; i < mixer->cfg->vi_num; i++) { 329 struct sun8i_layer *layer; 330 331 if (i == 0 && !mixer->cfg->ui_num) 332 type = DRM_PLANE_TYPE_PRIMARY; 333 else 334 type = DRM_PLANE_TYPE_OVERLAY; 335 336 phy_index = i; 337 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) 338 phy_index = mixer->cfg->map[i]; 339 340 layer = sun8i_vi_layer_init_one(drm, type, mixer->engine.regs, 341 i, phy_index, plane_cnt, 342 &mixer->cfg->lay_cfg); 343 if (IS_ERR(layer)) { 344 dev_err(drm->dev, 345 "Couldn't initialize overlay plane\n"); 346 return ERR_CAST(layer); 347 } 348 349 planes[i] = &layer->plane; 350 } 351 352 for (i = 0; i < mixer->cfg->ui_num; i++) { 353 unsigned int index = mixer->cfg->vi_num + i; 354 struct sun8i_layer *layer; 355 356 if (i == 0) 357 type = DRM_PLANE_TYPE_PRIMARY; 358 else 359 type = DRM_PLANE_TYPE_OVERLAY; 360 361 phy_index = index; 362 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) 363 phy_index = mixer->cfg->map[index]; 364 365 layer = sun8i_ui_layer_init_one(drm, type, mixer->engine.regs, 366 index, phy_index, plane_cnt, 367 &mixer->cfg->lay_cfg); 368 if (IS_ERR(layer)) { 369 dev_err(drm->dev, "Couldn't initialize %s plane\n", 370 i ? "overlay" : "primary"); 371 return ERR_CAST(layer); 372 } 373 374 planes[index] = &layer->plane; 375 } 376 377 return planes; 378 } 379 380 static void sun8i_mixer_mode_set(struct sunxi_engine *engine, 381 const struct drm_display_mode *mode) 382 { 383 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine); 384 struct regmap *bld_regs; 385 u32 bld_base, size, val; 386 bool interlaced; 387 388 bld_base = sun8i_blender_base(mixer); 389 bld_regs = sun8i_blender_regmap(mixer); 390 interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); 391 size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay); 392 393 DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n", 394 mode->hdisplay, mode->vdisplay); 395 396 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) 397 regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size); 398 else 399 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size); 400 401 regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size); 402 403 if (interlaced) 404 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED; 405 else 406 val = 0; 407 408 regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base), 409 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val); 410 411 DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n", 412 interlaced ? "on" : "off"); 413 } 414 415 static const struct sunxi_engine_ops sun8i_engine_ops = { 416 .commit = sun8i_mixer_commit, 417 .layers_init = sun8i_layers_init, 418 .mode_set = sun8i_mixer_mode_set, 419 }; 420 421 static const struct regmap_config sun8i_mixer_regmap_config = { 422 .name = "layers", 423 .reg_bits = 32, 424 .val_bits = 32, 425 .reg_stride = 4, 426 .max_register = 0xffffc, /* guessed */ 427 }; 428 429 static const struct regmap_config sun8i_top_regmap_config = { 430 .name = "top", 431 .reg_bits = 32, 432 .val_bits = 32, 433 .reg_stride = 4, 434 .max_register = 0x3c, 435 }; 436 437 static const struct regmap_config sun8i_disp_regmap_config = { 438 .name = "display", 439 .reg_bits = 32, 440 .val_bits = 32, 441 .reg_stride = 4, 442 .max_register = 0x20000, 443 }; 444 445 static int sun8i_mixer_of_get_id(struct device_node *node) 446 { 447 struct device_node *ep, *remote; 448 struct of_endpoint of_ep; 449 450 /* Output port is 1, and we want the first endpoint. */ 451 ep = of_graph_get_endpoint_by_regs(node, 1, -1); 452 if (!ep) 453 return -EINVAL; 454 455 remote = of_graph_get_remote_endpoint(ep); 456 of_node_put(ep); 457 if (!remote) 458 return -EINVAL; 459 460 of_graph_parse_endpoint(remote, &of_ep); 461 of_node_put(remote); 462 return of_ep.id; 463 } 464 465 static void sun8i_mixer_init(struct sun8i_mixer *mixer) 466 { 467 struct regmap *top_regs, *disp_regs; 468 unsigned int base = sun8i_blender_base(mixer); 469 int plane_cnt, i; 470 471 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) { 472 top_regs = mixer->top_regs; 473 disp_regs = mixer->disp_regs; 474 } else { 475 top_regs = mixer->engine.regs; 476 disp_regs = mixer->engine.regs; 477 } 478 479 /* Enable the mixer */ 480 regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL, 481 SUN8I_MIXER_GLOBAL_CTL_RT_EN); 482 483 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) 484 regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1); 485 486 /* Set background color to black */ 487 regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base), 488 SUN8I_MIXER_BLEND_COLOR_BLACK); 489 490 /* 491 * Set fill color of bottom plane to black. Generally not needed 492 * except when VI plane is at bottom (zpos = 0) and enabled. 493 */ 494 regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base), 495 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0)); 496 regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0), 497 SUN8I_MIXER_BLEND_COLOR_BLACK); 498 499 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num; 500 for (i = 0; i < plane_cnt; i++) 501 regmap_write(disp_regs, 502 SUN8I_MIXER_BLEND_MODE(base, i), 503 SUN8I_MIXER_BLEND_MODE_DEF); 504 505 regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base), 506 SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); 507 } 508 509 static int sun8i_mixer_bind(struct device *dev, struct device *master, 510 void *data) 511 { 512 struct platform_device *pdev = to_platform_device(dev); 513 struct drm_device *drm = data; 514 struct sun4i_drv *drv = drm->dev_private; 515 struct sun8i_mixer *mixer; 516 void __iomem *regs; 517 int i, ret; 518 519 /* 520 * The mixer uses single 32-bit register to store memory 521 * addresses, so that it cannot deal with 64-bit memory 522 * addresses. 523 * Restrict the DMA mask so that the mixer won't be 524 * allocated some memory that is too high. 525 */ 526 ret = dma_set_mask(dev, DMA_BIT_MASK(32)); 527 if (ret) { 528 dev_err(dev, "Cannot do 32-bit DMA.\n"); 529 return ret; 530 } 531 532 mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); 533 if (!mixer) 534 return -ENOMEM; 535 dev_set_drvdata(dev, mixer); 536 mixer->engine.ops = &sun8i_engine_ops; 537 mixer->engine.node = dev->of_node; 538 539 /* 540 * This assume we have the same DMA constraints for all our the 541 * devices in our pipeline (all the backends, but also the 542 * frontends). This sounds bad, but it has always been the case 543 * for us, and DRM doesn't do per-device allocation either, so 544 * we would need to fix DRM first... 545 * 546 * Always use the first bound backend as the DMA device. While 547 * our device trees always have all backends enabled, some in 548 * the wild may actually have the first one disabled. If both 549 * are enabled, the order in which they are bound is guaranteed 550 * since the driver adds components in order. 551 */ 552 if (drm_dev_dma_dev(drm) == drm->dev) 553 drm_dev_set_dma_dev(drm, dev); 554 555 /* 556 * While this function can fail, we shouldn't do anything 557 * if this happens. Some early DE2 DT entries don't provide 558 * mixer id but work nevertheless because matching between 559 * TCON and mixer is done by comparing node pointers (old 560 * way) instead comparing ids. If this function fails and 561 * id is needed, it will fail during id matching anyway. 562 */ 563 mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node); 564 565 mixer->cfg = of_device_get_match_data(dev); 566 if (!mixer->cfg) 567 return -EINVAL; 568 569 regs = devm_platform_ioremap_resource(pdev, 0); 570 if (IS_ERR(regs)) 571 return PTR_ERR(regs); 572 573 mixer->engine.regs = devm_regmap_init_mmio(dev, regs, 574 &sun8i_mixer_regmap_config); 575 if (IS_ERR(mixer->engine.regs)) { 576 dev_err(dev, "Couldn't create the mixer regmap\n"); 577 return PTR_ERR(mixer->engine.regs); 578 } 579 580 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) { 581 regs = devm_platform_ioremap_resource_byname(pdev, "top"); 582 if (IS_ERR(regs)) 583 return PTR_ERR(regs); 584 585 mixer->top_regs = devm_regmap_init_mmio(dev, regs, 586 &sun8i_top_regmap_config); 587 if (IS_ERR(mixer->top_regs)) { 588 dev_err(dev, "Couldn't create the top regmap\n"); 589 return PTR_ERR(mixer->top_regs); 590 } 591 592 regs = devm_platform_ioremap_resource_byname(pdev, "display"); 593 if (IS_ERR(regs)) 594 return PTR_ERR(regs); 595 596 mixer->disp_regs = devm_regmap_init_mmio(dev, regs, 597 &sun8i_disp_regmap_config); 598 if (IS_ERR(mixer->disp_regs)) { 599 dev_err(dev, "Couldn't create the disp regmap\n"); 600 return PTR_ERR(mixer->disp_regs); 601 } 602 } 603 604 mixer->reset = devm_reset_control_get(dev, NULL); 605 if (IS_ERR(mixer->reset)) { 606 dev_err(dev, "Couldn't get our reset line\n"); 607 return PTR_ERR(mixer->reset); 608 } 609 610 ret = reset_control_deassert(mixer->reset); 611 if (ret) { 612 dev_err(dev, "Couldn't deassert our reset line\n"); 613 return ret; 614 } 615 616 mixer->bus_clk = devm_clk_get(dev, "bus"); 617 if (IS_ERR(mixer->bus_clk)) { 618 dev_err(dev, "Couldn't get the mixer bus clock\n"); 619 ret = PTR_ERR(mixer->bus_clk); 620 goto err_assert_reset; 621 } 622 clk_prepare_enable(mixer->bus_clk); 623 624 mixer->mod_clk = devm_clk_get(dev, "mod"); 625 if (IS_ERR(mixer->mod_clk)) { 626 dev_err(dev, "Couldn't get the mixer module clock\n"); 627 ret = PTR_ERR(mixer->mod_clk); 628 goto err_disable_bus_clk; 629 } 630 631 /* 632 * It seems that we need to enforce that rate for whatever 633 * reason for the mixer to be functional. Make sure it's the 634 * case. 635 */ 636 if (mixer->cfg->mod_rate) 637 clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate); 638 639 clk_prepare_enable(mixer->mod_clk); 640 641 list_add_tail(&mixer->engine.list, &drv->engine_list); 642 643 /* Reset registers and disable unused sub-engines */ 644 if (mixer->cfg->de_type == SUN8I_MIXER_DE3) { 645 for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4) 646 regmap_write(mixer->engine.regs, i, 0); 647 648 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0); 649 regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0); 650 regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0); 651 regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0); 652 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0); 653 regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0); 654 regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0); 655 regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0); 656 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0); 657 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0); 658 } else if (mixer->cfg->de_type == SUN8I_MIXER_DE2) { 659 for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4) 660 regmap_write(mixer->engine.regs, i, 0); 661 662 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0); 663 regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0); 664 regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0); 665 regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0); 666 regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0); 667 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0); 668 regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0); 669 } 670 671 sun8i_mixer_init(mixer); 672 673 return 0; 674 675 err_disable_bus_clk: 676 clk_disable_unprepare(mixer->bus_clk); 677 err_assert_reset: 678 reset_control_assert(mixer->reset); 679 return ret; 680 } 681 682 static void sun8i_mixer_unbind(struct device *dev, struct device *master, 683 void *data) 684 { 685 struct sun8i_mixer *mixer = dev_get_drvdata(dev); 686 687 list_del(&mixer->engine.list); 688 689 clk_disable_unprepare(mixer->mod_clk); 690 clk_disable_unprepare(mixer->bus_clk); 691 reset_control_assert(mixer->reset); 692 } 693 694 static const struct component_ops sun8i_mixer_ops = { 695 .bind = sun8i_mixer_bind, 696 .unbind = sun8i_mixer_unbind, 697 }; 698 699 static int sun8i_mixer_probe(struct platform_device *pdev) 700 { 701 return component_add(&pdev->dev, &sun8i_mixer_ops); 702 } 703 704 static void sun8i_mixer_remove(struct platform_device *pdev) 705 { 706 component_del(&pdev->dev, &sun8i_mixer_ops); 707 } 708 709 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = { 710 .lay_cfg = { 711 .ccsc = CCSC_MIXER0_LAYOUT, 712 .de_type = SUN8I_MIXER_DE2, 713 .vi_scaler_num = 1, 714 .scaler_mask = 0xf, 715 .scanline_yuv = 2048, 716 .de2_fcc_alpha = 1, 717 }, 718 .de_type = SUN8I_MIXER_DE2, 719 .ui_num = 3, 720 .vi_num = 1, 721 }; 722 723 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = { 724 .lay_cfg = { 725 .ccsc = CCSC_MIXER1_LAYOUT, 726 .de_type = SUN8I_MIXER_DE2, 727 .vi_scaler_num = 1, 728 .scaler_mask = 0x3, 729 .scanline_yuv = 2048, 730 .de2_fcc_alpha = 1, 731 }, 732 .de_type = SUN8I_MIXER_DE2, 733 .ui_num = 1, 734 .vi_num = 1, 735 }; 736 737 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = { 738 .lay_cfg = { 739 .ccsc = CCSC_MIXER0_LAYOUT, 740 .de_type = SUN8I_MIXER_DE2, 741 .vi_scaler_num = 1, 742 .scaler_mask = 0xf, 743 .scanline_yuv = 2048, 744 .de2_fcc_alpha = 1, 745 }, 746 .de_type = SUN8I_MIXER_DE2, 747 .mod_rate = 432000000, 748 .ui_num = 3, 749 .vi_num = 1, 750 }; 751 752 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = { 753 .lay_cfg = { 754 .ccsc = CCSC_MIXER0_LAYOUT, 755 .de_type = SUN8I_MIXER_DE2, 756 .vi_scaler_num = 1, 757 .scaler_mask = 0xf, 758 .scanline_yuv = 2048, 759 .de2_fcc_alpha = 1, 760 }, 761 .de_type = SUN8I_MIXER_DE2, 762 .mod_rate = 297000000, 763 .ui_num = 3, 764 .vi_num = 1, 765 }; 766 767 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = { 768 .lay_cfg = { 769 .ccsc = CCSC_MIXER1_LAYOUT, 770 .de_type = SUN8I_MIXER_DE2, 771 .vi_scaler_num = 1, 772 .scaler_mask = 0x3, 773 .scanline_yuv = 2048, 774 .de2_fcc_alpha = 1, 775 }, 776 .de_type = SUN8I_MIXER_DE2, 777 .mod_rate = 297000000, 778 .ui_num = 1, 779 .vi_num = 1, 780 }; 781 782 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { 783 .lay_cfg = { 784 .ccsc = CCSC_MIXER0_LAYOUT, 785 .de_type = SUN8I_MIXER_DE2, 786 .vi_scaler_num = 2, 787 .scaler_mask = 0x3, 788 .scanline_yuv = 2048, 789 }, 790 .de_type = SUN8I_MIXER_DE2, 791 .mod_rate = 150000000, 792 .vi_num = 2, 793 .ui_num = 1, 794 }; 795 796 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = { 797 .lay_cfg = { 798 .ccsc = CCSC_D1_MIXER0_LAYOUT, 799 .de_type = SUN8I_MIXER_DE2, 800 .vi_scaler_num = 1, 801 .scaler_mask = 0x3, 802 .scanline_yuv = 2048, 803 .de2_fcc_alpha = 1, 804 }, 805 .de_type = SUN8I_MIXER_DE2, 806 .mod_rate = 297000000, 807 .ui_num = 1, 808 .vi_num = 1, 809 }; 810 811 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = { 812 .lay_cfg = { 813 .ccsc = CCSC_MIXER1_LAYOUT, 814 .de_type = SUN8I_MIXER_DE2, 815 .vi_scaler_num = 1, 816 .scaler_mask = 0x1, 817 .scanline_yuv = 1024, 818 .de2_fcc_alpha = 1, 819 }, 820 .de_type = SUN8I_MIXER_DE2, 821 .mod_rate = 297000000, 822 .ui_num = 0, 823 .vi_num = 1, 824 }; 825 826 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = { 827 .lay_cfg = { 828 .ccsc = CCSC_MIXER0_LAYOUT, 829 .de_type = SUN8I_MIXER_DE2, 830 .vi_scaler_num = 1, 831 .scaler_mask = 0xf, 832 .scanline_yuv = 4096, 833 .de2_fcc_alpha = 1, 834 }, 835 .de_type = SUN8I_MIXER_DE2, 836 .mod_rate = 297000000, 837 .ui_num = 3, 838 .vi_num = 1, 839 }; 840 841 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = { 842 .lay_cfg = { 843 .ccsc = CCSC_MIXER1_LAYOUT, 844 .de_type = SUN8I_MIXER_DE2, 845 .vi_scaler_num = 1, 846 .scaler_mask = 0x3, 847 .scanline_yuv = 2048, 848 .de2_fcc_alpha = 1, 849 }, 850 .de_type = SUN8I_MIXER_DE2, 851 .mod_rate = 297000000, 852 .ui_num = 1, 853 .vi_num = 1, 854 }; 855 856 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = { 857 .lay_cfg = { 858 .de_type = SUN8I_MIXER_DE3, 859 .vi_scaler_num = 1, 860 .scaler_mask = 0xf, 861 .scanline_yuv = 4096, 862 }, 863 .de_type = SUN8I_MIXER_DE3, 864 .mod_rate = 600000000, 865 .ui_num = 3, 866 .vi_num = 1, 867 }; 868 869 static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = { 870 .lay_cfg = { 871 .de_type = SUN8I_MIXER_DE33, 872 .scaler_mask = 0xf, 873 .scanline_yuv = 4096, 874 }, 875 .de_type = SUN8I_MIXER_DE33, 876 .mod_rate = 600000000, 877 .ui_num = 3, 878 .vi_num = 1, 879 .map = {0, 6, 7, 8}, 880 }; 881 882 static const struct of_device_id sun8i_mixer_of_table[] = { 883 { 884 .compatible = "allwinner,sun8i-a83t-de2-mixer-0", 885 .data = &sun8i_a83t_mixer0_cfg, 886 }, 887 { 888 .compatible = "allwinner,sun8i-a83t-de2-mixer-1", 889 .data = &sun8i_a83t_mixer1_cfg, 890 }, 891 { 892 .compatible = "allwinner,sun8i-h3-de2-mixer-0", 893 .data = &sun8i_h3_mixer0_cfg, 894 }, 895 { 896 .compatible = "allwinner,sun8i-r40-de2-mixer-0", 897 .data = &sun8i_r40_mixer0_cfg, 898 }, 899 { 900 .compatible = "allwinner,sun8i-r40-de2-mixer-1", 901 .data = &sun8i_r40_mixer1_cfg, 902 }, 903 { 904 .compatible = "allwinner,sun8i-v3s-de2-mixer", 905 .data = &sun8i_v3s_mixer_cfg, 906 }, 907 { 908 .compatible = "allwinner,sun20i-d1-de2-mixer-0", 909 .data = &sun20i_d1_mixer0_cfg, 910 }, 911 { 912 .compatible = "allwinner,sun20i-d1-de2-mixer-1", 913 .data = &sun20i_d1_mixer1_cfg, 914 }, 915 { 916 .compatible = "allwinner,sun50i-a64-de2-mixer-0", 917 .data = &sun50i_a64_mixer0_cfg, 918 }, 919 { 920 .compatible = "allwinner,sun50i-a64-de2-mixer-1", 921 .data = &sun50i_a64_mixer1_cfg, 922 }, 923 { 924 .compatible = "allwinner,sun50i-h6-de3-mixer-0", 925 .data = &sun50i_h6_mixer0_cfg, 926 }, 927 { 928 .compatible = "allwinner,sun50i-h616-de33-mixer-0", 929 .data = &sun50i_h616_mixer0_cfg, 930 }, 931 { } 932 }; 933 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table); 934 935 static struct platform_driver sun8i_mixer_platform_driver = { 936 .probe = sun8i_mixer_probe, 937 .remove = sun8i_mixer_remove, 938 .driver = { 939 .name = "sun8i-mixer", 940 .of_match_table = sun8i_mixer_of_table, 941 }, 942 }; 943 module_platform_driver(sun8i_mixer_platform_driver); 944 945 MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>"); 946 MODULE_DESCRIPTION("Allwinner DE2 Mixer driver"); 947 MODULE_LICENSE("GPL"); 948