1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
- */
- #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
- #include <drm/sde_drm.h>
- #include <drm/drm_probe_helper.h>
- #include "msm_kms.h"
- #include "sde_kms.h"
- #include "sde_wb.h"
- #include "sde_formats.h"
- /* maximum display mode resolution if not available from catalog */
- #define SDE_WB_MODE_MAX_WIDTH 5120
- #define SDE_WB_MODE_MAX_HEIGHT 5120
- static const struct drm_display_mode sde_custom_wb_modes[] = {
- /* 5120x2160@60Hz */
- { DRM_MODE("5120x2160", DRM_MODE_TYPE_DRIVER, 693264, 5120, 5128,
- 5160, 5200, 0, 2160, 2208, 2216, 2222, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
- { DRM_MODE("2160x5120", DRM_MODE_TYPE_DRIVER, 693264, 2160, 2208,
- 2216, 2222, 0, 5120, 5128, 5160, 5200, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
- { DRM_MODE("5120x2560", DRM_MODE_TYPE_DRIVER, 818064, 5120, 5128,
- 5160, 5200, 0, 2560, 2608, 2616, 2622, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
- };
- /* Serialization lock for sde_wb_list */
- static DEFINE_MUTEX(sde_wb_list_lock);
- /* List of all writeback devices installed */
- static LIST_HEAD(sde_wb_list);
- /**
- * sde_wb_is_format_valid - check if given format/modifier is supported
- * @wb_dev: Pointer to writeback device
- * @pixel_format: Fourcc pixel format
- * @format_modifier: Format modifier
- * Returns: true if valid; false otherwise
- */
- static int sde_wb_is_format_valid(struct sde_wb_device *wb_dev,
- u32 pixel_format, u64 format_modifier)
- {
- const struct sde_format_extended *fmts = wb_dev->wb_cfg->format_list;
- int i;
- if (!fmts)
- return false;
- for (i = 0; fmts[i].fourcc_format; i++)
- if ((fmts[i].modifier == format_modifier) &&
- (fmts[i].fourcc_format == pixel_format))
- return true;
- return false;
- }
- enum drm_connector_status
- sde_wb_connector_detect(struct drm_connector *connector,
- bool force,
- void *display)
- {
- enum drm_connector_status rc = connector_status_unknown;
- SDE_DEBUG("\n");
- if (display)
- rc = ((struct sde_wb_device *)display)->detect_status;
- return rc;
- }
- static int sde_wb_connector_add_custom_modes(struct drm_connector *connector,
- u32 hdisplay, u32 vdisplay)
- {
- int i, num_modes = 0;
- struct drm_display_mode *mode;
- struct drm_device *dev = connector->dev;
- if (!hdisplay || !vdisplay)
- return 0;
- if (hdisplay > SDE_WB_MODE_MAX_WIDTH)
- hdisplay = SDE_WB_MODE_MAX_WIDTH;
- if (vdisplay > SDE_WB_MODE_MAX_HEIGHT)
- vdisplay = SDE_WB_MODE_MAX_HEIGHT;
- for (i = 0; i < ARRAY_SIZE(sde_custom_wb_modes); i++) {
- const struct drm_display_mode *ptr = &sde_custom_wb_modes[i];
- if (ptr->hdisplay > hdisplay || ptr->vdisplay > vdisplay)
- continue;
- mode = drm_mode_duplicate(dev, ptr);
- if (mode) {
- drm_mode_probed_add(connector, mode);
- num_modes++;
- }
- }
- return num_modes;
- }
- int sde_wb_connector_get_modes(struct drm_connector *connector, void *display,
- const struct msm_resource_caps_info *avail_res)
- {
- struct sde_wb_device *wb_dev;
- int num_modes = 0;
- if (!connector || !display)
- return 0;
- wb_dev = display;
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- if (wb_dev->count_modes && wb_dev->modes) {
- struct drm_display_mode *mode;
- int i, ret;
- for (i = 0; i < wb_dev->count_modes; i++) {
- mode = drm_mode_create(connector->dev);
- if (!mode) {
- SDE_ERROR("failed to create mode\n");
- break;
- }
- ret = drm_mode_convert_umode(wb_dev->drm_dev, mode,
- &wb_dev->modes[i]);
- if (ret) {
- SDE_ERROR("failed to convert mode %d\n", ret);
- break;
- }
- drm_mode_probed_add(connector, mode);
- num_modes++;
- }
- } else {
- u32 max_width = SDE_WB_MODE_MAX_WIDTH;
- if (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk)
- max_width = max(wb_dev->wb_cfg->sblk->maxlinewidth,
- wb_dev->wb_cfg->sblk->maxlinewidth_linear);
- num_modes = drm_add_modes_noedid(connector, max_width,
- SDE_WB_MODE_MAX_HEIGHT);
- num_modes += sde_wb_connector_add_custom_modes(connector, max_width,
- SDE_WB_MODE_MAX_HEIGHT);
- }
- mutex_unlock(&wb_dev->wb_lock);
- return num_modes;
- }
- struct drm_framebuffer *
- sde_wb_connector_state_get_output_fb(struct drm_connector_state *state)
- {
- if (!state || !state->connector ||
- (state->connector->connector_type !=
- DRM_MODE_CONNECTOR_VIRTUAL)) {
- SDE_ERROR("invalid params\n");
- return NULL;
- }
- SDE_DEBUG("\n");
- return sde_connector_get_out_fb(state);
- }
- int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state,
- struct sde_rect *roi)
- {
- if (!state || !roi || !state->connector ||
- (state->connector->connector_type !=
- DRM_MODE_CONNECTOR_VIRTUAL)) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- roi->x = sde_connector_get_property(state, CONNECTOR_PROP_DST_X);
- roi->y = sde_connector_get_property(state, CONNECTOR_PROP_DST_Y);
- roi->w = sde_connector_get_property(state, CONNECTOR_PROP_DST_W);
- roi->h = sde_connector_get_property(state, CONNECTOR_PROP_DST_H);
- return 0;
- }
- /**
- * sde_wb_connector_set_modes - set writeback modes and connection status
- * @wb_dev: Pointer to write back device
- * @count_modes: Count of modes
- * @modes: Pointer to writeback mode requested
- * @connected: Connection status requested
- * Returns: 0 if success; error code otherwise
- */
- static
- int sde_wb_connector_set_modes(struct sde_wb_device *wb_dev,
- u32 count_modes, struct drm_mode_modeinfo __user *modes,
- bool connected)
- {
- struct drm_mode_modeinfo *modeinfo = NULL;
- int ret = 0;
- int i;
- if (!wb_dev || !wb_dev->connector ||
- (wb_dev->connector->connector_type !=
- DRM_MODE_CONNECTOR_VIRTUAL)) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- if (connected) {
- SDE_DEBUG("connect\n");
- if (!count_modes || !modes) {
- SDE_ERROR("invalid count_modes :%u and modes :%d\n",
- count_modes, !modes);
- return -EINVAL;
- }
- modeinfo = kcalloc(count_modes,
- sizeof(struct drm_mode_modeinfo),
- GFP_KERNEL);
- if (!modeinfo) {
- SDE_ERROR("invalid params\n");
- ret = -ENOMEM;
- goto error;
- }
- if (copy_from_user(modeinfo, modes,
- count_modes *
- sizeof(struct drm_mode_modeinfo))) {
- SDE_ERROR("failed to copy modes\n");
- kfree(modeinfo);
- ret = -EFAULT;
- goto error;
- }
- for (i = 0; i < count_modes; i++) {
- struct drm_display_mode dispmode;
- memset(&dispmode, 0, sizeof(dispmode));
- ret = drm_mode_convert_umode(wb_dev->drm_dev,
- &dispmode, &modeinfo[i]);
- if (ret) {
- SDE_ERROR(
- "failed to convert mode %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x status:%d rc:%d\n",
- i,
- modeinfo[i].name,
- modeinfo[i].vrefresh,
- modeinfo[i].clock,
- modeinfo[i].hdisplay,
- modeinfo[i].hsync_start,
- modeinfo[i].hsync_end,
- modeinfo[i].htotal,
- modeinfo[i].vdisplay,
- modeinfo[i].vsync_start,
- modeinfo[i].vsync_end,
- modeinfo[i].vtotal,
- modeinfo[i].type,
- modeinfo[i].flags,
- dispmode.status,
- ret);
- kfree(modeinfo);
- goto error;
- }
- }
- if (wb_dev->modes) {
- wb_dev->count_modes = 0;
- kfree(wb_dev->modes);
- wb_dev->modes = NULL;
- }
- wb_dev->count_modes = count_modes;
- wb_dev->modes = modeinfo;
- wb_dev->detect_status = connector_status_connected;
- } else {
- SDE_DEBUG("disconnect\n");
- if (wb_dev->modes) {
- wb_dev->count_modes = 0;
- kfree(wb_dev->modes);
- wb_dev->modes = NULL;
- }
- wb_dev->detect_status = connector_status_disconnected;
- }
- error:
- return ret;
- }
- static void _sde_wb_connector_clear_dnsc_blur(struct drm_connector_state *state)
- {
- struct sde_connector_state *cstate = to_sde_connector_state(state);
- int i;
- for (i = 0; i < cstate->dnsc_blur_count; i++)
- memset(&cstate->dnsc_blur_cfg[i], 0, sizeof(struct sde_drm_dnsc_blur_cfg));
- cstate->dnsc_blur_count = 0;
- }
- static int _sde_wb_connector_set_dnsc_blur(struct sde_wb_device *wb_dev,
- struct drm_connector_state *state, void __user *usr_ptr)
- {
- struct sde_connector_state *cstate = to_sde_connector_state(state);
- struct sde_kms *sde_kms = sde_connector_get_kms(wb_dev->connector);
- struct sde_drm_dnsc_blur_cfg *dnsc_blur_cfg = &cstate->dnsc_blur_cfg[0];
- u32 copy_count;
- int ret = 0, i;
- if (!sde_kms || !sde_kms->catalog)
- return -EINVAL;
- if (!usr_ptr)
- goto disable;
- /* copy only the first block */
- if (copy_from_user(dnsc_blur_cfg, usr_ptr, sizeof(struct sde_drm_dnsc_blur_cfg))) {
- SDE_ERROR("failed to copy dnsc_blur block 0 data\n");
- ret = -EINVAL;
- goto disable;
- }
- if (dnsc_blur_cfg->num_blocks > sde_kms->catalog->dnsc_blur_count) {
- SDE_ERROR("invalid number of dnsc_blur blocks:%d\n", dnsc_blur_cfg->num_blocks);
- ret = -EINVAL;
- goto disable;
- }
- /* no further data required */
- if (dnsc_blur_cfg->num_blocks <= 1)
- goto end;
- dnsc_blur_cfg++;
- usr_ptr += sizeof(struct sde_drm_dnsc_blur_cfg);
- copy_count = dnsc_blur_cfg->num_blocks - 1;
- /* copy rest of the blocks */
- if ((dnsc_blur_cfg->flags & DNSC_BLUR_INDEPENDENT_BLK_CFG)) {
- if (copy_from_user(dnsc_blur_cfg, usr_ptr,
- copy_count * sizeof(struct sde_drm_dnsc_blur_cfg))) {
- SDE_ERROR("failed to copy dnsc_blur data\n");
- ret = -EINVAL;
- goto disable;
- }
- /* duplicate rest of the blocks */
- } else if (dnsc_blur_cfg->flags & DNSC_BLUR_MIRROR_BLK_CFG) {
- for (i = 0; i < copy_count; i++) {
- memcpy(dnsc_blur_cfg, &cstate->dnsc_blur_cfg[0],
- sizeof(struct sde_drm_dnsc_blur_cfg));
- dnsc_blur_cfg++;
- }
- }
- end:
- cstate->dnsc_blur_count = dnsc_blur_cfg->num_blocks;
- return 0;
- disable:
- _sde_wb_connector_clear_dnsc_blur(state);
- return ret;
- }
- static int _sde_wb_connector_set_out_fb(struct sde_wb_device *wb_dev,
- struct drm_connector_state *state)
- {
- struct drm_framebuffer *out_fb;
- const struct sde_format *sde_format;
- int rc = 0;
- out_fb = sde_connector_get_out_fb(state);
- if (!out_fb)
- goto end;
- sde_format = sde_get_sde_format_ext(out_fb->format->format, out_fb->modifier);
- if (!sde_format) {
- SDE_ERROR("failed to get sde format\n");
- rc = -EINVAL;
- goto end;
- }
- if (!sde_wb_is_format_valid(wb_dev, out_fb->format->format, out_fb->modifier)) {
- SDE_ERROR("unsupported writeback format 0x%x/0x%llx\n",
- out_fb->format->format, out_fb->modifier);
- rc = -EINVAL;
- goto end;
- }
- end:
- return rc;
- }
- int sde_wb_connector_set_property(struct drm_connector *connector,
- struct drm_connector_state *state, int idx, uint64_t value, void *display)
- {
- struct sde_wb_device *wb_dev = display;
- int rc = 0;
- if (!connector || !state || !wb_dev) {
- SDE_ERROR("invalid argument(s)\n");
- return -EINVAL;
- }
- switch (idx) {
- case CONNECTOR_PROP_OUT_FB:
- rc = _sde_wb_connector_set_out_fb(wb_dev, state);
- break;
- case CONNECTOR_PROP_DNSC_BLUR:
- rc = _sde_wb_connector_set_dnsc_blur(wb_dev, state,
- (void __user *)(uintptr_t)value);
- break;
- default:
- /* nothing to do */
- break;
- }
- return rc;
- }
- int sde_wb_get_info(struct drm_connector *connector,
- struct msm_display_info *info, void *display)
- {
- struct sde_wb_device *wb_dev = display;
- u32 max_width = SDE_WB_MODE_MAX_WIDTH;
- if (!info || !wb_dev) {
- pr_err("invalid params\n");
- return -EINVAL;
- }
- if (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk)
- max_width = max(wb_dev->wb_cfg->sblk->maxlinewidth,
- wb_dev->wb_cfg->sblk->maxlinewidth_linear);
- memset(info, 0, sizeof(struct msm_display_info));
- info->intf_type = DRM_MODE_CONNECTOR_VIRTUAL;
- info->num_of_h_tiles = 1;
- info->h_tile_instance[0] = sde_wb_get_index(display);
- info->is_connected = true;
- info->capabilities = MSM_DISPLAY_CAP_HOT_PLUG | MSM_DISPLAY_CAP_EDID;
- info->max_width = max_width;
- info->max_height = SDE_WB_MODE_MAX_HEIGHT;
- return 0;
- }
- int sde_wb_get_mode_info(struct drm_connector *connector,
- const struct drm_display_mode *drm_mode,
- struct msm_sub_mode *sub_mode,
- struct msm_mode_info *mode_info,
- void *display, const struct msm_resource_caps_info *avail_res)
- {
- const u32 dual_lm = 2;
- const u32 single_lm = 1;
- const u32 single_intf = 1;
- const u32 no_enc = 0;
- struct msm_display_topology *topology;
- struct sde_wb_device *wb_dev = display;
- u16 hdisplay;
- int i;
- if (!drm_mode || !mode_info || !avail_res ||
- !avail_res->max_mixer_width || !display) {
- pr_err("invalid params\n");
- return -EINVAL;
- }
- hdisplay = drm_mode->hdisplay;
- /* find maximum display width to support */
- for (i = 0; i < wb_dev->count_modes; i++)
- hdisplay = max(hdisplay, wb_dev->modes[i].hdisplay);
- topology = &mode_info->topology;
- topology->num_lm = (avail_res->max_mixer_width <= hdisplay) ?
- dual_lm : single_lm;
- topology->num_enc = no_enc;
- topology->num_intf = single_intf;
- mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
- mode_info->wide_bus_en = false;
- mode_info->comp_info.comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_NONE;
- return 0;
- }
- int sde_wb_connector_set_info_blob(struct drm_connector *connector,
- void *info, void *display, struct msm_mode_info *mode_info)
- {
- struct sde_wb_device *wb_dev = display;
- const struct sde_format_extended *format_list;
- struct sde_kms *sde_kms;
- struct sde_mdss_cfg *catalog;
- int i;
- if (!connector || !info || !display || !wb_dev->wb_cfg) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- sde_kms = sde_connector_get_kms(connector);
- if (!sde_kms)
- return -EINVAL;
- catalog = sde_kms->catalog;
- format_list = wb_dev->wb_cfg->format_list;
- /* Populate info buffer */
- if (format_list) {
- sde_kms_info_start(info, "pixel_formats");
- while (format_list->fourcc_format) {
- sde_kms_info_append_format(info, format_list->fourcc_format,
- format_list->modifier);
- ++format_list;
- }
- sde_kms_info_stop(info);
- }
- sde_kms_info_add_keyint(info, "wb_intf_index", wb_dev->wb_idx - WB_0);
- sde_kms_info_add_keyint(info, "maxlinewidth", wb_dev->wb_cfg->sblk->maxlinewidth);
- sde_kms_info_add_keyint(info, "maxlinewidth_linear",
- wb_dev->wb_cfg->sblk->maxlinewidth_linear);
- sde_kms_info_start(info, "features");
- if (wb_dev->wb_cfg && (wb_dev->wb_cfg->features & BIT(SDE_WB_UBWC)))
- sde_kms_info_append(info, "wb_ubwc");
- sde_kms_info_stop(info);
- sde_kms_info_add_keyint(info, "has_cwb_dither", test_bit(SDE_FEATURE_CWB_DITHER,
- catalog->features));
- if (catalog->dnsc_blur_count && catalog->dnsc_blur_filters) {
- sde_kms_info_add_keyint(info, "dnsc_blur_count", catalog->dnsc_blur_count);
- sde_kms_info_start(info, "dnsc_blur_info");
- for (i = 0; i < catalog->dnsc_blur_filter_count; i++)
- sde_kms_info_append_dnsc_blur_filter_info(info,
- &catalog->dnsc_blur_filters[i]);
- sde_kms_info_stop(info);
- }
- return 0;
- }
- static void _sde_wb_connector_install_dither_property(struct sde_wb_device *wb_dev)
- {
- struct sde_connector *c_conn = to_sde_connector(wb_dev->connector);
- struct sde_kms *sde_kms = sde_connector_get_kms(wb_dev->connector);
- struct sde_mdss_cfg *catalog;
- char prop_name[DRM_PROP_NAME_LEN];
- u32 version = 0;
- if (!sde_kms || !sde_kms->catalog)
- return;
- catalog = sde_kms->catalog;
- if (!test_bit(SDE_FEATURE_CWB_DITHER, catalog->features))
- return;
- version = SDE_COLOR_PROCESS_MAJOR(catalog->pingpong[0].sblk->dither.version);
- snprintf(prop_name, ARRAY_SIZE(prop_name), "%s%d", "SDE_PP_CWB_DITHER_V", version);
- switch (version) {
- case 2:
- msm_property_install_blob(&c_conn->property_info, prop_name,
- DRM_MODE_PROP_BLOB, CONNECTOR_PROP_PP_CWB_DITHER);
- break;
- default:
- SDE_ERROR("unsupported cwb dither version %d\n", version);
- return;
- }
- }
- int sde_wb_connector_post_init(struct drm_connector *connector, void *display)
- {
- struct sde_connector *c_conn;
- struct sde_wb_device *wb_dev = display;
- struct msm_drm_private *priv;
- struct sde_kms *sde_kms;
- struct sde_mdss_cfg *catalog;
- static const struct drm_prop_enum_list e_fb_translation_mode[] = {
- {SDE_DRM_FB_NON_SEC, "non_sec"},
- {SDE_DRM_FB_SEC, "sec"},
- };
- static const struct drm_prop_enum_list e_cache_state[] = {
- {CACHE_STATE_DISABLED, "cache_state_disabled"},
- {CACHE_STATE_ENABLED, "cache_state_enabled"},
- };
- static const struct drm_prop_enum_list e_wb_usage_type[] = {
- {WB_USAGE_WFD, "wb_usage_wfd"},
- {WB_USAGE_CWB, "wb_usage_cwb"},
- {WB_USAGE_OFFLINE_WB, "wb_usage_offline_wb"},
- };
- if (!connector || !display || !wb_dev->wb_cfg || !wb_dev->drm_dev->dev_private) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- priv = wb_dev->drm_dev->dev_private;
- sde_kms = to_sde_kms(priv->kms);
- if (!sde_kms || !sde_kms->catalog) {
- SDE_ERROR("invalid sde_kms\n");
- return -EINVAL;
- }
- catalog = sde_kms->catalog;
- c_conn = to_sde_connector(connector);
- wb_dev->connector = connector;
- wb_dev->detect_status = connector_status_connected;
- if (test_bit(SDE_SYS_CACHE_DISP, catalog->sde_sys_cache_type_map)
- || test_bit(SDE_SYS_CACHE_DISP_WB, catalog->sde_sys_cache_type_map))
- msm_property_install_enum(&c_conn->property_info, "cache_state",
- 0x0, 0, e_cache_state, ARRAY_SIZE(e_cache_state),
- 0, CONNECTOR_PROP_CACHE_STATE);
- /*
- * Add extra connector properties
- */
- msm_property_install_range(&c_conn->property_info, "FB_ID",
- 0x0, 0, ~0, 0, CONNECTOR_PROP_OUT_FB);
- msm_property_install_range(&c_conn->property_info, "DST_X",
- 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_X);
- msm_property_install_range(&c_conn->property_info, "DST_Y",
- 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_Y);
- msm_property_install_range(&c_conn->property_info, "DST_W",
- 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_W);
- msm_property_install_range(&c_conn->property_info, "DST_H",
- 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_H);
- msm_property_install_enum(&c_conn->property_info,
- "fb_translation_mode",
- 0x0,
- 0, e_fb_translation_mode,
- ARRAY_SIZE(e_fb_translation_mode), 0,
- CONNECTOR_PROP_FB_TRANSLATION_MODE);
- if (wb_dev->wb_cfg->features & BIT(SDE_WB_PROG_LINE))
- msm_property_install_range(&c_conn->property_info, "early_fence_line",
- 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_EARLY_FENCE_LINE);
- if (catalog->dnsc_blur_count && catalog->dnsc_blur_filters)
- msm_property_install_range(&c_conn->property_info, "dnsc_blur",
- 0x0, 0, ~0, 0, CONNECTOR_PROP_DNSC_BLUR);
- msm_property_install_enum(&c_conn->property_info, "wb_usage_type",
- 0x0, 0, e_wb_usage_type, ARRAY_SIZE(e_wb_usage_type),
- 0, CONNECTOR_PROP_WB_USAGE_TYPE);
- _sde_wb_connector_install_dither_property(wb_dev);
- return 0;
- }
- struct drm_framebuffer *sde_wb_get_output_fb(struct sde_wb_device *wb_dev)
- {
- struct drm_framebuffer *fb;
- if (!wb_dev || !wb_dev->connector) {
- SDE_ERROR("invalid params\n");
- return NULL;
- }
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- fb = sde_wb_connector_state_get_output_fb(wb_dev->connector->state);
- mutex_unlock(&wb_dev->wb_lock);
- return fb;
- }
- int sde_wb_get_output_roi(struct sde_wb_device *wb_dev, struct sde_rect *roi)
- {
- int rc;
- if (!wb_dev || !wb_dev->connector || !roi) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- rc = sde_wb_connector_state_get_output_roi(
- wb_dev->connector->state, roi);
- mutex_unlock(&wb_dev->wb_lock);
- return rc;
- }
- u32 sde_wb_get_num_of_displays(void)
- {
- u32 count = 0;
- struct sde_wb_device *wb_dev;
- SDE_DEBUG("\n");
- mutex_lock(&sde_wb_list_lock);
- list_for_each_entry(wb_dev, &sde_wb_list, wb_list) {
- count++;
- }
- mutex_unlock(&sde_wb_list_lock);
- return count;
- }
- int wb_display_get_displays(void **display_array, u32 max_display_count)
- {
- struct sde_wb_device *curr;
- int i = 0;
- SDE_DEBUG("\n");
- if (!display_array || !max_display_count) {
- if (!display_array)
- SDE_ERROR("invalid param\n");
- return 0;
- }
- mutex_lock(&sde_wb_list_lock);
- list_for_each_entry(curr, &sde_wb_list, wb_list) {
- if (i >= max_display_count)
- break;
- display_array[i++] = curr;
- }
- mutex_unlock(&sde_wb_list_lock);
- return i;
- }
- int sde_wb_config(struct drm_device *drm_dev, void *data,
- struct drm_file *file_priv)
- {
- struct sde_drm_wb_cfg *config = data;
- struct msm_drm_private *priv;
- struct sde_wb_device *wb_dev = NULL;
- struct sde_wb_device *curr;
- struct drm_connector *connector;
- uint32_t flags;
- uint32_t connector_id;
- uint32_t count_modes;
- uint64_t modes;
- int rc;
- if (!drm_dev || !data) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- flags = config->flags;
- connector_id = config->connector_id;
- count_modes = config->count_modes;
- modes = config->modes;
- priv = drm_dev->dev_private;
- connector = drm_connector_lookup(drm_dev, file_priv, connector_id);
- if (!connector) {
- SDE_ERROR("failed to find connector\n");
- rc = -ENOENT;
- goto fail;
- }
- mutex_lock(&sde_wb_list_lock);
- list_for_each_entry(curr, &sde_wb_list, wb_list) {
- if (curr->connector == connector) {
- wb_dev = curr;
- break;
- }
- }
- mutex_unlock(&sde_wb_list_lock);
- if (!wb_dev) {
- SDE_ERROR("failed to find wb device\n");
- rc = -ENOENT;
- goto fail;
- }
- mutex_lock(&wb_dev->wb_lock);
- rc = sde_wb_connector_set_modes(wb_dev, count_modes,
- (struct drm_mode_modeinfo __user *) (uintptr_t) modes,
- (flags & SDE_DRM_WB_CFG_FLAGS_CONNECTED) ? true : false);
- mutex_unlock(&wb_dev->wb_lock);
- drm_helper_hpd_irq_event(drm_dev);
- fail:
- return rc;
- }
- /**
- * _sde_wb_dev_init - perform device initialization
- * @wb_dev: Pointer to writeback device
- */
- static int _sde_wb_dev_init(struct sde_wb_device *wb_dev)
- {
- int rc = 0;
- if (!wb_dev) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- return rc;
- }
- /**
- * _sde_wb_dev_deinit - perform device de-initialization
- * @wb_dev: Pointer to writeback device
- */
- static int _sde_wb_dev_deinit(struct sde_wb_device *wb_dev)
- {
- int rc = 0;
- if (!wb_dev) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- return rc;
- }
- /**
- * sde_wb_bind - bind writeback device with controlling device
- * @dev: Pointer to base of platform device
- * @master: Pointer to container of drm device
- * @data: Pointer to private data
- * Returns: Zero on success
- */
- static int sde_wb_bind(struct device *dev, struct device *master, void *data)
- {
- struct sde_wb_device *wb_dev;
- if (!dev || !master) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- wb_dev = platform_get_drvdata(to_platform_device(dev));
- if (!wb_dev) {
- SDE_ERROR("invalid wb device\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- wb_dev->drm_dev = dev_get_drvdata(master);
- mutex_unlock(&wb_dev->wb_lock);
- return 0;
- }
- /**
- * sde_wb_unbind - unbind writeback from controlling device
- * @dev: Pointer to base of platform device
- * @master: Pointer to container of drm device
- * @data: Pointer to private data
- */
- static void sde_wb_unbind(struct device *dev,
- struct device *master, void *data)
- {
- struct sde_wb_device *wb_dev;
- if (!dev) {
- SDE_ERROR("invalid params\n");
- return;
- }
- wb_dev = platform_get_drvdata(to_platform_device(dev));
- if (!wb_dev) {
- SDE_ERROR("invalid wb device\n");
- return;
- }
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- wb_dev->drm_dev = NULL;
- mutex_unlock(&wb_dev->wb_lock);
- }
- static const struct component_ops sde_wb_comp_ops = {
- .bind = sde_wb_bind,
- .unbind = sde_wb_unbind,
- };
- /**
- * sde_wb_drm_init - perform DRM initialization
- * @wb_dev: Pointer to writeback device
- * @encoder: Pointer to associated encoder
- */
- int sde_wb_drm_init(struct sde_wb_device *wb_dev, struct drm_encoder *encoder)
- {
- int rc = 0;
- if (!wb_dev || !wb_dev->drm_dev || !encoder) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- mutex_lock(&wb_dev->wb_lock);
- if (wb_dev->drm_dev->dev_private) {
- struct msm_drm_private *priv = wb_dev->drm_dev->dev_private;
- struct sde_kms *sde_kms = to_sde_kms(priv->kms);
- if (wb_dev->index < sde_kms->catalog->wb_count) {
- wb_dev->wb_idx = sde_kms->catalog->wb[wb_dev->index].id;
- wb_dev->wb_cfg = &sde_kms->catalog->wb[wb_dev->index];
- }
- }
- wb_dev->drm_dev = encoder->dev;
- wb_dev->encoder = encoder;
- mutex_unlock(&wb_dev->wb_lock);
- return rc;
- }
- int sde_wb_drm_deinit(struct sde_wb_device *wb_dev)
- {
- int rc = 0;
- if (!wb_dev) {
- SDE_ERROR("invalid params\n");
- return -EINVAL;
- }
- SDE_DEBUG("\n");
- return rc;
- }
- /**
- * sde_wb_probe - load writeback module
- * @pdev: Pointer to platform device
- */
- static int sde_wb_probe(struct platform_device *pdev)
- {
- struct sde_wb_device *wb_dev;
- int ret;
- wb_dev = devm_kzalloc(&pdev->dev, sizeof(*wb_dev), GFP_KERNEL);
- if (!wb_dev)
- return -ENOMEM;
- SDE_DEBUG("\n");
- ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
- &wb_dev->index);
- if (ret) {
- SDE_DEBUG("cell index not set, default to 0\n");
- wb_dev->index = 0;
- }
- wb_dev->name = of_get_property(pdev->dev.of_node, "label", NULL);
- if (!wb_dev->name) {
- SDE_DEBUG("label not set, default to unknown\n");
- wb_dev->name = "unknown";
- }
- wb_dev->wb_idx = SDE_NONE;
- mutex_init(&wb_dev->wb_lock);
- platform_set_drvdata(pdev, wb_dev);
- mutex_lock(&sde_wb_list_lock);
- list_add_tail(&wb_dev->wb_list, &sde_wb_list);
- mutex_unlock(&sde_wb_list_lock);
- if (!_sde_wb_dev_init(wb_dev)) {
- ret = component_add(&pdev->dev, &sde_wb_comp_ops);
- if (ret)
- pr_err("component add failed\n");
- }
- return ret;
- }
- /**
- * sde_wb_remove - unload writeback module
- * @pdev: Pointer to platform device
- */
- static int sde_wb_remove(struct platform_device *pdev)
- {
- struct sde_wb_device *wb_dev;
- struct sde_wb_device *curr, *next;
- wb_dev = platform_get_drvdata(pdev);
- if (!wb_dev)
- return 0;
- SDE_DEBUG("\n");
- (void)_sde_wb_dev_deinit(wb_dev);
- mutex_lock(&sde_wb_list_lock);
- list_for_each_entry_safe(curr, next, &sde_wb_list, wb_list) {
- if (curr == wb_dev) {
- list_del(&wb_dev->wb_list);
- break;
- }
- }
- mutex_unlock(&sde_wb_list_lock);
- kfree(wb_dev->modes);
- mutex_destroy(&wb_dev->wb_lock);
- platform_set_drvdata(pdev, NULL);
- devm_kfree(&pdev->dev, wb_dev);
- return 0;
- }
- static const struct of_device_id dt_match[] = {
- { .compatible = "qcom,wb-display"},
- {}
- };
- static struct platform_driver sde_wb_driver = {
- .probe = sde_wb_probe,
- .remove = sde_wb_remove,
- .driver = {
- .name = "sde_wb",
- .of_match_table = dt_match,
- .suppress_bind_attrs = true,
- },
- };
- void __init sde_wb_register(void)
- {
- platform_driver_register(&sde_wb_driver);
- }
- void __exit sde_wb_unregister(void)
- {
- platform_driver_unregister(&sde_wb_driver);
- }
|