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, 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 if (of_property_present(dev->of_node, "iommus")) { 540 /* 541 * This assume we have the same DMA constraints for 542 * all our the mixers in our pipeline. This sounds 543 * bad, but it has always been the case for us, and 544 * DRM doesn't do per-device allocation either, so we 545 * would need to fix DRM first... 546 */ 547 ret = of_dma_configure(drm->dev, dev->of_node, true); 548 if (ret) 549 return ret; 550 } 551 552 /* 553 * While this function can fail, we shouldn't do anything 554 * if this happens. Some early DE2 DT entries don't provide 555 * mixer id but work nevertheless because matching between 556 * TCON and mixer is done by comparing node pointers (old 557 * way) instead comparing ids. If this function fails and 558 * id is needed, it will fail during id matching anyway. 559 */ 560 mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node); 561 562 mixer->cfg = of_device_get_match_data(dev); 563 if (!mixer->cfg) 564 return -EINVAL; 565 566 regs = devm_platform_ioremap_resource(pdev, 0); 567 if (IS_ERR(regs)) 568 return PTR_ERR(regs); 569 570 mixer->engine.regs = devm_regmap_init_mmio(dev, regs, 571 &sun8i_mixer_regmap_config); 572 if (IS_ERR(mixer->engine.regs)) { 573 dev_err(dev, "Couldn't create the mixer regmap\n"); 574 return PTR_ERR(mixer->engine.regs); 575 } 576 577 if (mixer->cfg->de_type == SUN8I_MIXER_DE33) { 578 regs = devm_platform_ioremap_resource_byname(pdev, "top"); 579 if (IS_ERR(regs)) 580 return PTR_ERR(regs); 581 582 mixer->top_regs = devm_regmap_init_mmio(dev, regs, 583 &sun8i_top_regmap_config); 584 if (IS_ERR(mixer->top_regs)) { 585 dev_err(dev, "Couldn't create the top regmap\n"); 586 return PTR_ERR(mixer->top_regs); 587 } 588 589 regs = devm_platform_ioremap_resource_byname(pdev, "display"); 590 if (IS_ERR(regs)) 591 return PTR_ERR(regs); 592 593 mixer->disp_regs = devm_regmap_init_mmio(dev, regs, 594 &sun8i_disp_regmap_config); 595 if (IS_ERR(mixer->disp_regs)) { 596 dev_err(dev, "Couldn't create the disp regmap\n"); 597 return PTR_ERR(mixer->disp_regs); 598 } 599 } 600 601 mixer->reset = devm_reset_control_get(dev, NULL); 602 if (IS_ERR(mixer->reset)) { 603 dev_err(dev, "Couldn't get our reset line\n"); 604 return PTR_ERR(mixer->reset); 605 } 606 607 ret = reset_control_deassert(mixer->reset); 608 if (ret) { 609 dev_err(dev, "Couldn't deassert our reset line\n"); 610 return ret; 611 } 612 613 mixer->bus_clk = devm_clk_get(dev, "bus"); 614 if (IS_ERR(mixer->bus_clk)) { 615 dev_err(dev, "Couldn't get the mixer bus clock\n"); 616 ret = PTR_ERR(mixer->bus_clk); 617 goto err_assert_reset; 618 } 619 clk_prepare_enable(mixer->bus_clk); 620 621 mixer->mod_clk = devm_clk_get(dev, "mod"); 622 if (IS_ERR(mixer->mod_clk)) { 623 dev_err(dev, "Couldn't get the mixer module clock\n"); 624 ret = PTR_ERR(mixer->mod_clk); 625 goto err_disable_bus_clk; 626 } 627 628 /* 629 * It seems that we need to enforce that rate for whatever 630 * reason for the mixer to be functional. Make sure it's the 631 * case. 632 */ 633 if (mixer->cfg->mod_rate) 634 clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate); 635 636 clk_prepare_enable(mixer->mod_clk); 637 638 list_add_tail(&mixer->engine.list, &drv->engine_list); 639 640 /* Reset registers and disable unused sub-engines */ 641 if (mixer->cfg->de_type == SUN8I_MIXER_DE3) { 642 for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4) 643 regmap_write(mixer->engine.regs, i, 0); 644 645 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0); 646 regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0); 647 regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0); 648 regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0); 649 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0); 650 regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0); 651 regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0); 652 regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0); 653 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0); 654 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0); 655 } else if (mixer->cfg->de_type == SUN8I_MIXER_DE2) { 656 for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4) 657 regmap_write(mixer->engine.regs, i, 0); 658 659 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0); 660 regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0); 661 regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0); 662 regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0); 663 regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0); 664 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0); 665 regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0); 666 } 667 668 sun8i_mixer_init(mixer); 669 670 return 0; 671 672 err_disable_bus_clk: 673 clk_disable_unprepare(mixer->bus_clk); 674 err_assert_reset: 675 reset_control_assert(mixer->reset); 676 return ret; 677 } 678 679 static void sun8i_mixer_unbind(struct device *dev, struct device *master, 680 void *data) 681 { 682 struct sun8i_mixer *mixer = dev_get_drvdata(dev); 683 684 list_del(&mixer->engine.list); 685 686 clk_disable_unprepare(mixer->mod_clk); 687 clk_disable_unprepare(mixer->bus_clk); 688 reset_control_assert(mixer->reset); 689 } 690 691 static const struct component_ops sun8i_mixer_ops = { 692 .bind = sun8i_mixer_bind, 693 .unbind = sun8i_mixer_unbind, 694 }; 695 696 static int sun8i_mixer_probe(struct platform_device *pdev) 697 { 698 return component_add(&pdev->dev, &sun8i_mixer_ops); 699 } 700 701 static void sun8i_mixer_remove(struct platform_device *pdev) 702 { 703 component_del(&pdev->dev, &sun8i_mixer_ops); 704 } 705 706 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = { 707 .lay_cfg = { 708 .ccsc = CCSC_MIXER0_LAYOUT, 709 .de_type = SUN8I_MIXER_DE2, 710 .vi_scaler_num = 1, 711 .scaler_mask = 0xf, 712 .scanline_yuv = 2048, 713 .de2_fcc_alpha = 1, 714 }, 715 .de_type = SUN8I_MIXER_DE2, 716 .ui_num = 3, 717 .vi_num = 1, 718 }; 719 720 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = { 721 .lay_cfg = { 722 .ccsc = CCSC_MIXER1_LAYOUT, 723 .de_type = SUN8I_MIXER_DE2, 724 .vi_scaler_num = 1, 725 .scaler_mask = 0x3, 726 .scanline_yuv = 2048, 727 .de2_fcc_alpha = 1, 728 }, 729 .de_type = SUN8I_MIXER_DE2, 730 .ui_num = 1, 731 .vi_num = 1, 732 }; 733 734 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = { 735 .lay_cfg = { 736 .ccsc = CCSC_MIXER0_LAYOUT, 737 .de_type = SUN8I_MIXER_DE2, 738 .vi_scaler_num = 1, 739 .scaler_mask = 0xf, 740 .scanline_yuv = 2048, 741 .de2_fcc_alpha = 1, 742 }, 743 .de_type = SUN8I_MIXER_DE2, 744 .mod_rate = 432000000, 745 .ui_num = 3, 746 .vi_num = 1, 747 }; 748 749 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = { 750 .lay_cfg = { 751 .ccsc = CCSC_MIXER0_LAYOUT, 752 .de_type = SUN8I_MIXER_DE2, 753 .vi_scaler_num = 1, 754 .scaler_mask = 0xf, 755 .scanline_yuv = 2048, 756 .de2_fcc_alpha = 1, 757 }, 758 .de_type = SUN8I_MIXER_DE2, 759 .mod_rate = 297000000, 760 .ui_num = 3, 761 .vi_num = 1, 762 }; 763 764 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = { 765 .lay_cfg = { 766 .ccsc = CCSC_MIXER1_LAYOUT, 767 .de_type = SUN8I_MIXER_DE2, 768 .vi_scaler_num = 1, 769 .scaler_mask = 0x3, 770 .scanline_yuv = 2048, 771 .de2_fcc_alpha = 1, 772 }, 773 .de_type = SUN8I_MIXER_DE2, 774 .mod_rate = 297000000, 775 .ui_num = 1, 776 .vi_num = 1, 777 }; 778 779 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { 780 .lay_cfg = { 781 .ccsc = CCSC_MIXER0_LAYOUT, 782 .de_type = SUN8I_MIXER_DE2, 783 .vi_scaler_num = 2, 784 .scaler_mask = 0x3, 785 .scanline_yuv = 2048, 786 }, 787 .de_type = SUN8I_MIXER_DE2, 788 .mod_rate = 150000000, 789 .vi_num = 2, 790 .ui_num = 1, 791 }; 792 793 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = { 794 .lay_cfg = { 795 .ccsc = CCSC_D1_MIXER0_LAYOUT, 796 .de_type = SUN8I_MIXER_DE2, 797 .vi_scaler_num = 1, 798 .scaler_mask = 0x3, 799 .scanline_yuv = 2048, 800 .de2_fcc_alpha = 1, 801 }, 802 .de_type = SUN8I_MIXER_DE2, 803 .mod_rate = 297000000, 804 .ui_num = 1, 805 .vi_num = 1, 806 }; 807 808 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = { 809 .lay_cfg = { 810 .ccsc = CCSC_MIXER1_LAYOUT, 811 .de_type = SUN8I_MIXER_DE2, 812 .vi_scaler_num = 1, 813 .scaler_mask = 0x1, 814 .scanline_yuv = 1024, 815 .de2_fcc_alpha = 1, 816 }, 817 .de_type = SUN8I_MIXER_DE2, 818 .mod_rate = 297000000, 819 .ui_num = 0, 820 .vi_num = 1, 821 }; 822 823 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = { 824 .lay_cfg = { 825 .ccsc = CCSC_MIXER0_LAYOUT, 826 .de_type = SUN8I_MIXER_DE2, 827 .vi_scaler_num = 1, 828 .scaler_mask = 0xf, 829 .scanline_yuv = 4096, 830 .de2_fcc_alpha = 1, 831 }, 832 .de_type = SUN8I_MIXER_DE2, 833 .mod_rate = 297000000, 834 .ui_num = 3, 835 .vi_num = 1, 836 }; 837 838 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = { 839 .lay_cfg = { 840 .ccsc = CCSC_MIXER1_LAYOUT, 841 .de_type = SUN8I_MIXER_DE2, 842 .vi_scaler_num = 1, 843 .scaler_mask = 0x3, 844 .scanline_yuv = 2048, 845 .de2_fcc_alpha = 1, 846 }, 847 .de_type = SUN8I_MIXER_DE2, 848 .mod_rate = 297000000, 849 .ui_num = 1, 850 .vi_num = 1, 851 }; 852 853 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = { 854 .lay_cfg = { 855 .de_type = SUN8I_MIXER_DE3, 856 .vi_scaler_num = 1, 857 .scaler_mask = 0xf, 858 .scanline_yuv = 4096, 859 }, 860 .de_type = SUN8I_MIXER_DE3, 861 .mod_rate = 600000000, 862 .ui_num = 3, 863 .vi_num = 1, 864 }; 865 866 static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = { 867 .lay_cfg = { 868 .de_type = SUN8I_MIXER_DE33, 869 .scaler_mask = 0xf, 870 .scanline_yuv = 4096, 871 }, 872 .de_type = SUN8I_MIXER_DE33, 873 .mod_rate = 600000000, 874 .ui_num = 3, 875 .vi_num = 1, 876 .map = {0, 6, 7, 8}, 877 }; 878 879 static const struct of_device_id sun8i_mixer_of_table[] = { 880 { 881 .compatible = "allwinner,sun8i-a83t-de2-mixer-0", 882 .data = &sun8i_a83t_mixer0_cfg, 883 }, 884 { 885 .compatible = "allwinner,sun8i-a83t-de2-mixer-1", 886 .data = &sun8i_a83t_mixer1_cfg, 887 }, 888 { 889 .compatible = "allwinner,sun8i-h3-de2-mixer-0", 890 .data = &sun8i_h3_mixer0_cfg, 891 }, 892 { 893 .compatible = "allwinner,sun8i-r40-de2-mixer-0", 894 .data = &sun8i_r40_mixer0_cfg, 895 }, 896 { 897 .compatible = "allwinner,sun8i-r40-de2-mixer-1", 898 .data = &sun8i_r40_mixer1_cfg, 899 }, 900 { 901 .compatible = "allwinner,sun8i-v3s-de2-mixer", 902 .data = &sun8i_v3s_mixer_cfg, 903 }, 904 { 905 .compatible = "allwinner,sun20i-d1-de2-mixer-0", 906 .data = &sun20i_d1_mixer0_cfg, 907 }, 908 { 909 .compatible = "allwinner,sun20i-d1-de2-mixer-1", 910 .data = &sun20i_d1_mixer1_cfg, 911 }, 912 { 913 .compatible = "allwinner,sun50i-a64-de2-mixer-0", 914 .data = &sun50i_a64_mixer0_cfg, 915 }, 916 { 917 .compatible = "allwinner,sun50i-a64-de2-mixer-1", 918 .data = &sun50i_a64_mixer1_cfg, 919 }, 920 { 921 .compatible = "allwinner,sun50i-h6-de3-mixer-0", 922 .data = &sun50i_h6_mixer0_cfg, 923 }, 924 { 925 .compatible = "allwinner,sun50i-h616-de33-mixer-0", 926 .data = &sun50i_h616_mixer0_cfg, 927 }, 928 { } 929 }; 930 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table); 931 932 static struct platform_driver sun8i_mixer_platform_driver = { 933 .probe = sun8i_mixer_probe, 934 .remove = sun8i_mixer_remove, 935 .driver = { 936 .name = "sun8i-mixer", 937 .of_match_table = sun8i_mixer_of_table, 938 }, 939 }; 940 module_platform_driver(sun8i_mixer_platform_driver); 941 942 MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>"); 943 MODULE_DESCRIPTION("Allwinner DE2 Mixer driver"); 944 MODULE_LICENSE("GPL"); 945