#include <drm/drm_managed.h>
#include <drm/drm_prime.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_vblank.h>
DEFINE_DRM_GEM_FOPS(armada_drm_fops);
static const struct drm_driver armada_drm_driver = {
- .lastclose = drm_fb_helper_lastclose,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = armada_gem_prime_import,
static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
.fb_create = armada_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
drm_mode_config_reset(&priv->drm);
- ret = armada_fbdev_init(&priv->drm);
- if (ret)
- goto err_comp;
-
drm_kms_helper_poll_init(&priv->drm);
ret = drm_dev_register(&priv->drm, 0);
armada_drm_debugfs_init(priv->drm.primary);
#endif
+ armada_fbdev_setup(&priv->drm);
+
return 0;
err_poll:
drm_kms_helper_poll_fini(&priv->drm);
- armada_fbdev_fini(&priv->drm);
err_comp:
component_unbind_all(dev, &priv->drm);
err_kms:
struct armada_private *priv = drm_to_armada_dev(drm);
drm_kms_helper_poll_fini(&priv->drm);
- armada_fbdev_fini(&priv->drm);
drm_dev_unregister(&priv->drm);
#include <linux/kernel.h>
#include <linux/module.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include "armada_fb.h"
#include "armada_gem.h"
+static void armada_fbdev_fb_destroy(struct fb_info *info)
+{
+ struct drm_fb_helper *fbh = info->par;
+
+ drm_fb_helper_fini(fbh);
+
+ fbh->fb->funcs->destroy(fbh->fb);
+
+ drm_client_release(&fbh->client);
+ drm_fb_helper_unprepare(fbh);
+ kfree(fbh);
+}
+
static const struct fb_ops armada_fb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
+ .fb_destroy = armada_fbdev_fb_destroy,
};
static int armada_fbdev_create(struct drm_fb_helper *fbh,
*/
static void armada_fbdev_client_unregister(struct drm_client_dev *client)
-{ }
+{
+ struct drm_fb_helper *fbh = drm_fb_helper_from_client(client);
+
+ if (fbh->info) {
+ drm_fb_helper_unregister_info(fbh);
+ } else {
+ drm_client_release(&fbh->client);
+ drm_fb_helper_unprepare(fbh);
+ kfree(fbh);
+ }
+}
static int armada_fbdev_client_restore(struct drm_client_dev *client)
{
static int armada_fbdev_client_hotplug(struct drm_client_dev *client)
{
+ struct drm_fb_helper *fbh = drm_fb_helper_from_client(client);
+ struct drm_device *dev = client->dev;
+ int ret;
+
+ if (dev->fb_helper)
+ return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+ ret = drm_fb_helper_init(dev, fbh);
+ if (ret)
+ goto err_drm_err;
+
+ if (!drm_drv_uses_atomic_modeset(dev))
+ drm_helper_disable_unused_functions(dev);
+
+ ret = drm_fb_helper_initial_config(fbh);
+ if (ret)
+ goto err_drm_fb_helper_fini;
+
return 0;
+
+err_drm_fb_helper_fini:
+ drm_fb_helper_fini(fbh);
+err_drm_err:
+ drm_err(dev, "armada: Failed to setup fbdev emulation (ret=%d)\n", ret);
+ return ret;
}
static const struct drm_client_funcs armada_fbdev_client_funcs = {
.hotplug = armada_fbdev_client_hotplug,
};
-int armada_fbdev_init(struct drm_device *dev)
+void armada_fbdev_setup(struct drm_device *dev)
{
- struct armada_private *priv = drm_to_armada_dev(dev);
struct drm_fb_helper *fbh;
int ret;
- fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL);
- if (!fbh)
- return -ENOMEM;
-
- priv->fbdev = fbh;
+ drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+ drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+ fbh = kzalloc(sizeof(*fbh), GFP_KERNEL);
+ if (!fbh)
+ return;
drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs);
- ret = drm_client_init(dev, &fbh->client, "armada-fbdev",
- &armada_fbdev_client_funcs);
- if (ret)
- goto err_drm_fb_helper_unprepare;
-
- ret = drm_fb_helper_init(dev, fbh);
+ ret = drm_client_init(dev, &fbh->client, "fbdev", &armada_fbdev_client_funcs);
if (ret) {
- DRM_ERROR("failed to initialize drm fb helper\n");
- goto err_drm_client_release;
+ drm_err(dev, "Failed to register client: %d\n", ret);
+ goto err_drm_client_init;
}
- ret = drm_fb_helper_initial_config(fbh);
- if (ret) {
- DRM_ERROR("failed to set initial config\n");
- goto err_drm_fb_helper_fini;
- }
-
- return 0;
-
-err_drm_fb_helper_fini:
- drm_fb_helper_fini(fbh);
-err_drm_client_release:
- drm_client_release(&fbh->client);
-err_drm_fb_helper_unprepare:
- drm_fb_helper_unprepare(fbh);
- priv->fbdev = NULL;
- return ret;
-}
-
-void armada_fbdev_fini(struct drm_device *dev)
-{
- struct armada_private *priv = drm_to_armada_dev(dev);
- struct drm_fb_helper *fbh = priv->fbdev;
-
- if (fbh) {
- drm_fb_helper_unregister_info(fbh);
+ ret = armada_fbdev_client_hotplug(&fbh->client);
+ if (ret)
+ drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
- drm_fb_helper_fini(fbh);
- drm_client_release(&fbh->client);
+ drm_client_register(&fbh->client);
- if (fbh->fb)
- fbh->fb->funcs->destroy(fbh->fb);
+ return;
- drm_fb_helper_unprepare(fbh);
-
- priv->fbdev = NULL;
- }
+err_drm_client_init:
+ drm_fb_helper_unprepare(fbh);
+ kfree(fbh);
+ return;
}