#define REG_SET(x, base, reg, v, mode) \
__REG_SET_##mode(x, base + reg.offset, reg.mask, reg.shift, v)
+#define REG_SET_MASK(x, base, reg, v, mode) \
+ __REG_SET_##mode(x, base + reg.offset, reg.mask, reg.shift, v)
#define VOP_WIN_SET(x, win, name, v) \
REG_SET(x, win->base, win->phy->name, v, RELAXED)
#define VOP_CTRL_SET(x, name, v) \
REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL)
+#define VOP_INTR_GET(vop, name) \
+ vop_read_reg(vop, 0, &vop->data->ctrl->name)
+
+#define VOP_INTR_SET(vop, name, v) \
+ REG_SET(vop, 0, vop->data->intr->name, v, NORMAL)
+#define VOP_INTR_SET_TYPE(vop, name, type, v) \
+ do { \
+ int i, reg = 0; \
+ for (i = 0; i < vop->data->intr->nintrs; i++) { \
+ if (vop->data->intr->intrs[i] & type) \
+ reg |= (v) << i; \
+ } \
+ VOP_INTR_SET(vop, name, reg); \
+ } while (0)
+#define VOP_INTR_GET_TYPE(vop, name, type) \
+ vop_get_intr_type(vop, &vop->data->intr->name, type)
+
#define VOP_WIN_GET(x, win, name) \
vop_read_reg(x, win->base, &win->phy->name)
struct vop_reg cfg_done;
};
+struct vop_intr {
+ const int *intrs;
+ uint32_t nintrs;
+ struct vop_reg enable;
+ struct vop_reg clear;
+ struct vop_reg status;
+};
struct vop_scl_regs {
struct vop_reg cbcr_vsd_mode;
struct vop_reg cbcr_vsu_mode;
const struct vop_reg_data *init_table;
unsigned int table_size;
const struct vop_ctrl *ctrl;
+ const struct vop_intr *intr;
const struct vop_win_data *win;
unsigned int win_size;
};
{ .base = 0x50, .phy = &win23_data, .type = DRM_PLANE_TYPE_CURSOR },
};
+static const int rk3288_vop_intrs[] = {
+ DSP_HOLD_VALID_INTR,
+ FS_INTR,
+ LINE_FLAG_INTR,
+ BUS_ERROR_INTR,
+};
+
+static const struct vop_intr rk3288_vop_intr = {
+ .intrs = rk3288_vop_intrs,
+ .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
+ .status = VOP_REG(INTR_CTRL0, 0xf, 0),
+ .enable = VOP_REG(INTR_CTRL0, 0xf, 4),
+ .clear = VOP_REG(INTR_CTRL0, 0xf, 8),
+};
+
static const struct vop_data rk3288_vop = {
.init_table = vop_init_reg_table,
+ .intr = &rk3288_vop_intr,
.table_size = ARRAY_SIZE(vop_init_reg_table),
.ctrl = &ctrl_data,
.win = rk3288_vop_win_data,
}
}
+static inline uint32_t vop_get_intr_type(struct vop *vop,
+ const struct vop_reg *reg, int type)
+{
+ uint32_t i, ret = 0;
+ uint32_t regs = vop_read_reg(vop, 0, reg);
+
+ for (i = 0; i < vop->data->intr->nintrs; i++) {
+ if ((type & vop->data->intr->intrs[i]) && (regs & 1 << i))
+ ret |= vop->data->intr->intrs[i];
+ }
+
+ return ret;
+}
+
static inline void vop_cfg_done(struct vop *vop)
{
VOP_CTRL_SET(vop, cfg_done, 1);
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
- DSP_HOLD_VALID_INTR_EN(1));
+ VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1);
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
- DSP_HOLD_VALID_INTR_EN(0));
+ VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 0);
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(1));
+ VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1);
spin_unlock_irqrestore(&vop->irq_lock, flags);
return;
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
+
+ VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
+
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
{
struct vop *vop = data;
struct drm_crtc *crtc = &vop->crtc;
- uint32_t intr0_reg, active_irqs;
+ uint32_t active_irqs;
unsigned long flags;
int ret = IRQ_NONE;
/*
- * INTR_CTRL0 register has interrupt status, enable and clear bits, we
+ * interrupt register has interrupt status, enable and clear bits, we
* must hold irq_lock to avoid a race with enable/disable_vblank().
*/
spin_lock_irqsave(&vop->irq_lock, flags);
- intr0_reg = vop_readl(vop, INTR_CTRL0);
- active_irqs = intr0_reg & INTR_MASK;
+
+ active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK);
/* Clear all active interrupt sources */
if (active_irqs)
- vop_writel(vop, INTR_CTRL0,
- intr0_reg | (active_irqs << INTR_CLR_SHIFT));
+ VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
+
spin_unlock_irqrestore(&vop->irq_lock, flags);
/* This is expected for vop iommu irqs, since the irq is shared */