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

drm_simple_kms_helper.c (13676B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Noralf Trønnes
      4 */
      5
      6#include <linux/module.h>
      7#include <linux/slab.h>
      8
      9#include <drm/drm_atomic.h>
     10#include <drm/drm_atomic_helper.h>
     11#include <drm/drm_bridge.h>
     12#include <drm/drm_drv.h>
     13#include <drm/drm_gem_atomic_helper.h>
     14#include <drm/drm_managed.h>
     15#include <drm/drm_plane_helper.h>
     16#include <drm/drm_probe_helper.h>
     17#include <drm/drm_simple_kms_helper.h>
     18
     19/**
     20 * DOC: overview
     21 *
     22 * This helper library provides helpers for drivers for simple display
     23 * hardware.
     24 *
     25 * drm_simple_display_pipe_init() initializes a simple display pipeline
     26 * which has only one full-screen scanout buffer feeding one output. The
     27 * pipeline is represented by &struct drm_simple_display_pipe and binds
     28 * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
     29 * entity. Some flexibility for code reuse is provided through a separately
     30 * allocated &drm_connector object and supporting optional &drm_bridge
     31 * encoder drivers.
     32 *
     33 * Many drivers require only a very simple encoder that fulfills the minimum
     34 * requirements of the display pipeline and does not add additional
     35 * functionality. The function drm_simple_encoder_init() provides an
     36 * implementation of such an encoder.
     37 */
     38
     39static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
     40	.destroy = drm_encoder_cleanup,
     41};
     42
     43/**
     44 * drm_simple_encoder_init - Initialize a preallocated encoder with
     45 *                           basic functionality.
     46 * @dev: drm device
     47 * @encoder: the encoder to initialize
     48 * @encoder_type: user visible type of the encoder
     49 *
     50 * Initialises a preallocated encoder that has no further functionality.
     51 * Settings for possible CRTC and clones are left to their initial values.
     52 * The encoder will be cleaned up automatically as part of the mode-setting
     53 * cleanup.
     54 *
     55 * The caller of drm_simple_encoder_init() is responsible for freeing
     56 * the encoder's memory after the encoder has been cleaned up. At the
     57 * moment this only works reliably if the encoder data structure is
     58 * stored in the device structure. Free the encoder's memory as part of
     59 * the device release function.
     60 *
     61 * Note: consider using drmm_simple_encoder_alloc() instead of
     62 * drm_simple_encoder_init() to let the DRM managed resource infrastructure
     63 * take care of cleanup and deallocation.
     64 *
     65 * Returns:
     66 * Zero on success, error code on failure.
     67 */
     68int drm_simple_encoder_init(struct drm_device *dev,
     69			    struct drm_encoder *encoder,
     70			    int encoder_type)
     71{
     72	return drm_encoder_init(dev, encoder,
     73				&drm_simple_encoder_funcs_cleanup,
     74				encoder_type, NULL);
     75}
     76EXPORT_SYMBOL(drm_simple_encoder_init);
     77
     78void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
     79				  size_t offset, int encoder_type)
     80{
     81	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
     82				    NULL);
     83}
     84EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
     85
     86static enum drm_mode_status
     87drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
     88			       const struct drm_display_mode *mode)
     89{
     90	struct drm_simple_display_pipe *pipe;
     91
     92	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     93	if (!pipe->funcs || !pipe->funcs->mode_valid)
     94		/* Anything goes */
     95		return MODE_OK;
     96
     97	return pipe->funcs->mode_valid(pipe, mode);
     98}
     99
    100static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
    101				     struct drm_atomic_state *state)
    102{
    103	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
    104									  crtc);
    105	bool has_primary = crtc_state->plane_mask &
    106			   drm_plane_mask(crtc->primary);
    107
    108	/* We always want to have an active plane with an active CRTC */
    109	if (has_primary != crtc_state->enable)
    110		return -EINVAL;
    111
    112	return drm_atomic_add_affected_planes(state, crtc);
    113}
    114
    115static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
    116				       struct drm_atomic_state *state)
    117{
    118	struct drm_plane *plane;
    119	struct drm_simple_display_pipe *pipe;
    120
    121	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    122	if (!pipe->funcs || !pipe->funcs->enable)
    123		return;
    124
    125	plane = &pipe->plane;
    126	pipe->funcs->enable(pipe, crtc->state, plane->state);
    127}
    128
    129static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
    130					struct drm_atomic_state *state)
    131{
    132	struct drm_simple_display_pipe *pipe;
    133
    134	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    135	if (!pipe->funcs || !pipe->funcs->disable)
    136		return;
    137
    138	pipe->funcs->disable(pipe);
    139}
    140
    141static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
    142	.mode_valid = drm_simple_kms_crtc_mode_valid,
    143	.atomic_check = drm_simple_kms_crtc_check,
    144	.atomic_enable = drm_simple_kms_crtc_enable,
    145	.atomic_disable = drm_simple_kms_crtc_disable,
    146};
    147
    148static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
    149{
    150	struct drm_simple_display_pipe *pipe;
    151
    152	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    153	if (!pipe->funcs || !pipe->funcs->reset_crtc)
    154		return drm_atomic_helper_crtc_reset(crtc);
    155
    156	return pipe->funcs->reset_crtc(pipe);
    157}
    158
    159static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
    160{
    161	struct drm_simple_display_pipe *pipe;
    162
    163	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    164	if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
    165		return drm_atomic_helper_crtc_duplicate_state(crtc);
    166
    167	return pipe->funcs->duplicate_crtc_state(pipe);
    168}
    169
    170static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
    171{
    172	struct drm_simple_display_pipe *pipe;
    173
    174	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    175	if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
    176		drm_atomic_helper_crtc_destroy_state(crtc, state);
    177	else
    178		pipe->funcs->destroy_crtc_state(pipe, state);
    179}
    180
    181static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
    182{
    183	struct drm_simple_display_pipe *pipe;
    184
    185	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    186	if (!pipe->funcs || !pipe->funcs->enable_vblank)
    187		return 0;
    188
    189	return pipe->funcs->enable_vblank(pipe);
    190}
    191
    192static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
    193{
    194	struct drm_simple_display_pipe *pipe;
    195
    196	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
    197	if (!pipe->funcs || !pipe->funcs->disable_vblank)
    198		return;
    199
    200	pipe->funcs->disable_vblank(pipe);
    201}
    202
    203static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
    204	.reset = drm_simple_kms_crtc_reset,
    205	.destroy = drm_crtc_cleanup,
    206	.set_config = drm_atomic_helper_set_config,
    207	.page_flip = drm_atomic_helper_page_flip,
    208	.atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
    209	.atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
    210	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
    211	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
    212};
    213
    214static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
    215					struct drm_atomic_state *state)
    216{
    217	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
    218									     plane);
    219	struct drm_simple_display_pipe *pipe;
    220	struct drm_crtc_state *crtc_state;
    221	int ret;
    222
    223	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    224	crtc_state = drm_atomic_get_new_crtc_state(state,
    225						   &pipe->crtc);
    226
    227	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
    228						  DRM_PLANE_HELPER_NO_SCALING,
    229						  DRM_PLANE_HELPER_NO_SCALING,
    230						  false, true);
    231	if (ret)
    232		return ret;
    233
    234	if (!plane_state->visible)
    235		return 0;
    236
    237	if (!pipe->funcs || !pipe->funcs->check)
    238		return 0;
    239
    240	return pipe->funcs->check(pipe, plane_state, crtc_state);
    241}
    242
    243static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
    244					struct drm_atomic_state *state)
    245{
    246	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
    247									    plane);
    248	struct drm_simple_display_pipe *pipe;
    249
    250	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    251	if (!pipe->funcs || !pipe->funcs->update)
    252		return;
    253
    254	pipe->funcs->update(pipe, old_pstate);
    255}
    256
    257static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
    258					   struct drm_plane_state *state)
    259{
    260	struct drm_simple_display_pipe *pipe;
    261
    262	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    263	if (!pipe->funcs || !pipe->funcs->prepare_fb) {
    264		if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
    265			return 0;
    266
    267		WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
    268
    269		return drm_gem_simple_display_pipe_prepare_fb(pipe, state);
    270	}
    271
    272	return pipe->funcs->prepare_fb(pipe, state);
    273}
    274
    275static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
    276					    struct drm_plane_state *state)
    277{
    278	struct drm_simple_display_pipe *pipe;
    279
    280	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    281	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
    282		return;
    283
    284	pipe->funcs->cleanup_fb(pipe, state);
    285}
    286
    287static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
    288						uint32_t format,
    289						uint64_t modifier)
    290{
    291	return modifier == DRM_FORMAT_MOD_LINEAR;
    292}
    293
    294static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
    295	.prepare_fb = drm_simple_kms_plane_prepare_fb,
    296	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
    297	.atomic_check = drm_simple_kms_plane_atomic_check,
    298	.atomic_update = drm_simple_kms_plane_atomic_update,
    299};
    300
    301static void drm_simple_kms_plane_reset(struct drm_plane *plane)
    302{
    303	struct drm_simple_display_pipe *pipe;
    304
    305	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    306	if (!pipe->funcs || !pipe->funcs->reset_plane)
    307		return drm_atomic_helper_plane_reset(plane);
    308
    309	return pipe->funcs->reset_plane(pipe);
    310}
    311
    312static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
    313{
    314	struct drm_simple_display_pipe *pipe;
    315
    316	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    317	if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
    318		return drm_atomic_helper_plane_duplicate_state(plane);
    319
    320	return pipe->funcs->duplicate_plane_state(pipe);
    321}
    322
    323static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
    324					       struct drm_plane_state *state)
    325{
    326	struct drm_simple_display_pipe *pipe;
    327
    328	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
    329	if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
    330		drm_atomic_helper_plane_destroy_state(plane, state);
    331	else
    332		pipe->funcs->destroy_plane_state(pipe, state);
    333}
    334
    335static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
    336	.update_plane		= drm_atomic_helper_update_plane,
    337	.disable_plane		= drm_atomic_helper_disable_plane,
    338	.destroy		= drm_plane_cleanup,
    339	.reset			= drm_simple_kms_plane_reset,
    340	.atomic_duplicate_state	= drm_simple_kms_plane_duplicate_state,
    341	.atomic_destroy_state	= drm_simple_kms_plane_destroy_state,
    342	.format_mod_supported   = drm_simple_kms_format_mod_supported,
    343};
    344
    345/**
    346 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
    347 * @pipe: simple display pipe object
    348 * @bridge: bridge to attach
    349 *
    350 * Makes it possible to still use the drm_simple_display_pipe helpers when
    351 * a DRM bridge has to be used.
    352 *
    353 * Note that you probably want to initialize the pipe by passing a NULL
    354 * connector to drm_simple_display_pipe_init().
    355 *
    356 * Returns:
    357 * Zero on success, negative error code on failure.
    358 */
    359int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
    360					  struct drm_bridge *bridge)
    361{
    362	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
    363}
    364EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
    365
    366/**
    367 * drm_simple_display_pipe_init - Initialize a simple display pipeline
    368 * @dev: DRM device
    369 * @pipe: simple display pipe object to initialize
    370 * @funcs: callbacks for the display pipe (optional)
    371 * @formats: array of supported formats (DRM_FORMAT\_\*)
    372 * @format_count: number of elements in @formats
    373 * @format_modifiers: array of formats modifiers
    374 * @connector: connector to attach and register (optional)
    375 *
    376 * Sets up a display pipeline which consist of a really simple
    377 * plane-crtc-encoder pipe.
    378 *
    379 * If a connector is supplied, the pipe will be coupled with the provided
    380 * connector. You may supply a NULL connector when using drm bridges, that
    381 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
    382 *
    383 * Teardown of a simple display pipe is all handled automatically by the drm
    384 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
    385 * release the memory for the structure themselves.
    386 *
    387 * Returns:
    388 * Zero on success, negative error code on failure.
    389 */
    390int drm_simple_display_pipe_init(struct drm_device *dev,
    391			struct drm_simple_display_pipe *pipe,
    392			const struct drm_simple_display_pipe_funcs *funcs,
    393			const uint32_t *formats, unsigned int format_count,
    394			const uint64_t *format_modifiers,
    395			struct drm_connector *connector)
    396{
    397	struct drm_encoder *encoder = &pipe->encoder;
    398	struct drm_plane *plane = &pipe->plane;
    399	struct drm_crtc *crtc = &pipe->crtc;
    400	int ret;
    401
    402	pipe->connector = connector;
    403	pipe->funcs = funcs;
    404
    405	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
    406	ret = drm_universal_plane_init(dev, plane, 0,
    407				       &drm_simple_kms_plane_funcs,
    408				       formats, format_count,
    409				       format_modifiers,
    410				       DRM_PLANE_TYPE_PRIMARY, NULL);
    411	if (ret)
    412		return ret;
    413
    414	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
    415	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
    416					&drm_simple_kms_crtc_funcs, NULL);
    417	if (ret)
    418		return ret;
    419
    420	encoder->possible_crtcs = drm_crtc_mask(crtc);
    421	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
    422	if (ret || !connector)
    423		return ret;
    424
    425	return drm_connector_attach_encoder(connector, encoder);
    426}
    427EXPORT_SYMBOL(drm_simple_display_pipe_init);
    428
    429MODULE_LICENSE("GPL");