Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d53987ea authored by Xiaowen Wu's avatar Xiaowen Wu
Browse files

drm/msm/sde: allow sde components creation from external module



Add capability of adding new sde components from external modules.

msm_drv: add maximum crtc/encoder/connector/bridge num to 16
sde_crtc: add priv_handle for external use
sde_encoder: add sde_encoder_ops callback function as init parameters
sde_rm: add ext h/w block creation, allow empty ctl/lm reservation

Change-Id: I66dcd824ccf4048c51068bd78538dd9e1aeac66b
Signed-off-by: default avatarXiaowen Wu <wxiaowen@codeaurora.org>
parent c543b1e1
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -65,11 +65,11 @@ struct msm_gem_address_space;
struct msm_gem_vma;

#define NUM_DOMAINS    4    /* one for KMS, then one per gpu core (?) */
#define MAX_CRTCS      8
#define MAX_CRTCS      16
#define MAX_PLANES     20
#define MAX_ENCODERS   8
#define MAX_BRIDGES    8
#define MAX_CONNECTORS 8
#define MAX_ENCODERS   16
#define MAX_BRIDGES    16
#define MAX_CONNECTORS 16

#define TEARDOWN_DEADLOCK_RETRY_MAX 5

+3 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -186,6 +186,7 @@ struct sde_crtc_fps_info {
 * @output_fence  : output release fence context
 * @stage_cfg     : H/w mixer stage configuration
 * @debugfs_root  : Parent of debugfs node
 * @priv_handle   : Pointer to external private handle, if present
 * @vblank_cb_count : count of vblank callback since last reset
 * @play_count    : frame count between crtc enable and disable
 * @vblank_cb_time  : ktime at vblank count reset
@@ -249,6 +250,7 @@ struct sde_crtc {

	struct sde_hw_stage_cfg stage_cfg;
	struct dentry *debugfs_root;
	void *priv_handle;

	u32 vblank_cb_count;
	u64 play_count;
+34 −3
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ enum sde_enc_rc_states {
 * @enc_spin_lock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
 * @bus_scaling_client:	Client handle to the bus scaling interface
 * @te_source:		vsync source pin information
 * @ops:		Encoder ops from init function
 * @num_phys_encs:	Actual number of physical encoders contained.
 * @phys_encs:		Container of physical encoders managed.
 * @cur_master:		Pointer to the current master in this mode. Optimization
@@ -231,6 +232,8 @@ struct sde_encoder_virt {
	uint32_t display_num_of_h_tiles;
	uint32_t te_source;

	struct sde_encoder_ops ops;

	unsigned int num_phys_encs;
	struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
	struct sde_encoder_phys *cur_master;
@@ -2793,7 +2796,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

		if (phys) {
			if (!sde_enc->hw_pp[i]) {
			if (!sde_enc->hw_pp[i] && sde_enc->topology.num_intf) {
				SDE_ERROR_ENC(sde_enc,
				    "invalid pingpong block for the encoder\n");
				return;
@@ -5106,6 +5109,23 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc,
		SDE_DEBUG("h_tile_instance %d = %d, split_role %d\n",
				i, controller_id, phys_params.split_role);

		if (sde_enc->ops.phys_init) {
			struct sde_encoder_phys *enc;

			enc = sde_enc->ops.phys_init(intf_type,
					controller_id,
					&phys_params);
			if (enc) {
				sde_enc->phys_encs[sde_enc->num_phys_encs] =
					enc;
				++sde_enc->num_phys_encs;
			} else
				SDE_ERROR_ENC(sde_enc,
						"failed to add phys encs\n");

			continue;
		}

		if (intf_type == INTF_WB) {
			phys_params.intf_idx = INTF_MAX;
			phys_params.wb_idx = sde_encoder_get_wb(
@@ -5171,9 +5191,10 @@ static const struct drm_encoder_funcs sde_encoder_funcs = {
		.early_unregister = sde_encoder_early_unregister,
};

struct drm_encoder *sde_encoder_init(
struct drm_encoder *sde_encoder_init_with_ops(
		struct drm_device *dev,
		struct msm_display_info *disp_info)
		struct msm_display_info *disp_info,
		const struct sde_encoder_ops *ops)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct sde_kms *sde_kms = to_sde_kms(priv->kms);
@@ -5189,6 +5210,9 @@ struct drm_encoder *sde_encoder_init(
		goto fail;
	}

	if (ops)
		sde_enc->ops = *ops;

	mutex_init(&sde_enc->enc_lock);
	ret = sde_encoder_setup_display(sde_enc, sde_kms, disp_info,
			&drm_enc_mode);
@@ -5251,6 +5275,13 @@ struct drm_encoder *sde_encoder_init(
	return ERR_PTR(ret);
}

struct drm_encoder *sde_encoder_init(
		struct drm_device *dev,
		struct msm_display_info *disp_info)
{
	return sde_encoder_init_with_ops(dev, disp_info, NULL);
}

int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
	enum msm_event_wait event)
{
+29 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -75,6 +75,22 @@ struct sde_encoder_rsc_config {
	u32 inline_rotate_prefill;
};

/**
 * struct sde_encoder_ops - callback functions for generic sde encoder
 * Individual callbacks documented below.
 */
struct sde_encoder_ops {
	/**
	 * phys_init - phys initialization function
	 * @type: controller type
	 * @controller_id: controller id
	 * @phys_init_params: Pointer of structure sde_enc_phys_init_params
	 * Returns: Pointer of sde_encoder_phys, NULL if failed
	 */
	void *(*phys_init)(enum sde_intf_type type,
			u32 controller_id, void *phys_init_params);
};

/**
 * sde_encoder_get_hw_resources - Populate table of required hardware resources
 * @encoder:	encoder pointer
@@ -219,6 +235,18 @@ struct drm_encoder *sde_encoder_init(
		struct drm_device *dev,
		struct msm_display_info *disp_info);

/**
 * sde_encoder_init_with_ops - initialize virtual encoder object with init ops
 * @dev:        Pointer to drm device structure
 * @disp_info:  Pointer to display information structure
 * @ops:        Pointer to encoder ops structure
 * Returns:     Pointer to newly created drm encoder
 */
struct drm_encoder *sde_encoder_init_with_ops(
		struct drm_device *dev,
		struct msm_display_info *disp_info,
		const struct sde_encoder_ops *ops);

/**
 * sde_encoder_destroy - destroy previously initialized virtual encoder
 * @drm_enc:    Pointer to previously created drm encoder structure
+106 −6
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -816,8 +816,8 @@ static int _sde_rm_reserve_lms(
	int i, rc = 0;

	if (!reqs->topology->num_lm) {
		SDE_ERROR("invalid number of lm: %d\n", reqs->topology->num_lm);
		return -EINVAL;
		SDE_DEBUG("invalid number of lm: %d\n", reqs->topology->num_lm);
		return 0;
	}

	/* Find a primary mixer */
@@ -931,6 +931,11 @@ static int _sde_rm_reserve_ctls(
	struct sde_rm_hw_iter iter;
	int i = 0;

	if (!top->num_ctl) {
		SDE_DEBUG("invalid number of ctl: %d\n", top->num_ctl);
		return 0;
	}

	memset(&ctls, 0, sizeof(ctls));

	sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CTL);
@@ -1641,10 +1646,8 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc)
	mutex_lock(&rm->rm_lock);

	rsvp = _sde_rm_get_rsvp(rm, enc);
	if (!rsvp) {
		SDE_ERROR("failed to find rsvp for enc %d\n", enc->base.id);
	if (!rsvp)
		goto end;
	}

	conn = _sde_rm_get_connector(enc);
	if (!conn) {
@@ -1833,3 +1836,100 @@ int sde_rm_reserve(

	return ret;
}

int sde_rm_ext_blk_create_reserve(struct sde_rm *rm,
		struct sde_hw_blk *hw, struct drm_encoder *enc)
{
	struct sde_rm_hw_blk *blk;
	struct sde_rm_rsvp *rsvp;
	int ret = 0;

	if (!rm || !hw || !enc) {
		SDE_ERROR("invalid parameters\n");
		return -EINVAL;
	}

	if (hw->type >= SDE_HW_BLK_MAX) {
		SDE_ERROR("invalid HW type\n");
		return -EINVAL;
	}

	mutex_lock(&rm->rm_lock);

	rsvp = _sde_rm_get_rsvp(rm, enc);
	if (!rsvp) {
		rsvp = kzalloc(sizeof(*rsvp), GFP_KERNEL);
		if (!rsvp) {
			ret = -ENOMEM;
			goto end;
		}

		rsvp->seq = ++rm->rsvp_next_seq;
		rsvp->enc_id = enc->base.id;
		list_add_tail(&rsvp->list, &rm->rsvps);

		SDE_DEBUG("create rsvp %d for enc %d\n",
					rsvp->seq, rsvp->enc_id);
	}

	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
	if (!blk) {
		ret = -ENOMEM;
		goto end;
	}

	blk->type = hw->type;
	blk->id = hw->id;
	blk->hw = hw;
	blk->rsvp = rsvp;
	list_add_tail(&blk->list, &rm->hw_blks[hw->type]);

	SDE_DEBUG("create blk %d %d for rsvp %d enc %d\n", blk->type, blk->id,
					rsvp->seq, rsvp->enc_id);

end:
	mutex_unlock(&rm->rm_lock);
	return ret;
}

int sde_rm_ext_blk_destroy(struct sde_rm *rm,
		struct drm_encoder *enc)
{
	struct sde_rm_hw_blk *blk = NULL, *p;
	struct sde_rm_rsvp *rsvp;
	enum sde_hw_blk_type type;
	int ret = 0;

	if (!rm || !enc) {
		SDE_ERROR("invalid parameters\n");
		return -EINVAL;
	}

	mutex_lock(&rm->rm_lock);

	rsvp = _sde_rm_get_rsvp(rm, enc);
	if (!rsvp) {
		ret = -ENOENT;
		SDE_ERROR("failed to find rsvp for enc %d\n", enc->base.id);
		goto end;
	}

	for (type = 0; type < SDE_HW_BLK_MAX; type++) {
		list_for_each_entry_safe(blk, p, &rm->hw_blks[type], list) {
			if (blk->rsvp == rsvp) {
				list_del(&blk->list);
				SDE_DEBUG("del blk %d %d from rsvp %d enc %d\n",
						blk->type, blk->id,
						rsvp->seq, rsvp->enc_id);
				kfree(blk);
			}
		}
	}

	SDE_DEBUG("del rsvp %d\n", rsvp->seq);
	list_del(&rsvp->list);
	kfree(rsvp);
end:
	mutex_unlock(&rm->rm_lock);
	return ret;
}
Loading