| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2015 MediaTek Inc. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | | -#include <asm/barrier.h> |
|---|
| 15 | | -#include <drm/drmP.h> |
|---|
| 16 | | -#include <drm/drm_atomic_helper.h> |
|---|
| 17 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 18 | | -#include <drm/drm_plane_helper.h> |
|---|
| 19 | 6 | #include <linux/clk.h> |
|---|
| 20 | 7 | #include <linux/pm_runtime.h> |
|---|
| 8 | +#include <linux/soc/mediatek/mtk-cmdq.h> |
|---|
| 9 | +#include <linux/soc/mediatek/mtk-mmsys.h> |
|---|
| 10 | + |
|---|
| 11 | +#include <asm/barrier.h> |
|---|
| 21 | 12 | #include <soc/mediatek/smi.h> |
|---|
| 13 | + |
|---|
| 14 | +#include <drm/drm_atomic_helper.h> |
|---|
| 15 | +#include <drm/drm_plane_helper.h> |
|---|
| 16 | +#include <drm/drm_probe_helper.h> |
|---|
| 17 | +#include <drm/drm_vblank.h> |
|---|
| 22 | 18 | |
|---|
| 23 | 19 | #include "mtk_drm_drv.h" |
|---|
| 24 | 20 | #include "mtk_drm_crtc.h" |
|---|
| .. | .. |
|---|
| 33 | 29 | * @enabled: records whether crtc_enable succeeded |
|---|
| 34 | 30 | * @planes: array of 4 drm_plane structures, one for each overlay plane |
|---|
| 35 | 31 | * @pending_planes: whether any plane has pending changes to be applied |
|---|
| 36 | | - * @config_regs: memory mapped mmsys configuration register space |
|---|
| 32 | + * @mmsys_dev: pointer to the mmsys device for configuration registers |
|---|
| 37 | 33 | * @mutex: handle to one of the ten disp_mutex streams |
|---|
| 38 | 34 | * @ddp_comp_nr: number of components in ddp_comp |
|---|
| 39 | 35 | * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc |
|---|
| .. | .. |
|---|
| 48 | 44 | struct drm_plane *planes; |
|---|
| 49 | 45 | unsigned int layer_nr; |
|---|
| 50 | 46 | bool pending_planes; |
|---|
| 47 | + bool pending_async_planes; |
|---|
| 51 | 48 | |
|---|
| 52 | | - void __iomem *config_regs; |
|---|
| 49 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 50 | + struct cmdq_client *cmdq_client; |
|---|
| 51 | + u32 cmdq_event; |
|---|
| 52 | +#endif |
|---|
| 53 | + |
|---|
| 54 | + struct device *mmsys_dev; |
|---|
| 53 | 55 | struct mtk_disp_mutex *mutex; |
|---|
| 54 | 56 | unsigned int ddp_comp_nr; |
|---|
| 55 | 57 | struct mtk_ddp_comp **ddp_comp; |
|---|
| 58 | + |
|---|
| 59 | + /* lock for display hardware access */ |
|---|
| 60 | + struct mutex hw_lock; |
|---|
| 56 | 61 | }; |
|---|
| 57 | 62 | |
|---|
| 58 | 63 | struct mtk_crtc_state { |
|---|
| .. | .. |
|---|
| 98 | 103 | static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) |
|---|
| 99 | 104 | { |
|---|
| 100 | 105 | struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 101 | | - int i; |
|---|
| 102 | | - |
|---|
| 103 | | - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 104 | | - clk_unprepare(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 105 | 106 | |
|---|
| 106 | 107 | mtk_disp_mutex_put(mtk_crtc->mutex); |
|---|
| 107 | 108 | |
|---|
| .. | .. |
|---|
| 112 | 113 | { |
|---|
| 113 | 114 | struct mtk_crtc_state *state; |
|---|
| 114 | 115 | |
|---|
| 115 | | - if (crtc->state) { |
|---|
| 116 | + if (crtc->state) |
|---|
| 116 | 117 | __drm_atomic_helper_crtc_destroy_state(crtc->state); |
|---|
| 117 | 118 | |
|---|
| 118 | | - state = to_mtk_crtc_state(crtc->state); |
|---|
| 119 | | - memset(state, 0, sizeof(*state)); |
|---|
| 120 | | - } else { |
|---|
| 121 | | - state = kzalloc(sizeof(*state), GFP_KERNEL); |
|---|
| 122 | | - if (!state) |
|---|
| 123 | | - return; |
|---|
| 124 | | - crtc->state = &state->base; |
|---|
| 125 | | - } |
|---|
| 119 | + kfree(to_mtk_crtc_state(crtc->state)); |
|---|
| 120 | + crtc->state = NULL; |
|---|
| 126 | 121 | |
|---|
| 127 | | - state->base.crtc = crtc; |
|---|
| 122 | + state = kzalloc(sizeof(*state), GFP_KERNEL); |
|---|
| 123 | + if (state) |
|---|
| 124 | + __drm_atomic_helper_crtc_reset(crtc, &state->base); |
|---|
| 128 | 125 | } |
|---|
| 129 | 126 | |
|---|
| 130 | 127 | static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc) |
|---|
| .. | .. |
|---|
| 164 | 161 | |
|---|
| 165 | 162 | state->pending_width = crtc->mode.hdisplay; |
|---|
| 166 | 163 | state->pending_height = crtc->mode.vdisplay; |
|---|
| 167 | | - state->pending_vrefresh = crtc->mode.vrefresh; |
|---|
| 164 | + state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode); |
|---|
| 168 | 165 | wmb(); /* Make sure the above parameters are set before update */ |
|---|
| 169 | 166 | state->pending_config = true; |
|---|
| 170 | 167 | } |
|---|
| .. | .. |
|---|
| 192 | 189 | int ret; |
|---|
| 193 | 190 | int i; |
|---|
| 194 | 191 | |
|---|
| 195 | | - DRM_DEBUG_DRIVER("%s\n", __func__); |
|---|
| 196 | 192 | for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 197 | | - ret = clk_enable(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 193 | + ret = clk_prepare_enable(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 198 | 194 | if (ret) { |
|---|
| 199 | 195 | DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); |
|---|
| 200 | 196 | goto err; |
|---|
| .. | .. |
|---|
| 204 | 200 | return 0; |
|---|
| 205 | 201 | err: |
|---|
| 206 | 202 | while (--i >= 0) |
|---|
| 207 | | - clk_disable(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 203 | + clk_disable_unprepare(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 208 | 204 | return ret; |
|---|
| 209 | 205 | } |
|---|
| 210 | 206 | |
|---|
| .. | .. |
|---|
| 212 | 208 | { |
|---|
| 213 | 209 | int i; |
|---|
| 214 | 210 | |
|---|
| 215 | | - DRM_DEBUG_DRIVER("%s\n", __func__); |
|---|
| 216 | 211 | for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 217 | | - clk_disable(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 212 | + clk_disable_unprepare(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 218 | 213 | } |
|---|
| 214 | + |
|---|
| 215 | +static |
|---|
| 216 | +struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, |
|---|
| 217 | + struct drm_plane *plane, |
|---|
| 218 | + unsigned int *local_layer) |
|---|
| 219 | +{ |
|---|
| 220 | + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 221 | + struct mtk_ddp_comp *comp; |
|---|
| 222 | + int i, count = 0; |
|---|
| 223 | + unsigned int local_index = plane - mtk_crtc->planes; |
|---|
| 224 | + |
|---|
| 225 | + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 226 | + comp = mtk_crtc->ddp_comp[i]; |
|---|
| 227 | + if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) { |
|---|
| 228 | + *local_layer = local_index - count; |
|---|
| 229 | + return comp; |
|---|
| 230 | + } |
|---|
| 231 | + count += mtk_ddp_comp_layer_nr(comp); |
|---|
| 232 | + } |
|---|
| 233 | + |
|---|
| 234 | + WARN(1, "Failed to find component for plane %d\n", plane->index); |
|---|
| 235 | + return NULL; |
|---|
| 236 | +} |
|---|
| 237 | + |
|---|
| 238 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 239 | +static void ddp_cmdq_cb(struct cmdq_cb_data data) |
|---|
| 240 | +{ |
|---|
| 241 | + cmdq_pkt_destroy(data.data); |
|---|
| 242 | +} |
|---|
| 243 | +#endif |
|---|
| 219 | 244 | |
|---|
| 220 | 245 | static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) |
|---|
| 221 | 246 | { |
|---|
| .. | .. |
|---|
| 227 | 252 | int ret; |
|---|
| 228 | 253 | int i; |
|---|
| 229 | 254 | |
|---|
| 230 | | - DRM_DEBUG_DRIVER("%s\n", __func__); |
|---|
| 231 | 255 | if (WARN_ON(!crtc->state)) |
|---|
| 232 | 256 | return -EINVAL; |
|---|
| 233 | 257 | |
|---|
| 234 | 258 | width = crtc->state->adjusted_mode.hdisplay; |
|---|
| 235 | 259 | height = crtc->state->adjusted_mode.vdisplay; |
|---|
| 236 | | - vrefresh = crtc->state->adjusted_mode.vrefresh; |
|---|
| 260 | + vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode); |
|---|
| 237 | 261 | |
|---|
| 238 | 262 | drm_for_each_encoder(encoder, crtc->dev) { |
|---|
| 239 | 263 | if (encoder->crtc != crtc) |
|---|
| .. | .. |
|---|
| 250 | 274 | drm_connector_list_iter_end(&conn_iter); |
|---|
| 251 | 275 | } |
|---|
| 252 | 276 | |
|---|
| 253 | | - ret = pm_runtime_get_sync(crtc->dev->dev); |
|---|
| 277 | + ret = pm_runtime_resume_and_get(crtc->dev->dev); |
|---|
| 254 | 278 | if (ret < 0) { |
|---|
| 255 | 279 | DRM_ERROR("Failed to enable power domain: %d\n", ret); |
|---|
| 256 | 280 | return ret; |
|---|
| .. | .. |
|---|
| 268 | 292 | goto err_mutex_unprepare; |
|---|
| 269 | 293 | } |
|---|
| 270 | 294 | |
|---|
| 271 | | - DRM_DEBUG_DRIVER("mediatek_ddp_ddp_path_setup\n"); |
|---|
| 272 | 295 | for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { |
|---|
| 273 | | - mtk_ddp_add_comp_to_path(mtk_crtc->config_regs, |
|---|
| 274 | | - mtk_crtc->ddp_comp[i]->id, |
|---|
| 275 | | - mtk_crtc->ddp_comp[i + 1]->id); |
|---|
| 296 | + mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, |
|---|
| 297 | + mtk_crtc->ddp_comp[i]->id, |
|---|
| 298 | + mtk_crtc->ddp_comp[i + 1]->id); |
|---|
| 276 | 299 | mtk_disp_mutex_add_comp(mtk_crtc->mutex, |
|---|
| 277 | 300 | mtk_crtc->ddp_comp[i]->id); |
|---|
| 278 | 301 | } |
|---|
| .. | .. |
|---|
| 282 | 305 | for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 283 | 306 | struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; |
|---|
| 284 | 307 | |
|---|
| 285 | | - mtk_ddp_comp_config(comp, width, height, vrefresh, bpc); |
|---|
| 308 | + if (i == 1) |
|---|
| 309 | + mtk_ddp_comp_bgclr_in_on(comp); |
|---|
| 310 | + |
|---|
| 311 | + mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL); |
|---|
| 286 | 312 | mtk_ddp_comp_start(comp); |
|---|
| 287 | 313 | } |
|---|
| 288 | 314 | |
|---|
| .. | .. |
|---|
| 290 | 316 | for (i = 0; i < mtk_crtc->layer_nr; i++) { |
|---|
| 291 | 317 | struct drm_plane *plane = &mtk_crtc->planes[i]; |
|---|
| 292 | 318 | struct mtk_plane_state *plane_state; |
|---|
| 319 | + struct mtk_ddp_comp *comp; |
|---|
| 320 | + unsigned int local_layer; |
|---|
| 293 | 321 | |
|---|
| 294 | 322 | plane_state = to_mtk_plane_state(plane->state); |
|---|
| 295 | | - mtk_ddp_comp_layer_config(mtk_crtc->ddp_comp[0], i, |
|---|
| 296 | | - plane_state); |
|---|
| 323 | + comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); |
|---|
| 324 | + if (comp) |
|---|
| 325 | + mtk_ddp_comp_layer_config(comp, local_layer, |
|---|
| 326 | + plane_state, NULL); |
|---|
| 297 | 327 | } |
|---|
| 298 | 328 | |
|---|
| 299 | 329 | return 0; |
|---|
| .. | .. |
|---|
| 311 | 341 | struct drm_crtc *crtc = &mtk_crtc->base; |
|---|
| 312 | 342 | int i; |
|---|
| 313 | 343 | |
|---|
| 314 | | - DRM_DEBUG_DRIVER("%s\n", __func__); |
|---|
| 315 | | - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 344 | + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 316 | 345 | mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]); |
|---|
| 346 | + if (i == 1) |
|---|
| 347 | + mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]); |
|---|
| 348 | + } |
|---|
| 349 | + |
|---|
| 317 | 350 | for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 318 | 351 | mtk_disp_mutex_remove_comp(mtk_crtc->mutex, |
|---|
| 319 | 352 | mtk_crtc->ddp_comp[i]->id); |
|---|
| 320 | 353 | mtk_disp_mutex_disable(mtk_crtc->mutex); |
|---|
| 321 | 354 | for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { |
|---|
| 322 | | - mtk_ddp_remove_comp_from_path(mtk_crtc->config_regs, |
|---|
| 323 | | - mtk_crtc->ddp_comp[i]->id, |
|---|
| 324 | | - mtk_crtc->ddp_comp[i + 1]->id); |
|---|
| 355 | + mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, |
|---|
| 356 | + mtk_crtc->ddp_comp[i]->id, |
|---|
| 357 | + mtk_crtc->ddp_comp[i + 1]->id); |
|---|
| 325 | 358 | mtk_disp_mutex_remove_comp(mtk_crtc->mutex, |
|---|
| 326 | 359 | mtk_crtc->ddp_comp[i]->id); |
|---|
| 327 | 360 | } |
|---|
| .. | .. |
|---|
| 339 | 372 | } |
|---|
| 340 | 373 | } |
|---|
| 341 | 374 | |
|---|
| 342 | | -static void mtk_crtc_ddp_config(struct drm_crtc *crtc) |
|---|
| 375 | +static void mtk_crtc_ddp_config(struct drm_crtc *crtc, |
|---|
| 376 | + struct cmdq_pkt *cmdq_handle) |
|---|
| 343 | 377 | { |
|---|
| 344 | 378 | struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 345 | 379 | struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); |
|---|
| 346 | 380 | struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; |
|---|
| 347 | 381 | unsigned int i; |
|---|
| 382 | + unsigned int local_layer; |
|---|
| 348 | 383 | |
|---|
| 349 | 384 | /* |
|---|
| 350 | 385 | * TODO: instead of updating the registers here, we should prepare |
|---|
| .. | .. |
|---|
| 354 | 389 | if (state->pending_config) { |
|---|
| 355 | 390 | mtk_ddp_comp_config(comp, state->pending_width, |
|---|
| 356 | 391 | state->pending_height, |
|---|
| 357 | | - state->pending_vrefresh, 0); |
|---|
| 392 | + state->pending_vrefresh, 0, |
|---|
| 393 | + cmdq_handle); |
|---|
| 358 | 394 | |
|---|
| 359 | 395 | state->pending_config = false; |
|---|
| 360 | 396 | } |
|---|
| .. | .. |
|---|
| 366 | 402 | |
|---|
| 367 | 403 | plane_state = to_mtk_plane_state(plane->state); |
|---|
| 368 | 404 | |
|---|
| 369 | | - if (plane_state->pending.config) { |
|---|
| 370 | | - mtk_ddp_comp_layer_config(comp, i, plane_state); |
|---|
| 371 | | - plane_state->pending.config = false; |
|---|
| 372 | | - } |
|---|
| 405 | + if (!plane_state->pending.config) |
|---|
| 406 | + continue; |
|---|
| 407 | + |
|---|
| 408 | + comp = mtk_drm_ddp_comp_for_plane(crtc, plane, |
|---|
| 409 | + &local_layer); |
|---|
| 410 | + |
|---|
| 411 | + if (comp) |
|---|
| 412 | + mtk_ddp_comp_layer_config(comp, local_layer, |
|---|
| 413 | + plane_state, |
|---|
| 414 | + cmdq_handle); |
|---|
| 415 | + plane_state->pending.config = false; |
|---|
| 373 | 416 | } |
|---|
| 374 | 417 | mtk_crtc->pending_planes = false; |
|---|
| 375 | 418 | } |
|---|
| 419 | + |
|---|
| 420 | + if (mtk_crtc->pending_async_planes) { |
|---|
| 421 | + for (i = 0; i < mtk_crtc->layer_nr; i++) { |
|---|
| 422 | + struct drm_plane *plane = &mtk_crtc->planes[i]; |
|---|
| 423 | + struct mtk_plane_state *plane_state; |
|---|
| 424 | + |
|---|
| 425 | + plane_state = to_mtk_plane_state(plane->state); |
|---|
| 426 | + |
|---|
| 427 | + if (!plane_state->pending.async_config) |
|---|
| 428 | + continue; |
|---|
| 429 | + |
|---|
| 430 | + comp = mtk_drm_ddp_comp_for_plane(crtc, plane, |
|---|
| 431 | + &local_layer); |
|---|
| 432 | + |
|---|
| 433 | + if (comp) |
|---|
| 434 | + mtk_ddp_comp_layer_config(comp, local_layer, |
|---|
| 435 | + plane_state, |
|---|
| 436 | + cmdq_handle); |
|---|
| 437 | + plane_state->pending.async_config = false; |
|---|
| 438 | + } |
|---|
| 439 | + mtk_crtc->pending_async_planes = false; |
|---|
| 440 | + } |
|---|
| 441 | +} |
|---|
| 442 | + |
|---|
| 443 | +static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc) |
|---|
| 444 | +{ |
|---|
| 445 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 446 | + struct cmdq_pkt *cmdq_handle; |
|---|
| 447 | +#endif |
|---|
| 448 | + struct drm_crtc *crtc = &mtk_crtc->base; |
|---|
| 449 | + struct mtk_drm_private *priv = crtc->dev->dev_private; |
|---|
| 450 | + unsigned int pending_planes = 0, pending_async_planes = 0; |
|---|
| 451 | + int i; |
|---|
| 452 | + |
|---|
| 453 | + mutex_lock(&mtk_crtc->hw_lock); |
|---|
| 454 | + for (i = 0; i < mtk_crtc->layer_nr; i++) { |
|---|
| 455 | + struct drm_plane *plane = &mtk_crtc->planes[i]; |
|---|
| 456 | + struct mtk_plane_state *plane_state; |
|---|
| 457 | + |
|---|
| 458 | + plane_state = to_mtk_plane_state(plane->state); |
|---|
| 459 | + if (plane_state->pending.dirty) { |
|---|
| 460 | + plane_state->pending.config = true; |
|---|
| 461 | + plane_state->pending.dirty = false; |
|---|
| 462 | + pending_planes |= BIT(i); |
|---|
| 463 | + } else if (plane_state->pending.async_dirty) { |
|---|
| 464 | + plane_state->pending.async_config = true; |
|---|
| 465 | + plane_state->pending.async_dirty = false; |
|---|
| 466 | + pending_async_planes |= BIT(i); |
|---|
| 467 | + } |
|---|
| 468 | + } |
|---|
| 469 | + if (pending_planes) |
|---|
| 470 | + mtk_crtc->pending_planes = true; |
|---|
| 471 | + if (pending_async_planes) |
|---|
| 472 | + mtk_crtc->pending_async_planes = true; |
|---|
| 473 | + |
|---|
| 474 | + if (priv->data->shadow_register) { |
|---|
| 475 | + mtk_disp_mutex_acquire(mtk_crtc->mutex); |
|---|
| 476 | + mtk_crtc_ddp_config(crtc, NULL); |
|---|
| 477 | + mtk_disp_mutex_release(mtk_crtc->mutex); |
|---|
| 478 | + } |
|---|
| 479 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 480 | + if (mtk_crtc->cmdq_client) { |
|---|
| 481 | + mbox_flush(mtk_crtc->cmdq_client->chan, 2000); |
|---|
| 482 | + cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE); |
|---|
| 483 | + cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); |
|---|
| 484 | + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); |
|---|
| 485 | + mtk_crtc_ddp_config(crtc, cmdq_handle); |
|---|
| 486 | + cmdq_pkt_finalize(cmdq_handle); |
|---|
| 487 | + cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle); |
|---|
| 488 | + } |
|---|
| 489 | +#endif |
|---|
| 490 | + mutex_unlock(&mtk_crtc->hw_lock); |
|---|
| 491 | +} |
|---|
| 492 | + |
|---|
| 493 | +int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, |
|---|
| 494 | + struct mtk_plane_state *state) |
|---|
| 495 | +{ |
|---|
| 496 | + unsigned int local_layer; |
|---|
| 497 | + struct mtk_ddp_comp *comp; |
|---|
| 498 | + |
|---|
| 499 | + comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); |
|---|
| 500 | + if (comp) |
|---|
| 501 | + return mtk_ddp_comp_layer_check(comp, local_layer, state); |
|---|
| 502 | + return 0; |
|---|
| 503 | +} |
|---|
| 504 | + |
|---|
| 505 | +void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, |
|---|
| 506 | + struct drm_plane_state *new_state) |
|---|
| 507 | +{ |
|---|
| 508 | + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 509 | + const struct drm_plane_helper_funcs *plane_helper_funcs = |
|---|
| 510 | + plane->helper_private; |
|---|
| 511 | + |
|---|
| 512 | + if (!mtk_crtc->enabled) |
|---|
| 513 | + return; |
|---|
| 514 | + |
|---|
| 515 | + plane_helper_funcs->atomic_update(plane, new_state); |
|---|
| 516 | + mtk_drm_crtc_hw_config(mtk_crtc); |
|---|
| 376 | 517 | } |
|---|
| 377 | 518 | |
|---|
| 378 | 519 | static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, |
|---|
| .. | .. |
|---|
| 422 | 563 | } |
|---|
| 423 | 564 | mtk_crtc->pending_planes = true; |
|---|
| 424 | 565 | |
|---|
| 566 | + mtk_drm_crtc_hw_config(mtk_crtc); |
|---|
| 425 | 567 | /* Wait for planes to be disabled */ |
|---|
| 426 | 568 | drm_crtc_wait_one_vblank(crtc); |
|---|
| 427 | 569 | |
|---|
| .. | .. |
|---|
| 453 | 595 | struct drm_crtc_state *old_crtc_state) |
|---|
| 454 | 596 | { |
|---|
| 455 | 597 | struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 456 | | - struct mtk_drm_private *priv = crtc->dev->dev_private; |
|---|
| 457 | | - unsigned int pending_planes = 0; |
|---|
| 458 | 598 | int i; |
|---|
| 459 | 599 | |
|---|
| 460 | 600 | if (mtk_crtc->event) |
|---|
| 461 | 601 | mtk_crtc->pending_needs_vblank = true; |
|---|
| 462 | | - for (i = 0; i < mtk_crtc->layer_nr; i++) { |
|---|
| 463 | | - struct drm_plane *plane = &mtk_crtc->planes[i]; |
|---|
| 464 | | - struct mtk_plane_state *plane_state; |
|---|
| 465 | | - |
|---|
| 466 | | - plane_state = to_mtk_plane_state(plane->state); |
|---|
| 467 | | - if (plane_state->pending.dirty) { |
|---|
| 468 | | - plane_state->pending.config = true; |
|---|
| 469 | | - plane_state->pending.dirty = false; |
|---|
| 470 | | - pending_planes |= BIT(i); |
|---|
| 471 | | - } |
|---|
| 472 | | - } |
|---|
| 473 | | - if (pending_planes) |
|---|
| 474 | | - mtk_crtc->pending_planes = true; |
|---|
| 475 | 602 | if (crtc->state->color_mgmt_changed) |
|---|
| 476 | | - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 603 | + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 477 | 604 | mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); |
|---|
| 478 | | - |
|---|
| 479 | | - if (priv->data->shadow_register) { |
|---|
| 480 | | - mtk_disp_mutex_acquire(mtk_crtc->mutex); |
|---|
| 481 | | - mtk_crtc_ddp_config(crtc); |
|---|
| 482 | | - mtk_disp_mutex_release(mtk_crtc->mutex); |
|---|
| 483 | | - } |
|---|
| 605 | + mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); |
|---|
| 606 | + } |
|---|
| 607 | + mtk_drm_crtc_hw_config(mtk_crtc); |
|---|
| 484 | 608 | } |
|---|
| 485 | 609 | |
|---|
| 486 | 610 | static const struct drm_crtc_funcs mtk_crtc_funcs = { |
|---|
| .. | .. |
|---|
| 538 | 662 | struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
|---|
| 539 | 663 | struct mtk_drm_private *priv = crtc->dev->dev_private; |
|---|
| 540 | 664 | |
|---|
| 665 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 666 | + if (!priv->data->shadow_register && !mtk_crtc->cmdq_client) |
|---|
| 667 | +#else |
|---|
| 541 | 668 | if (!priv->data->shadow_register) |
|---|
| 542 | | - mtk_crtc_ddp_config(crtc); |
|---|
| 669 | +#endif |
|---|
| 670 | + mtk_crtc_ddp_config(crtc, NULL); |
|---|
| 543 | 671 | |
|---|
| 544 | 672 | mtk_drm_finish_page_flip(mtk_crtc); |
|---|
| 673 | +} |
|---|
| 674 | + |
|---|
| 675 | +static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc, |
|---|
| 676 | + int comp_idx) |
|---|
| 677 | +{ |
|---|
| 678 | + struct mtk_ddp_comp *comp; |
|---|
| 679 | + |
|---|
| 680 | + if (comp_idx > 1) |
|---|
| 681 | + return 0; |
|---|
| 682 | + |
|---|
| 683 | + comp = mtk_crtc->ddp_comp[comp_idx]; |
|---|
| 684 | + if (!comp->funcs) |
|---|
| 685 | + return 0; |
|---|
| 686 | + |
|---|
| 687 | + if (comp_idx == 1 && !comp->funcs->bgclr_in_on) |
|---|
| 688 | + return 0; |
|---|
| 689 | + |
|---|
| 690 | + return mtk_ddp_comp_layer_nr(comp); |
|---|
| 691 | +} |
|---|
| 692 | + |
|---|
| 693 | +static inline |
|---|
| 694 | +enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx, |
|---|
| 695 | + unsigned int num_planes) |
|---|
| 696 | +{ |
|---|
| 697 | + if (plane_idx == 0) |
|---|
| 698 | + return DRM_PLANE_TYPE_PRIMARY; |
|---|
| 699 | + else if (plane_idx == (num_planes - 1)) |
|---|
| 700 | + return DRM_PLANE_TYPE_CURSOR; |
|---|
| 701 | + else |
|---|
| 702 | + return DRM_PLANE_TYPE_OVERLAY; |
|---|
| 703 | + |
|---|
| 704 | +} |
|---|
| 705 | + |
|---|
| 706 | +static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev, |
|---|
| 707 | + struct mtk_drm_crtc *mtk_crtc, |
|---|
| 708 | + int comp_idx, int pipe) |
|---|
| 709 | +{ |
|---|
| 710 | + int num_planes = mtk_drm_crtc_num_comp_planes(mtk_crtc, comp_idx); |
|---|
| 711 | + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx]; |
|---|
| 712 | + int i, ret; |
|---|
| 713 | + |
|---|
| 714 | + for (i = 0; i < num_planes; i++) { |
|---|
| 715 | + ret = mtk_plane_init(drm_dev, |
|---|
| 716 | + &mtk_crtc->planes[mtk_crtc->layer_nr], |
|---|
| 717 | + BIT(pipe), |
|---|
| 718 | + mtk_drm_crtc_plane_type(mtk_crtc->layer_nr, |
|---|
| 719 | + num_planes), |
|---|
| 720 | + mtk_ddp_comp_supported_rotations(comp)); |
|---|
| 721 | + if (ret) |
|---|
| 722 | + return ret; |
|---|
| 723 | + |
|---|
| 724 | + mtk_crtc->layer_nr++; |
|---|
| 725 | + } |
|---|
| 726 | + return 0; |
|---|
| 545 | 727 | } |
|---|
| 546 | 728 | |
|---|
| 547 | 729 | int mtk_drm_crtc_create(struct drm_device *drm_dev, |
|---|
| .. | .. |
|---|
| 550 | 732 | struct mtk_drm_private *priv = drm_dev->dev_private; |
|---|
| 551 | 733 | struct device *dev = drm_dev->dev; |
|---|
| 552 | 734 | struct mtk_drm_crtc *mtk_crtc; |
|---|
| 553 | | - enum drm_plane_type type; |
|---|
| 554 | | - unsigned int zpos; |
|---|
| 735 | + unsigned int num_comp_planes = 0; |
|---|
| 555 | 736 | int pipe = priv->num_pipes; |
|---|
| 556 | 737 | int ret; |
|---|
| 557 | 738 | int i; |
|---|
| 739 | + bool has_ctm = false; |
|---|
| 740 | + uint gamma_lut_size = 0; |
|---|
| 558 | 741 | |
|---|
| 559 | 742 | if (!path) |
|---|
| 560 | 743 | return 0; |
|---|
| .. | .. |
|---|
| 576 | 759 | if (!mtk_crtc) |
|---|
| 577 | 760 | return -ENOMEM; |
|---|
| 578 | 761 | |
|---|
| 579 | | - mtk_crtc->config_regs = priv->config_regs; |
|---|
| 762 | + mtk_crtc->mmsys_dev = priv->mmsys_dev; |
|---|
| 580 | 763 | mtk_crtc->ddp_comp_nr = path_len; |
|---|
| 581 | 764 | mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr, |
|---|
| 582 | 765 | sizeof(*mtk_crtc->ddp_comp), |
|---|
| .. | .. |
|---|
| 601 | 784 | if (!comp) { |
|---|
| 602 | 785 | dev_err(dev, "Component %pOF not initialized\n", node); |
|---|
| 603 | 786 | ret = -ENODEV; |
|---|
| 604 | | - goto unprepare; |
|---|
| 605 | | - } |
|---|
| 606 | | - |
|---|
| 607 | | - ret = clk_prepare(comp->clk); |
|---|
| 608 | | - if (ret) { |
|---|
| 609 | | - dev_err(dev, |
|---|
| 610 | | - "Failed to prepare clock for component %pOF: %d\n", |
|---|
| 611 | | - node, ret); |
|---|
| 612 | | - goto unprepare; |
|---|
| 787 | + return ret; |
|---|
| 613 | 788 | } |
|---|
| 614 | 789 | |
|---|
| 615 | 790 | mtk_crtc->ddp_comp[i] = comp; |
|---|
| 791 | + |
|---|
| 792 | + if (comp->funcs) { |
|---|
| 793 | + if (comp->funcs->gamma_set) |
|---|
| 794 | + gamma_lut_size = MTK_LUT_SIZE; |
|---|
| 795 | + |
|---|
| 796 | + if (comp->funcs->ctm_set) |
|---|
| 797 | + has_ctm = true; |
|---|
| 798 | + } |
|---|
| 616 | 799 | } |
|---|
| 617 | 800 | |
|---|
| 618 | | - mtk_crtc->layer_nr = mtk_ddp_comp_layer_nr(mtk_crtc->ddp_comp[0]); |
|---|
| 619 | | - mtk_crtc->planes = devm_kcalloc(dev, mtk_crtc->layer_nr, |
|---|
| 620 | | - sizeof(struct drm_plane), |
|---|
| 621 | | - GFP_KERNEL); |
|---|
| 801 | + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) |
|---|
| 802 | + num_comp_planes += mtk_drm_crtc_num_comp_planes(mtk_crtc, i); |
|---|
| 622 | 803 | |
|---|
| 623 | | - for (zpos = 0; zpos < mtk_crtc->layer_nr; zpos++) { |
|---|
| 624 | | - type = (zpos == 0) ? DRM_PLANE_TYPE_PRIMARY : |
|---|
| 625 | | - (zpos == 1) ? DRM_PLANE_TYPE_CURSOR : |
|---|
| 626 | | - DRM_PLANE_TYPE_OVERLAY; |
|---|
| 627 | | - ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos], |
|---|
| 628 | | - BIT(pipe), type); |
|---|
| 804 | + mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes, |
|---|
| 805 | + sizeof(struct drm_plane), GFP_KERNEL); |
|---|
| 806 | + |
|---|
| 807 | + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { |
|---|
| 808 | + ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i, |
|---|
| 809 | + pipe); |
|---|
| 629 | 810 | if (ret) |
|---|
| 630 | | - goto unprepare; |
|---|
| 811 | + return ret; |
|---|
| 631 | 812 | } |
|---|
| 632 | 813 | |
|---|
| 633 | 814 | ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe); |
|---|
| 634 | 815 | if (ret < 0) |
|---|
| 635 | | - goto unprepare; |
|---|
| 636 | | - drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE); |
|---|
| 637 | | - drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE); |
|---|
| 816 | + return ret; |
|---|
| 817 | + |
|---|
| 818 | + if (gamma_lut_size) |
|---|
| 819 | + drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); |
|---|
| 820 | + drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); |
|---|
| 638 | 821 | priv->num_pipes++; |
|---|
| 822 | + mutex_init(&mtk_crtc->hw_lock); |
|---|
| 639 | 823 | |
|---|
| 824 | +#if IS_REACHABLE(CONFIG_MTK_CMDQ) |
|---|
| 825 | + mtk_crtc->cmdq_client = |
|---|
| 826 | + cmdq_mbox_create(mtk_crtc->mmsys_dev, |
|---|
| 827 | + drm_crtc_index(&mtk_crtc->base), |
|---|
| 828 | + 2000); |
|---|
| 829 | + if (IS_ERR(mtk_crtc->cmdq_client)) { |
|---|
| 830 | + dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", |
|---|
| 831 | + drm_crtc_index(&mtk_crtc->base)); |
|---|
| 832 | + mtk_crtc->cmdq_client = NULL; |
|---|
| 833 | + } |
|---|
| 834 | + |
|---|
| 835 | + if (mtk_crtc->cmdq_client) { |
|---|
| 836 | + ret = of_property_read_u32_index(priv->mutex_node, |
|---|
| 837 | + "mediatek,gce-events", |
|---|
| 838 | + drm_crtc_index(&mtk_crtc->base), |
|---|
| 839 | + &mtk_crtc->cmdq_event); |
|---|
| 840 | + if (ret) { |
|---|
| 841 | + dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", |
|---|
| 842 | + drm_crtc_index(&mtk_crtc->base)); |
|---|
| 843 | + cmdq_mbox_destroy(mtk_crtc->cmdq_client); |
|---|
| 844 | + mtk_crtc->cmdq_client = NULL; |
|---|
| 845 | + } |
|---|
| 846 | + } |
|---|
| 847 | +#endif |
|---|
| 640 | 848 | return 0; |
|---|
| 641 | | - |
|---|
| 642 | | -unprepare: |
|---|
| 643 | | - while (--i >= 0) |
|---|
| 644 | | - clk_unprepare(mtk_crtc->ddp_comp[i]->clk); |
|---|
| 645 | | - |
|---|
| 646 | | - return ret; |
|---|
| 647 | 849 | } |
|---|