0001
0002
0003
0004
0005
0006
0007
0008 #include <drm/drm_fourcc.h>
0009 #include <drm/drm_util.h>
0010
0011 #include "mdp5_kms.h"
0012 #include "mdp5_smp.h"
0013
0014
0015 struct mdp5_smp {
0016 struct drm_device *dev;
0017
0018 uint8_t reserved[MAX_CLIENTS];
0019
0020 int blk_cnt;
0021 int blk_size;
0022
0023
0024 u32 alloc_w[22];
0025 u32 alloc_r[22];
0026 u32 pipe_reqprio_fifo_wm0[SSPP_MAX];
0027 u32 pipe_reqprio_fifo_wm1[SSPP_MAX];
0028 u32 pipe_reqprio_fifo_wm2[SSPP_MAX];
0029 };
0030
0031 static inline
0032 struct mdp5_kms *get_kms(struct mdp5_smp *smp)
0033 {
0034 struct msm_drm_private *priv = smp->dev->dev_private;
0035
0036 return to_mdp5_kms(to_mdp_kms(priv->kms));
0037 }
0038
0039 static inline u32 pipe2client(enum mdp5_pipe pipe, int plane)
0040 {
0041 #define CID_UNUSED 0
0042
0043 if (WARN_ON(plane >= pipe2nclients(pipe)))
0044 return CID_UNUSED;
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 return mdp5_cfg->smp.clients[pipe] + plane;
0059 }
0060
0061
0062 static int smp_request_block(struct mdp5_smp *smp,
0063 struct mdp5_smp_state *state,
0064 u32 cid, int nblks)
0065 {
0066 void *cs = state->client_state[cid];
0067 int i, avail, cnt = smp->blk_cnt;
0068 uint8_t reserved;
0069
0070
0071 WARN_ON(!bitmap_empty(cs, cnt));
0072
0073 reserved = smp->reserved[cid];
0074
0075 if (reserved) {
0076 nblks = max(0, nblks - reserved);
0077 DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
0078 }
0079
0080 avail = cnt - bitmap_weight(state->state, cnt);
0081 if (nblks > avail) {
0082 DRM_DEV_ERROR(smp->dev->dev, "out of blks (req=%d > avail=%d)\n",
0083 nblks, avail);
0084 return -ENOSPC;
0085 }
0086
0087 for (i = 0; i < nblks; i++) {
0088 int blk = find_first_zero_bit(state->state, cnt);
0089 set_bit(blk, cs);
0090 set_bit(blk, state->state);
0091 }
0092
0093 return 0;
0094 }
0095
0096 static void set_fifo_thresholds(struct mdp5_smp *smp,
0097 enum mdp5_pipe pipe, int nblks)
0098 {
0099 u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE);
0100 u32 val;
0101
0102
0103 val = (nblks * smp_entries_per_blk) / 4;
0104
0105 smp->pipe_reqprio_fifo_wm0[pipe] = val * 1;
0106 smp->pipe_reqprio_fifo_wm1[pipe] = val * 2;
0107 smp->pipe_reqprio_fifo_wm2[pipe] = val * 3;
0108 }
0109
0110
0111
0112
0113
0114
0115
0116 uint32_t mdp5_smp_calculate(struct mdp5_smp *smp,
0117 const struct mdp_format *format,
0118 u32 width, bool hdecim)
0119 {
0120 const struct drm_format_info *info = drm_format_info(format->base.pixel_format);
0121 struct mdp5_kms *mdp5_kms = get_kms(smp);
0122 int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
0123 int i, hsub, nplanes, nlines;
0124 uint32_t blkcfg = 0;
0125
0126 nplanes = info->num_planes;
0127 hsub = info->hsub;
0128
0129
0130 nlines = 2;
0131
0132
0133
0134
0135
0136 if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
0137 nplanes = 2;
0138
0139
0140
0141
0142 if (hdecim && (hsub > 1))
0143 hsub = 1;
0144 }
0145
0146 for (i = 0; i < nplanes; i++) {
0147 int n, fetch_stride, cpp;
0148
0149 cpp = info->cpp[i];
0150 fetch_stride = width * cpp / (i ? hsub : 1);
0151
0152 n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size);
0153
0154
0155 if (rev == 0)
0156 n = roundup_pow_of_two(n);
0157
0158 blkcfg |= (n << (8 * i));
0159 }
0160
0161 return blkcfg;
0162 }
0163
0164 int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
0165 enum mdp5_pipe pipe, uint32_t blkcfg)
0166 {
0167 struct mdp5_kms *mdp5_kms = get_kms(smp);
0168 struct drm_device *dev = mdp5_kms->dev;
0169 int i, ret;
0170
0171 for (i = 0; i < pipe2nclients(pipe); i++) {
0172 u32 cid = pipe2client(pipe, i);
0173 int n = blkcfg & 0xff;
0174
0175 if (!n)
0176 continue;
0177
0178 DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
0179 ret = smp_request_block(smp, state, cid, n);
0180 if (ret) {
0181 DRM_DEV_ERROR(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
0182 n, ret);
0183 return ret;
0184 }
0185
0186 blkcfg >>= 8;
0187 }
0188
0189 state->assigned |= (1 << pipe);
0190
0191 return 0;
0192 }
0193
0194
0195 void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
0196 enum mdp5_pipe pipe)
0197 {
0198 int i;
0199 int cnt = smp->blk_cnt;
0200
0201 for (i = 0; i < pipe2nclients(pipe); i++) {
0202 u32 cid = pipe2client(pipe, i);
0203 void *cs = state->client_state[cid];
0204
0205
0206 bitmap_andnot(state->state, state->state, cs, cnt);
0207
0208
0209 bitmap_zero(cs, cnt);
0210 }
0211
0212 state->released |= (1 << pipe);
0213 }
0214
0215
0216
0217
0218 static unsigned update_smp_state(struct mdp5_smp *smp,
0219 u32 cid, mdp5_smp_state_t *assigned)
0220 {
0221 int cnt = smp->blk_cnt;
0222 unsigned nblks = 0;
0223 u32 blk, val;
0224
0225 for_each_set_bit(blk, *assigned, cnt) {
0226 int idx = blk / 3;
0227 int fld = blk % 3;
0228
0229 val = smp->alloc_w[idx];
0230
0231 switch (fld) {
0232 case 0:
0233 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
0234 val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
0235 break;
0236 case 1:
0237 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
0238 val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
0239 break;
0240 case 2:
0241 val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
0242 val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
0243 break;
0244 }
0245
0246 smp->alloc_w[idx] = val;
0247 smp->alloc_r[idx] = val;
0248
0249 nblks++;
0250 }
0251
0252 return nblks;
0253 }
0254
0255 static void write_smp_alloc_regs(struct mdp5_smp *smp)
0256 {
0257 struct mdp5_kms *mdp5_kms = get_kms(smp);
0258 int i, num_regs;
0259
0260 num_regs = smp->blk_cnt / 3 + 1;
0261
0262 for (i = 0; i < num_regs; i++) {
0263 mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i),
0264 smp->alloc_w[i]);
0265 mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i),
0266 smp->alloc_r[i]);
0267 }
0268 }
0269
0270 static void write_smp_fifo_regs(struct mdp5_smp *smp)
0271 {
0272 struct mdp5_kms *mdp5_kms = get_kms(smp);
0273 int i;
0274
0275 for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
0276 struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
0277 enum mdp5_pipe pipe = hwpipe->pipe;
0278
0279 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe),
0280 smp->pipe_reqprio_fifo_wm0[pipe]);
0281 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe),
0282 smp->pipe_reqprio_fifo_wm1[pipe]);
0283 mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe),
0284 smp->pipe_reqprio_fifo_wm2[pipe]);
0285 }
0286 }
0287
0288 void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
0289 {
0290 enum mdp5_pipe pipe;
0291
0292 for_each_set_bit(pipe, &state->assigned, sizeof(state->assigned) * 8) {
0293 unsigned i, nblks = 0;
0294
0295 for (i = 0; i < pipe2nclients(pipe); i++) {
0296 u32 cid = pipe2client(pipe, i);
0297 void *cs = state->client_state[cid];
0298
0299 nblks += update_smp_state(smp, cid, cs);
0300
0301 DBG("assign %s:%u, %u blks",
0302 pipe2name(pipe), i, nblks);
0303 }
0304
0305 set_fifo_thresholds(smp, pipe, nblks);
0306 }
0307
0308 write_smp_alloc_regs(smp);
0309 write_smp_fifo_regs(smp);
0310
0311 state->assigned = 0;
0312 }
0313
0314 void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
0315 {
0316 enum mdp5_pipe pipe;
0317
0318 for_each_set_bit(pipe, &state->released, sizeof(state->released) * 8) {
0319 DBG("release %s", pipe2name(pipe));
0320 set_fifo_thresholds(smp, pipe, 0);
0321 }
0322
0323 write_smp_fifo_regs(smp);
0324
0325 state->released = 0;
0326 }
0327
0328 void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p)
0329 {
0330 struct mdp5_kms *mdp5_kms = get_kms(smp);
0331 struct mdp5_hw_pipe_state *hwpstate;
0332 struct mdp5_smp_state *state;
0333 struct mdp5_global_state *global_state;
0334 int total = 0, i, j;
0335
0336 drm_printf(p, "name\tinuse\tplane\n");
0337 drm_printf(p, "----\t-----\t-----\n");
0338
0339 if (drm_can_sleep())
0340 drm_modeset_lock(&mdp5_kms->glob_state_lock, NULL);
0341
0342 global_state = mdp5_get_existing_global_state(mdp5_kms);
0343
0344
0345 hwpstate = &global_state->hwpipe;
0346 state = &global_state->smp;
0347
0348 for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
0349 struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
0350 struct drm_plane *plane = hwpstate->hwpipe_to_plane[hwpipe->idx];
0351 enum mdp5_pipe pipe = hwpipe->pipe;
0352 for (j = 0; j < pipe2nclients(pipe); j++) {
0353 u32 cid = pipe2client(pipe, j);
0354 void *cs = state->client_state[cid];
0355 int inuse = bitmap_weight(cs, smp->blk_cnt);
0356
0357 drm_printf(p, "%s:%d\t%d\t%s\n",
0358 pipe2name(pipe), j, inuse,
0359 plane ? plane->name : NULL);
0360
0361 total += inuse;
0362 }
0363 }
0364
0365 drm_printf(p, "TOTAL:\t%d\t(of %d)\n", total, smp->blk_cnt);
0366 drm_printf(p, "AVAIL:\t%d\n", smp->blk_cnt -
0367 bitmap_weight(state->state, smp->blk_cnt));
0368
0369 if (drm_can_sleep())
0370 drm_modeset_unlock(&mdp5_kms->glob_state_lock);
0371 }
0372
0373 void mdp5_smp_destroy(struct mdp5_smp *smp)
0374 {
0375 kfree(smp);
0376 }
0377
0378 struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg)
0379 {
0380 struct mdp5_smp_state *state;
0381 struct mdp5_global_state *global_state;
0382 struct mdp5_smp *smp = NULL;
0383 int ret;
0384
0385 smp = kzalloc(sizeof(*smp), GFP_KERNEL);
0386 if (unlikely(!smp)) {
0387 ret = -ENOMEM;
0388 goto fail;
0389 }
0390
0391 smp->dev = mdp5_kms->dev;
0392 smp->blk_cnt = cfg->mmb_count;
0393 smp->blk_size = cfg->mmb_size;
0394
0395 global_state = mdp5_get_existing_global_state(mdp5_kms);
0396 state = &global_state->smp;
0397
0398
0399 bitmap_copy(state->state, cfg->reserved_state, smp->blk_cnt);
0400 memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved));
0401
0402 return smp;
0403 fail:
0404 if (smp)
0405 mdp5_smp_destroy(smp);
0406
0407 return ERR_PTR(ret);
0408 }