429 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * RZ/G2L Display Unit CRTCs4 *5 * Copyright (C) 2023 Renesas Electronics Corporation6 *7 * Based on rcar_du_crtc.c8 */9 10#include <linux/clk.h>11#include <linux/mutex.h>12#include <linux/platform_device.h>13#include <linux/reset.h>14 15#include <drm/drm_atomic.h>16#include <drm/drm_atomic_helper.h>17#include <drm/drm_bridge.h>18#include <drm/drm_crtc.h>19#include <drm/drm_device.h>20#include <drm/drm_framebuffer.h>21#include <drm/drm_gem_dma_helper.h>22#include <drm/drm_vblank.h>23 24#include "rzg2l_du_crtc.h"25#include "rzg2l_du_drv.h"26#include "rzg2l_du_encoder.h"27#include "rzg2l_du_kms.h"28#include "rzg2l_du_vsp.h"29 30#define DU_MCR0 0x0031#define DU_MCR0_DPI_OE BIT(0)32#define DU_MCR0_DI_EN BIT(8)33 34#define DU_DITR0 0x1035#define DU_DITR0_DEMD_HIGH (BIT(8) | BIT(9))36#define DU_DITR0_VSPOL BIT(16)37#define DU_DITR0_HSPOL BIT(17)38 39#define DU_DITR1 0x1440#define DU_DITR1_VSA(x) ((x) << 0)41#define DU_DITR1_VACTIVE(x) ((x) << 16)42 43#define DU_DITR2 0x1844#define DU_DITR2_VBP(x) ((x) << 0)45#define DU_DITR2_VFP(x) ((x) << 16)46 47#define DU_DITR3 0x1c48#define DU_DITR3_HSA(x) ((x) << 0)49#define DU_DITR3_HACTIVE(x) ((x) << 16)50 51#define DU_DITR4 0x2052#define DU_DITR4_HBP(x) ((x) << 0)53#define DU_DITR4_HFP(x) ((x) << 16)54 55#define DU_MCR1 0x4056#define DU_MCR1_PB_AUTOCLR BIT(16)57 58#define DU_PBCR0 0x4c59#define DU_PBCR0_PB_DEP(x) ((x) << 0)60 61/* -----------------------------------------------------------------------------62 * Hardware Setup63 */64 65static void rzg2l_du_crtc_set_display_timing(struct rzg2l_du_crtc *rcrtc)66{67 const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;68 unsigned long mode_clock = mode->clock * 1000;69 u32 ditr0, ditr1, ditr2, ditr3, ditr4, pbcr0;70 struct rzg2l_du_device *rcdu = rcrtc->dev;71 72 clk_prepare_enable(rcrtc->rzg2l_clocks.dclk);73 clk_set_rate(rcrtc->rzg2l_clocks.dclk, mode_clock);74 75 ditr0 = (DU_DITR0_DEMD_HIGH76 | ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DU_DITR0_VSPOL : 0)77 | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DU_DITR0_HSPOL : 0));78 79 ditr1 = DU_DITR1_VSA(mode->vsync_end - mode->vsync_start)80 | DU_DITR1_VACTIVE(mode->vdisplay);81 82 ditr2 = DU_DITR2_VBP(mode->vtotal - mode->vsync_end)83 | DU_DITR2_VFP(mode->vsync_start - mode->vdisplay);84 85 ditr3 = DU_DITR3_HSA(mode->hsync_end - mode->hsync_start)86 | DU_DITR3_HACTIVE(mode->hdisplay);87 88 ditr4 = DU_DITR4_HBP(mode->htotal - mode->hsync_end)89 | DU_DITR4_HFP(mode->hsync_start - mode->hdisplay);90 91 pbcr0 = DU_PBCR0_PB_DEP(0x1f);92 93 writel(ditr0, rcdu->mmio + DU_DITR0);94 writel(ditr1, rcdu->mmio + DU_DITR1);95 writel(ditr2, rcdu->mmio + DU_DITR2);96 writel(ditr3, rcdu->mmio + DU_DITR3);97 writel(ditr4, rcdu->mmio + DU_DITR4);98 writel(pbcr0, rcdu->mmio + DU_PBCR0);99 100 /* Enable auto clear */101 writel(DU_MCR1_PB_AUTOCLR, rcdu->mmio + DU_MCR1);102}103 104/* -----------------------------------------------------------------------------105 * Page Flip106 */107 108void rzg2l_du_crtc_finish_page_flip(struct rzg2l_du_crtc *rcrtc)109{110 struct drm_pending_vblank_event *event;111 struct drm_device *dev = rcrtc->crtc.dev;112 unsigned long flags;113 114 spin_lock_irqsave(&dev->event_lock, flags);115 event = rcrtc->event;116 rcrtc->event = NULL;117 spin_unlock_irqrestore(&dev->event_lock, flags);118 119 if (!event)120 return;121 122 spin_lock_irqsave(&dev->event_lock, flags);123 drm_crtc_send_vblank_event(&rcrtc->crtc, event);124 wake_up(&rcrtc->flip_wait);125 spin_unlock_irqrestore(&dev->event_lock, flags);126 127 drm_crtc_vblank_put(&rcrtc->crtc);128}129 130static bool rzg2l_du_crtc_page_flip_pending(struct rzg2l_du_crtc *rcrtc)131{132 struct drm_device *dev = rcrtc->crtc.dev;133 unsigned long flags;134 bool pending;135 136 spin_lock_irqsave(&dev->event_lock, flags);137 pending = rcrtc->event;138 spin_unlock_irqrestore(&dev->event_lock, flags);139 140 return pending;141}142 143static void rzg2l_du_crtc_wait_page_flip(struct rzg2l_du_crtc *rcrtc)144{145 struct rzg2l_du_device *rcdu = rcrtc->dev;146 147 if (wait_event_timeout(rcrtc->flip_wait,148 !rzg2l_du_crtc_page_flip_pending(rcrtc),149 msecs_to_jiffies(50)))150 return;151 152 dev_warn(rcdu->dev, "page flip timeout\n");153 154 rzg2l_du_crtc_finish_page_flip(rcrtc);155}156 157/* -----------------------------------------------------------------------------158 * Start/Stop and Suspend/Resume159 */160 161static void rzg2l_du_crtc_setup(struct rzg2l_du_crtc *rcrtc)162{163 /* Configure display timings and output routing */164 rzg2l_du_crtc_set_display_timing(rcrtc);165 166 /* Enable the VSP compositor. */167 rzg2l_du_vsp_enable(rcrtc);168 169 /* Turn vertical blanking interrupt reporting on. */170 drm_crtc_vblank_on(&rcrtc->crtc);171}172 173static int rzg2l_du_crtc_get(struct rzg2l_du_crtc *rcrtc)174{175 int ret;176 177 /*178 * Guard against double-get, as the function is called from both the179 * .atomic_enable() and .atomic_flush() handlers.180 */181 if (rcrtc->initialized)182 return 0;183 184 ret = clk_prepare_enable(rcrtc->rzg2l_clocks.aclk);185 if (ret < 0)186 return ret;187 188 ret = clk_prepare_enable(rcrtc->rzg2l_clocks.pclk);189 if (ret < 0)190 goto error_bus_clock;191 192 ret = reset_control_deassert(rcrtc->rstc);193 if (ret < 0)194 goto error_peri_clock;195 196 rzg2l_du_crtc_setup(rcrtc);197 rcrtc->initialized = true;198 199 return 0;200 201error_peri_clock:202 clk_disable_unprepare(rcrtc->rzg2l_clocks.pclk);203error_bus_clock:204 clk_disable_unprepare(rcrtc->rzg2l_clocks.aclk);205 return ret;206}207 208static void rzg2l_du_crtc_put(struct rzg2l_du_crtc *rcrtc)209{210 clk_disable_unprepare(rcrtc->rzg2l_clocks.dclk);211 reset_control_assert(rcrtc->rstc);212 clk_disable_unprepare(rcrtc->rzg2l_clocks.pclk);213 clk_disable_unprepare(rcrtc->rzg2l_clocks.aclk);214 215 rcrtc->initialized = false;216}217 218static void rzg2l_du_start_stop(struct rzg2l_du_crtc *rcrtc, bool start)219{220 struct rzg2l_du_crtc_state *rstate = to_rzg2l_crtc_state(rcrtc->crtc.state);221 struct rzg2l_du_device *rcdu = rcrtc->dev;222 u32 val = DU_MCR0_DI_EN;223 224 if (rstate->outputs & BIT(RZG2L_DU_OUTPUT_DPAD0))225 val |= DU_MCR0_DPI_OE;226 227 writel(start ? val : 0, rcdu->mmio + DU_MCR0);228}229 230static void rzg2l_du_crtc_start(struct rzg2l_du_crtc *rcrtc)231{232 rzg2l_du_start_stop(rcrtc, true);233}234 235static void rzg2l_du_crtc_stop(struct rzg2l_du_crtc *rcrtc)236{237 struct drm_crtc *crtc = &rcrtc->crtc;238 239 /*240 * Disable vertical blanking interrupt reporting. We first need to wait241 * for page flip completion before stopping the CRTC as userspace242 * expects page flips to eventually complete.243 */244 rzg2l_du_crtc_wait_page_flip(rcrtc);245 drm_crtc_vblank_off(crtc);246 247 /* Disable the VSP compositor. */248 rzg2l_du_vsp_disable(rcrtc);249 250 rzg2l_du_start_stop(rcrtc, false);251}252 253/* -----------------------------------------------------------------------------254 * CRTC Functions255 */256 257static void rzg2l_du_crtc_atomic_enable(struct drm_crtc *crtc,258 struct drm_atomic_state *state)259{260 struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc);261 262 rzg2l_du_crtc_get(rcrtc);263 264 rzg2l_du_crtc_start(rcrtc);265}266 267static void rzg2l_du_crtc_atomic_disable(struct drm_crtc *crtc,268 struct drm_atomic_state *state)269{270 struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc);271 272 rzg2l_du_crtc_stop(rcrtc);273 rzg2l_du_crtc_put(rcrtc);274 275 spin_lock_irq(&crtc->dev->event_lock);276 if (crtc->state->event) {277 drm_crtc_send_vblank_event(crtc, crtc->state->event);278 crtc->state->event = NULL;279 }280 spin_unlock_irq(&crtc->dev->event_lock);281}282 283static void rzg2l_du_crtc_atomic_flush(struct drm_crtc *crtc,284 struct drm_atomic_state *state)285{286 struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc);287 struct drm_device *dev = rcrtc->crtc.dev;288 unsigned long flags;289 290 WARN_ON(!crtc->state->enable);291 292 if (crtc->state->event) {293 WARN_ON(drm_crtc_vblank_get(crtc) != 0);294 295 spin_lock_irqsave(&dev->event_lock, flags);296 rcrtc->event = crtc->state->event;297 crtc->state->event = NULL;298 spin_unlock_irqrestore(&dev->event_lock, flags);299 }300 301 rzg2l_du_vsp_atomic_flush(rcrtc);302}303 304static const struct drm_crtc_helper_funcs crtc_helper_funcs = {305 .atomic_flush = rzg2l_du_crtc_atomic_flush,306 .atomic_enable = rzg2l_du_crtc_atomic_enable,307 .atomic_disable = rzg2l_du_crtc_atomic_disable,308};309 310static struct drm_crtc_state *311rzg2l_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc)312{313 struct rzg2l_du_crtc_state *state;314 struct rzg2l_du_crtc_state *copy;315 316 if (WARN_ON(!crtc->state))317 return NULL;318 319 state = to_rzg2l_crtc_state(crtc->state);320 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);321 if (!copy)322 return NULL;323 324 __drm_atomic_helper_crtc_duplicate_state(crtc, ©->state);325 326 return ©->state;327}328 329static void rzg2l_du_crtc_atomic_destroy_state(struct drm_crtc *crtc,330 struct drm_crtc_state *state)331{332 __drm_atomic_helper_crtc_destroy_state(state);333 kfree(to_rzg2l_crtc_state(state));334}335 336static void rzg2l_du_crtc_reset(struct drm_crtc *crtc)337{338 struct rzg2l_du_crtc_state *state;339 340 if (crtc->state) {341 rzg2l_du_crtc_atomic_destroy_state(crtc, crtc->state);342 crtc->state = NULL;343 }344 345 state = kzalloc(sizeof(*state), GFP_KERNEL);346 if (!state)347 return;348 349 __drm_atomic_helper_crtc_reset(crtc, &state->state);350}351 352static int rzg2l_du_crtc_enable_vblank(struct drm_crtc *crtc)353{354 struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc);355 356 rcrtc->vblank_enable = true;357 358 return 0;359}360 361static void rzg2l_du_crtc_disable_vblank(struct drm_crtc *crtc)362{363 struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc);364 365 rcrtc->vblank_enable = false;366}367 368static const struct drm_crtc_funcs crtc_funcs_rz = {369 .reset = rzg2l_du_crtc_reset,370 .set_config = drm_atomic_helper_set_config,371 .page_flip = drm_atomic_helper_page_flip,372 .atomic_duplicate_state = rzg2l_du_crtc_atomic_duplicate_state,373 .atomic_destroy_state = rzg2l_du_crtc_atomic_destroy_state,374 .enable_vblank = rzg2l_du_crtc_enable_vblank,375 .disable_vblank = rzg2l_du_crtc_disable_vblank,376};377 378/* -----------------------------------------------------------------------------379 * Initialization380 */381 382int rzg2l_du_crtc_create(struct rzg2l_du_device *rcdu)383{384 struct rzg2l_du_crtc *rcrtc = &rcdu->crtcs[0];385 struct drm_crtc *crtc = &rcrtc->crtc;386 struct drm_plane *primary;387 int ret;388 389 rcrtc->rstc = devm_reset_control_get_shared(rcdu->dev, NULL);390 if (IS_ERR(rcrtc->rstc)) {391 dev_err(rcdu->dev, "can't get cpg reset\n");392 return PTR_ERR(rcrtc->rstc);393 }394 395 rcrtc->rzg2l_clocks.aclk = devm_clk_get(rcdu->dev, "aclk");396 if (IS_ERR(rcrtc->rzg2l_clocks.aclk)) {397 dev_err(rcdu->dev, "no axi clock for DU\n");398 return PTR_ERR(rcrtc->rzg2l_clocks.aclk);399 }400 401 rcrtc->rzg2l_clocks.pclk = devm_clk_get(rcdu->dev, "pclk");402 if (IS_ERR(rcrtc->rzg2l_clocks.pclk)) {403 dev_err(rcdu->dev, "no peripheral clock for DU\n");404 return PTR_ERR(rcrtc->rzg2l_clocks.pclk);405 }406 407 rcrtc->rzg2l_clocks.dclk = devm_clk_get(rcdu->dev, "vclk");408 if (IS_ERR(rcrtc->rzg2l_clocks.dclk)) {409 dev_err(rcdu->dev, "no video clock for DU\n");410 return PTR_ERR(rcrtc->rzg2l_clocks.dclk);411 }412 413 init_waitqueue_head(&rcrtc->flip_wait);414 rcrtc->dev = rcdu;415 416 primary = rzg2l_du_vsp_get_drm_plane(rcrtc, rcrtc->vsp_pipe);417 if (IS_ERR(primary))418 return PTR_ERR(primary);419 420 ret = drmm_crtc_init_with_planes(&rcdu->ddev, crtc, primary, NULL,421 &crtc_funcs_rz, NULL);422 if (ret < 0)423 return ret;424 425 drm_crtc_helper_add(crtc, &crtc_helper_funcs);426 427 return 0;428}429