cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tidss_crtc.c (11846B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
      4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      5 */
      6
      7#include <drm/drm_atomic.h>
      8#include <drm/drm_atomic_helper.h>
      9#include <drm/drm_crtc.h>
     10#include <drm/drm_crtc_helper.h>
     11#include <drm/drm_fb_cma_helper.h>
     12#include <drm/drm_gem_cma_helper.h>
     13#include <drm/drm_plane_helper.h>
     14#include <drm/drm_vblank.h>
     15
     16#include "tidss_crtc.h"
     17#include "tidss_dispc.h"
     18#include "tidss_drv.h"
     19#include "tidss_irq.h"
     20#include "tidss_plane.h"
     21
     22/* Page flip and frame done IRQs */
     23
     24static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
     25{
     26	struct drm_device *ddev = tcrtc->crtc.dev;
     27	struct tidss_device *tidss = to_tidss(ddev);
     28	struct drm_pending_vblank_event *event;
     29	unsigned long flags;
     30	bool busy;
     31
     32	spin_lock_irqsave(&ddev->event_lock, flags);
     33
     34	/*
     35	 * New settings are taken into use at VFP, and GO bit is cleared at
     36	 * the same time. This happens before the vertical blank interrupt.
     37	 * So there is a small change that the driver sets GO bit after VFP, but
     38	 * before vblank, and we have to check for that case here.
     39	 */
     40	busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport);
     41	if (busy) {
     42		spin_unlock_irqrestore(&ddev->event_lock, flags);
     43		return;
     44	}
     45
     46	event = tcrtc->event;
     47	tcrtc->event = NULL;
     48
     49	if (!event) {
     50		spin_unlock_irqrestore(&ddev->event_lock, flags);
     51		return;
     52	}
     53
     54	drm_crtc_send_vblank_event(&tcrtc->crtc, event);
     55
     56	spin_unlock_irqrestore(&ddev->event_lock, flags);
     57
     58	drm_crtc_vblank_put(&tcrtc->crtc);
     59}
     60
     61void tidss_crtc_vblank_irq(struct drm_crtc *crtc)
     62{
     63	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
     64
     65	drm_crtc_handle_vblank(crtc);
     66
     67	tidss_crtc_finish_page_flip(tcrtc);
     68}
     69
     70void tidss_crtc_framedone_irq(struct drm_crtc *crtc)
     71{
     72	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
     73
     74	complete(&tcrtc->framedone_completion);
     75}
     76
     77void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus)
     78{
     79	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
     80
     81	dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n",
     82			    tcrtc->hw_videoport, irqstatus);
     83}
     84
     85/* drm_crtc_helper_funcs */
     86
     87static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
     88				   struct drm_atomic_state *state)
     89{
     90	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
     91									  crtc);
     92	struct drm_device *ddev = crtc->dev;
     93	struct tidss_device *tidss = to_tidss(ddev);
     94	struct dispc_device *dispc = tidss->dispc;
     95	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
     96	u32 hw_videoport = tcrtc->hw_videoport;
     97	const struct drm_display_mode *mode;
     98	enum drm_mode_status ok;
     99
    100	dev_dbg(ddev->dev, "%s\n", __func__);
    101
    102	if (!crtc_state->enable)
    103		return 0;
    104
    105	mode = &crtc_state->adjusted_mode;
    106
    107	ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
    108	if (ok != MODE_OK) {
    109		dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
    110			__func__, mode->hdisplay, mode->vdisplay, mode->clock);
    111		return -EINVAL;
    112	}
    113
    114	return dispc_vp_bus_check(dispc, hw_videoport, crtc_state);
    115}
    116
    117/*
    118 * This needs all affected planes to be present in the atomic
    119 * state. The untouched planes are added to the state in
    120 * tidss_atomic_check().
    121 */
    122static void tidss_crtc_position_planes(struct tidss_device *tidss,
    123				       struct drm_crtc *crtc,
    124				       struct drm_crtc_state *old_state,
    125				       bool newmodeset)
    126{
    127	struct drm_atomic_state *ostate = old_state->state;
    128	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    129	struct drm_crtc_state *cstate = crtc->state;
    130	int layer;
    131
    132	if (!newmodeset && !cstate->zpos_changed &&
    133	    !to_tidss_crtc_state(cstate)->plane_pos_changed)
    134		return;
    135
    136	for (layer = 0; layer < tidss->feat->num_planes; layer++) {
    137		struct drm_plane_state *pstate;
    138		struct drm_plane *plane;
    139		bool layer_active = false;
    140		int i;
    141
    142		for_each_new_plane_in_state(ostate, plane, pstate, i) {
    143			if (pstate->crtc != crtc || !pstate->visible)
    144				continue;
    145
    146			if (pstate->normalized_zpos == layer) {
    147				layer_active = true;
    148				break;
    149			}
    150		}
    151
    152		if (layer_active) {
    153			struct tidss_plane *tplane = to_tidss_plane(plane);
    154
    155			dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
    156					    tcrtc->hw_videoport,
    157					    pstate->crtc_x, pstate->crtc_y,
    158					    layer);
    159		}
    160		dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
    161				       layer_active);
    162	}
    163}
    164
    165static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
    166				    struct drm_atomic_state *state)
    167{
    168	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
    169									      crtc);
    170	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    171	struct drm_device *ddev = crtc->dev;
    172	struct tidss_device *tidss = to_tidss(ddev);
    173	unsigned long flags;
    174
    175	dev_dbg(ddev->dev,
    176		"%s: %s enabled %d, needs modeset %d, event %p\n", __func__,
    177		crtc->name, drm_atomic_crtc_needs_modeset(crtc->state),
    178		crtc->state->enable, crtc->state->event);
    179
    180	/* There is nothing to do if CRTC is not going to be enabled. */
    181	if (!crtc->state->enable)
    182		return;
    183
    184	/*
    185	 * Flush CRTC changes with go bit only if new modeset is not
    186	 * coming, so CRTC is enabled trough out the commit.
    187	 */
    188	if (drm_atomic_crtc_needs_modeset(crtc->state))
    189		return;
    190
    191	/* If the GO bit is stuck we better quit here. */
    192	if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport)))
    193		return;
    194
    195	/* We should have event if CRTC is enabled through out this commit. */
    196	if (WARN_ON(!crtc->state->event))
    197		return;
    198
    199	/* Write vp properties to HW if needed. */
    200	dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
    201
    202	/* Update plane positions if needed. */
    203	tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
    204
    205	WARN_ON(drm_crtc_vblank_get(crtc) != 0);
    206
    207	spin_lock_irqsave(&ddev->event_lock, flags);
    208	dispc_vp_go(tidss->dispc, tcrtc->hw_videoport);
    209
    210	WARN_ON(tcrtc->event);
    211
    212	tcrtc->event = crtc->state->event;
    213	crtc->state->event = NULL;
    214
    215	spin_unlock_irqrestore(&ddev->event_lock, flags);
    216}
    217
    218static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
    219				     struct drm_atomic_state *state)
    220{
    221	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
    222									 crtc);
    223	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    224	struct drm_device *ddev = crtc->dev;
    225	struct tidss_device *tidss = to_tidss(ddev);
    226	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
    227	unsigned long flags;
    228	int r;
    229
    230	dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
    231
    232	tidss_runtime_get(tidss);
    233
    234	r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport,
    235				  mode->clock * 1000);
    236	if (r != 0)
    237		return;
    238
    239	r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport);
    240	if (r != 0)
    241		return;
    242
    243	dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
    244	tidss_crtc_position_planes(tidss, crtc, old_state, true);
    245
    246	/* Turn vertical blanking interrupt reporting on. */
    247	drm_crtc_vblank_on(crtc);
    248
    249	dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state);
    250
    251	dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state);
    252
    253	spin_lock_irqsave(&ddev->event_lock, flags);
    254
    255	if (crtc->state->event) {
    256		drm_crtc_send_vblank_event(crtc, crtc->state->event);
    257		crtc->state->event = NULL;
    258	}
    259
    260	spin_unlock_irqrestore(&ddev->event_lock, flags);
    261}
    262
    263static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
    264				      struct drm_atomic_state *state)
    265{
    266	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    267	struct drm_device *ddev = crtc->dev;
    268	struct tidss_device *tidss = to_tidss(ddev);
    269	unsigned long flags;
    270
    271	dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
    272
    273	reinit_completion(&tcrtc->framedone_completion);
    274
    275	dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport);
    276
    277	if (!wait_for_completion_timeout(&tcrtc->framedone_completion,
    278					 msecs_to_jiffies(500)))
    279		dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d",
    280			tcrtc->hw_videoport);
    281
    282	dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport);
    283
    284	spin_lock_irqsave(&ddev->event_lock, flags);
    285	if (crtc->state->event) {
    286		drm_crtc_send_vblank_event(crtc, crtc->state->event);
    287		crtc->state->event = NULL;
    288	}
    289	spin_unlock_irqrestore(&ddev->event_lock, flags);
    290
    291	drm_crtc_vblank_off(crtc);
    292
    293	dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport);
    294
    295	tidss_runtime_put(tidss);
    296}
    297
    298static
    299enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
    300					   const struct drm_display_mode *mode)
    301{
    302	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    303	struct drm_device *ddev = crtc->dev;
    304	struct tidss_device *tidss = to_tidss(ddev);
    305
    306	return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
    307}
    308
    309static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
    310	.atomic_check = tidss_crtc_atomic_check,
    311	.atomic_flush = tidss_crtc_atomic_flush,
    312	.atomic_enable = tidss_crtc_atomic_enable,
    313	.atomic_disable = tidss_crtc_atomic_disable,
    314
    315	.mode_valid = tidss_crtc_mode_valid,
    316};
    317
    318/* drm_crtc_funcs */
    319
    320static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
    321{
    322	struct drm_device *ddev = crtc->dev;
    323	struct tidss_device *tidss = to_tidss(ddev);
    324
    325	dev_dbg(ddev->dev, "%s\n", __func__);
    326
    327	tidss_runtime_get(tidss);
    328
    329	tidss_irq_enable_vblank(crtc);
    330
    331	return 0;
    332}
    333
    334static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
    335{
    336	struct drm_device *ddev = crtc->dev;
    337	struct tidss_device *tidss = to_tidss(ddev);
    338
    339	dev_dbg(ddev->dev, "%s\n", __func__);
    340
    341	tidss_irq_disable_vblank(crtc);
    342
    343	tidss_runtime_put(tidss);
    344}
    345
    346static void tidss_crtc_reset(struct drm_crtc *crtc)
    347{
    348	struct tidss_crtc_state *tcrtc;
    349
    350	if (crtc->state)
    351		__drm_atomic_helper_crtc_destroy_state(crtc->state);
    352
    353	kfree(crtc->state);
    354
    355	tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
    356	if (!tcrtc) {
    357		crtc->state = NULL;
    358		return;
    359	}
    360
    361	__drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
    362}
    363
    364static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
    365{
    366	struct tidss_crtc_state *state, *current_state;
    367
    368	if (WARN_ON(!crtc->state))
    369		return NULL;
    370
    371	current_state = to_tidss_crtc_state(crtc->state);
    372
    373	state = kmalloc(sizeof(*state), GFP_KERNEL);
    374	if (!state)
    375		return NULL;
    376
    377	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
    378
    379	state->plane_pos_changed = false;
    380
    381	state->bus_format = current_state->bus_format;
    382	state->bus_flags = current_state->bus_flags;
    383
    384	return &state->base;
    385}
    386
    387static void tidss_crtc_destroy(struct drm_crtc *crtc)
    388{
    389	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
    390
    391	drm_crtc_cleanup(crtc);
    392	kfree(tcrtc);
    393}
    394
    395static const struct drm_crtc_funcs tidss_crtc_funcs = {
    396	.reset = tidss_crtc_reset,
    397	.destroy = tidss_crtc_destroy,
    398	.set_config = drm_atomic_helper_set_config,
    399	.page_flip = drm_atomic_helper_page_flip,
    400	.atomic_duplicate_state = tidss_crtc_duplicate_state,
    401	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
    402	.enable_vblank = tidss_crtc_enable_vblank,
    403	.disable_vblank = tidss_crtc_disable_vblank,
    404};
    405
    406struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
    407				     u32 hw_videoport,
    408				     struct drm_plane *primary)
    409{
    410	struct tidss_crtc *tcrtc;
    411	struct drm_crtc *crtc;
    412	unsigned int gamma_lut_size = 0;
    413	bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
    414	int ret;
    415
    416	tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
    417	if (!tcrtc)
    418		return ERR_PTR(-ENOMEM);
    419
    420	tcrtc->hw_videoport = hw_videoport;
    421	init_completion(&tcrtc->framedone_completion);
    422
    423	crtc =  &tcrtc->crtc;
    424
    425	ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
    426					NULL, &tidss_crtc_funcs, NULL);
    427	if (ret < 0) {
    428		kfree(tcrtc);
    429		return ERR_PTR(ret);
    430	}
    431
    432	drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
    433
    434	/*
    435	 * The dispc gamma functions adapt to what ever size we ask
    436	 * from it no matter what HW supports. X-server assumes 256
    437	 * element gamma tables so lets use that.
    438	 */
    439	if (tidss->feat->vp_feat.color.gamma_size)
    440		gamma_lut_size = 256;
    441
    442	drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
    443	if (gamma_lut_size)
    444		drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
    445
    446	return tcrtc;
    447}