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

Commit 56566123 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: Implement TE configuration in interface module"

parents d7d22d93 934e511c
Loading
Loading
Loading
Loading
+185 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * GNU General Public License for more details.
 */
 */
#include <linux/iopoll.h>


#include "sde_hwio.h"
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_catalog.h"
@@ -69,6 +70,21 @@
#define INTF_MISR_SIGNATURE		0x184
#define INTF_MISR_SIGNATURE		0x184


#define INTF_MUX                        0x25C
#define INTF_MUX                        0x25C
#define INTF_TEAR_MDP_VSYNC_SEL         0x280
#define INTF_TEAR_TEAR_CHECK_EN         0x284
#define INTF_TEAR_SYNC_CONFIG_VSYNC     0x288
#define INTF_TEAR_SYNC_CONFIG_HEIGHT    0x28C
#define INTF_TEAR_SYNC_WRCOUNT          0x290
#define INTF_TEAR_VSYNC_INIT_VAL        0x294
#define INTF_TEAR_INT_COUNT_VAL         0x298
#define INTF_TEAR_SYNC_THRESH           0x29C
#define INTF_TEAR_START_POS             0x2A0
#define INTF_TEAR_RD_PTR_IRQ            0x2A4
#define INTF_TEAR_WR_PTR_IRQ            0x2A8
#define INTF_TEAR_OUT_LINE_COUNT        0x2AC
#define INTF_TEAR_LINE_COUNT            0x2B0
#define INTF_TEAR_AUTOREFRESH_CONFIG    0x2B4
#define INTF_TEAR_TEAR_DETECT_CTRL      0x2B8


static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
		struct sde_mdss_cfg *m,
		struct sde_mdss_cfg *m,
@@ -321,6 +337,163 @@ static u32 sde_hw_intf_get_line_count(struct sde_hw_intf *intf)
	return SDE_REG_READ(c, INTF_LINE_COUNT);
	return SDE_REG_READ(c, INTF_LINE_COUNT);
}
}


static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf,
		struct sde_hw_tear_check *te)
{
	struct sde_hw_blk_reg_map *c;
	int cfg;

	if (!intf)
		return -EINVAL;

	c = &intf->hw;

	cfg = BIT(19); /* VSYNC_COUNTER_EN */
	if (te->hw_vsync_mode)
		cfg |= BIT(20);

	cfg |= te->vsync_count;

	SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg);
	SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height);
	SDE_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val);
	SDE_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq);
	SDE_REG_WRITE(c, INTF_TEAR_START_POS, te->start_pos);
	SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH,
			((te->sync_threshold_continue << 16) |
			 te->sync_threshold_start));
	SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT,
			(te->start_pos + te->sync_threshold_start + 1));

	return 0;
}

static int sde_hw_intf_setup_autorefresh_config(struct sde_hw_intf *intf,
		struct sde_hw_autorefresh *cfg)
{
	struct sde_hw_blk_reg_map *c;
	u32 refresh_cfg;

	if (!intf || !cfg)
		return -EINVAL;

	c = &intf->hw;

	if (cfg->enable)
		refresh_cfg = BIT(31) | cfg->frame_count;
	else
		refresh_cfg = 0;

	SDE_REG_WRITE(c, INTF_TEAR_AUTOREFRESH_CONFIG, refresh_cfg);

	return 0;
}

static int sde_hw_intf_get_autorefresh_config(struct sde_hw_intf *intf,
		struct sde_hw_autorefresh *cfg)
{
	struct sde_hw_blk_reg_map *c;
	u32 val;

	if (!intf || !cfg)
		return -EINVAL;

	c = &intf->hw;
	val = SDE_REG_READ(c, INTF_TEAR_AUTOREFRESH_CONFIG);
	cfg->enable = (val & BIT(31)) >> 31;
	cfg->frame_count = val & 0xffff;

	return 0;
}

static int sde_hw_intf_poll_timeout_wr_ptr(struct sde_hw_intf *intf,
		u32 timeout_us)
{
	struct sde_hw_blk_reg_map *c;
	u32 val;
	int rc;

	if (!intf)
		return -EINVAL;

	c = &intf->hw;
	rc = readl_poll_timeout(c->base_off + c->blk_off + INTF_TEAR_LINE_COUNT,
			val, (val & 0xffff) >= 1, 10, timeout_us);

	return rc;
}

static int sde_hw_intf_enable_te(struct sde_hw_intf *intf, bool enable)
{
	struct sde_hw_blk_reg_map *c;

	if (!intf)
		return -EINVAL;

	c = &intf->hw;
	SDE_REG_WRITE(c, INTF_TEAR_TEAR_CHECK_EN, enable);
	return 0;
}

static int sde_hw_intf_connect_external_te(struct sde_hw_intf *intf,
		bool enable_external_te)
{
	struct sde_hw_blk_reg_map *c = &intf->hw;
	u32 cfg;
	int orig;

	if (!intf)
		return -EINVAL;

	c = &intf->hw;
	cfg = SDE_REG_READ(c, INTF_TEAR_SYNC_CONFIG_VSYNC);
	orig = (bool)(cfg & BIT(20));
	if (enable_external_te)
		cfg |= BIT(20);
	else
		cfg &= ~BIT(20);
	SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg);

	return orig;
}

