// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2024 NXP */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dc-de.h" #include "dc-drv.h" #include "dc-kms.h" static const struct drm_mode_config_funcs dc_drm_mode_config_funcs = { .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm, int crtc_index) { struct dc_crtc *dc_crtc = &dc_drm->dc_crtc[crtc_index]; struct drm_device *drm = &dc_drm->base; struct drm_crtc *crtc = &dc_crtc->base; struct drm_connector *connector; struct device *dev = drm->dev; struct drm_encoder *encoder; struct drm_bridge *bridge; int ret; bridge = devm_drm_of_get_bridge(dev, dc_crtc->de->tc->dev->of_node, 0, 0); if (IS_ERR(bridge)) { ret = PTR_ERR(bridge); if (ret == -ENODEV) return 0; return dev_err_probe(dev, ret, "failed to find bridge for CRTC%u\n", crtc->index); } encoder = &dc_drm->encoder[crtc_index]; ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE); if (ret) { dev_err(dev, "failed to initialize encoder for CRTC%u: %d\n", crtc->index, ret); return ret; } encoder->possible_crtcs = drm_crtc_mask(crtc); ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { dev_err(dev, "failed to attach bridge to encoder for CRTC%u: %d\n", crtc->index, ret); return ret; } connector = drm_bridge_connector_init(drm, encoder); if (IS_ERR(connector)) { ret = PTR_ERR(connector); dev_err(dev, "failed to init bridge connector for CRTC%u: %d\n", crtc->index, ret); return ret; } ret = drm_connector_attach_encoder(connector, encoder); if (ret) dev_err(dev, "failed to attach encoder to connector for CRTC%u: %d\n", crtc->index, ret); return ret; } int dc_kms_init(struct dc_drm_device *dc_drm) { struct drm_device *drm = &dc_drm->base; int ret, i; ret = drmm_mode_config_init(drm); if (ret) return ret; drm->mode_config.min_width = 60; drm->mode_config.min_height = 60; drm->mode_config.max_width = 8192; drm->mode_config.max_height = 8192; drm->mode_config.funcs = &dc_drm_mode_config_funcs; drm->vblank_disable_immediate = true; drm->max_vblank_count = DC_FRAMEGEN_MAX_FRAME_INDEX; for (i = 0; i < DC_DISPLAYS; i++) { ret = dc_crtc_init(dc_drm, i); if (ret) return ret; ret = dc_kms_init_encoder_per_crtc(dc_drm, i); if (ret) return ret; } for (i = 0; i < DC_DISPLAYS; i++) { ret = dc_crtc_post_init(dc_drm, i); if (ret) return ret; } ret = drm_vblank_init(drm, DC_DISPLAYS); if (ret) { dev_err(drm->dev, "failed to init vblank support: %d\n", ret); return ret; } drm_mode_config_reset(drm); drm_kms_helper_poll_init(drm); return 0; } void dc_kms_uninit(struct dc_drm_device *dc_drm) { drm_kms_helper_poll_fini(&dc_drm->base); }