mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
drm/rockchip: vop bandwidth interface
Change-Id: I1970d4e613775626481f471865f6945c378de6a7 Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
This commit is contained in:
@@ -37,11 +37,14 @@ struct iommu_domain;
|
||||
* @loader_protect: protect loader logo crtc's power
|
||||
* @enable_vblank: enable crtc vblank irq.
|
||||
* @disable_vblank: disable crtc vblank irq.
|
||||
* @bandwidth: report present crtc bandwidth consume.
|
||||
*/
|
||||
struct rockchip_crtc_funcs {
|
||||
int (*loader_protect)(struct drm_crtc *crtc, bool on);
|
||||
int (*enable_vblank)(struct drm_crtc *crtc);
|
||||
void (*disable_vblank)(struct drm_crtc *crtc);
|
||||
size_t (*bandwidth)(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *crtc_state);
|
||||
void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv);
|
||||
int (*debugfs_init)(struct drm_minor *minor, struct drm_crtc *crtc);
|
||||
int (*debugfs_dump)(struct drm_crtc *crtc, struct seq_file *s);
|
||||
@@ -67,6 +70,7 @@ struct rockchip_atomic_commit {
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_device *dev;
|
||||
struct mutex lock;
|
||||
size_t bandwidth;
|
||||
};
|
||||
|
||||
struct rockchip_dclk_pll {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <soc/rockchip/rockchip_dmc.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
@@ -211,11 +212,38 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
|
||||
drm_fb_helper_hotplug_event(fb_helper);
|
||||
}
|
||||
|
||||
static int rockchip_drm_bandwidth_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
size_t *bandwidth)
|
||||
{
|
||||
struct rockchip_drm_private *priv = dev->dev_private;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
const struct rockchip_crtc_funcs *funcs;
|
||||
struct drm_crtc *crtc;
|
||||
int i, ret = 0;
|
||||
|
||||
*bandwidth = 0;
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
funcs = priv->crtc_funcs[drm_crtc_index(crtc)];
|
||||
|
||||
if (funcs && funcs->bandwidth)
|
||||
*bandwidth += funcs->bandwidth(crtc, crtc_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check ddr frequency support here here.
|
||||
*/
|
||||
ret = rockchip_dmcfreq_vop_bandwidth_request(*bandwidth);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
|
||||
{
|
||||
struct drm_atomic_state *state = commit->state;
|
||||
struct drm_device *dev = commit->dev;
|
||||
size_t bandwidth = commit->bandwidth;
|
||||
|
||||
/*
|
||||
* TODO: do fence wait here.
|
||||
@@ -242,6 +270,8 @@ rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
|
||||
|
||||
rockchip_drm_backlight_update(dev);
|
||||
|
||||
rockchip_dmcfreq_vop_bandwidth_update(bandwidth);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, true);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, state);
|
||||
@@ -265,12 +295,22 @@ int rockchip_drm_atomic_commit(struct drm_device *dev,
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct rockchip_atomic_commit *commit = &private->commit;
|
||||
size_t bandwidth;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rockchip_drm_bandwidth_atomic_check(dev, state, &bandwidth);
|
||||
if (ret) {
|
||||
/*
|
||||
* TODO:
|
||||
* Just report bandwidth can't support now.
|
||||
*/
|
||||
DRM_ERROR("vop bandwidth too large %zd\n", bandwidth);
|
||||
}
|
||||
|
||||
/* serialize outstanding asynchronous commits */
|
||||
mutex_lock(&commit->lock);
|
||||
flush_work(&commit->work);
|
||||
@@ -279,6 +319,7 @@ int rockchip_drm_atomic_commit(struct drm_device *dev,
|
||||
|
||||
commit->dev = dev;
|
||||
commit->state = state;
|
||||
commit->bandwidth = bandwidth;
|
||||
|
||||
if (async)
|
||||
schedule_work(&commit->work);
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
#define VOP_WIN_SUPPORT(vop, win, name) \
|
||||
VOP_REG_SUPPORT(vop, win->phy->name)
|
||||
|
||||
#define VOP_WIN_SCL_EXT_SUPPORT(vop, win, name) \
|
||||
VOP_REG_SUPPORT(vop, win->phy->scl->ext->name)
|
||||
|
||||
#define VOP_CTRL_SUPPORT(vop, name) \
|
||||
VOP_REG_SUPPORT(vop, vop->data->ctrl->name)
|
||||
|
||||
@@ -1724,6 +1727,124 @@ vop_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
struct vop_bandwidth {
|
||||
size_t bandwidth;
|
||||
int y1;
|
||||
int y2;
|
||||
};
|
||||
|
||||
static int vop_bandwidth_cmp(const void *a, const void *b)
|
||||
{
|
||||
struct vop_bandwidth *pa = (struct vop_bandwidth *)a;
|
||||
struct vop_bandwidth *pb = (struct vop_bandwidth *)b;
|
||||
|
||||
return pa->y1 - pb->y2;
|
||||
}
|
||||
|
||||
static size_t vop_plane_line_bandwidth(struct drm_plane_state *pstate)
|
||||
{
|
||||
struct vop_plane_state *vop_plane_state = to_vop_plane_state(pstate);
|
||||
struct vop_win *win = to_vop_win(pstate->plane);
|
||||
struct drm_crtc *crtc = pstate->crtc;
|
||||
struct vop *vop = to_vop(crtc);
|
||||
struct drm_framebuffer *fb = pstate->fb;
|
||||
struct drm_rect *dest = &vop_plane_state->dest;
|
||||
struct drm_rect *src = &vop_plane_state->src;
|
||||
int bpp = drm_format_plane_bpp(fb->pixel_format, 0);
|
||||
int src_width = drm_rect_width(src) >> 16;
|
||||
int src_height = drm_rect_height(src) >> 16;
|
||||
int dest_width = drm_rect_width(dest);
|
||||
int dest_height = drm_rect_height(dest);
|
||||
int vskiplines = scl_get_vskiplines(src_height, dest_height);
|
||||
size_t bandwidth;
|
||||
|
||||
if (!src_width || !src_height || !dest_width || !dest_height)
|
||||
return 0;
|
||||
|
||||
bandwidth = src_width * bpp / 8;
|
||||
|
||||
bandwidth = bandwidth * src_width / dest_width;
|
||||
bandwidth = bandwidth * src_height / dest_height;
|
||||
if (vskiplines == 2 && VOP_WIN_SCL_EXT_SUPPORT(vop, win, vsd_yrgb_gt2))
|
||||
bandwidth /= 2;
|
||||
else if (vskiplines == 4 &&
|
||||
VOP_WIN_SCL_EXT_SUPPORT(vop, win, vsd_yrgb_gt4))
|
||||
bandwidth /= 4;
|
||||
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
static u64 vop_calc_max_bandwidth(struct vop_bandwidth *bw, int start,
|
||||
int count, int y2)
|
||||
{
|
||||
u64 max_bandwidth = 0;
|
||||
int i;
|
||||
|
||||
for (i = start; i < count; i++) {
|
||||
u64 bandwidth = 0;
|
||||
|
||||
if (bw[i].y1 > y2)
|
||||
continue;
|
||||
bandwidth = bw[i].bandwidth;
|
||||
bandwidth += vop_calc_max_bandwidth(bw, i + 1, count,
|
||||
min(bw[i].y2, y2));
|
||||
|
||||
if (bandwidth > max_bandwidth)
|
||||
max_bandwidth = bandwidth;
|
||||
}
|
||||
|
||||
return max_bandwidth;
|
||||
}
|
||||
|
||||
static size_t vop_crtc_bandwidth(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_atomic_state *state = crtc_state->state;
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
u16 htotal = adjusted_mode->crtc_htotal;
|
||||
u16 vdisplay = adjusted_mode->crtc_vdisplay;
|
||||
int clock = adjusted_mode->crtc_clock;
|
||||
struct vop *vop = to_vop(crtc);
|
||||
const struct vop_data *vop_data = vop->data;
|
||||
struct vop_plane_state *vop_plane_state;
|
||||
struct drm_plane_state *pstate;
|
||||
struct vop_bandwidth *pbandwidth;
|
||||
struct drm_plane *plane;
|
||||
size_t bandwidth;
|
||||
size_t max_bandwidth;
|
||||
int i, cnt = 0;
|
||||
|
||||
if (!htotal || !vdisplay)
|
||||
return 0;
|
||||
|
||||
pbandwidth = kmalloc_array(vop_data->win_size, sizeof(*pbandwidth),
|
||||
GFP_KERNEL);
|
||||
if (!pbandwidth)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_plane_in_state(state, plane, pstate, i) {
|
||||
if (pstate->crtc != crtc || !pstate->fb)
|
||||
continue;
|
||||
|
||||
vop_plane_state = to_vop_plane_state(pstate);
|
||||
pbandwidth[cnt].y1 = vop_plane_state->dest.y1;
|
||||
pbandwidth[cnt].y2 = vop_plane_state->dest.y2;
|
||||
pbandwidth[cnt++].bandwidth = vop_plane_line_bandwidth(pstate);
|
||||
}
|
||||
|
||||
sort(pbandwidth, cnt, sizeof(pbandwidth[0]), vop_bandwidth_cmp, NULL);
|
||||
|
||||
max_bandwidth = vop_calc_max_bandwidth(pbandwidth, 0, cnt, vdisplay);
|
||||
/*
|
||||
* bandwidth(MB/s)
|
||||
* = line_bandwidth / line_time
|
||||
* = line_bandwidth(Byte) * clock(KHZ) / 1000 / htotal
|
||||
*/
|
||||
bandwidth = max_bandwidth * clock / 1000 / htotal;
|
||||
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
static const struct rockchip_crtc_funcs private_crtc_funcs = {
|
||||
.loader_protect = vop_crtc_loader_protect,
|
||||
.enable_vblank = vop_crtc_enable_vblank,
|
||||
@@ -1733,6 +1854,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
|
||||
.debugfs_dump = vop_crtc_debugfs_dump,
|
||||
.regs_dump = vop_crtc_regs_dump,
|
||||
.mode_valid = vop_crtc_mode_valid,
|
||||
.bandwidth = vop_crtc_bandwidth,
|
||||
};
|
||||
|
||||
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
|
||||
Reference in New Issue
Block a user