// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com>
*/
if (WARN_ON(plane >= pipe2nclients(pipe))) return CID_UNUSED;
/* * Note on SMP clients: * For ViG pipes, fetch Y/Cr/Cb-components clients are always * consecutive, and in that order. * * e.g.: * if mdp5_cfg->smp.clients[SSPP_VIG0] = N, * Y plane's client ID is N * Cr plane's client ID is N + 1 * Cb plane's client ID is N + 2
*/
return mdp5_cfg->smp.clients[pipe] + plane;
}
/* allocate blocks for the specified request: */ staticint smp_request_block(struct mdp5_smp *smp, struct mdp5_smp_state *state,
u32 cid, int nblks)
{ void *cs = state->client_state[cid]; int i, avail, cnt = smp->blk_cnt;
uint8_t reserved;
/* we shouldn't be requesting blocks for an in-use client: */
WARN_ON(!bitmap_empty(cs, cnt));
/* 1/4 of SMP pool that is being fetched */
val = (nblks * smp_entries_per_blk) / 4;
smp->pipe_reqprio_fifo_wm0[pipe] = val * 1;
smp->pipe_reqprio_fifo_wm1[pipe] = val * 2;
smp->pipe_reqprio_fifo_wm2[pipe] = val * 3;
}
/* * NOTE: looks like if horizontal decimation is used (if we supported that) * then the width used to calculate SMP block requirements is the post- * decimated width. Ie. SMP buffering sits downstream of decimation (which * presumably happens during the dma from scanout buffer).
*/
uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, conststruct msm_format *format,
u32 width, bool hdecim)
{ conststruct drm_format_info *info = drm_format_info(format->pixel_format); struct mdp5_kms *mdp5_kms = get_kms(smp); int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); int i, hsub, nplanes, nlines;
uint32_t blkcfg = 0;
nplanes = info->num_planes;
hsub = info->hsub;
/* different if BWC (compressed framebuffer?) enabled: */
nlines = 2;
/* Newer MDPs have split/packing logic, which fetches sub-sampled * U and V components (splits them from Y if necessary) and packs * them together, writes to SMP using a single client.
*/ if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
nplanes = 2;
/* if decimation is enabled, HW decimates less on the * sub sampled chroma components
*/ if (hdecim && (hsub > 1))
hsub = 1;
}
for (i = 0; i < nplanes; i++) { int n, fetch_stride, cpp;
n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size);
/* for hw rev v1.00 */ if (rev == 0)
n = roundup_pow_of_two(n);
blkcfg |= (n << (8 * i));
}
return blkcfg;
}
int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state, enum mdp5_pipe pipe, uint32_t blkcfg)
{ struct mdp5_kms *mdp5_kms = get_kms(smp); struct drm_device *dev = mdp5_kms->dev; int i, ret;
for (i = 0; i < pipe2nclients(pipe); i++) {
u32 cid = pipe2client(pipe, i); int n = blkcfg & 0xff;
if (!n) continue;
DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
ret = smp_request_block(smp, state, cid, n); if (ret) {
DRM_DEV_ERROR(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
n, ret); return ret;
}
blkcfg >>= 8;
}
state->assigned |= (1 << pipe);
return 0;
}
/* Release SMP blocks for all clients of the pipe */ void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state, enum mdp5_pipe pipe)
{ int i; int cnt = smp->blk_cnt;
for (i = 0; i < pipe2nclients(pipe); i++) {
u32 cid = pipe2client(pipe, i); void *cs = state->client_state[cid];
/* update global state: */
bitmap_andnot(state->state, state->state, cs, cnt);
/* clear client's state */
bitmap_zero(cs, cnt);
}
state->released |= (1 << pipe);
}
/* NOTE: SMP_ALLOC_* regs are *not* double buffered, so release has to * happen after scanout completes.
*/ staticunsigned update_smp_state(struct mdp5_smp *smp,
u32 cid, mdp5_smp_state_t *assigned)
{ int cnt = smp->blk_cnt; unsigned nblks = 0;
u32 blk, val;
for_each_set_bit(blk, *assigned, cnt) { int idx = blk / 3; int fld = blk % 3;
val = smp->alloc_w[idx];
switch (fld) { case 0:
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); break; case 1:
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); break; case 2:
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); break;
}
smp->alloc_w[idx] = val;
smp->alloc_r[idx] = val;
nblks++;
}
return nblks;
}
staticvoid write_smp_alloc_regs(struct mdp5_smp *smp)
{ struct mdp5_kms *mdp5_kms = get_kms(smp); int i, num_regs;
num_regs = smp->blk_cnt / 3 + 1;
for (i = 0; i < num_regs; i++) {
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i),
smp->alloc_w[i]);
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i),
smp->alloc_r[i]);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.