@@ -5,6 +5,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
@@ -72,6 +73,7 @@ struct bochs_device {
/* drm */
struct drm_device *dev;
+ struct drm_plane primary;
struct drm_crtc crtc;
struct drm_encoder encoder;
struct drm_connector connector;
@@ -11,6 +11,10 @@
static int defx = 1024;
static int defy = 768;
+static const uint32_t bochs_primary_formats[] = {
+ DRM_FORMAT_XRGB8888,
+};
+
module_param(defx, int, 0444);
module_param(defy, int, 0444);
MODULE_PARM_DESC(defx, "default x resolution");
@@ -37,59 +41,12 @@ static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}
-static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct bochs_device *bochs =
- container_of(crtc, struct bochs_device, crtc);
- struct bochs_framebuffer *bochs_fb;
- struct bochs_bo *bo;
- u64 gpu_addr = 0;
- int ret;
-
- if (old_fb) {
- bochs_fb = to_bochs_framebuffer(old_fb);
- bo = gem_to_bochs_bo(bochs_fb->obj);
- ret = ttm_bo_reserve(&bo->bo, true, false, false, NULL);
- if (ret) {
- DRM_ERROR("failed to reserve old_fb bo\n");
- } else {
- bochs_bo_unpin(bo);
- ttm_bo_unreserve(&bo->bo);
- }
- }
-
- if (WARN_ON(crtc->primary->fb == NULL))
- return -EINVAL;
-
- bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
- bo = gem_to_bochs_bo(bochs_fb->obj);
- ret = ttm_bo_reserve(&bo->bo, true, false, false, NULL);
- if (ret)
- return ret;
-
- ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
- if (ret) {
- ttm_bo_unreserve(&bo->bo);
- return ret;
- }
-
- ttm_bo_unreserve(&bo->bo);
- bochs_hw_setbase(bochs, x, y, gpu_addr);
- return 0;
-}
-
-static int bochs_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y, struct drm_framebuffer *old_fb)
+static void bochs_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct bochs_device *bochs =
container_of(crtc, struct bochs_device, crtc);
- bochs_hw_setmode(bochs, mode);
- bochs_crtc_mode_set_base(crtc, x, y, old_fb);
- return 0;
+ bochs_hw_setmode(bochs, &crtc->mode);
}
static void bochs_crtc_prepare(struct drm_crtc *crtc)
@@ -116,7 +73,7 @@ static int bochs_crtc_page_flip(struct drm_crtc *crtc,
unsigned long irqflags;
crtc->primary->fb = fb;
- bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
+ drm_helper_crtc_mode_set_base(crtc, 0, 0, old_fb);
if (event) {
spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
drm_send_vblank_event(bochs->dev, -1, event);
@@ -136,8 +93,9 @@ static const struct drm_crtc_funcs bochs_crtc_funcs = {
static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
.dpms = bochs_crtc_dpms,
.mode_fixup = bochs_crtc_mode_fixup,
- .mode_set = bochs_crtc_mode_set,
- .mode_set_base = bochs_crtc_mode_set_base,
+ .mode_set = drm_helper_crtc_mode_set,
+ .mode_set_base = drm_helper_crtc_mode_set_base,
+ .mode_set_nofb = bochs_crtc_mode_set_nofb,
.prepare = bochs_crtc_prepare,
.commit = bochs_crtc_commit,
};
@@ -146,12 +104,116 @@ static void bochs_crtc_init(struct drm_device *dev)
{
struct bochs_device *bochs = dev->dev_private;
struct drm_crtc *crtc = &bochs->crtc;
+ struct drm_plane *primary = &bochs->primary;
- drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
+ drm_crtc_init_with_planes(dev, crtc, primary, NULL, &bochs_crtc_funcs);
drm_mode_crtc_set_gamma_size(crtc, 256);
drm_crtc_helper_add(crtc, &bochs_helper_funcs);
}
+static int bochs_plane_prepare_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb,
+ const struct drm_plane_state *new_state)
+{
+ struct bochs_framebuffer *bochs_fb;
+ struct bochs_bo *bo;
+ int ret;
+
+ if (WARN_ON(plane->fb == NULL))
+ return -EINVAL;
+
+ bochs_fb = to_bochs_framebuffer(plane->fb);
+ bo = gem_to_bochs_bo(bochs_fb->obj);
+ ttm_bo_reserve(&bo->bo, true, false, false, NULL);
+
+ ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+ if (ret) {
+ ttm_bo_unreserve(&bo->bo);
+ return ret;
+ }
+
+ ttm_bo_unreserve(&bo->bo);
+ return 0;
+}
+
+static void bochs_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_framebuffer *old_fb,
+ const struct drm_plane_state *old_state)
+{
+ struct bochs_framebuffer *bochs_fb;
+ struct bochs_bo *bo;
+
+ bochs_fb = to_bochs_framebuffer(old_fb);
+ bo = gem_to_bochs_bo(bochs_fb->obj);
+
+ /*
+ * Since cleanup can't fail, change the interruptible argument i.e. the
+ * second argument to false, this make sure ttm_bo_unpin can't fail.
+ */
+ ttm_bo_reserve(&bo->bo, false, false, false, NULL);
+ bochs_bo_unpin(bo);
+ ttm_bo_unreserve(&bo->bo);
+}
+
+static int bochs_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ return 0;
+}
+
+static void bochs_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct bochs_device *bochs =
+ container_of(plane, struct bochs_device, primary);
+ struct bochs_framebuffer *bochs_fb =
+ to_bochs_framebuffer(plane->state->fb);
+ struct bochs_bo *bo = gem_to_bochs_bo(bochs_fb->obj);
+ u64 gpu_addr = bo->bo.offset;
+
+ int x = plane->state->src_x >> 16;
+ int y = plane->state->src_y >> 16;
+
+ bochs_hw_setbase(bochs, x, y, gpu_addr);
+}
+
+static void bochs_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+}
+
+static const struct drm_plane_funcs bochs_plane_funcs = {
+ .update_plane = drm_plane_helper_update,
+ .disable_plane = drm_plane_helper_disable,
+};
+
+static const struct drm_plane_helper_funcs bochs_plane_helper_funcs = {
+ .prepare_fb = bochs_plane_prepare_fb,
+ .cleanup_fb = bochs_plane_cleanup_fb,
+ .atomic_check = bochs_plane_atomic_check,
+ .atomic_update = bochs_plane_atomic_update,
+ .atomic_disable = bochs_plane_atomic_disable,
+};
+
+static void bochs_plane_init(struct drm_device *dev)
+{
+ struct bochs_device *bochs = dev->dev_private;
+ struct drm_plane *primary = &bochs->primary;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary, 0,
+ &bochs_plane_funcs,
+ bochs_primary_formats,
+ ARRAY_SIZE(bochs_primary_formats),
+ DRM_PLANE_TYPE_PRIMARY);
+ if (ret) {
+ DRM_DEBUG_KMS("Failed to init primary plane init");
+ return;
+ }
+
+ drm_plane_helper_add(primary, &bochs_plane_helper_funcs);
+}
+
static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -285,6 +347,7 @@ int bochs_kms_init(struct bochs_device *bochs)
bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs;
+ bochs_plane_init(bochs->dev);
bochs_crtc_init(bochs->dev);
bochs_encoder_init(bochs->dev);
bochs_connector_init(bochs->dev);