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

ipuv3-crtc.c (12175B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * i.MX IPUv3 Graphics driver
      4 *
      5 * Copyright (C) 2011 Sascha Hauer, Pengutronix
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/component.h>
     10#include <linux/device.h>
     11#include <linux/dma-mapping.h>
     12#include <linux/errno.h>
     13#include <linux/export.h>
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16
     17#include <video/imx-ipu-v3.h>
     18
     19#include <drm/drm_atomic.h>
     20#include <drm/drm_atomic_helper.h>
     21#include <drm/drm_fb_cma_helper.h>
     22#include <drm/drm_gem_cma_helper.h>
     23#include <drm/drm_managed.h>
     24#include <drm/drm_probe_helper.h>
     25#include <drm/drm_vblank.h>
     26
     27#include "imx-drm.h"
     28#include "ipuv3-plane.h"
     29
     30#define DRIVER_DESC		"i.MX IPUv3 Graphics"
     31
     32struct ipu_crtc {
     33	struct device		*dev;
     34	struct drm_crtc		base;
     35
     36	/* plane[0] is the full plane, plane[1] is the partial plane */
     37	struct ipu_plane	*plane[2];
     38
     39	struct ipu_dc		*dc;
     40	struct ipu_di		*di;
     41	int			irq;
     42	struct drm_pending_vblank_event *event;
     43};
     44
     45static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
     46{
     47	return container_of(crtc, struct ipu_crtc, base);
     48}
     49
     50static void ipu_crtc_atomic_enable(struct drm_crtc *crtc,
     51				   struct drm_atomic_state *state)
     52{
     53	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
     54	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
     55
     56	ipu_prg_enable(ipu);
     57	ipu_dc_enable(ipu);
     58	ipu_dc_enable_channel(ipu_crtc->dc);
     59	ipu_di_enable(ipu_crtc->di);
     60}
     61
     62static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc,
     63				    struct drm_crtc_state *old_crtc_state)
     64{
     65	bool disable_partial = false;
     66	bool disable_full = false;
     67	struct drm_plane *plane;
     68
     69	drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
     70		if (plane == &ipu_crtc->plane[0]->base)
     71			disable_full = true;
     72		if (ipu_crtc->plane[1] && plane == &ipu_crtc->plane[1]->base)
     73			disable_partial = true;
     74	}
     75
     76	if (disable_partial)
     77		ipu_plane_disable(ipu_crtc->plane[1], true);
     78	if (disable_full)
     79		ipu_plane_disable(ipu_crtc->plane[0], true);
     80}
     81
     82static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
     83				    struct drm_atomic_state *state)
     84{
     85	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
     86									      crtc);
     87	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
     88	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
     89
     90	ipu_dc_disable_channel(ipu_crtc->dc);
     91	ipu_di_disable(ipu_crtc->di);
     92	/*
     93	 * Planes must be disabled before DC clock is removed, as otherwise the
     94	 * attached IDMACs will be left in undefined state, possibly hanging
     95	 * the IPU or even system.
     96	 */
     97	ipu_crtc_disable_planes(ipu_crtc, old_crtc_state);
     98	ipu_dc_disable(ipu);
     99	ipu_prg_disable(ipu);
    100
    101	drm_crtc_vblank_off(crtc);
    102
    103	spin_lock_irq(&crtc->dev->event_lock);
    104	if (crtc->state->event && !crtc->state->active) {
    105		drm_crtc_send_vblank_event(crtc, crtc->state->event);
    106		crtc->state->event = NULL;
    107	}
    108	spin_unlock_irq(&crtc->dev->event_lock);
    109}
    110
    111static void imx_drm_crtc_reset(struct drm_crtc *crtc)
    112{
    113	struct imx_crtc_state *state;
    114
    115	if (crtc->state)
    116		__drm_atomic_helper_crtc_destroy_state(crtc->state);
    117
    118	kfree(to_imx_crtc_state(crtc->state));
    119	crtc->state = NULL;
    120
    121	state = kzalloc(sizeof(*state), GFP_KERNEL);
    122	if (state)
    123		__drm_atomic_helper_crtc_reset(crtc, &state->base);
    124}
    125
    126static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc)
    127{
    128	struct imx_crtc_state *state;
    129
    130	state = kzalloc(sizeof(*state), GFP_KERNEL);
    131	if (!state)
    132		return NULL;
    133
    134	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
    135
    136	WARN_ON(state->base.crtc != crtc);
    137	state->base.crtc = crtc;
    138
    139	return &state->base;
    140}
    141
    142static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc,
    143				       struct drm_crtc_state *state)
    144{
    145	__drm_atomic_helper_crtc_destroy_state(state);
    146	kfree(to_imx_crtc_state(state));
    147}
    148
    149static int ipu_enable_vblank(struct drm_crtc *crtc)
    150{
    151	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
    152
    153	enable_irq(ipu_crtc->irq);
    154
    155	return 0;
    156}
    157
    158static void ipu_disable_vblank(struct drm_crtc *crtc)
    159{
    160	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
    161
    162	disable_irq_nosync(ipu_crtc->irq);
    163}
    164
    165static const struct drm_crtc_funcs ipu_crtc_funcs = {
    166	.set_config = drm_atomic_helper_set_config,
    167	.page_flip = drm_atomic_helper_page_flip,
    168	.reset = imx_drm_crtc_reset,
    169	.atomic_duplicate_state = imx_drm_crtc_duplicate_state,
    170	.atomic_destroy_state = imx_drm_crtc_destroy_state,
    171	.enable_vblank = ipu_enable_vblank,
    172	.disable_vblank = ipu_disable_vblank,
    173};
    174
    175static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
    176{
    177	struct ipu_crtc *ipu_crtc = dev_id;
    178	struct drm_crtc *crtc = &ipu_crtc->base;
    179	unsigned long flags;
    180	int i;
    181
    182	drm_crtc_handle_vblank(crtc);
    183
    184	if (ipu_crtc->event) {
    185		for (i = 0; i < ARRAY_SIZE(ipu_crtc->plane); i++) {
    186			struct ipu_plane *plane = ipu_crtc->plane[i];
    187
    188			if (!plane)
    189				continue;
    190
    191			if (ipu_plane_atomic_update_pending(&plane->base))
    192				break;
    193		}
    194
    195		if (i == ARRAY_SIZE(ipu_crtc->plane)) {
    196			spin_lock_irqsave(&crtc->dev->event_lock, flags);
    197			drm_crtc_send_vblank_event(crtc, ipu_crtc->event);
    198			ipu_crtc->event = NULL;
    199			drm_crtc_vblank_put(crtc);
    200			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
    201		}
    202	}
    203
    204	return IRQ_HANDLED;
    205}
    206
    207static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
    208				  const struct drm_display_mode *mode,
    209				  struct drm_display_mode *adjusted_mode)
    210{
    211	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
    212	struct videomode vm;
    213	int ret;
    214
    215	drm_display_mode_to_videomode(adjusted_mode, &vm);
    216
    217	ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
    218	if (ret)
    219		return false;
    220
    221	if ((vm.vsync_len == 0) || (vm.hsync_len == 0))
    222		return false;
    223
    224	drm_display_mode_from_videomode(&vm, adjusted_mode);
    225
    226	return true;
    227}
    228
    229static int ipu_crtc_atomic_check(struct drm_crtc *crtc,
    230				 struct drm_atomic_state *state)
    231{
    232	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
    233									  crtc);
    234	u32 primary_plane_mask = drm_plane_mask(crtc->primary);
    235
    236	if (crtc_state->active && (primary_plane_mask & crtc_state->plane_mask) == 0)
    237		return -EINVAL;
    238
    239	return 0;
    240}
    241
    242static void ipu_crtc_atomic_begin(struct drm_crtc *crtc,
    243				  struct drm_atomic_state *state)
    244{
    245	drm_crtc_vblank_on(crtc);
    246}
    247
    248static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
    249				  struct drm_atomic_state *state)
    250{
    251	spin_lock_irq(&crtc->dev->event_lock);
    252	if (crtc->state->event) {
    253		struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
    254
    255		WARN_ON(drm_crtc_vblank_get(crtc));
    256		ipu_crtc->event = crtc->state->event;
    257		crtc->state->event = NULL;
    258	}
    259	spin_unlock_irq(&crtc->dev->event_lock);
    260}
    261
    262static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc)
    263{
    264	struct drm_device *dev = crtc->dev;
    265	struct drm_encoder *encoder;
    266	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
    267	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
    268	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
    269	struct ipu_di_signal_cfg sig_cfg = {};
    270	unsigned long encoder_types = 0;
    271
    272	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
    273			mode->hdisplay);
    274	dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
    275			mode->vdisplay);
    276
    277	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
    278		if (encoder->crtc == crtc)
    279			encoder_types |= BIT(encoder->encoder_type);
    280	}
    281
    282	dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
    283		__func__, encoder_types);
    284
    285	/*
    286	 * If we have DAC or LDB, then we need the IPU DI clock to be
    287	 * the same as the LDB DI clock. For TVDAC, derive the IPU DI
    288	 * clock from 27 MHz TVE_DI clock, but allow to divide it.
    289	 */
    290	if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
    291			     BIT(DRM_MODE_ENCODER_LVDS)))
    292		sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
    293	else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
    294		sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
    295	else
    296		sig_cfg.clkflags = 0;
    297
    298	sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW);
    299	/* Default to driving pixel data on negative clock edges */
    300	sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags &
    301			     DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE);
    302	sig_cfg.bus_format = imx_crtc_state->bus_format;
    303	sig_cfg.v_to_h_sync = 0;
    304	sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin;
    305	sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin;
    306
    307	drm_display_mode_to_videomode(mode, &sig_cfg.mode);
    308	if (!IS_ALIGNED(sig_cfg.mode.hactive, 8)) {
    309		unsigned int new_hactive = ALIGN(sig_cfg.mode.hactive, 8);
    310
    311		dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n",
    312			 sig_cfg.mode.hactive, new_hactive);
    313
    314		sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive;
    315		sig_cfg.mode.hactive = new_hactive;
    316	}
    317
    318	ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
    319			 mode->flags & DRM_MODE_FLAG_INTERLACE,
    320			 imx_crtc_state->bus_format, sig_cfg.mode.hactive);
    321	ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
    322}
    323
    324static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
    325	.mode_fixup = ipu_crtc_mode_fixup,
    326	.mode_set_nofb = ipu_crtc_mode_set_nofb,
    327	.atomic_check = ipu_crtc_atomic_check,
    328	.atomic_begin = ipu_crtc_atomic_begin,
    329	.atomic_flush = ipu_crtc_atomic_flush,
    330	.atomic_disable = ipu_crtc_atomic_disable,
    331	.atomic_enable = ipu_crtc_atomic_enable,
    332};
    333
    334static void ipu_put_resources(struct drm_device *dev, void *ptr)
    335{
    336	struct ipu_crtc *ipu_crtc = ptr;
    337
    338	if (!IS_ERR_OR_NULL(ipu_crtc->dc))
    339		ipu_dc_put(ipu_crtc->dc);
    340	if (!IS_ERR_OR_NULL(ipu_crtc->di))
    341		ipu_di_put(ipu_crtc->di);
    342}
    343
    344static int ipu_get_resources(struct drm_device *dev, struct ipu_crtc *ipu_crtc,
    345			     struct ipu_client_platformdata *pdata)
    346{
    347	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
    348	int ret;
    349
    350	ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
    351	if (IS_ERR(ipu_crtc->dc))
    352		return PTR_ERR(ipu_crtc->dc);
    353
    354	ret = drmm_add_action_or_reset(dev, ipu_put_resources, ipu_crtc);
    355	if (ret)
    356		return ret;
    357
    358	ipu_crtc->di = ipu_di_get(ipu, pdata->di);
    359	if (IS_ERR(ipu_crtc->di))
    360		return PTR_ERR(ipu_crtc->di);
    361
    362	return 0;
    363}
    364
    365static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
    366{
    367	struct ipu_client_platformdata *pdata = dev->platform_data;
    368	struct ipu_soc *ipu = dev_get_drvdata(dev->parent);
    369	struct drm_device *drm = data;
    370	struct ipu_plane *primary_plane;
    371	struct ipu_crtc *ipu_crtc;
    372	struct drm_crtc *crtc;
    373	int dp = -EINVAL;
    374	int ret;
    375
    376	if (pdata->dp >= 0)
    377		dp = IPU_DP_FLOW_SYNC_BG;
    378	primary_plane = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
    379				       DRM_PLANE_TYPE_PRIMARY);
    380	if (IS_ERR(primary_plane))
    381		return PTR_ERR(primary_plane);
    382
    383	ipu_crtc = drmm_crtc_alloc_with_planes(drm, struct ipu_crtc, base,
    384					       &primary_plane->base, NULL,
    385					       &ipu_crtc_funcs, NULL);
    386	if (IS_ERR(ipu_crtc))
    387		return PTR_ERR(ipu_crtc);
    388
    389	ipu_crtc->dev = dev;
    390	ipu_crtc->plane[0] = primary_plane;
    391
    392	crtc = &ipu_crtc->base;
    393	crtc->port = pdata->of_node;
    394	drm_crtc_helper_add(crtc, &ipu_helper_funcs);
    395
    396	ret = ipu_get_resources(drm, ipu_crtc, pdata);
    397	if (ret) {
    398		dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
    399			ret);
    400		return ret;
    401	}
    402
    403	/* If this crtc is using the DP, add an overlay plane */
    404	if (pdata->dp >= 0 && pdata->dma[1] > 0) {
    405		ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
    406						IPU_DP_FLOW_SYNC_FG,
    407						drm_crtc_mask(&ipu_crtc->base),
    408						DRM_PLANE_TYPE_OVERLAY);
    409		if (IS_ERR(ipu_crtc->plane[1]))
    410			ipu_crtc->plane[1] = NULL;
    411	}
    412
    413	ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
    414	ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
    415			"imx_drm", ipu_crtc);
    416	if (ret < 0) {
    417		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
    418		return ret;
    419	}
    420	/* Only enable IRQ when we actually need it to trigger work. */
    421	disable_irq(ipu_crtc->irq);
    422
    423	return 0;
    424}
    425
    426static const struct component_ops ipu_crtc_ops = {
    427	.bind = ipu_drm_bind,
    428};
    429
    430static int ipu_drm_probe(struct platform_device *pdev)
    431{
    432	struct device *dev = &pdev->dev;
    433	int ret;
    434
    435	if (!dev->platform_data)
    436		return -EINVAL;
    437
    438	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
    439	if (ret)
    440		return ret;
    441
    442	return component_add(dev, &ipu_crtc_ops);
    443}
    444
    445static int ipu_drm_remove(struct platform_device *pdev)
    446{
    447	component_del(&pdev->dev, &ipu_crtc_ops);
    448	return 0;
    449}
    450
    451struct platform_driver ipu_drm_driver = {
    452	.driver = {
    453		.name = "imx-ipuv3-crtc",
    454	},
    455	.probe = ipu_drm_probe,
    456	.remove = ipu_drm_remove,
    457};