1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4 * Copyright (C) 2013 Red Hat 5 * Author: Rob Clark <robdclark@gmail.com> 6 */ 7 8 #include <drm/drm_util.h> 9 10 #include "mdp5_kms.h" 11 #include "mdp5_smp.h" 12 13 14 struct mdp5_smp { 15 struct drm_device *dev; 16 17 uint8_t reserved[MAX_CLIENTS]; /* fixed MMBs allocation per client */ 18 19 int blk_cnt; 20 int blk_size; 21 22 /* register cache */ 23 u32 alloc_w[22]; 24 u32 alloc_r[22]; 25 u32 pipe_reqprio_fifo_wm0[SSPP_MAX]; 26 u32 pipe_reqprio_fifo_wm1[SSPP_MAX]; 27 u32 pipe_reqprio_fifo_wm2[SSPP_MAX]; 28 }; 29 30 static inline 31 struct mdp5_kms *get_kms(struct mdp5_smp *smp) 32 { 33 struct msm_drm_private *priv = smp->dev->dev_private; 34 35 return to_mdp5_kms(to_mdp_kms(priv->kms)); 36 } 37 38 static inline u32 pipe2client(enum mdp5_pipe pipe, int plane) 39 { 40 #define CID_UNUSED 0 41 42 if (WARN_ON(plane >= pipe2nclients(pipe))) 43 return CID_UNUSED; 44 45 /* 46 * Note on SMP clients: 47 * For ViG pipes, fetch Y/Cr/Cb-components clients are always 48 * consecutive, and in that order. 49 * 50 * e.g.: 51 * if mdp5_cfg->smp.clients[SSPP_VIG0] = N, 52 * Y plane's client ID is N 53 * Cr plane's client ID is N + 1 54 * Cb plane's client ID is N + 2 55 */ 56 57 return mdp5_cfg->smp.clients[pipe] + plane; 58 } 59 60 /* allocate blocks for the specified request: */ 61 static int smp_request_block(struct mdp5_smp *smp, 62 struct mdp5_smp_state *state, 63 u32 cid, int nblks) 64 { 65 void *cs = state->client_state[cid]; 66 int i, avail, cnt = smp->blk_cnt; 67 uint8_t reserved; 68 69 /* we shouldn't be requesting blocks for an in-use client: */ 70 WARN_ON(bitmap_weight(cs, cnt) > 0); 71 72 reserved = smp->reserved[cid]; 73 74 if (reserved) { 75 nblks = max(0, nblks - reserved); 76 DBG("%d MMBs allocated (%d reserved)", nblks, reserved); 77 } 78 79 avail = cnt - bitmap_weight(state->state, cnt); 80 if (nblks > avail) { 81 DRM_DEV_ERROR(smp->dev->dev, "out of blks (req=%d > avail=%d)\n", 82 nblks, avail); 83 return -ENOSPC; 84 } 85 86 for (i = 0; i < nblks; i++) { 87 int blk = find_first_zero_bit(state->state, cnt); 88 set_bit(blk, cs); 89 set_bit(blk, state->state); 90 } 91 92 return 0; 93 } 94 95 static void set_fifo_thresholds(struct mdp5_smp *smp, 96 enum mdp5_pipe pipe, int nblks) 97 { 98 u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE); 99 u32 val; 100 101 /* 1/4 of SMP pool that is being fetched */ 102 val = (nblks * smp_entries_per_blk) / 4; 103 104 smp->pipe_reqprio_fifo_wm0[pipe] = val * 1; 105 smp->pipe_reqprio_fifo_wm1[pipe] = val * 2; 106 smp->pipe_reqprio_fifo_wm2[pipe] = val * 3; 107 } 108 109 /* 110 * NOTE: looks like if horizontal decimation is used (if we supported that) 111 * then the width used to calculate SMP block requirements is the post- 112 * decimated width. Ie. SMP buffering sits downstream of decimation (which 113 * presumably happens during the dma from scanout buffer). 114 */ 115 uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, 116 const struct mdp_format *format, 117 u32 width, bool hdecim) 118 { 119 const struct drm_format_info *info = drm_format_info(format->base.pixel_format); 120 struct mdp5_kms *mdp5_kms = get_kms(smp); 121 int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); 122 int i, hsub, nplanes, nlines; 123 u32 fmt = format->base.pixel_format; 124 uint32_t blkcfg = 0; 125 126 nplanes = info->num_planes; 127 hsub = info->hsub; 128 129 /* different if BWC (compressed framebuffer?) enabled: */ 130 nlines = 2; 131 132 /* Newer MDPs have split/packing logic, which fetches sub-sampled 133 * U and V components (splits them from Y if necessary) and packs 134 * them together, writes to SMP using a single client. 135 */ 136 if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) { 137 fmt = DRM_FORMAT_NV24; 138 nplanes = 2; 139 140 /* if decimation is enabled, HW decimates less on the 141 * sub sampled chroma components 142 */ 143 if (hdecim && (hsub > 1)) 144 hsub = 1; 145 } 146 147 for (i = 0; i < nplanes; i++) { 148 int n, fetch_stride, cpp; 149 150 cpp = info->cpp[i]; 151 fetch_stride = width * cpp / (i ? hsub : 1); 152 153 n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); 154 155 /* for hw rev v1.00 */ 156 if (rev == 0) 157 n = roundup_pow_of_two(n); 158 159 blkcfg |= (n << (8 * i)); 160 } 161 162 return blkcfg; 163 } 164 165 int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state, 166 enum mdp5_pipe pipe, uint32_t blkcfg) 167 { 168 struct mdp5_kms *mdp5_kms = get_kms(smp); 169 struct drm_device *dev = mdp5_kms->dev; 170 int i, ret; 171 172 for (i = 0; i < pipe2nclients(pipe); i++) { 173 u32 cid = pipe2client(pipe, i); 174 int n = blkcfg & 0xff; 175 176 if (!n) 177 continue; 178 179 DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n); 180 ret = smp_request_block(smp, state, cid, n); 181 if (ret) { 182 DRM_DEV_ERROR(dev->dev, "Cannot allocate %d SMP blocks: %d\n", 183 n, ret); 184 return ret; 185 } 186 187 blkcfg >>= 8; 188 } 189 190 state->assigned |= (1 << pipe); 191 192 return 0; 193 } 194 195 /* Release SMP blocks for all clients of the pipe */ 196 void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state, 197 enum mdp5_pipe pipe) 198 { 199 int i; 200 int cnt = smp->blk_cnt; 201 202 for (i = 0; i < pipe2nclients(pipe); i++) { 203 u32 cid = pipe2client(pipe, i); 204 void *cs = state->client_state[cid]; 205 206 /* update global state: */ 207 bitmap_andnot(state->state, state->state, cs, cnt); 208 209 /* clear client's state */ 210 bitmap_zero(cs, cnt); 211 } 212 213 state->released |= (1 << pipe); 214 } 215 216 /* NOTE: SMP_ALLOC_* regs are *not* double buffered, so release has to 217 * happen after scanout completes. 218 */ 219 static unsigned update_smp_state(struct mdp5_smp *smp, 220 u32 cid, mdp5_smp_state_t *assigned) 221 { 222 int cnt = smp->blk_cnt; 223 unsigned nblks = 0; 224 u32 blk, val; 225 226 for_each_set_bit(blk, *assigned, cnt) { 227 int idx = blk / 3; 228 int fld = blk % 3; 229 230 val = smp->alloc_w[idx]; 231 232 switch (fld) { 233 case 0: 234 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; 235 val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); 236 break; 237 case 1: 238 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; 239 val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); 240 break; 241 case 2: 242 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; 243 val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); 244 break; 245 } 246 247 smp->alloc_w[idx] = val; 248 smp->alloc_r[idx] = val; 249 250 nblks++; 251 } 252 253 return nblks; 254 } 255 256 static void write_smp_alloc_regs(struct mdp5_smp *smp) 257 { 258 struct mdp5_kms *mdp5_kms = get_kms(smp); 259 int i, num_regs; 260 261 num_regs = smp->blk_cnt / 3 + 1; 262 263 for (i = 0; i < num_regs; i++) { 264 mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i), 265 smp->alloc_w[i]); 266 mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i), 267 smp->alloc_r[i]); 268 } 269 } 270 271 static void write_smp_fifo_regs(struct mdp5_smp *smp) 272 { 273 struct mdp5_kms *mdp5_kms = get_kms(smp); 274 int i; 275 276 for (i = 0; i < mdp5_kms->num_hwpipes; i++) { 277 struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i]; 278 enum mdp5_pipe pipe = hwpipe->pipe; 279 280 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), 281 smp->pipe_reqprio_fifo_wm0[pipe]); 282 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), 283 smp->pipe_reqprio_fifo_wm1[pipe]); 284 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), 285 smp->pipe_reqprio_fifo_wm2[pipe]); 286 } 287 } 288 289 void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state) 290 { 291 enum mdp5_pipe pipe; 292 293 for_each_set_bit(pipe, &state->assigned, sizeof(state->assigned) * 8) { 294 unsigned i, nblks = 0; 295 296 for (i = 0; i < pipe2nclients(pipe); i++) { 297 u32 cid = pipe2client(pipe, i); 298 void *cs = state->client_state[cid]; 299 300 nblks += update_smp_state(smp, cid, cs); 301 302 DBG("assign %s:%u, %u blks", 303 pipe2name(pipe), i, nblks); 304 } 305 306 set_fifo_thresholds(smp, pipe, nblks); 307 } 308 309 write_smp_alloc_regs(smp); 310 write_smp_fifo_regs(smp); 311 312 state->assigned = 0; 313 } 314 315 void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state) 316 { 317 enum mdp5_pipe pipe; 318 319 for_each_set_bit(pipe, &state->released, sizeof(state->released) * 8) { 320 DBG("release %s", pipe2name(pipe)); 321 set_fifo_thresholds(smp, pipe, 0); 322 } 323 324 write_smp_fifo_regs(smp); 325 326 state->released = 0; 327 } 328 329 void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) 330 { 331 struct mdp5_kms *mdp5_kms = get_kms(smp); 332 struct mdp5_hw_pipe_state *hwpstate; 333 struct mdp5_smp_state *state; 334 struct mdp5_global_state *global_state; 335 int total = 0, i, j; 336 337 drm_printf(p, "name\tinuse\tplane\n"); 338 drm_printf(p, "----\t-----\t-----\n"); 339 340 if (drm_can_sleep()) 341 drm_modeset_lock(&mdp5_kms->glob_state_lock, NULL); 342 343 global_state = mdp5_get_existing_global_state(mdp5_kms); 344 345 /* grab these *after* we hold the state_lock */ 346 hwpstate = &global_state->hwpipe; 347 state = &global_state->smp; 348 349 for (i = 0; i < mdp5_kms->num_hwpipes; i++) { 350 struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i]; 351 struct drm_plane *plane = hwpstate->hwpipe_to_plane[hwpipe->idx]; 352 enum mdp5_pipe pipe = hwpipe->pipe; 353 for (j = 0; j < pipe2nclients(pipe); j++) { 354 u32 cid = pipe2client(pipe, j); 355 void *cs = state->client_state[cid]; 356 int inuse = bitmap_weight(cs, smp->blk_cnt); 357 358 drm_printf(p, "%s:%d\t%d\t%s\n", 359 pipe2name(pipe), j, inuse, 360 plane ? plane->name : NULL); 361 362 total += inuse; 363 } 364 } 365 366 drm_printf(p, "TOTAL:\t%d\t(of %d)\n", total, smp->blk_cnt); 367 drm_printf(p, "AVAIL:\t%d\n", smp->blk_cnt - 368 bitmap_weight(state->state, smp->blk_cnt)); 369 370 if (drm_can_sleep()) 371 drm_modeset_unlock(&mdp5_kms->glob_state_lock); 372 } 373 374 void mdp5_smp_destroy(struct mdp5_smp *smp) 375 { 376 kfree(smp); 377 } 378 379 struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg) 380 { 381 struct mdp5_smp_state *state; 382 struct mdp5_global_state *global_state; 383 struct mdp5_smp *smp = NULL; 384 int ret; 385 386 smp = kzalloc(sizeof(*smp), GFP_KERNEL); 387 if (unlikely(!smp)) { 388 ret = -ENOMEM; 389 goto fail; 390 } 391 392 smp->dev = mdp5_kms->dev; 393 smp->blk_cnt = cfg->mmb_count; 394 smp->blk_size = cfg->mmb_size; 395 396 global_state = mdp5_get_existing_global_state(mdp5_kms); 397 state = &global_state->smp; 398 399 /* statically tied MMBs cannot be re-allocated: */ 400 bitmap_copy(state->state, cfg->reserved_state, smp->blk_cnt); 401 memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); 402 403 return smp; 404 fail: 405 if (smp) 406 mdp5_smp_destroy(smp); 407 408 return ERR_PTR(ret); 409 } 410