0001
0002
0003
0004
0005
0006
0007 #include <drm/drm_atomic.h>
0008 #include <drm/drm_atomic_helper.h>
0009 #include <drm/drm_crtc.h>
0010 #include <drm/drm_crtc_helper.h>
0011 #include <drm/drm_fb_cma_helper.h>
0012 #include <drm/drm_gem_cma_helper.h>
0013 #include <drm/drm_plane_helper.h>
0014 #include <drm/drm_vblank.h>
0015
0016 #include "tidss_crtc.h"
0017 #include "tidss_dispc.h"
0018 #include "tidss_drv.h"
0019 #include "tidss_irq.h"
0020 #include "tidss_plane.h"
0021
0022
0023
0024 static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
0025 {
0026 struct drm_device *ddev = tcrtc->crtc.dev;
0027 struct tidss_device *tidss = to_tidss(ddev);
0028 struct drm_pending_vblank_event *event;
0029 unsigned long flags;
0030 bool busy;
0031
0032 spin_lock_irqsave(&ddev->event_lock, flags);
0033
0034
0035
0036
0037
0038
0039
0040 busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport);
0041 if (busy) {
0042 spin_unlock_irqrestore(&ddev->event_lock, flags);
0043 return;
0044 }
0045
0046 event = tcrtc->event;
0047 tcrtc->event = NULL;
0048
0049 if (!event) {
0050 spin_unlock_irqrestore(&ddev->event_lock, flags);
0051 return;
0052 }
0053
0054 drm_crtc_send_vblank_event(&tcrtc->crtc, event);
0055
0056 spin_unlock_irqrestore(&ddev->event_lock, flags);
0057
0058 drm_crtc_vblank_put(&tcrtc->crtc);
0059 }
0060
0061 void tidss_crtc_vblank_irq(struct drm_crtc *crtc)
0062 {
0063 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0064
0065 drm_crtc_handle_vblank(crtc);
0066
0067 tidss_crtc_finish_page_flip(tcrtc);
0068 }
0069
0070 void tidss_crtc_framedone_irq(struct drm_crtc *crtc)
0071 {
0072 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0073
0074 complete(&tcrtc->framedone_completion);
0075 }
0076
0077 void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus)
0078 {
0079 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0080
0081 dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n",
0082 tcrtc->hw_videoport, irqstatus);
0083 }
0084
0085
0086
0087 static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
0088 struct drm_atomic_state *state)
0089 {
0090 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0091 crtc);
0092 struct drm_device *ddev = crtc->dev;
0093 struct tidss_device *tidss = to_tidss(ddev);
0094 struct dispc_device *dispc = tidss->dispc;
0095 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0096 u32 hw_videoport = tcrtc->hw_videoport;
0097 const struct drm_display_mode *mode;
0098 enum drm_mode_status ok;
0099
0100 dev_dbg(ddev->dev, "%s\n", __func__);
0101
0102 if (!crtc_state->enable)
0103 return 0;
0104
0105 mode = &crtc_state->adjusted_mode;
0106
0107 ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
0108 if (ok != MODE_OK) {
0109 dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
0110 __func__, mode->hdisplay, mode->vdisplay, mode->clock);
0111 return -EINVAL;
0112 }
0113
0114 return dispc_vp_bus_check(dispc, hw_videoport, crtc_state);
0115 }
0116
0117
0118
0119
0120
0121
0122 static void tidss_crtc_position_planes(struct tidss_device *tidss,
0123 struct drm_crtc *crtc,
0124 struct drm_crtc_state *old_state,
0125 bool newmodeset)
0126 {
0127 struct drm_atomic_state *ostate = old_state->state;
0128 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0129 struct drm_crtc_state *cstate = crtc->state;
0130 int layer;
0131
0132 if (!newmodeset && !cstate->zpos_changed &&
0133 !to_tidss_crtc_state(cstate)->plane_pos_changed)
0134 return;
0135
0136 for (layer = 0; layer < tidss->feat->num_planes; layer++) {
0137 struct drm_plane_state *pstate;
0138 struct drm_plane *plane;
0139 bool layer_active = false;
0140 int i;
0141
0142 for_each_new_plane_in_state(ostate, plane, pstate, i) {
0143 if (pstate->crtc != crtc || !pstate->visible)
0144 continue;
0145
0146 if (pstate->normalized_zpos == layer) {
0147 layer_active = true;
0148 break;
0149 }
0150 }
0151
0152 if (layer_active) {
0153 struct tidss_plane *tplane = to_tidss_plane(plane);
0154
0155 dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
0156 tcrtc->hw_videoport,
0157 pstate->crtc_x, pstate->crtc_y,
0158 layer);
0159 }
0160 dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
0161 layer_active);
0162 }
0163 }
0164
0165 static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
0166 struct drm_atomic_state *state)
0167 {
0168 struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
0169 crtc);
0170 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0171 struct drm_device *ddev = crtc->dev;
0172 struct tidss_device *tidss = to_tidss(ddev);
0173 unsigned long flags;
0174
0175 dev_dbg(ddev->dev,
0176 "%s: %s enabled %d, needs modeset %d, event %p\n", __func__,
0177 crtc->name, drm_atomic_crtc_needs_modeset(crtc->state),
0178 crtc->state->enable, crtc->state->event);
0179
0180
0181 if (!crtc->state->enable)
0182 return;
0183
0184
0185
0186
0187
0188 if (drm_atomic_crtc_needs_modeset(crtc->state))
0189 return;
0190
0191
0192 if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport)))
0193 return;
0194
0195
0196 if (WARN_ON(!crtc->state->event))
0197 return;
0198
0199
0200 dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
0201
0202
0203 tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
0204
0205 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
0206
0207 spin_lock_irqsave(&ddev->event_lock, flags);
0208 dispc_vp_go(tidss->dispc, tcrtc->hw_videoport);
0209
0210 WARN_ON(tcrtc->event);
0211
0212 tcrtc->event = crtc->state->event;
0213 crtc->state->event = NULL;
0214
0215 spin_unlock_irqrestore(&ddev->event_lock, flags);
0216 }
0217
0218 static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
0219 struct drm_atomic_state *state)
0220 {
0221 struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
0222 crtc);
0223 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0224 struct drm_device *ddev = crtc->dev;
0225 struct tidss_device *tidss = to_tidss(ddev);
0226 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
0227 unsigned long flags;
0228 int r;
0229
0230 dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
0231
0232 tidss_runtime_get(tidss);
0233
0234 r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport,
0235 mode->clock * 1000);
0236 if (r != 0)
0237 return;
0238
0239 r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport);
0240 if (r != 0)
0241 return;
0242
0243 dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
0244 tidss_crtc_position_planes(tidss, crtc, old_state, true);
0245
0246
0247 drm_crtc_vblank_on(crtc);
0248
0249 dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state);
0250
0251 dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state);
0252
0253 spin_lock_irqsave(&ddev->event_lock, flags);
0254
0255 if (crtc->state->event) {
0256 drm_crtc_send_vblank_event(crtc, crtc->state->event);
0257 crtc->state->event = NULL;
0258 }
0259
0260 spin_unlock_irqrestore(&ddev->event_lock, flags);
0261 }
0262
0263 static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
0264 struct drm_atomic_state *state)
0265 {
0266 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0267 struct drm_device *ddev = crtc->dev;
0268 struct tidss_device *tidss = to_tidss(ddev);
0269 unsigned long flags;
0270
0271 dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
0272
0273 reinit_completion(&tcrtc->framedone_completion);
0274
0275 dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport);
0276
0277 if (!wait_for_completion_timeout(&tcrtc->framedone_completion,
0278 msecs_to_jiffies(500)))
0279 dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d",
0280 tcrtc->hw_videoport);
0281
0282 dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport);
0283
0284 spin_lock_irqsave(&ddev->event_lock, flags);
0285 if (crtc->state->event) {
0286 drm_crtc_send_vblank_event(crtc, crtc->state->event);
0287 crtc->state->event = NULL;
0288 }
0289 spin_unlock_irqrestore(&ddev->event_lock, flags);
0290
0291 drm_crtc_vblank_off(crtc);
0292
0293 dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport);
0294
0295 tidss_runtime_put(tidss);
0296 }
0297
0298 static
0299 enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
0300 const struct drm_display_mode *mode)
0301 {
0302 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0303 struct drm_device *ddev = crtc->dev;
0304 struct tidss_device *tidss = to_tidss(ddev);
0305
0306 return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
0307 }
0308
0309 static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
0310 .atomic_check = tidss_crtc_atomic_check,
0311 .atomic_flush = tidss_crtc_atomic_flush,
0312 .atomic_enable = tidss_crtc_atomic_enable,
0313 .atomic_disable = tidss_crtc_atomic_disable,
0314
0315 .mode_valid = tidss_crtc_mode_valid,
0316 };
0317
0318
0319
0320 static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
0321 {
0322 struct drm_device *ddev = crtc->dev;
0323 struct tidss_device *tidss = to_tidss(ddev);
0324
0325 dev_dbg(ddev->dev, "%s\n", __func__);
0326
0327 tidss_runtime_get(tidss);
0328
0329 tidss_irq_enable_vblank(crtc);
0330
0331 return 0;
0332 }
0333
0334 static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
0335 {
0336 struct drm_device *ddev = crtc->dev;
0337 struct tidss_device *tidss = to_tidss(ddev);
0338
0339 dev_dbg(ddev->dev, "%s\n", __func__);
0340
0341 tidss_irq_disable_vblank(crtc);
0342
0343 tidss_runtime_put(tidss);
0344 }
0345
0346 static void tidss_crtc_reset(struct drm_crtc *crtc)
0347 {
0348 struct tidss_crtc_state *tcrtc;
0349
0350 if (crtc->state)
0351 __drm_atomic_helper_crtc_destroy_state(crtc->state);
0352
0353 kfree(crtc->state);
0354
0355 tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
0356 if (!tcrtc) {
0357 crtc->state = NULL;
0358 return;
0359 }
0360
0361 __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
0362 }
0363
0364 static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
0365 {
0366 struct tidss_crtc_state *state, *current_state;
0367
0368 if (WARN_ON(!crtc->state))
0369 return NULL;
0370
0371 current_state = to_tidss_crtc_state(crtc->state);
0372
0373 state = kmalloc(sizeof(*state), GFP_KERNEL);
0374 if (!state)
0375 return NULL;
0376
0377 __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
0378
0379 state->plane_pos_changed = false;
0380
0381 state->bus_format = current_state->bus_format;
0382 state->bus_flags = current_state->bus_flags;
0383
0384 return &state->base;
0385 }
0386
0387 static void tidss_crtc_destroy(struct drm_crtc *crtc)
0388 {
0389 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0390
0391 drm_crtc_cleanup(crtc);
0392 kfree(tcrtc);
0393 }
0394
0395 static const struct drm_crtc_funcs tidss_crtc_funcs = {
0396 .reset = tidss_crtc_reset,
0397 .destroy = tidss_crtc_destroy,
0398 .set_config = drm_atomic_helper_set_config,
0399 .page_flip = drm_atomic_helper_page_flip,
0400 .atomic_duplicate_state = tidss_crtc_duplicate_state,
0401 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0402 .enable_vblank = tidss_crtc_enable_vblank,
0403 .disable_vblank = tidss_crtc_disable_vblank,
0404 };
0405
0406 struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
0407 u32 hw_videoport,
0408 struct drm_plane *primary)
0409 {
0410 struct tidss_crtc *tcrtc;
0411 struct drm_crtc *crtc;
0412 unsigned int gamma_lut_size = 0;
0413 bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
0414 int ret;
0415
0416 tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
0417 if (!tcrtc)
0418 return ERR_PTR(-ENOMEM);
0419
0420 tcrtc->hw_videoport = hw_videoport;
0421 init_completion(&tcrtc->framedone_completion);
0422
0423 crtc = &tcrtc->crtc;
0424
0425 ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
0426 NULL, &tidss_crtc_funcs, NULL);
0427 if (ret < 0) {
0428 kfree(tcrtc);
0429 return ERR_PTR(ret);
0430 }
0431
0432 drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
0433
0434
0435
0436
0437
0438
0439 if (tidss->feat->vp_feat.color.gamma_size)
0440 gamma_lut_size = 256;
0441
0442 drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
0443 if (gamma_lut_size)
0444 drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
0445
0446 return tcrtc;
0447 }