static int sde_hw_intf_get_vsync_info(struct sde_hw_intf *intf,
		struct sde_hw_pp_vsync_info *info)
{
	struct sde_hw_blk_reg_map *c = &intf->hw;
	u32 val;

	if (!intf || !info)
		return -EINVAL;

	c = &intf->hw;

	val = SDE_REG_READ(c, INTF_TEAR_VSYNC_INIT_VAL);
	info->rd_ptr_init_val = val & 0xffff;

	val = SDE_REG_READ(c, INTF_TEAR_INT_COUNT_VAL);
	info->rd_ptr_frame_count = (val & 0xffff0000) >> 16;
	info->rd_ptr_line_count = val & 0xffff;

	val = SDE_REG_READ(c, INTF_TEAR_LINE_COUNT);
	info->wr_ptr_line_count = val & 0xffff;

	return 0;
}

static void sde_hw_intf_vsync_sel(struct sde_hw_intf *intf,
		u32 vsync_source)
{
	struct sde_hw_blk_reg_map *c;

	if (!intf)
		return;

	c = &intf->hw;

	SDE_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf));
}

static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
		unsigned long cap)
		unsigned long cap)
{
{
@@ -333,8 +506,20 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
	ops->get_line_count = sde_hw_intf_get_line_count;
	ops->get_line_count = sde_hw_intf_get_line_count;
	if (cap & BIT(SDE_INTF_ROT_START))
	if (cap & BIT(SDE_INTF_ROT_START))
		ops->setup_rot_start = sde_hw_intf_setup_rot_start;
		ops->setup_rot_start = sde_hw_intf_setup_rot_start;

	if (cap & BIT(SDE_INTF_INPUT_CTRL))
	if (cap & BIT(SDE_INTF_INPUT_CTRL))
		ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk;
		ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk;

	if (cap & BIT(SDE_INTF_TE)) {
		ops->setup_tearcheck = sde_hw_intf_setup_te_config;
		ops->enable_tearcheck = sde_hw_intf_enable_te;
		ops->connect_external_te = sde_hw_intf_connect_external_te;
		ops->get_vsync_info = sde_hw_intf_get_vsync_info;
		ops->setup_autorefresh = sde_hw_intf_setup_autorefresh_config;
		ops->get_autorefresh = sde_hw_intf_get_autorefresh_config;
		ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr;
		ops->vsync_sel = sde_hw_intf_vsync_sel;
	}
}
}


static struct sde_hw_blk_ops sde_hw_ops = {
static struct sde_hw_blk_ops sde_hw_ops = {
+55 −0
Original line number Original line Diff line number Diff line
@@ -88,11 +88,66 @@ struct sde_hw_intf_ops {


	u32 (*collect_misr)(struct sde_hw_intf *intf);
	u32 (*collect_misr)(struct sde_hw_intf *intf);


	/**
	 * returns the current scan line count of the display
	 * video mode panels use get_line_count whereas get_vsync_info
	 * is used for command mode panels
	 */
	u32 (*get_line_count)(struct sde_hw_intf *intf);
	u32 (*get_line_count)(struct sde_hw_intf *intf);


	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
			bool enable,
			bool enable,
			const enum sde_pingpong pp);
			const enum sde_pingpong pp);

	/**
	 * enables vysnc generation and sets up init value of
	 * read pointer and programs the tear check cofiguration
	 */
	int (*setup_tearcheck)(struct sde_hw_intf *intf,
			struct sde_hw_tear_check *cfg);

	/**
	 * enables tear check block
	 */
	int (*enable_tearcheck)(struct sde_hw_intf *intf,
			bool enable);

	/**
	 * read, modify, write to either set or clear listening to external TE
	 * @Return: 1 if TE was originally connected, 0 if not, or -ERROR
	 */
	int (*connect_external_te)(struct sde_hw_intf *intf,
			bool enable_external_te);

	/**
	 * provides the programmed and current
	 * line_count
	 */
	int (*get_vsync_info)(struct sde_hw_intf *intf,
			struct sde_hw_pp_vsync_info  *info);

	/**
	 * configure and enable the autorefresh config
	 */
	int (*setup_autorefresh)(struct sde_hw_intf *intf,
			struct sde_hw_autorefresh *cfg);

	/**
	 * retrieve autorefresh config from hardware
	 */
	int (*get_autorefresh)(struct sde_hw_intf *intf,
			struct sde_hw_autorefresh *cfg);

	/**
	 * poll until write pointer transmission starts
	 * @Return: 0 on success, -ETIMEDOUT on timeout
	 */
	int (*poll_timeout_wr_ptr)(struct sde_hw_intf *intf, u32 timeout_us);

	/**
	 * Select vsync signal for tear-effect configuration
	 */
	void (*vsync_sel)(struct sde_hw_intf *intf, u32 vsync_source);
};
};


struct sde_hw_intf {
struct sde_hw_intf {