Commit 20d84aa8 authored by james qian wang (Arm Technology China)'s avatar james qian wang (Arm Technology China) Committed by Liviu Dudau
Browse files

drm/komeda: Add komeda_crtc_prepare/unprepare



These two function will be used by komeda_crtc_enable/disable to do some
prepartion works when enable/disable a crtc. like enable a crtc:
  1. Adjust display operation mode.
  2. Enable/prepare needed clk.

v2: Rebase

Signed-off-by: default avatarJames Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Signed-off-by: default avatarLiviu Dudau <liviu.dudau@arm.com>
parent a2491b90
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -243,6 +243,37 @@ static int d71_disable_irq(struct komeda_dev *mdev)
	return 0;
}

static int to_d71_opmode(int core_mode)
{
	switch (core_mode) {
	case KOMEDA_MODE_DISP0:
		return DO0_ACTIVE_MODE;
	case KOMEDA_MODE_DISP1:
		return DO1_ACTIVE_MODE;
	case KOMEDA_MODE_DUAL_DISP:
		return DO01_ACTIVE_MODE;
	case KOMEDA_MODE_INACTIVE:
		return INACTIVE_MODE;
	default:
		WARN(1, "Unknown operation mode");
		return INACTIVE_MODE;
	}
}

static int d71_change_opmode(struct komeda_dev *mdev, int new_mode)
{
	struct d71_dev *d71 = mdev->chip_data;
	u32 opmode = to_d71_opmode(new_mode);
	int ret;

	malidp_write32_mask(d71->gcu_addr, BLK_CONTROL, 0x7, opmode);

	ret = dp_wait_cond(((malidp_read32(d71->gcu_addr, BLK_CONTROL) & 0x7) == opmode),
			   100, 1000, 10000);

	return ret > 0 ? 0 : -ETIMEDOUT;
}

static void d71_flush(struct komeda_dev *mdev,
		      int master_pipe, u32 active_pipes)
{
@@ -469,6 +500,7 @@ static struct komeda_dev_funcs d71_chip_funcs = {
	.irq_handler	= d71_irq_handler,
	.enable_irq	= d71_enable_irq,
	.disable_irq	= d71_disable_irq,
	.change_opmode	= d71_change_opmode,
	.flush		= d71_flush,
};

+104 −0
Original line number Diff line number Diff line
@@ -44,6 +44,110 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
	return 0;
}

u32 komeda_calc_mclk(struct komeda_crtc_state *kcrtc_st)
{
	unsigned long mclk = kcrtc_st->base.adjusted_mode.clock * 1000;

	return mclk;
}

/* For active a crtc, mainly need two parts of preparation
 * 1. adjust display operation mode.
 * 2. enable needed clk
 */
int
komeda_crtc_prepare(struct komeda_crtc *kcrtc)
{
	struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
	struct komeda_pipeline *master = kcrtc->master;
	struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state);
	unsigned long pxlclk_rate = kcrtc_st->base.adjusted_mode.clock * 1000;
	u32 new_mode;
	int err;

	mutex_lock(&mdev->lock);

	new_mode = mdev->dpmode | BIT(master->id);
	if (WARN_ON(new_mode == mdev->dpmode)) {
		err = 0;
		goto unlock;
	}

	err = mdev->funcs->change_opmode(mdev, new_mode);
	if (err) {
		DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n,",
			  mdev->dpmode, new_mode);
		goto unlock;
	}

	mdev->dpmode = new_mode;
	/* Only need to enable mclk on single display mode, but no need to
	 * enable mclk it on dual display mode, since the dual mode always
	 * switch from single display mode, the mclk already enabled, no need
	 * to enable it again.
	 */
	if (new_mode != KOMEDA_MODE_DUAL_DISP) {
		err = clk_set_rate(mdev->mclk, komeda_calc_mclk(kcrtc_st));
		if (err)
			DRM_ERROR("failed to set mclk.\n");
		err = clk_prepare_enable(mdev->mclk);
		if (err)
			DRM_ERROR("failed to enable mclk.\n");
	}

	err = clk_prepare_enable(master->aclk);
	if (err)
		DRM_ERROR("failed to enable axi clk for pipe%d.\n", master->id);
	err = clk_set_rate(master->pxlclk, pxlclk_rate);
	if (err)
		DRM_ERROR("failed to set pxlclk for pipe%d\n", master->id);
	err = clk_prepare_enable(master->pxlclk);
	if (err)
		DRM_ERROR("failed to enable pxl clk for pipe%d.\n", master->id);

