199 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.4 * Author: James.Qian.Wang <james.qian.wang@arm.com>5 *6 */7#include <drm/drm_framebuffer.h>8#include "komeda_dev.h"9#include "komeda_kms.h"10 11static int12komeda_wb_init_data_flow(struct komeda_layer *wb_layer,13 struct drm_connector_state *conn_st,14 struct komeda_crtc_state *kcrtc_st,15 struct komeda_data_flow_cfg *dflow)16{17 struct drm_framebuffer *fb = conn_st->writeback_job->fb;18 19 memset(dflow, 0, sizeof(*dflow));20 21 dflow->out_w = fb->width;22 dflow->out_h = fb->height;23 24 /* the write back data comes from the compiz */25 pipeline_composition_size(kcrtc_st, &dflow->in_w, &dflow->in_h);26 dflow->input.component = &wb_layer->base.pipeline->compiz->base;27 /* compiz doesn't output alpha */28 dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;29 dflow->rot = DRM_MODE_ROTATE_0;30 31 komeda_complete_data_flow_cfg(wb_layer, dflow, fb);32 33 return 0;34}35 36static int37komeda_wb_encoder_atomic_check(struct drm_encoder *encoder,38 struct drm_crtc_state *crtc_st,39 struct drm_connector_state *conn_st)40{41 struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_st);42 struct drm_writeback_job *writeback_job = conn_st->writeback_job;43 struct komeda_layer *wb_layer;44 struct komeda_data_flow_cfg dflow;45 int err;46 47 if (!writeback_job)48 return 0;49 50 if (!crtc_st->active) {51 DRM_DEBUG_ATOMIC("Cannot write the composition result out on a inactive CRTC.\n");52 return -EINVAL;53 }54 55 wb_layer = to_kconn(to_wb_conn(conn_st->connector))->wb_layer;56 57 /*58 * No need for a full modested when the only connector changed is the59 * writeback connector.60 */61 if (crtc_st->connectors_changed &&62 is_only_changed_connector(crtc_st, conn_st->connector))63 crtc_st->connectors_changed = false;64 65 err = komeda_wb_init_data_flow(wb_layer, conn_st, kcrtc_st, &dflow);66 if (err)67 return err;68 69 if (dflow.en_split)70 err = komeda_build_wb_split_data_flow(wb_layer,71 conn_st, kcrtc_st, &dflow);72 else73 err = komeda_build_wb_data_flow(wb_layer,74 conn_st, kcrtc_st, &dflow);75 76 return err;77}78 79static const struct drm_encoder_helper_funcs komeda_wb_encoder_helper_funcs = {80 .atomic_check = komeda_wb_encoder_atomic_check,81};82 83static int84komeda_wb_connector_get_modes(struct drm_connector *connector)85{86 return 0;87}88 89static enum drm_mode_status90komeda_wb_connector_mode_valid(struct drm_connector *connector,91 struct drm_display_mode *mode)92{93 struct drm_device *dev = connector->dev;94 struct drm_mode_config *mode_config = &dev->mode_config;95 int w = mode->hdisplay, h = mode->vdisplay;96 97 if ((w < mode_config->min_width) || (w > mode_config->max_width))98 return MODE_BAD_HVALUE;99 100 if ((h < mode_config->min_height) || (h > mode_config->max_height))101 return MODE_BAD_VVALUE;102 103 return MODE_OK;104}105 106static const struct drm_connector_helper_funcs komeda_wb_conn_helper_funcs = {107 .get_modes = komeda_wb_connector_get_modes,108 .mode_valid = komeda_wb_connector_mode_valid,109};110 111static enum drm_connector_status112komeda_wb_connector_detect(struct drm_connector *connector, bool force)113{114 return connector_status_connected;115}116 117static int118komeda_wb_connector_fill_modes(struct drm_connector *connector,119 uint32_t maxX, uint32_t maxY)120{121 return 0;122}123 124static void komeda_wb_connector_destroy(struct drm_connector *connector)125{126 drm_connector_cleanup(connector);127 kfree(to_kconn(to_wb_conn(connector)));128}129 130static const struct drm_connector_funcs komeda_wb_connector_funcs = {131 .reset = drm_atomic_helper_connector_reset,132 .detect = komeda_wb_connector_detect,133 .fill_modes = komeda_wb_connector_fill_modes,134 .destroy = komeda_wb_connector_destroy,135 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,136 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,137};138 139static int komeda_wb_connector_add(struct komeda_kms_dev *kms,140 struct komeda_crtc *kcrtc)141{142 struct komeda_dev *mdev = kms->base.dev_private;143 struct komeda_wb_connector *kwb_conn;144 struct drm_writeback_connector *wb_conn;145 struct drm_display_info *info;146 u32 *formats, n_formats = 0;147 int err;148 149 if (!kcrtc->master->wb_layer)150 return 0;151 152 kwb_conn = kzalloc(sizeof(*kwb_conn), GFP_KERNEL);153 if (!kwb_conn)154 return -ENOMEM;155 156 kwb_conn->wb_layer = kcrtc->master->wb_layer;157 158 wb_conn = &kwb_conn->base;159 160 formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,161 kwb_conn->wb_layer->layer_type,162 &n_formats);163 164 err = drm_writeback_connector_init(&kms->base, wb_conn,165 &komeda_wb_connector_funcs,166 &komeda_wb_encoder_helper_funcs,167 formats, n_formats,168 BIT(drm_crtc_index(&kcrtc->base)));169 komeda_put_fourcc_list(formats);170 if (err) {171 kfree(kwb_conn);172 return err;173 }174 175 drm_connector_helper_add(&wb_conn->base, &komeda_wb_conn_helper_funcs);176 177 info = &kwb_conn->base.base.display_info;178 info->bpc = __fls(kcrtc->master->improc->supported_color_depths);179 info->color_formats = kcrtc->master->improc->supported_color_formats;180 181 kcrtc->wb_conn = kwb_conn;182 183 return 0;184}185 186int komeda_kms_add_wb_connectors(struct komeda_kms_dev *kms,187 struct komeda_dev *mdev)188{189 int i, err;190 191 for (i = 0; i < kms->n_crtcs; i++) {192 err = komeda_wb_connector_add(kms, &kms->crtcs[i]);193 if (err)194 return err;195 }196 197 return 0;198}199