summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_drm_vop.c')
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c174
1 files changed, 69 insertions, 105 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 2900f1410d95..bf9ed0e63973 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -42,33 +42,20 @@
#include "rockchip_drm_psr.h"
#include "rockchip_drm_vop.h"
-#define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \
- vop_mask_write(x, off, mask, shift, v, write_mask, true)
-
-#define __REG_SET_NORMAL(x, off, mask, shift, v, write_mask) \
- vop_mask_write(x, off, mask, shift, v, write_mask, false)
-
-#define REG_SET(x, base, reg, v, mode) \
- __REG_SET_##mode(x, base + reg.offset, \
- reg.mask, reg.shift, v, reg.write_mask)
-#define REG_SET_MASK(x, base, reg, mask, v, mode) \
- __REG_SET_##mode(x, base + reg.offset, \
- mask, reg.shift, v, reg.write_mask)
-
#define VOP_WIN_SET(x, win, name, v) \
- REG_SET(x, win->base, win->phy->name, v, RELAXED)
+ vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
#define VOP_SCL_SET(x, win, name, v) \
- REG_SET(x, win->base, win->phy->scl->name, v, RELAXED)
+ vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name)
#define VOP_SCL_SET_EXT(x, win, name, v) \
- REG_SET(x, win->base, win->phy->scl->ext->name, v, RELAXED)
-#define VOP_CTRL_SET(x, name, v) \
- REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL)
+ vop_reg_set(vop, &win->phy->scl->ext->name, \
+ win->base, ~0, v, #name)
-#define VOP_INTR_GET(vop, name) \
- vop_read_reg(vop, 0, &vop->data->ctrl->name)
+#define VOP_INTR_SET_MASK(vop, name, mask, v) \
+ vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name)
+
+#define VOP_REG_SET(vop, group, name, v) \
+ vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name)
-#define VOP_INTR_SET(vop, name, mask, v) \
- REG_SET_MASK(vop, 0, vop->data->intr->name, mask, v, NORMAL)
#define VOP_INTR_SET_TYPE(vop, name, type, v) \
do { \
int i, reg = 0, mask = 0; \
@@ -78,13 +65,13 @@
mask |= 1 << i; \
} \
} \
- VOP_INTR_SET(vop, name, mask, reg); \
+ VOP_INTR_SET_MASK(vop, name, mask, 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)
+ vop_read_reg(x, win->offset, win->phy->name)
#define VOP_WIN_GET_YRGBADDR(vop, win) \
vop_readl(vop, win->base + win->phy->yrgb_mst.offset)
@@ -166,14 +153,22 @@ static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base,
return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask;
}
-static inline void vop_mask_write(struct vop *vop, uint32_t offset,
- uint32_t mask, uint32_t shift, uint32_t v,
- bool write_mask, bool relaxed)
+static void vop_reg_set(struct vop *vop, const struct vop_reg *reg,
+ uint32_t _offset, uint32_t _mask, uint32_t v,
+ const char *reg_name)
{
- if (!mask)
+ int offset, mask, shift;
+
+ if (!reg || !reg->mask) {
+ dev_dbg(vop->dev, "Warning: not support %s\n", reg_name);
return;
+ }
+
+ offset = reg->offset + _offset;
+ mask = reg->mask & _mask;
+ shift = reg->shift;
- if (write_mask) {
+ if (reg->write_mask) {
v = ((v << shift) & 0xffff) | (mask << (shift + 16));
} else {
uint32_t cached_val = vop->regsbak[offset >> 2];
@@ -182,7 +177,7 @@ static inline void vop_mask_write(struct vop *vop, uint32_t offset,
vop->regsbak[offset >> 2] = v;
}
- if (relaxed)
+ if (reg->relaxed)
writel_relaxed(v, vop->regs + offset);
else
writel(v, vop->regs + offset);
@@ -204,7 +199,7 @@ static inline uint32_t vop_get_intr_type(struct vop *vop,
static inline void vop_cfg_done(struct vop *vop)
{
- VOP_CTRL_SET(vop, cfg_done, 1);
+ VOP_REG_SET(vop, common, cfg_done, 1);
}
static bool has_rb_swapped(uint32_t format)
@@ -556,7 +551,7 @@ static int vop_enable(struct drm_crtc *crtc)
spin_lock(&vop->reg_lock);
- VOP_CTRL_SET(vop, standby, 0);
+ VOP_REG_SET(vop, common, standby, 1);
spin_unlock(&vop->reg_lock);
@@ -577,7 +572,8 @@ err_put_pm_runtime:
return ret;
}
-static void vop_crtc_disable(struct drm_crtc *crtc)
+static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
{
struct vop *vop = to_vop(crtc);
@@ -599,7 +595,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
spin_lock(&vop->reg_lock);
- VOP_CTRL_SET(vop, standby, 1);
+ VOP_REG_SET(vop, common, standby, 1);
spin_unlock(&vop->reg_lock);
@@ -870,7 +866,8 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}
-static void vop_crtc_enable(struct drm_crtc *crtc)
+static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
{
struct vop *vop = to_vop(crtc);
const struct vop_data *vop_data = vop->data;
@@ -897,70 +894,34 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
return;
}
- /*
- * If dclk rate is zero, mean that scanout is stop,
- * we don't need wait any more.
- */
- if (clk_get_rate(vop->dclk)) {
- /*
- * Rk3288 vop timing register is immediately, when configure
- * display timing on display time, may cause tearing.
- *
- * Vop standby will take effect at end of current frame,
- * if dsp hold valid irq happen, it means standby complete.
- *
- * mode set:
- * standby and wait complete --> |----
- * | display time
- * |----
- * |---> dsp hold irq
- * configure display timing --> |
- * standby exit |
- * | new frame start.
- */
-
- reinit_completion(&vop->dsp_hold_completion);
- vop_dsp_hold_valid_irq_enable(vop);
-
- spin_lock(&vop->reg_lock);
-
- VOP_CTRL_SET(vop, standby, 1);
-
- spin_unlock(&vop->reg_lock);
-
- wait_for_completion(&vop->dsp_hold_completion);
-
- vop_dsp_hold_valid_irq_disable(vop);
- }
-
pin_pol = BIT(DCLK_INVERT);
pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ?
BIT(HSYNC_POSITIVE) : 0;
pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
BIT(VSYNC_POSITIVE) : 0;
- VOP_CTRL_SET(vop, pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, pin_pol, pin_pol);
switch (s->output_type) {
case DRM_MODE_CONNECTOR_LVDS:
- VOP_CTRL_SET(vop, rgb_en, 1);
- VOP_CTRL_SET(vop, rgb_pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, rgb_en, 1);
+ VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol);
break;
case DRM_MODE_CONNECTOR_eDP:
- VOP_CTRL_SET(vop, edp_pin_pol, pin_pol);
- VOP_CTRL_SET(vop, edp_en, 1);
+ VOP_REG_SET(vop, output, edp_pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, edp_en, 1);
break;
case DRM_MODE_CONNECTOR_HDMIA:
- VOP_CTRL_SET(vop, hdmi_pin_pol, pin_pol);
- VOP_CTRL_SET(vop, hdmi_en, 1);
+ VOP_REG_SET(vop, output, hdmi_pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, hdmi_en, 1);
break;
case DRM_MODE_CONNECTOR_DSI:
- VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol);
- VOP_CTRL_SET(vop, mipi_en, 1);
+ VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, mipi_en, 1);
break;
case DRM_MODE_CONNECTOR_DisplayPort:
pin_pol &= ~BIT(DCLK_INVERT);
- VOP_CTRL_SET(vop, dp_pin_pol, pin_pol);
- VOP_CTRL_SET(vop, dp_en, 1);
+ VOP_REG_SET(vop, output, dp_pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, dp_en, 1);
break;
default:
DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n",
@@ -973,25 +934,25 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
!(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
s->output_mode = ROCKCHIP_OUT_MODE_P888;
- VOP_CTRL_SET(vop, out_mode, s->output_mode);
+ VOP_REG_SET(vop, common, out_mode, s->output_mode);
- VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
+ VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len);
val = hact_st << 16;
val |= hact_end;
- VOP_CTRL_SET(vop, hact_st_end, val);
- VOP_CTRL_SET(vop, hpost_st_end, val);
+ VOP_REG_SET(vop, modeset, hact_st_end, val);
+ VOP_REG_SET(vop, modeset, hpost_st_end, val);
- VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len);
+ VOP_REG_SET(vop, modeset, vtotal_pw, (vtotal << 16) | vsync_len);
val = vact_st << 16;
val |= vact_end;
- VOP_CTRL_SET(vop, vact_st_end, val);
- VOP_CTRL_SET(vop, vpost_st_end, val);
+ VOP_REG_SET(vop, modeset, vact_st_end, val);
+ VOP_REG_SET(vop, modeset, vpost_st_end, val);
- VOP_CTRL_SET(vop, line_flag_num[0], vact_end);
+ VOP_REG_SET(vop, intr, line_flag_num[0], vact_end);
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
- VOP_CTRL_SET(vop, standby, 0);
+ VOP_REG_SET(vop, common, standby, 0);
rockchip_drm_psr_activate(&vop->crtc);
}
@@ -1026,7 +987,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct drm_atomic_state *old_state = old_crtc_state->state;
- struct drm_plane_state *old_plane_state;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
struct vop *vop = to_vop(crtc);
struct drm_plane *plane;
int i;
@@ -1057,14 +1018,15 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
}
spin_unlock_irq(&crtc->dev->event_lock);
- for_each_plane_in_state(old_state, plane, old_plane_state, i) {
+ for_each_oldnew_plane_in_state(old_state, plane, old_plane_state,
+ new_plane_state, i) {
if (!old_plane_state->fb)
continue;
- if (old_plane_state->fb == plane->state->fb)
+ if (old_plane_state->fb == new_plane_state->fb)
continue;
- drm_framebuffer_reference(old_plane_state->fb);
+ drm_framebuffer_get(old_plane_state->fb);
drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
@@ -1078,11 +1040,11 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
}
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
- .enable = vop_crtc_enable,
- .disable = vop_crtc_disable,
.mode_fixup = vop_crtc_mode_fixup,
.atomic_flush = vop_crtc_atomic_flush,
.atomic_begin = vop_crtc_atomic_begin,
+ .atomic_enable = vop_crtc_atomic_enable,
+ .atomic_disable = vop_crtc_atomic_disable,
};
static void vop_crtc_destroy(struct drm_crtc *crtc)
@@ -1188,7 +1150,7 @@ static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
struct drm_framebuffer *fb = val;
drm_crtc_vblank_put(&vop->crtc);
- drm_framebuffer_unreference(fb);
+ drm_framebuffer_put(fb);
}
static void vop_handle_vblank(struct vop *vop)
@@ -1289,7 +1251,7 @@ static int vop_create_crtc(struct vop *vop)
0, &vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type, NULL);
+ NULL, win_data->type, NULL);
if (ret) {
DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
ret);
@@ -1328,7 +1290,7 @@ static int vop_create_crtc(struct vop *vop)
&vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type, NULL);
+ NULL, win_data->type, NULL);
if (ret) {
DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
ret);
@@ -1339,8 +1301,8 @@ static int vop_create_crtc(struct vop *vop)
port = of_get_child_by_name(dev->of_node, "port");
if (!port) {
- DRM_DEV_ERROR(vop->dev, "no port node found in %s\n",
- dev->of_node->full_name);
+ DRM_DEV_ERROR(vop->dev, "no port node found in %pOF\n",
+ dev->of_node);
ret = -ENOENT;
goto err_cleanup_crtc;
}
@@ -1394,7 +1356,6 @@ static void vop_destroy_crtc(struct vop *vop)
static int vop_initial(struct vop *vop)
{
const struct vop_data *vop_data = vop->data;
- const struct vop_reg_data *init_table = vop_data->init_table;
struct reset_control *ahb_rst;
int i, ret;
@@ -1454,13 +1415,16 @@ static int vop_initial(struct vop *vop)
memcpy(vop->regsbak, vop->regs, vop->len);
- for (i = 0; i < vop_data->table_size; i++)
- vop_writel(vop, init_table[i].offset, init_table[i].value);
+ VOP_REG_SET(vop, misc, global_regdone_en, 1);
+ VOP_REG_SET(vop, common, dsp_blank, 0);
for (i = 0; i < vop_data->win_size; i++) {
const struct vop_win_data *win = &vop_data->win[i];
+ int channel = i * 2 + 1;
+ VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel);
VOP_WIN_SET(vop, win, enable, 0);
+ VOP_WIN_SET(vop, win, gate, 1);
}
vop_cfg_done(vop);