unlock:
	mutex_unlock(&mdev->lock);

	return err;
}

int
komeda_crtc_unprepare(struct komeda_crtc *kcrtc)
{
	struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
	struct komeda_pipeline *master = kcrtc->master;
	u32 new_mode;
	int err;

	mutex_lock(&mdev->lock);

	new_mode = mdev->dpmode & (~BIT(master->id));

	if (WARN_ON(new_mode == mdev->dpmode)) {
		err = 0;
		goto unlock;
	}

	err = mdev->funcs->change_opmode(mdev, new_mode);
	if (err) {
		DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n,",
			  mdev->dpmode, new_mode);
		goto unlock;
	}

	mdev->dpmode = new_mode;

	clk_disable_unprepare(master->pxlclk);
	clk_disable_unprepare(master->aclk);
	if (new_mode == KOMEDA_MODE_INACTIVE)
		clk_disable_unprepare(mdev->mclk);

unlock:
	mutex_unlock(&mdev->lock);

	return err;
}

void komeda_crtc_handle_event(struct komeda_crtc   *kcrtc,
			      struct komeda_events *evts)
{
+2 −0
Original line number Diff line number Diff line
@@ -151,6 +151,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
	if (!mdev)
		return ERR_PTR(-ENOMEM);

	mutex_init(&mdev->lock);

	mdev->dev = dev;
	mdev->reg_base = devm_ioremap_resource(dev, io_res);
	if (IS_ERR(mdev->reg_base)) {
+26 −0
Original line number Diff line number Diff line
@@ -106,11 +106,34 @@ struct komeda_dev_funcs {

	/** @dump_register: Optional, dump registers to seq_file */
	void (*dump_register)(struct komeda_dev *mdev, struct seq_file *seq);
	/**
	 * @change_opmode:
	 *
	 * Notify HW to switch to a new display operation mode.
	 */
	int (*change_opmode)(struct komeda_dev *mdev, int new_mode);
	/** @flush: Notify the HW to flush or kickoff the update */
	void (*flush)(struct komeda_dev *mdev,
		      int master_pipe, u32 active_pipes);
};

/**
 * DISPLAY_MODE describes how many display been enabled, and which will be
 * passed to CHIP by &komeda_dev_funcs->change_opmode(), then CHIP can do the
 * pipeline resources assignment according to this usage hint.
 * -   KOMEDA_MODE_DISP0: Only one display enabled, pipeline-0 work as master.
 * -   KOMEDA_MODE_DISP1: Only one display enabled, pipeline-0 work as master.
 * -   KOMEDA_MODE_DUAL_DISP: Dual display mode, both display has been enabled.
 * And D71 supports assign two pipelines to one single display on mode
 * KOMEDA_MODE_DISP0/DISP1
 */
enum {
	KOMEDA_MODE_INACTIVE	= 0,
	KOMEDA_MODE_DISP0	= BIT(0),
	KOMEDA_MODE_DISP1	= BIT(1),
	KOMEDA_MODE_DUAL_DISP	= KOMEDA_MODE_DISP0 | KOMEDA_MODE_DISP1,
};

/**
 * struct komeda_dev
 *
@@ -133,6 +156,9 @@ struct komeda_dev {
	/** @irq: irq number */
	int irq;

	struct mutex lock; /* used to protect dpmode */
	u32 dpmode; /* current display mode */

	int n_pipelines;
	struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];