MISR support is the debug feature present in Snapdragon chipsets.
At the layer mixer and interfaces, MISR algorithm can generate CRC
signatures of the pixel data which can be used for validating
the frames generated. Since there are no clients for this feature,
strip down the support from the driver.
changes in v4:
- changed introduced in the series
changes in v5:
- update commit text with the need for the change(Sean)
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
#define LEFT_MIXER 0
#define RIGHT_MIXER 1
-#define MISR_BUFF_SIZE 256
-
static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
{
struct msm_drm_private *priv;
struct drm_crtc *crtc = arg;
struct dpu_crtc *dpu_crtc;
struct drm_encoder *encoder;
- struct dpu_crtc_mixer *m;
- u32 i, misr_status;
if (!crtc) {
DPU_ERROR("invalid crtc\n");
dpu_encoder_virt_restore(encoder);
}
-
- for (i = 0; i < dpu_crtc->num_mixers; ++i) {
- m = &dpu_crtc->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.setup_misr ||
- !dpu_crtc->misr_enable)
- continue;
-
- m->hw_lm->ops.setup_misr(m->hw_lm, true,
- dpu_crtc->misr_frame_count);
- }
break;
case DPU_POWER_EVENT_PRE_DISABLE:
- for (i = 0; i < dpu_crtc->num_mixers; ++i) {
- m = &dpu_crtc->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
- !dpu_crtc->misr_enable)
- continue;
-
- misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
- dpu_crtc->misr_data[i] = misr_status ? misr_status :
- dpu_crtc->misr_data[i];
- }
- break;
case DPU_POWER_EVENT_POST_DISABLE:
/**
* Nothing to do. All the planes on the CRTC will be
return single_open(file, _dpu_debugfs_status_show, inode->i_private);
}
-static ssize_t _dpu_crtc_misr_setup(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- struct dpu_crtc *dpu_crtc;
- struct dpu_crtc_mixer *m;
- int i = 0, rc;
- char buf[MISR_BUFF_SIZE + 1];
- u32 frame_count, enable;
- size_t buff_copy;
-
- if (!file || !file->private_data)
- return -EINVAL;
-
- dpu_crtc = file->private_data;
- buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
- if (copy_from_user(buf, user_buf, buff_copy)) {
- DPU_ERROR("buffer copy failed\n");
- return -EINVAL;
- }
-
- buf[buff_copy] = 0; /* end of string */
-
- if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
- return -EINVAL;
-
- rc = _dpu_crtc_power_enable(dpu_crtc, true);
- if (rc)
- return rc;
-
- mutex_lock(&dpu_crtc->crtc_lock);
- dpu_crtc->misr_enable = enable;
- dpu_crtc->misr_frame_count = frame_count;
- for (i = 0; i < dpu_crtc->num_mixers; ++i) {
- dpu_crtc->misr_data[i] = 0;
- m = &dpu_crtc->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
- continue;
-
- m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
- }
- mutex_unlock(&dpu_crtc->crtc_lock);
- _dpu_crtc_power_enable(dpu_crtc, false);
-
- return count;
-}
-
-static ssize_t _dpu_crtc_misr_read(struct file *file,
- char __user *user_buff, size_t count, loff_t *ppos)
-{
- struct dpu_crtc *dpu_crtc;
- struct dpu_crtc_mixer *m;
- int i = 0, rc;
- u32 misr_status;
- ssize_t len = 0;
- char buf[MISR_BUFF_SIZE + 1] = {'\0'};
-
- if (*ppos)
- return 0;
-
- if (!file || !file->private_data)
- return -EINVAL;
-
- dpu_crtc = file->private_data;
- rc = _dpu_crtc_power_enable(dpu_crtc, true);
- if (rc)
- return rc;
-
- mutex_lock(&dpu_crtc->crtc_lock);
- if (!dpu_crtc->misr_enable) {
- len += snprintf(buf + len, MISR_BUFF_SIZE - len,
- "disabled\n");
- goto buff_check;
- }
-
- for (i = 0; i < dpu_crtc->num_mixers; ++i) {
- m = &dpu_crtc->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.collect_misr)
- continue;
-
- misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
- dpu_crtc->misr_data[i] = misr_status ? misr_status :
- dpu_crtc->misr_data[i];
- len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
- m->hw_lm->idx - LM_0);
- len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
- dpu_crtc->misr_data[i]);
- }
-
-buff_check:
- if (count <= len) {
- len = 0;
- goto end;
- }
-
- if (copy_to_user(user_buff, buf, len)) {
- len = -EFAULT;
- goto end;
- }
-
- *ppos += len; /* increase offset */
-
-end:
- mutex_unlock(&dpu_crtc->crtc_lock);
- _dpu_crtc_power_enable(dpu_crtc, false);
- return len;
-}
-
#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \
static int __prefix ## _open(struct inode *inode, struct file *file) \
{ \
.llseek = seq_lseek,
.release = single_release,
};
- static const struct file_operations debugfs_misr_fops = {
- .open = simple_open,
- .read = _dpu_crtc_misr_read,
- .write = _dpu_crtc_misr_setup,
- };
if (!crtc)
return -EINVAL;
dpu_crtc->debugfs_root,
&dpu_crtc->base,
&dpu_crtc_debugfs_state_fops);
- debugfs_create_file("misr_data", 0600, dpu_crtc->debugfs_root,
- dpu_crtc, &debugfs_misr_fops);
return 0;
}
* @event_thread : Pointer to event handler thread
* @event_worker : Event worker queue
* @event_lock : Spinlock around event handling code
- * @misr_enable : boolean entry indicates misr enable/disable status.
- * @misr_frame_count : misr frame count provided by client
- * @misr_data : store misr data before turning off the clocks.
* @phandle: Pointer to power handler
* @power_event : registered power event handle
* @cur_perf : current performance committed to clock/bandwidth driver
/* for handling internal event thread */
spinlock_t event_lock;
- bool misr_enable;
- u32 misr_frame_count;
- u32 misr_data[CRTC_DUAL_MIXERS];
struct dpu_power_handle *phandle;
struct dpu_power_event *power_event;
#define MAX_CHANNELS_PER_ENC 2
-#define MISR_BUFF_SIZE 256
-
#define IDLE_SHORT_TIMEOUT 1
#define MAX_VDISPLAY_SPLIT 1080
* @frame_done_timer: watchdog timer for frame done event
* @vsync_event_timer: vsync timer
* @disp_info: local copy of msm_display_info struct
- * @misr_enable: misr enable/disable status
- * @misr_frame_count: misr frame count before start capturing the data
* @idle_pc_supported: indicate if idle power collaps is supported
* @rc_lock: resource control mutex lock to protect
* virt encoder over various state changes
struct timer_list vsync_event_timer;
struct msm_display_info disp_info;
- bool misr_enable;
- u32 misr_frame_count;
bool idle_pc_supported;
struct mutex rc_lock;
if (phys->ops.enable)
phys->ops.enable(phys);
}
-
- if (dpu_enc->misr_enable && (dpu_enc->disp_info.capabilities &
- MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr)
- phys->ops.setup_misr(phys, true,
- dpu_enc->misr_frame_count);
}
if (dpu_enc->cur_master->ops.enable)
return single_open(file, _dpu_encoder_status_show, inode->i_private);
}
-static ssize_t _dpu_encoder_misr_setup(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- struct dpu_encoder_virt *dpu_enc;
- int i = 0, rc;
- char buf[MISR_BUFF_SIZE + 1];
- size_t buff_copy;
- u32 frame_count, enable;
-
- if (!file || !file->private_data)
- return -EINVAL;
-
- dpu_enc = file->private_data;
-
- buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
- if (copy_from_user(buf, user_buf, buff_copy))
- return -EINVAL;
-
- buf[buff_copy] = 0; /* end of string */
-
- if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
- return -EINVAL;
-
- rc = _dpu_encoder_power_enable(dpu_enc, true);
- if (rc)
- return rc;
-
- mutex_lock(&dpu_enc->enc_lock);
- dpu_enc->misr_enable = enable;
- dpu_enc->misr_frame_count = frame_count;
- for (i = 0; i < dpu_enc->num_phys_encs; i++) {
- struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
-
- if (!phys || !phys->ops.setup_misr)
- continue;
-
- phys->ops.setup_misr(phys, enable, frame_count);
- }
- mutex_unlock(&dpu_enc->enc_lock);
- _dpu_encoder_power_enable(dpu_enc, false);
-
- return count;
-}
-
-static ssize_t _dpu_encoder_misr_read(struct file *file,
- char __user *user_buff, size_t count, loff_t *ppos)
-{
- struct dpu_encoder_virt *dpu_enc;
- int i = 0, len = 0;
- char buf[MISR_BUFF_SIZE + 1] = {'\0'};
- int rc;
-
- if (*ppos)
- return 0;
-
- if (!file || !file->private_data)
- return -EINVAL;
-
- dpu_enc = file->private_data;
-
- rc = _dpu_encoder_power_enable(dpu_enc, true);
- if (rc)
- return rc;
-
- mutex_lock(&dpu_enc->enc_lock);
- if (!dpu_enc->misr_enable) {
- len += snprintf(buf + len, MISR_BUFF_SIZE - len,
- "disabled\n");
- goto buff_check;
- } else if (dpu_enc->disp_info.capabilities &
- ~MSM_DISPLAY_CAP_VID_MODE) {
- len += snprintf(buf + len, MISR_BUFF_SIZE - len,
- "unsupported\n");
- goto buff_check;
- }
-
- for (i = 0; i < dpu_enc->num_phys_encs; i++) {
- struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
-
- if (!phys || !phys->ops.collect_misr)
- continue;
-
- len += snprintf(buf + len, MISR_BUFF_SIZE - len,
- "Intf idx:%d\n", phys->intf_idx - INTF_0);
- len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
- phys->ops.collect_misr(phys));
- }
-
-buff_check:
- if (count <= len) {
- len = 0;
- goto end;
- }
-
- if (copy_to_user(user_buff, buf, len)) {
- len = -EFAULT;
- goto end;
- }
-
- *ppos += len; /* increase offset */
-
-end:
- mutex_unlock(&dpu_enc->enc_lock);
- _dpu_encoder_power_enable(dpu_enc, false);
- return len;
-}
-
static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
{
struct dpu_encoder_virt *dpu_enc;
.release = single_release,
};
- static const struct file_operations debugfs_misr_fops = {
- .open = simple_open,
- .read = _dpu_encoder_misr_read,
- .write = _dpu_encoder_misr_setup,
- };
-
char name[DPU_NAME_SIZE];
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
debugfs_create_file("status", 0600,
dpu_enc->debugfs_root, dpu_enc, &debugfs_status_fops);
- debugfs_create_file("misr_data", 0600,
- dpu_enc->debugfs_root, dpu_enc, &debugfs_misr_fops);
-
for (i = 0; i < dpu_enc->num_phys_encs; i++)
if (dpu_enc->phys_encs[i] &&
dpu_enc->phys_encs[i]->ops.late_register)
* @handle_post_kickoff: Do any work necessary post-kickoff work
* @trigger_start: Process start event on physical encoder
* @needs_single_flush: Whether encoder slaves need to be flushed
- * @setup_misr: Sets up MISR, enable and disables based on sysfs
- * @collect_misr: Collects MISR data on frame update
* @hw_reset: Issue HW recovery such as CTL reset and clear
* DPU_ENC_ERR_NEEDS_HW_RESET state
* @irq_control: Handler to enable/disable all the encoder IRQs
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
-
- void (*setup_misr)(struct dpu_encoder_phys *phys_encs,
- bool enable, u32 frame_count);
- u32 (*collect_misr)(struct dpu_encoder_phys *phys_enc);
void (*hw_reset)(struct dpu_encoder_phys *phys_enc);
void (*irq_control)(struct dpu_encoder_phys *phys, bool enable);
void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc);
}
}
-static void dpu_encoder_phys_vid_setup_misr(struct dpu_encoder_phys *phys_enc,
- bool enable, u32 frame_count)
-{
- struct dpu_encoder_phys_vid *vid_enc;
-
- if (!phys_enc)
- return;
- vid_enc = to_dpu_encoder_phys_vid(phys_enc);
-
- if (vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
- vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf,
- enable, frame_count);
-}
-
-static u32 dpu_encoder_phys_vid_collect_misr(struct dpu_encoder_phys *phys_enc)
-{
- struct dpu_encoder_phys_vid *vid_enc;
-
- if (!phys_enc)
- return 0;
- vid_enc = to_dpu_encoder_phys_vid(phys_enc);
-
- return vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr ?
- vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0;
-}
-
static int dpu_encoder_phys_vid_get_line_count(
struct dpu_encoder_phys *phys_enc)
{
ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff;
ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff;
ops->needs_single_flush = dpu_encoder_phys_vid_needs_single_flush;
- ops->setup_misr = dpu_encoder_phys_vid_setup_misr;
- ops->collect_misr = dpu_encoder_phys_vid_collect_misr;
ops->hw_reset = dpu_encoder_helper_hw_reset;
ops->get_line_count = dpu_encoder_phys_vid_get_line_count;
}
#define INTF_FRAME_COUNT 0x0AC
#define INTF_LINE_COUNT 0x0B0
-#define INTF_MISR_CTRL 0x180
-#define INTF_MISR_SIGNATURE 0x184
-
static struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
struct dpu_mdss_cfg *m,
void __iomem *addr,
}
}
-static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf,
- bool enable, u32 frame_count)
-{
- struct dpu_hw_blk_reg_map *c = &intf->hw;
- u32 config = 0;
-
- DPU_REG_WRITE(c, INTF_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
- /* clear misr data */
- wmb();
-
- if (enable)
- config = (frame_count & MISR_FRAME_COUNT_MASK) |
- MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
-
- DPU_REG_WRITE(c, INTF_MISR_CTRL, config);
-}
-
-static u32 dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf)
-{
- struct dpu_hw_blk_reg_map *c = &intf->hw;
-
- return DPU_REG_READ(c, INTF_MISR_SIGNATURE);
-}
-
static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
{
struct dpu_hw_blk_reg_map *c;
ops->setup_prg_fetch = dpu_hw_intf_setup_prg_fetch;
ops->get_status = dpu_hw_intf_get_status;
ops->enable_timing = dpu_hw_intf_enable_timing_engine;
- ops->setup_misr = dpu_hw_intf_setup_misr;
- ops->collect_misr = dpu_hw_intf_collect_misr;
ops->get_line_count = dpu_hw_intf_get_line_count;
}
* @ setup_prog_fetch : enables/disables the programmable fetch logic
* @ enable_timing: enable/disable timing engine
* @ get_status: returns if timing engine is enabled or not
- * @ setup_misr: enables/disables MISR in HW register
- * @ collect_misr: reads and stores MISR data from HW register
* @ get_line_count: reads current vertical line counter
*/
struct dpu_hw_intf_ops {
void (*get_status)(struct dpu_hw_intf *intf,
struct intf_status *status);
- void (*setup_misr)(struct dpu_hw_intf *intf,
- bool enable, u32 frame_count);
-
- u32 (*collect_misr)(struct dpu_hw_intf *intf);
-
u32 (*get_line_count)(struct dpu_hw_intf *intf);
};
#define LM_BLEND0_FG_ALPHA 0x04
#define LM_BLEND0_BG_ALPHA 0x08
-#define LM_MISR_CTRL 0x310
-#define LM_MISR_SIGNATURE 0x314
-
static struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
struct dpu_mdss_cfg *m,
void __iomem *addr,
{
}
-static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx,
- bool enable, u32 frame_count)
-{
- struct dpu_hw_blk_reg_map *c = &ctx->hw;
- u32 config = 0;
-
- DPU_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
- /* clear misr data */
- wmb();
-
- if (enable)
- config = (frame_count & MISR_FRAME_COUNT_MASK) |
- MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
-
- DPU_REG_WRITE(c, LM_MISR_CTRL, config);
-}
-
-static u32 dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx)
-{
- struct dpu_hw_blk_reg_map *c = &ctx->hw;
-
- return DPU_REG_READ(c, LM_MISR_SIGNATURE);
-}
-
static void _setup_mixer_ops(struct dpu_mdss_cfg *m,
struct dpu_hw_lm_ops *ops,
unsigned long features)
ops->setup_alpha_out = dpu_hw_lm_setup_color3;
ops->setup_border_color = dpu_hw_lm_setup_border_color;
ops->setup_gc = dpu_hw_lm_gc;
- ops->setup_misr = dpu_hw_lm_setup_misr;
- ops->collect_misr = dpu_hw_lm_collect_misr;
};
static struct dpu_hw_blk_ops dpu_hw_ops = {
*/
void (*setup_gc)(struct dpu_hw_mixer *mixer,
void *cfg);
-
- /* setup_misr: enables/disables MISR in HW register */
- void (*setup_misr)(struct dpu_hw_mixer *ctx,
- bool enable, u32 frame_count);
-
- /* collect_misr: reads and stores MISR data from HW register */
- u32 (*collect_misr)(struct dpu_hw_mixer *ctx);
};
struct dpu_hw_mixer {
#define QSEED3_CLK_CTRL0 0x54
#define QSEED3_CLK_CTRL1 0x58
#define QSEED3_CLK_STATUS 0x5C
-#define QSEED3_MISR_CTRL 0x70
-#define QSEED3_MISR_SIGNATURE_0 0x74
-#define QSEED3_MISR_SIGNATURE_1 0x78
#define QSEED3_PHASE_INIT_Y_H 0x90
#define QSEED3_PHASE_INIT_Y_V 0x94
#define QSEED3_PHASE_INIT_UV_H 0x98
#define DPU_REG_WRITE(c, off, val) dpu_reg_write(c, off, val, #off)
#define DPU_REG_READ(c, off) dpu_reg_read(c, off)
-#define MISR_FRAME_COUNT_MASK 0xFF
-#define MISR_CTRL_ENABLE BIT(8)
-#define MISR_CTRL_STATUS BIT(9)
-#define MISR_CTRL_STATUS_CLEAR BIT(10)
-#define INTF_MISR_CTRL_FREE_RUN_MASK BIT(31)
-
void *dpu_hw_util_get_dir(void);
void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c,