v2: Fix the 3rd plane/cursor logic (Pradeep Bhat) v3: Fix one-by-one error in the DDB allocation code v4: Rebase on top of the skl_pipe_pixel_rate() argument change v5: Replace the available/start/end output parameters of skl_ddb_get_pipe_allocation_limits() by a single ddb entry constify a few arguments Make nth_active_pipe 0 indexed Use sizeof(variable) instead of sizeof(type) (Ville) v6: Use the for_each_crtc() macro instead of list_for_each_entry() Signed-off-by: Damien Lespiau <damien.lespiau@xxxxxxxxx> --- drivers/gpu/drm/i915/intel_pm.c | 148 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1db4aa8..3dc689e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2965,6 +2965,153 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); } +/* + * On gen9, we need to allocate Display Data Buffer (DDB) portions to the + * different active planes. + */ + +#define SKL_DDB_SIZE 896 /* in blocks */ + +static void +skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, + struct drm_crtc *for_crtc, + const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, + struct skl_ddb_entry *alloc /* out */) +{ + struct drm_crtc *crtc; + unsigned int pipe_size, ddb_size; + int nth_active_pipe; + + if (!params->active) { + alloc->start = 0; + alloc->end = 0; + return; + } + + ddb_size = SKL_DDB_SIZE; + + ddb_size -= 4; /* 4 blocks for bypass path allocation */ + + nth_active_pipe = 0; + for_each_crtc(dev, crtc) { + if (!intel_crtc_active(crtc)) + continue; + + if (crtc == for_crtc) + break; + + nth_active_pipe++; + } + + pipe_size = ddb_size / config->num_pipes_active; + alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active; + alloc->end = alloc->start + pipe_size - 1; +} + +static unsigned int skl_cursor_allocation(const struct intel_wm_config *config) +{ + if (config->num_pipes_active == 1) + return 32; + + return 8; +} + +static unsigned int +skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p) +{ + return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel; +} + +/* + * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching + * a 8192x4096@32bpp framebuffer: + * 3 * 4096 * 8192 * 4 < 2^32 + */ +static unsigned int +skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc, + const struct skl_pipe_wm_parameters *params) +{ + unsigned int total_data_rate = 0; + int plane; + + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; + + p = ¶ms->plane[plane]; + if (!p->enabled) + continue; + + total_data_rate += skl_plane_relative_data_rate(p); + } + + return total_data_rate; +} + +static void +skl_allocate_pipe_ddb(struct drm_crtc *crtc, + const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, + struct skl_ddb_allocation *ddb /* out */) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct skl_ddb_entry alloc; + uint16_t alloc_size, start, cursor_blocks; + unsigned int total_data_rate; + int plane; + + skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc); + alloc_size = skl_ddb_entry_size(&alloc); + if (alloc_size == 0) { + memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); + memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe])); + return; + } + + cursor_blocks = skl_cursor_allocation(config); + ddb->cursor[pipe].start = alloc.end - cursor_blocks + 1; + ddb->cursor[pipe].end = alloc.end; + + alloc_size -= cursor_blocks; + alloc.end -= cursor_blocks; + + /* + * Each active plane get a portion of the remaining space, in + * proportion to the amount of data they need to fetch from memory. + * + * FIXME: we may not allocate every single block here. + */ + total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); + + start = alloc.start; + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; + unsigned int data_rate; + uint16_t plane_blocks; + + p = ¶ms->plane[plane]; + if (!p->enabled) + continue; + + data_rate = skl_plane_relative_data_rate(p); + + /* + * promote the expression to 64 bits to avoid overflowing, the + * result is < available as data_rate / total_data_rate < 1 + */ + plane_blocks = div_u64((uint64_t)alloc_size * data_rate, + total_data_rate); + + ddb->plane[pipe][plane].start = start; + ddb->plane[pipe][plane].end = start + plane_blocks - 1; + + start += plane_blocks; + } + +} + static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config) { /* TODO: Take into account the scalers once we support them */ @@ -3286,6 +3433,7 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); skl_compute_wm_pipe_parameters(crtc, params); + skl_allocate_pipe_ddb(crtc, config, params, ddb); skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) -- 1.8.3.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx