diff options
| -rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_group.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_kms.c | 203 | ||||
| -rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_plane.c | 166 | ||||
| -rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_plane.h | 11 |
5 files changed, 228 insertions, 164 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 8459aaee8add..9e72133bb64b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | |||
| @@ -233,7 +233,8 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) | |||
| 233 | 233 | ||
| 234 | for (i = 0; i < num_planes; ++i) { | 234 | for (i = 0; i < num_planes; ++i) { |
| 235 | struct rcar_du_plane *plane = planes[i]; | 235 | struct rcar_du_plane *plane = planes[i]; |
| 236 | unsigned int index = plane->hwindex; | 236 | struct drm_plane_state *state = plane->plane.state; |
| 237 | unsigned int index = to_rcar_du_plane_state(state)->hwindex; | ||
| 237 | 238 | ||
| 238 | prio -= 4; | 239 | prio -= 4; |
| 239 | dspr |= (index + 1) << prio; | 240 | dspr |= (index + 1) << prio; |
| @@ -259,13 +260,13 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) | |||
| 259 | * split, or through a module parameter). Flicker would then | 260 | * split, or through a module parameter). Flicker would then |
| 260 | * occur only if we need to break the pre-association. | 261 | * occur only if we need to break the pre-association. |
| 261 | */ | 262 | */ |
| 262 | mutex_lock(&rcrtc->group->planes.lock); | 263 | mutex_lock(&rcrtc->group->lock); |
| 263 | if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) { | 264 | if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) { |
| 264 | rcar_du_group_write(rcrtc->group, DPTSR, dptsr); | 265 | rcar_du_group_write(rcrtc->group, DPTSR, dptsr); |
| 265 | if (rcrtc->group->used_crtcs) | 266 | if (rcrtc->group->used_crtcs) |
| 266 | rcar_du_group_restart(rcrtc->group); | 267 | rcar_du_group_restart(rcrtc->group); |
| 267 | } | 268 | } |
| 268 | mutex_unlock(&rcrtc->group->planes.lock); | 269 | mutex_unlock(&rcrtc->group->lock); |
| 269 | } | 270 | } |
| 270 | 271 | ||
| 271 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, | 272 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 0c38cdcda4ca..ed36433fbe84 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #ifndef __RCAR_DU_GROUP_H__ | 14 | #ifndef __RCAR_DU_GROUP_H__ |
| 15 | #define __RCAR_DU_GROUP_H__ | 15 | #define __RCAR_DU_GROUP_H__ |
| 16 | 16 | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | |||
| 17 | #include "rcar_du_plane.h" | 19 | #include "rcar_du_plane.h" |
| 18 | 20 | ||
| 19 | struct rcar_du_device; | 21 | struct rcar_du_device; |
| @@ -25,6 +27,7 @@ struct rcar_du_device; | |||
| 25 | * @index: group index | 27 | * @index: group index |
| 26 | * @use_count: number of users of the group (rcar_du_group_(get|put)) | 28 | * @use_count: number of users of the group (rcar_du_group_(get|put)) |
| 27 | * @used_crtcs: number of CRTCs currently in use | 29 | * @used_crtcs: number of CRTCs currently in use |
| 30 | * @lock: protects the DPTSR register | ||
| 28 | * @planes: planes handled by the group | 31 | * @planes: planes handled by the group |
| 29 | */ | 32 | */ |
| 30 | struct rcar_du_group { | 33 | struct rcar_du_group { |
| @@ -35,6 +38,8 @@ struct rcar_du_group { | |||
| 35 | unsigned int use_count; | 38 | unsigned int use_count; |
| 36 | unsigned int used_crtcs; | 39 | unsigned int used_crtcs; |
| 37 | 40 | ||
| 41 | struct mutex lock; | ||
| 42 | |||
| 38 | struct rcar_du_planes planes; | 43 | struct rcar_du_planes planes; |
| 39 | }; | 44 | }; |
| 40 | 45 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 8bc7242ba979..fb052bca574f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c | |||
| @@ -189,9 +189,206 @@ static void rcar_du_output_poll_changed(struct drm_device *dev) | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /* ----------------------------------------------------------------------------- | 191 | /* ----------------------------------------------------------------------------- |
| 192 | * Atomic Updates | 192 | * Atomic Check and Update |
| 193 | */ | 193 | */ |
| 194 | 194 | ||
| 195 | /* | ||
| 196 | * Atomic hardware plane allocator | ||
| 197 | * | ||
| 198 | * The hardware plane allocator is solely based on the atomic plane states | ||
| 199 | * without keeping any external state to avoid races between .atomic_check() | ||
| 200 | * and .atomic_commit(). | ||
| 201 | * | ||
| 202 | * The core idea is to avoid using a free planes bitmask that would need to be | ||
| 203 | * shared between check and commit handlers with a collective knowledge based on | ||
| 204 | * the allocated hardware plane(s) for each KMS plane. The allocator then loops | ||
| 205 | * over all plane states to compute the free planes bitmask, allocates hardware | ||
| 206 | * planes based on that bitmask, and stores the result back in the plane states. | ||
| 207 | * | ||
| 208 | * For this to work we need to access the current state of planes not touched by | ||
| 209 | * the atomic update. To ensure that it won't be modified, we need to lock all | ||
| 210 | * planes using drm_atomic_get_plane_state(). This effectively serializes atomic | ||
| 211 | * updates from .atomic_check() up to completion (when swapping the states if | ||
| 212 | * the check step has succeeded) or rollback (when freeing the states if the | ||
| 213 | * check step has failed). | ||
| 214 | * | ||
| 215 | * Allocation is performed in the .atomic_check() handler and applied | ||
| 216 | * automatically when the core swaps the old and new states. | ||
| 217 | */ | ||
| 218 | |||
| 219 | static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane, | ||
| 220 | struct rcar_du_plane_state *state) | ||
| 221 | { | ||
| 222 | const struct rcar_du_format_info *cur_format; | ||
| 223 | |||
| 224 | cur_format = to_rcar_du_plane_state(plane->plane.state)->format; | ||
| 225 | |||
| 226 | /* Lowering the number of planes doesn't strictly require reallocation | ||
| 227 | * as the extra hardware plane will be freed when committing, but doing | ||
| 228 | * so could lead to more fragmentation. | ||
| 229 | */ | ||
| 230 | return !cur_format || cur_format->planes != state->format->planes; | ||
| 231 | } | ||
| 232 | |||
| 233 | static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) | ||
| 234 | { | ||
| 235 | unsigned int mask; | ||
| 236 | |||
| 237 | if (state->hwindex == -1) | ||
| 238 | return 0; | ||
| 239 | |||
| 240 | mask = 1 << state->hwindex; | ||
| 241 | if (state->format->planes == 2) | ||
| 242 | mask |= 1 << ((state->hwindex + 1) % 8); | ||
| 243 | |||
| 244 | return mask; | ||
| 245 | } | ||
| 246 | |||
| 247 | static int rcar_du_plane_hwalloc(unsigned int num_planes, unsigned int free) | ||
| 248 | { | ||
| 249 | unsigned int i; | ||
| 250 | |||
| 251 | for (i = 0; i < RCAR_DU_NUM_HW_PLANES; ++i) { | ||
| 252 | if (!(free & (1 << i))) | ||
| 253 | continue; | ||
| 254 | |||
| 255 | if (num_planes == 1 || free & (1 << ((i + 1) % 8))) | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | |||
| 259 | return i == RCAR_DU_NUM_HW_PLANES ? -EBUSY : i; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int rcar_du_atomic_check(struct drm_device *dev, | ||
| 263 | struct drm_atomic_state *state) | ||
| 264 | { | ||
| 265 | struct rcar_du_device *rcdu = dev->dev_private; | ||
| 266 | unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
| 267 | unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, }; | ||
| 268 | bool needs_realloc = false; | ||
| 269 | unsigned int groups = 0; | ||
| 270 | unsigned int i; | ||
| 271 | int ret; | ||
| 272 | |||
| 273 | ret = drm_atomic_helper_check(dev, state); | ||
| 274 | if (ret < 0) | ||
| 275 | return ret; | ||
| 276 | |||
| 277 | /* Check if hardware planes need to be reallocated. */ | ||
| 278 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
| 279 | struct rcar_du_plane_state *plane_state; | ||
| 280 | struct rcar_du_plane *plane; | ||
| 281 | unsigned int index; | ||
| 282 | |||
| 283 | if (!state->planes[i]) | ||
| 284 | continue; | ||
| 285 | |||
| 286 | plane = to_rcar_plane(state->planes[i]); | ||
| 287 | plane_state = to_rcar_du_plane_state(state->plane_states[i]); | ||
| 288 | |||
| 289 | /* If the plane is being disabled we don't need to go through | ||
| 290 | * the full reallocation procedure. Just mark the hardware | ||
| 291 | * plane(s) as freed. | ||
| 292 | */ | ||
| 293 | if (!plane_state->format) { | ||
| 294 | index = plane - plane->group->planes.planes; | ||
| 295 | group_freed_planes[plane->group->index] |= 1 << index; | ||
| 296 | plane_state->hwindex = -1; | ||
| 297 | continue; | ||
| 298 | } | ||
| 299 | |||
| 300 | /* If the plane needs to be reallocated mark it as such, and | ||
| 301 | * mark the hardware plane(s) as free. | ||
| 302 | */ | ||
| 303 | if (rcar_du_plane_needs_realloc(plane, plane_state)) { | ||
| 304 | groups |= 1 << plane->group->index; | ||
| 305 | needs_realloc = true; | ||
| 306 | |||
| 307 | index = plane - plane->group->planes.planes; | ||
| 308 | group_freed_planes[plane->group->index] |= 1 << index; | ||
| 309 | plane_state->hwindex = -1; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | if (!needs_realloc) | ||
| 314 | return 0; | ||
| 315 | |||
| 316 | /* Grab all plane states for the groups that need reallocation to ensure | ||
| 317 | * locking and avoid racy updates. This serializes the update operation, | ||
| 318 | * but there's not much we can do about it as that's the hardware | ||
| 319 | * design. | ||
| 320 | * | ||
| 321 | * Compute the used planes mask for each group at the same time to avoid | ||
| 322 | * looping over the planes separately later. | ||
| 323 | */ | ||
| 324 | while (groups) { | ||
| 325 | unsigned int index = ffs(groups) - 1; | ||
| 326 | struct rcar_du_group *group = &rcdu->groups[index]; | ||
| 327 | unsigned int used_planes = 0; | ||
| 328 | |||
| 329 | for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { | ||
| 330 | struct rcar_du_plane *plane = &group->planes.planes[i]; | ||
| 331 | struct rcar_du_plane_state *plane_state; | ||
| 332 | struct drm_plane_state *s; | ||
| 333 | |||
| 334 | s = drm_atomic_get_plane_state(state, &plane->plane); | ||
| 335 | if (IS_ERR(s)) | ||
| 336 | return PTR_ERR(s); | ||
| 337 | |||
| 338 | /* If the plane has been freed in the above loop its | ||
| 339 | * hardware planes must not be added to the used planes | ||
| 340 | * bitmask. However, the current state doesn't reflect | ||
| 341 | * the free state yet, as we've modified the new state | ||
| 342 | * above. Use the local freed planes list to check for | ||
| 343 | * that condition instead. | ||
| 344 | */ | ||
| 345 | if (group_freed_planes[index] & (1 << i)) | ||
| 346 | continue; | ||
| 347 | |||
| 348 | plane_state = to_rcar_du_plane_state(plane->plane.state); | ||
| 349 | used_planes |= rcar_du_plane_hwmask(plane_state); | ||
| 350 | } | ||
| 351 | |||
| 352 | group_free_planes[index] = 0xff & ~used_planes; | ||
| 353 | groups &= ~(1 << index); | ||
| 354 | } | ||
| 355 | |||
| 356 | /* Reallocate hardware planes for each plane that needs it. */ | ||
| 357 | for (i = 0; i < dev->mode_config.num_total_plane; ++i) { | ||
| 358 | struct rcar_du_plane_state *plane_state; | ||
| 359 | struct rcar_du_plane *plane; | ||
| 360 | int idx; | ||
| 361 | |||
| 362 | if (!state->planes[i]) | ||
| 363 | continue; | ||
| 364 | |||
| 365 | plane = to_rcar_plane(state->planes[i]); | ||
| 366 | plane_state = to_rcar_du_plane_state(state->plane_states[i]); | ||
| 367 | |||
| 368 | /* Skip planes that are being disabled or don't need to be | ||
| 369 | * reallocated. | ||
| 370 | */ | ||
| 371 | if (!plane_state->format || | ||
| 372 | !rcar_du_plane_needs_realloc(plane, plane_state)) | ||
| 373 | continue; | ||
| 374 | |||
| 375 | idx = rcar_du_plane_hwalloc(plane_state->format->planes, | ||
| 376 | group_free_planes[plane->group->index]); | ||
| 377 | if (idx < 0) { | ||
| 378 | dev_dbg(rcdu->dev, "%s: no available hardware plane\n", | ||
| 379 | __func__); | ||
| 380 | return idx; | ||
| 381 | } | ||
| 382 | |||
| 383 | plane_state->hwindex = idx; | ||
| 384 | |||
| 385 | group_free_planes[plane->group->index] &= | ||
| 386 | ~rcar_du_plane_hwmask(plane_state); | ||
| 387 | } | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 195 | struct rcar_du_commit { | 392 | struct rcar_du_commit { |
| 196 | struct work_struct work; | 393 | struct work_struct work; |
| 197 | struct drm_device *dev; | 394 | struct drm_device *dev; |
| @@ -292,7 +489,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev, | |||
| 292 | static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { | 489 | static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { |
| 293 | .fb_create = rcar_du_fb_create, | 490 | .fb_create = rcar_du_fb_create, |
| 294 | .output_poll_changed = rcar_du_output_poll_changed, | 491 | .output_poll_changed = rcar_du_output_poll_changed, |
| 295 | .atomic_check = drm_atomic_helper_check, | 492 | .atomic_check = rcar_du_atomic_check, |
| 296 | .atomic_commit = rcar_du_atomic_commit, | 493 | .atomic_commit = rcar_du_atomic_commit, |
| 297 | }; | 494 | }; |
| 298 | 495 | ||
| @@ -498,6 +695,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) | |||
| 498 | for (i = 0; i < num_groups; ++i) { | 695 | for (i = 0; i < num_groups; ++i) { |
| 499 | struct rcar_du_group *rgrp = &rcdu->groups[i]; | 696 | struct rcar_du_group *rgrp = &rcdu->groups[i]; |
| 500 | 697 | ||
| 698 | mutex_init(&rgrp->lock); | ||
| 699 | |||
| 501 | rgrp->dev = rcdu; | 700 | rgrp->dev = rcdu; |
| 502 | rgrp->mmio_offset = mmio_offsets[i]; | 701 | rgrp->mmio_offset = mmio_offsets[i]; |
| 503 | rgrp->index = i; | 702 | rgrp->index = i; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 58b9e02e6910..35a2f04ab799 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c | |||
| @@ -28,11 +28,6 @@ | |||
| 28 | #define RCAR_DU_COLORKEY_SOURCE (1 << 24) | 28 | #define RCAR_DU_COLORKEY_SOURCE (1 << 24) |
| 29 | #define RCAR_DU_COLORKEY_MASK (1 << 24) | 29 | #define RCAR_DU_COLORKEY_MASK (1 << 24) |
| 30 | 30 | ||
| 31 | static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane) | ||
| 32 | { | ||
| 33 | return container_of(plane, struct rcar_du_plane, plane); | ||
| 34 | } | ||
| 35 | |||
| 36 | static u32 rcar_du_plane_read(struct rcar_du_group *rgrp, | 31 | static u32 rcar_du_plane_read(struct rcar_du_group *rgrp, |
| 37 | unsigned int index, u32 reg) | 32 | unsigned int index, u32 reg) |
| 38 | { | 33 | { |
| @@ -47,90 +42,6 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp, | |||
| 47 | data); | 42 | data); |
| 48 | } | 43 | } |
| 49 | 44 | ||
| 50 | static int rcar_du_plane_reserve_check(struct rcar_du_plane *plane, | ||
| 51 | const struct rcar_du_format_info *cur_format, | ||
| 52 | const struct rcar_du_format_info *new_format) | ||
| 53 | { | ||
| 54 | struct rcar_du_group *rgrp = plane->group; | ||
| 55 | unsigned int free; | ||
| 56 | unsigned int i; | ||
| 57 | int ret; | ||
| 58 | |||
| 59 | mutex_lock(&rgrp->planes.lock); | ||
| 60 | |||
| 61 | free = rgrp->planes.free; | ||
| 62 | |||
| 63 | if (plane->hwindex != -1) { | ||
| 64 | free |= 1 << plane->hwindex; | ||
| 65 | if (cur_format->planes == 2) | ||
| 66 | free |= 1 << ((plane->hwindex + 1) % 8); | ||
| 67 | } | ||
| 68 | |||
| 69 | for (i = 0; i < ARRAY_SIZE(rgrp->planes.planes); ++i) { | ||
| 70 | if (!(free & (1 << i))) | ||
| 71 | continue; | ||
| 72 | |||
| 73 | if (new_format->planes == 1 || free & (1 << ((i + 1) % 8))) | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | |||
| 77 | ret = i == ARRAY_SIZE(rgrp->planes.planes) ? -EBUSY : 0; | ||
| 78 | |||
| 79 | mutex_unlock(&rgrp->planes.lock); | ||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int rcar_du_plane_reserve(struct rcar_du_plane *plane, | ||
| 84 | const struct rcar_du_format_info *format) | ||
| 85 | { | ||
| 86 | struct rcar_du_group *rgrp = plane->group; | ||
| 87 | unsigned int i; | ||
| 88 | int ret = -EBUSY; | ||
| 89 | |||
| 90 | mutex_lock(&rgrp->planes.lock); | ||
| 91 | |||
| 92 | for (i = 0; i < RCAR_DU_NUM_HW_PLANES; ++i) { | ||
| 93 | if (!(rgrp->planes.free & (1 << i))) | ||
| 94 | continue; | ||
| 95 | |||
| 96 | if (format->planes == 1 || | ||
| 97 | rgrp->planes.free & (1 << ((i + 1) % 8))) | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (i == RCAR_DU_NUM_HW_PLANES) | ||
| 102 | goto done; | ||
| 103 | |||
| 104 | rgrp->planes.free &= ~(1 << i); | ||
| 105 | if (format->planes == 2) | ||
| 106 | rgrp->planes.free &= ~(1 << ((i + 1) % 8)); | ||
| 107 | |||
| 108 | plane->hwindex = i; | ||
| 109 | |||
| 110 | ret = 0; | ||
| 111 | |||
| 112 | done: | ||
| 113 | mutex_unlock(&rgrp->planes.lock); | ||
| 114 | return ret; | ||
| 115 | } | ||
| 116 | |||
| 117 | static void rcar_du_plane_release(struct rcar_du_plane *plane, | ||
| 118 | const struct rcar_du_format_info *format) | ||
| 119 | { | ||
| 120 | struct rcar_du_group *rgrp = plane->group; | ||
| 121 | |||
| 122 | if (plane->hwindex == -1) | ||
| 123 | return; | ||
| 124 | |||
| 125 | mutex_lock(&rgrp->planes.lock); | ||
| 126 | rgrp->planes.free |= 1 << plane->hwindex; | ||
| 127 | if (format->planes == 2) | ||
| 128 | rgrp->planes.free |= 1 << ((plane->hwindex + 1) % 8); | ||
| 129 | mutex_unlock(&rgrp->planes.lock); | ||
| 130 | |||
| 131 | plane->hwindex = -1; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane) | 45 | static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane) |
| 135 | { | 46 | { |
| 136 | struct rcar_du_plane_state *state = | 47 | struct rcar_du_plane_state *state = |
| @@ -139,7 +50,7 @@ static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane) | |||
| 139 | struct rcar_du_group *rgrp = plane->group; | 50 | struct rcar_du_group *rgrp = plane->group; |
| 140 | unsigned int src_x = state->state.src_x >> 16; | 51 | unsigned int src_x = state->state.src_x >> 16; |
| 141 | unsigned int src_y = state->state.src_y >> 16; | 52 | unsigned int src_y = state->state.src_y >> 16; |
| 142 | unsigned int index = plane->hwindex; | 53 | unsigned int index = state->hwindex; |
| 143 | struct drm_gem_cma_object *gem; | 54 | struct drm_gem_cma_object *gem; |
| 144 | bool interlaced; | 55 | bool interlaced; |
| 145 | u32 mwr; | 56 | u32 mwr; |
| @@ -278,7 +189,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane, | |||
| 278 | rcar_du_plane_setup_mode(plane, index); | 189 | rcar_du_plane_setup_mode(plane, index); |
| 279 | 190 | ||
| 280 | if (state->format->planes == 2) { | 191 | if (state->format->planes == 2) { |
| 281 | if (plane->hwindex != index) { | 192 | if (state->hwindex != index) { |
| 282 | if (state->format->fourcc == DRM_FORMAT_NV12 || | 193 | if (state->format->fourcc == DRM_FORMAT_NV12 || |
| 283 | state->format->fourcc == DRM_FORMAT_NV21) | 194 | state->format->fourcc == DRM_FORMAT_NV21) |
| 284 | ddcr2 |= PnDDCR2_Y420; | 195 | ddcr2 |= PnDDCR2_Y420; |
| @@ -313,9 +224,9 @@ void rcar_du_plane_setup(struct rcar_du_plane *plane) | |||
| 313 | struct rcar_du_plane_state *state = | 224 | struct rcar_du_plane_state *state = |
| 314 | to_rcar_du_plane_state(plane->plane.state); | 225 | to_rcar_du_plane_state(plane->plane.state); |
| 315 | 226 | ||
| 316 | __rcar_du_plane_setup(plane, plane->hwindex); | 227 | __rcar_du_plane_setup(plane, state->hwindex); |
| 317 | if (state->format->planes == 2) | 228 | if (state->format->planes == 2) |
| 318 | __rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8); | 229 | __rcar_du_plane_setup(plane, (state->hwindex + 1) % 8); |
| 319 | 230 | ||
| 320 | rcar_du_plane_setup_fb(plane); | 231 | rcar_du_plane_setup_fb(plane); |
| 321 | } | 232 | } |
| @@ -326,12 +237,11 @@ static int rcar_du_plane_atomic_check(struct drm_plane *plane, | |||
| 326 | struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state); | 237 | struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state); |
| 327 | struct rcar_du_plane *rplane = to_rcar_plane(plane); | 238 | struct rcar_du_plane *rplane = to_rcar_plane(plane); |
| 328 | struct rcar_du_device *rcdu = rplane->group->dev; | 239 | struct rcar_du_device *rcdu = rplane->group->dev; |
| 329 | const struct rcar_du_format_info *cur_format; | ||
| 330 | const struct rcar_du_format_info *new_format; | ||
| 331 | int ret; | ||
| 332 | 240 | ||
| 333 | if (!state->fb || !state->crtc) | 241 | if (!state->fb || !state->crtc) { |
| 242 | rstate->format = NULL; | ||
| 334 | return 0; | 243 | return 0; |
| 244 | } | ||
| 335 | 245 | ||
| 336 | if (state->src_w >> 16 != state->crtc_w || | 246 | if (state->src_w >> 16 != state->crtc_w || |
| 337 | state->src_h >> 16 != state->crtc_h) { | 247 | state->src_h >> 16 != state->crtc_h) { |
| @@ -339,72 +249,23 @@ static int rcar_du_plane_atomic_check(struct drm_plane *plane, | |||
| 339 | return -EINVAL; | 249 | return -EINVAL; |
| 340 | } | 250 | } |
| 341 | 251 | ||
| 342 | cur_format = to_rcar_du_plane_state(plane->state)->format; | 252 | rstate->format = rcar_du_format_info(state->fb->pixel_format); |
| 343 | new_format = rcar_du_format_info(state->fb->pixel_format); | 253 | if (rstate->format == NULL) { |
| 344 | if (new_format == NULL) { | ||
| 345 | dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, | 254 | dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, |
| 346 | state->fb->pixel_format); | 255 | state->fb->pixel_format); |
| 347 | return -EINVAL; | 256 | return -EINVAL; |
| 348 | } | 257 | } |
| 349 | 258 | ||
| 350 | /* If the number of required planes has changed we will need to | ||
| 351 | * reallocate hardware planes. Ensure free planes are available. | ||
| 352 | */ | ||
| 353 | if (!cur_format || new_format->planes != cur_format->planes) { | ||
| 354 | ret = rcar_du_plane_reserve_check(rplane, cur_format, | ||
| 355 | new_format); | ||
| 356 | if (ret < 0) { | ||
| 357 | dev_dbg(rcdu->dev, "%s: no available hardware plane\n", | ||
| 358 | __func__); | ||
| 359 | return ret; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | rstate->format = new_format; | ||
| 364 | |||
| 365 | return 0; | 259 | return 0; |
| 366 | } | 260 | } |
| 367 | 261 | ||
| 368 | static void rcar_du_plane_disable(struct rcar_du_plane *rplane, | ||
| 369 | const struct rcar_du_format_info *cur_format) | ||
| 370 | { | ||
| 371 | struct rcar_du_plane_state *rstate = | ||
| 372 | to_rcar_du_plane_state(rplane->plane.state); | ||
| 373 | |||
| 374 | if (!rplane->plane.state->crtc) | ||
| 375 | return; | ||
| 376 | |||
| 377 | rcar_du_plane_release(rplane, cur_format); | ||
| 378 | |||
| 379 | rstate->format = NULL; | ||
| 380 | } | ||
| 381 | |||
| 382 | static void rcar_du_plane_atomic_update(struct drm_plane *plane, | 262 | static void rcar_du_plane_atomic_update(struct drm_plane *plane, |
| 383 | struct drm_plane_state *old_state) | 263 | struct drm_plane_state *old_state) |
| 384 | { | 264 | { |
| 385 | struct rcar_du_plane *rplane = to_rcar_plane(plane); | 265 | struct rcar_du_plane *rplane = to_rcar_plane(plane); |
| 386 | struct drm_plane_state *state = plane->state; | ||
| 387 | struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state); | ||
| 388 | const struct rcar_du_format_info *cur_format; | ||
| 389 | const struct rcar_du_format_info *new_format; | ||
| 390 | 266 | ||
| 391 | cur_format = to_rcar_du_plane_state(old_state)->format; | 267 | if (plane->state->crtc) |
| 392 | new_format = rstate->format; | 268 | rcar_du_plane_setup(rplane); |
| 393 | |||
| 394 | if (!state->crtc) { | ||
| 395 | rcar_du_plane_disable(rplane, cur_format); | ||
| 396 | return; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* Reallocate hardware planes if the number of required planes has | ||
| 400 | * changed. | ||
| 401 | */ | ||
| 402 | if (!cur_format || new_format->planes != cur_format->planes) { | ||
| 403 | rcar_du_plane_release(rplane, cur_format); | ||
| 404 | rcar_du_plane_reserve(rplane, new_format); | ||
| 405 | } | ||
| 406 | |||
| 407 | rcar_du_plane_setup(rplane); | ||
| 408 | } | 269 | } |
| 409 | 270 | ||
| 410 | static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { | 271 | static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { |
| @@ -426,6 +287,7 @@ static void rcar_du_plane_reset(struct drm_plane *plane) | |||
| 426 | if (state == NULL) | 287 | if (state == NULL) |
| 427 | return; | 288 | return; |
| 428 | 289 | ||
| 290 | state->hwindex = -1; | ||
| 429 | state->alpha = 255; | 291 | state->alpha = 255; |
| 430 | state->colorkey = RCAR_DU_COLORKEY_NONE; | 292 | state->colorkey = RCAR_DU_COLORKEY_NONE; |
| 431 | state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; | 293 | state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; |
| @@ -534,9 +396,6 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp) | |||
| 534 | unsigned int i; | 396 | unsigned int i; |
| 535 | int ret; | 397 | int ret; |
| 536 | 398 | ||
| 537 | mutex_init(&planes->lock); | ||
| 538 | planes->free = 0xff; | ||
| 539 | |||
| 540 | planes->alpha = | 399 | planes->alpha = |
| 541 | drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); | 400 | drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); |
| 542 | if (planes->alpha == NULL) | 401 | if (planes->alpha == NULL) |
| @@ -572,7 +431,6 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp) | |||
| 572 | struct rcar_du_plane *plane = &planes->planes[i]; | 431 | struct rcar_du_plane *plane = &planes->planes[i]; |
| 573 | 432 | ||
| 574 | plane->group = rgrp; | 433 | plane->group = rgrp; |
| 575 | plane->hwindex = -1; | ||
| 576 | 434 | ||
| 577 | ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs, | 435 | ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs, |
| 578 | &rcar_du_plane_funcs, formats, | 436 | &rcar_du_plane_funcs, formats, |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index 0941c4830edd..abff0ebeb195 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h | |||
| @@ -14,8 +14,6 @@ | |||
| 14 | #ifndef __RCAR_DU_PLANE_H__ | 14 | #ifndef __RCAR_DU_PLANE_H__ |
| 15 | #define __RCAR_DU_PLANE_H__ | 15 | #define __RCAR_DU_PLANE_H__ |
| 16 | 16 | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | |||
| 19 | #include <drm/drmP.h> | 17 | #include <drm/drmP.h> |
| 20 | #include <drm/drm_crtc.h> | 18 | #include <drm/drm_crtc.h> |
| 21 | 19 | ||
| @@ -33,13 +31,15 @@ struct rcar_du_group; | |||
| 33 | struct rcar_du_plane { | 31 | struct rcar_du_plane { |
| 34 | struct drm_plane plane; | 32 | struct drm_plane plane; |
| 35 | struct rcar_du_group *group; | 33 | struct rcar_du_group *group; |
| 36 | int hwindex; /* 0-based, -1 means unused */ | ||
| 37 | }; | 34 | }; |
| 38 | 35 | ||
| 36 | static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane) | ||
| 37 | { | ||
| 38 | return container_of(plane, struct rcar_du_plane, plane); | ||
| 39 | } | ||
| 40 | |||
| 39 | struct rcar_du_planes { | 41 | struct rcar_du_planes { |
| 40 | struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; | 42 | struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; |
| 41 | unsigned int free; | ||
| 42 | struct mutex lock; | ||
| 43 | 43 | ||
| 44 | struct drm_property *alpha; | 44 | struct drm_property *alpha; |
| 45 | struct drm_property *colorkey; | 45 | struct drm_property *colorkey; |
| @@ -50,6 +50,7 @@ struct rcar_du_plane_state { | |||
| 50 | struct drm_plane_state state; | 50 | struct drm_plane_state state; |
| 51 | 51 | ||
| 52 | const struct rcar_du_format_info *format; | 52 | const struct rcar_du_format_info *format; |
| 53 | int hwindex; /* 0-based, -1 means unused */ | ||
| 53 | 54 | ||
| 54 | unsigned int alpha; | 55 | unsigned int alpha; |
| 55 | unsigned int colorkey; | 56 | unsigned int colorkey; |
