drm/tegra: Move subdevice infrastructure to host1x

The Tegra DRM driver currently uses some infrastructure to defer the DRM
core initialization until all required devices have registered. The same
infrastructure can potentially be used by any other driver that requires
more than a single sub-device of the host1x module.

Make the infrastructure more generic and keep only the DRM specific code
in the DRM part of the driver. Eventually this will make it easy to move
the DRM driver part back to the DRM subsystem.

Signed-off-by: Thierry Reding <treding@nvidia.com>
diff --git a/drivers/gpu/host1x/drm/bus.c b/drivers/gpu/host1x/drm/bus.c
new file mode 100644
index 0000000..565f8f7
--- /dev/null
+++ b/drivers/gpu/host1x/drm/bus.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "drm.h"
+
+static int drm_host1x_set_busid(struct drm_device *dev,
+				struct drm_master *master)
+{
+	const char *device = dev_name(dev->dev);
+	const char *driver = dev->driver->name;
+	const char *bus = dev->dev->bus->name;
+	int length;
+
+	master->unique_len = strlen(bus) + 1 + strlen(device);
+	master->unique_size = master->unique_len;
+
+	master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
+	if (!master->unique)
+		return -ENOMEM;
+
+	snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device);
+
+	length = strlen(driver) + 1 + master->unique_len;
+
+	dev->devname = kmalloc(length + 1, GFP_KERNEL);
+	if (!dev->devname)
+		return -ENOMEM;
+
+	snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique);
+
+	return 0;
+}
+
+static struct drm_bus drm_host1x_bus = {
+	.bus_type = DRIVER_BUS_HOST1X,
+	.set_busid = drm_host1x_set_busid,
+};
+
+int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
+{
+	struct drm_device *drm;
+	int ret;
+
+	INIT_LIST_HEAD(&driver->device_list);
+	driver->bus = &drm_host1x_bus;
+
+	drm = drm_dev_alloc(driver, &device->dev);
+	if (!drm)
+		return -ENOMEM;
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto err_free;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
+		 driver->major, driver->minor, driver->patchlevel,
+		 driver->date, drm->primary->index);
+
+	return 0;
+
+err_free:
+	drm_dev_free(drm);
+	return ret;
+}
+
+void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device)
+{
+	struct tegra_drm *tegra = dev_get_drvdata(&device->dev);
+
+	drm_put_dev(tegra->drm);
+}
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index 5106df0..588d4ba 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -11,7 +11,6 @@
 #include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
 
-#include "host1x_client.h"
 #include "dc.h"
 #include "drm.h"
 #include "gem.h"
@@ -1040,28 +1039,28 @@
 
 static int tegra_dc_init(struct host1x_client *client)
 {
-	struct tegra_drm_client *drm = to_tegra_drm_client(client);
-	struct tegra_dc *dc = tegra_drm_client_to_dc(drm);
+	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+	struct tegra_dc *dc = host1x_client_to_dc(client);
 	int err;
 
-	dc->pipe = drm->drm->mode_config.num_crtc;
+	dc->pipe = tegra->drm->mode_config.num_crtc;
 
-	drm_crtc_init(drm->drm, &dc->base, &tegra_crtc_funcs);
+	drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
 	drm_mode_crtc_set_gamma_size(&dc->base, 256);
 	drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
 
-	err = tegra_dc_rgb_init(drm->drm, dc);
+	err = tegra_dc_rgb_init(tegra->drm, dc);
 	if (err < 0 && err != -ENODEV) {
 		dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
 		return err;
 	}
 
-	err = tegra_dc_add_planes(drm->drm, dc);
+	err = tegra_dc_add_planes(tegra->drm, dc);
 	if (err < 0)
 		return err;
 
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		err = tegra_dc_debugfs_init(dc, drm->drm->primary);
+		err = tegra_dc_debugfs_init(dc, tegra->drm->primary);
 		if (err < 0)
 			dev_err(dc->dev, "debugfs setup failed: %d\n", err);
 	}
@@ -1079,8 +1078,7 @@
 
 static int tegra_dc_exit(struct host1x_client *client)
 {
-	struct tegra_drm_client *drm = to_tegra_drm_client(client);
-	struct tegra_dc *dc = tegra_drm_client_to_dc(drm);
+	struct tegra_dc *dc = host1x_client_to_dc(client);
 	int err;
 
 	devm_free_irq(dc->dev, dc->irq, dc);
@@ -1107,7 +1105,6 @@
 
 static int tegra_dc_probe(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct resource *regs;
 	struct tegra_dc *dc;
 	int err;
@@ -1141,9 +1138,9 @@
 		return -ENXIO;
 	}
 
-	INIT_LIST_HEAD(&dc->client.base.list);
-	dc->client.base.ops = &dc_client_ops;
-	dc->client.base.dev = &pdev->dev;
+	INIT_LIST_HEAD(&dc->client.list);
+	dc->client.ops = &dc_client_ops;
+	dc->client.dev = &pdev->dev;
 
 	err = tegra_dc_rgb_probe(dc);
 	if (err < 0 && err != -ENODEV) {
@@ -1151,7 +1148,7 @@
 		return err;
 	}
 
-	err = host1x_register_client(tegra, &dc->client.base);
+	err = host1x_client_register(&dc->client);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
 			err);
@@ -1165,11 +1162,10 @@
 
 static int tegra_dc_remove(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct tegra_dc *dc = platform_get_drvdata(pdev);
 	int err;
 
-	err = host1x_unregister_client(tegra, &dc->client.base);
+	err = host1x_client_unregister(&dc->client);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
 			err);
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
index 1abcdbc..c2db409b 100644
--- a/drivers/gpu/host1x/drm/drm.c
+++ b/drivers/gpu/host1x/drm/drm.c
@@ -7,7 +7,8 @@
  * published by the Free Software Foundation.
  */
 
-#include "host1x_client.h"
+#include <linux/host1x.h>
+
 #include "drm.h"
 #include "gem.h"
 
@@ -22,239 +23,25 @@
 	struct list_head contexts;
 };
 
-struct host1x_subdev {
-	struct host1x_client *client;
-	struct device_node *np;
-	struct list_head list;
-};
-
-static int host1x_subdev_add(struct tegra_drm *tegra, struct device_node *np)
+static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 {
-	struct host1x_subdev *subdev;
-
-	subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
-	if (!subdev)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&subdev->list);
-	subdev->np = of_node_get(np);
-
-	list_add_tail(&subdev->list, &tegra->subdevs);
-
-	return 0;
-}
-
-static int host1x_subdev_register(struct tegra_drm *tegra,
-				  struct host1x_subdev *subdev,
-				  struct host1x_client *client)
-{
-	mutex_lock(&tegra->subdevs_lock);
-	list_del_init(&subdev->list);
-	list_add_tail(&subdev->list, &tegra->active);
-	subdev->client = client;
-	mutex_unlock(&tegra->subdevs_lock);
-
-	return 0;
-}
-
-static int host1x_subdev_unregister(struct tegra_drm *tegra,
-				    struct host1x_subdev *subdev)
-{
-	mutex_lock(&tegra->subdevs_lock);
-	list_del_init(&subdev->list);
-	mutex_unlock(&tegra->subdevs_lock);
-
-	of_node_put(subdev->np);
-	kfree(subdev);
-
-	return 0;
-}
-
-static int tegra_parse_dt(struct tegra_drm *tegra)
-{
-	static const char * const compat[] = {
-		"nvidia,tegra20-dc",
-		"nvidia,tegra20-hdmi",
-		"nvidia,tegra20-gr2d",
-		"nvidia,tegra30-dc",
-		"nvidia,tegra30-hdmi",
-		"nvidia,tegra30-gr2d",
-	};
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < ARRAY_SIZE(compat); i++) {
-		struct device_node *np;
-
-		for_each_child_of_node(tegra->dev->of_node, np) {
-			if (of_device_is_compatible(np, compat[i]) &&
-			    of_device_is_available(np)) {
-				err = host1x_subdev_add(tegra, np);
-				if (err < 0)
-					return err;
-			}
-		}
-	}
-
-	return 0;
-}
-
-int tegra_drm_alloc(struct platform_device *pdev)
-{
+	struct host1x_device *device = to_host1x_device(drm->dev);
 	struct tegra_drm *tegra;
 	int err;
 
-	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
 	if (!tegra)
 		return -ENOMEM;
 
-	mutex_init(&tegra->subdevs_lock);
-	INIT_LIST_HEAD(&tegra->subdevs);
-	INIT_LIST_HEAD(&tegra->active);
+	dev_set_drvdata(drm->dev, tegra);
 	mutex_init(&tegra->clients_lock);
 	INIT_LIST_HEAD(&tegra->clients);
-	tegra->dev = &pdev->dev;
-
-	err = tegra_parse_dt(tegra);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
-		return err;
-	}
-
-	host1x_set_drm_data(&pdev->dev, tegra);
-
-	return 0;
-}
-
-int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm)
-{
-	struct host1x_client *client;
-	int err;
-
-	mutex_lock(&tegra->clients_lock);
-
-	list_for_each_entry(client, &tegra->clients, list) {
-		struct tegra_drm_client *tdc = to_tegra_drm_client(client);
-
-		/* associate client with DRM device */
-		tdc->drm = drm;
-
-		if (client->ops && client->ops->init) {
-			err = client->ops->init(client);
-			if (err < 0) {
-				dev_err(tegra->dev,
-					"DRM setup failed for %s: %d\n",
-					dev_name(client->dev), err);
-				mutex_unlock(&tegra->clients_lock);
-				return err;
-			}
-		}
-	}
-
-	mutex_unlock(&tegra->clients_lock);
-
-	return 0;
-}
-
-int tegra_drm_exit(struct tegra_drm *tegra)
-{
-	struct host1x_client *client;
-	struct platform_device *pdev;
-	int err;
-
-	if (!tegra->drm)
-		return 0;
-
-	mutex_lock(&tegra->clients_lock);
-
-	list_for_each_entry_reverse(client, &tegra->clients, list) {
-		if (client->ops && client->ops->exit) {
-			err = client->ops->exit(client);
-			if (err < 0) {
-				dev_err(tegra->dev,
-					"DRM cleanup failed for %s: %d\n",
-					dev_name(client->dev), err);
-				mutex_unlock(&tegra->clients_lock);
-				return err;
-			}
-		}
-	}
-
-	mutex_unlock(&tegra->clients_lock);
-
-	pdev = to_platform_device(tegra->dev);
-	drm_platform_exit(&tegra_drm_driver, pdev);
-	tegra->drm = NULL;
-
-	return 0;
-}
-
-int host1x_register_client(struct tegra_drm *tegra,
-			   struct host1x_client *client)
-{
-	struct host1x_subdev *subdev, *tmp;
-	int err;
-
-	mutex_lock(&tegra->clients_lock);
-	list_add_tail(&client->list, &tegra->clients);
-	mutex_unlock(&tegra->clients_lock);
-
-	list_for_each_entry_safe(subdev, tmp, &tegra->subdevs, list)
-		if (subdev->np == client->dev->of_node)
-			host1x_subdev_register(tegra, subdev, client);
-
-	if (list_empty(&tegra->subdevs)) {
-		struct platform_device *pdev = to_platform_device(tegra->dev);
-
-		err = drm_platform_init(&tegra_drm_driver, pdev);
-		if (err < 0) {
-			dev_err(tegra->dev, "drm_platform_init(): %d\n", err);
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-int host1x_unregister_client(struct tegra_drm *tegra,
-			     struct host1x_client *client)
-{
-	struct host1x_subdev *subdev, *tmp;
-	int err;
-
-	list_for_each_entry_safe(subdev, tmp, &tegra->active, list) {
-		if (subdev->client == client) {
-			err = tegra_drm_exit(tegra);
-			if (err < 0) {
-				dev_err(tegra->dev, "tegra_drm_exit(): %d\n",
-					err);
-				return err;
-			}
-
-			host1x_subdev_unregister(tegra, subdev);
-			break;
-		}
-	}
-
-	mutex_lock(&tegra->clients_lock);
-	list_del_init(&client->list);
-	mutex_unlock(&tegra->clients_lock);
-
-	return 0;
-}
-
-static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
-{
-	struct tegra_drm *tegra;
-	int err;
-
-	tegra = host1x_get_drm_data(drm->dev);
 	drm->dev_private = tegra;
 	tegra->drm = drm;
 
 	drm_mode_config_init(drm);
 
-	err = tegra_drm_init(tegra, drm);
+	err = host1x_device_init(device);
 	if (err < 0)
 		return err;
 
@@ -280,9 +67,16 @@
 
 static int tegra_drm_unload(struct drm_device *drm)
 {
+	struct host1x_device *device = to_host1x_device(drm->dev);
+	int err;
+
 	drm_kms_helper_poll_fini(drm);
 	tegra_drm_fb_exit(drm);
 
+	err = host1x_device_exit(device);
+	if (err < 0)
+		return err;
+
 	drm_mode_config_cleanup(drm);
 
 	return 0;
@@ -370,10 +164,11 @@
 static int tegra_syncpt_read(struct drm_device *drm, void *data,
 			     struct drm_file *file)
 {
+	struct host1x *host = dev_get_drvdata(drm->dev->parent);
 	struct drm_tegra_syncpt_read *args = data;
-	struct host1x *host = dev_get_drvdata(drm->dev);
-	struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
+	struct host1x_syncpt *sp;
 
+	sp = host1x_syncpt_get(host, args->id);
 	if (!sp)
 		return -EINVAL;
 
@@ -384,10 +179,11 @@
 static int tegra_syncpt_incr(struct drm_device *drm, void *data,
 			     struct drm_file *file)
 {
+	struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
 	struct drm_tegra_syncpt_incr *args = data;
-	struct host1x *host = dev_get_drvdata(drm->dev);
-	struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
+	struct host1x_syncpt *sp;
 
+	sp = host1x_syncpt_get(host1x, args->id);
 	if (!sp)
 		return -EINVAL;
 
@@ -397,10 +193,11 @@
 static int tegra_syncpt_wait(struct drm_device *drm, void *data,
 			     struct drm_file *file)
 {
+	struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
 	struct drm_tegra_syncpt_wait *args = data;
-	struct host1x *host = dev_get_drvdata(drm->dev);
-	struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
+	struct host1x_syncpt *sp;
 
+	sp = host1x_syncpt_get(host1x, args->id);
 	if (!sp)
 		return -EINVAL;
 
@@ -422,7 +219,7 @@
 	if (!context)
 		return -ENOMEM;
 
-	list_for_each_entry(client, &tegra->clients, base.list)
+	list_for_each_entry(client, &tegra->clients, list)
 		if (client->base.class == args->client) {
 			err = client->ops->open_channel(client, context);
 			if (err)
@@ -441,8 +238,8 @@
 static int tegra_close_channel(struct drm_device *drm, void *data,
 			       struct drm_file *file)
 {
-	struct drm_tegra_close_channel *args = data;
 	struct tegra_drm_file *fpriv = file->driver_priv;
+	struct drm_tegra_close_channel *args = data;
 	struct tegra_drm_context *context;
 
 	context = tegra_drm_get_context(args->context);
@@ -652,3 +449,97 @@
 	.minor = DRIVER_MINOR,
 	.patchlevel = DRIVER_PATCHLEVEL,
 };
+
+int tegra_drm_register_client(struct tegra_drm *tegra,
+			      struct tegra_drm_client *client)
+{
+	mutex_lock(&tegra->clients_lock);
+	list_add_tail(&client->list, &tegra->clients);
+	mutex_unlock(&tegra->clients_lock);
+
+	return 0;
+}
+
+int tegra_drm_unregister_client(struct tegra_drm *tegra,
+				struct tegra_drm_client *client)
+{
+	mutex_lock(&tegra->clients_lock);
+	list_del_init(&client->list);
+	mutex_unlock(&tegra->clients_lock);
+
+	return 0;
+}
+
+static int host1x_drm_probe(struct host1x_device *device)
+{
+	return drm_host1x_init(&tegra_drm_driver, device);
+}
+
+static int host1x_drm_remove(struct host1x_device *device)
+{
+	drm_host1x_exit(&tegra_drm_driver, device);
+
+	return 0;
+}
+
+static const struct of_device_id host1x_drm_subdevs[] = {
+	{ .compatible = "nvidia,tegra20-dc", },
+	{ .compatible = "nvidia,tegra20-hdmi", },
+	{ .compatible = "nvidia,tegra20-gr2d", },
+	{ .compatible = "nvidia,tegra30-dc", },
+	{ .compatible = "nvidia,tegra30-hdmi", },
+	{ .compatible = "nvidia,tegra30-gr2d", },
+	{ /* sentinel */ }
+};
+
+static struct host1x_driver host1x_drm_driver = {
+	.name = "drm",
+	.probe = host1x_drm_probe,
+	.remove = host1x_drm_remove,
+	.subdevs = host1x_drm_subdevs,
+};
+
+static int __init host1x_drm_init(void)
+{
+	int err;
+
+	err = host1x_driver_register(&host1x_drm_driver);
+	if (err < 0)
+		return err;
+
+	err = platform_driver_register(&tegra_dc_driver);
+	if (err < 0)
+		goto unregister_host1x;
+
+	err = platform_driver_register(&tegra_hdmi_driver);
+	if (err < 0)
+		goto unregister_dc;
+
+	err = platform_driver_register(&tegra_gr2d_driver);
+	if (err < 0)
+		goto unregister_hdmi;
+
+	return 0;
+
+unregister_hdmi:
+	platform_driver_unregister(&tegra_hdmi_driver);
+unregister_dc:
+	platform_driver_unregister(&tegra_dc_driver);
+unregister_host1x:
+	host1x_driver_unregister(&host1x_drm_driver);
+	return err;
+}
+module_init(host1x_drm_init);
+
+static void __exit host1x_drm_exit(void)
+{
+	platform_driver_unregister(&tegra_gr2d_driver);
+	platform_driver_unregister(&tegra_hdmi_driver);
+	platform_driver_unregister(&tegra_dc_driver);
+	host1x_driver_unregister(&host1x_drm_driver);
+}
+module_exit(host1x_drm_exit);
+
+MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
+MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h
index 8c26c6b..25522e2 100644
--- a/drivers/gpu/host1x/drm/drm.h
+++ b/drivers/gpu/host1x/drm/drm.h
@@ -32,11 +32,6 @@
 
 struct tegra_drm {
 	struct drm_device *drm;
-	struct device *dev;
-
-	struct mutex subdevs_lock;
-	struct list_head subdevs;
-	struct list_head active;
 
 	struct mutex clients_lock;
 	struct list_head clients;
@@ -63,29 +58,29 @@
 
 struct tegra_drm_client {
 	struct host1x_client base;
-	struct drm_device *drm;
+	struct list_head list;
 
 	const struct tegra_drm_client_ops *ops;
 };
 
 static inline struct tegra_drm_client *
-to_tegra_drm_client(struct host1x_client *client)
+host1x_to_drm_client(struct host1x_client *client)
 {
 	return container_of(client, struct tegra_drm_client, base);
 }
 
+extern int tegra_drm_register_client(struct tegra_drm *tegra,
+				     struct tegra_drm_client *client);
+extern int tegra_drm_unregister_client(struct tegra_drm *tegra,
+				       struct tegra_drm_client *client);
+
 extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
 extern int tegra_drm_exit(struct tegra_drm *tegra);
 
-extern int host1x_register_client(struct tegra_drm *tegra,
-				  struct host1x_client *client);
-extern int host1x_unregister_client(struct tegra_drm *tegra,
-				    struct host1x_client *client);
-
 struct tegra_output;
 
 struct tegra_dc {
-	struct tegra_drm_client client;
+	struct host1x_client client;
 	struct device *dev;
 	spinlock_t lock;
 
@@ -109,7 +104,7 @@
 };
 
 static inline struct tegra_dc *
-tegra_drm_client_to_dc(struct tegra_drm_client *client)
+host1x_client_to_dc(struct host1x_client *client)
 {
 	return container_of(client, struct tegra_dc, client);
 }
@@ -235,6 +230,10 @@
 	return output ? -ENOSYS : -EINVAL;
 }
 
+/* from bus.c */
+int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device);
+void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device);
+
 /* from rgb.c */
 extern int tegra_dc_rgb_probe(struct tegra_dc *dc);
 extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
@@ -252,6 +251,8 @@
 extern void tegra_drm_fb_exit(struct drm_device *drm);
 extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
 
-extern struct drm_driver tegra_drm_driver;
+extern struct platform_driver tegra_dc_driver;
+extern struct platform_driver tegra_hdmi_driver;
+extern struct platform_driver tegra_gr2d_driver;
 
 #endif /* HOST1X_DRM_H */
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
index dfb8224..4e407e3 100644
--- a/drivers/gpu/host1x/drm/gr2d.c
+++ b/drivers/gpu/host1x/drm/gr2d.c
@@ -16,7 +16,6 @@
 
 #include <linux/clk.h>
 
-#include "host1x_client.h"
 #include "drm.h"
 #include "gem.h"
 
@@ -35,19 +34,45 @@
 	return container_of(client, struct gr2d, client);
 }
 
-static int gr2d_client_init(struct host1x_client *client)
+static int gr2d_init(struct host1x_client *client)
 {
-	return 0;
+	struct tegra_drm_client *drm = host1x_to_drm_client(client);
+	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+	struct gr2d *gr2d = to_gr2d(drm);
+
+	gr2d->channel = host1x_channel_request(client->dev);
+	if (!gr2d->channel)
+		return -ENOMEM;
+
+	client->syncpts[0] = host1x_syncpt_request(client->dev, false);
+	if (!client->syncpts[0]) {
+		host1x_channel_free(gr2d->channel);
+		return -ENOMEM;
+	}
+
+	return tegra_drm_register_client(tegra, drm);
 }
 
-static int gr2d_client_exit(struct host1x_client *client)
+static int gr2d_exit(struct host1x_client *client)
 {
+	struct tegra_drm_client *drm = host1x_to_drm_client(client);
+	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+	struct gr2d *gr2d = to_gr2d(drm);
+	int err;
+
+	err = tegra_drm_unregister_client(tegra, drm);
+	if (err < 0)
+		return err;
+
+	host1x_syncpt_free(client->syncpts[0]);
+	host1x_channel_free(gr2d->channel);
+
 	return 0;
 }
 
 static const struct host1x_client_ops gr2d_client_ops = {
-	.init = gr2d_client_init,
-	.exit = gr2d_client_exit,
+	.init = gr2d_init,
+	.exit = gr2d_exit,
 };
 
 static int gr2d_open_channel(struct tegra_drm_client *client,
@@ -240,7 +265,6 @@
 
 static int gr2d_probe(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct device *dev = &pdev->dev;
 	struct host1x_syncpt **syncpts;
 	struct gr2d *gr2d;
@@ -267,25 +291,17 @@
 		return err;
 	}
 
-	gr2d->channel = host1x_channel_request(dev);
-	if (!gr2d->channel)
-		return -ENOMEM;
-
-	*syncpts = host1x_syncpt_request(dev, false);
-	if (!(*syncpts)) {
-		host1x_channel_free(gr2d->channel);
-		return -ENOMEM;
-	}
-
 	INIT_LIST_HEAD(&gr2d->client.base.list);
 	gr2d->client.base.ops = &gr2d_client_ops;
 	gr2d->client.base.dev = dev;
 	gr2d->client.base.class = HOST1X_CLASS_GR2D;
 	gr2d->client.base.syncpts = syncpts;
 	gr2d->client.base.num_syncpts = 1;
+
+	INIT_LIST_HEAD(&gr2d->client.list);
 	gr2d->client.ops = &gr2d_ops;
 
-	err = host1x_register_client(tegra, &gr2d->client.base);
+	err = host1x_client_register(&gr2d->client.base);
 	if (err < 0) {
 		dev_err(dev, "failed to register host1x client: %d\n", err);
 		return err;
@@ -302,22 +318,16 @@
 
 static int gr2d_remove(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct gr2d *gr2d = platform_get_drvdata(pdev);
-	unsigned int i;
 	int err;
 
-	err = host1x_unregister_client(tegra, &gr2d->client.base);
+	err = host1x_client_unregister(&gr2d->client.base);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
 			err);
 		return err;
 	}
 
-	for (i = 0; i < gr2d->client.base.num_syncpts; i++)
-		host1x_syncpt_free(gr2d->client.base.syncpts[i]);
-
-	host1x_channel_free(gr2d->channel);
 	clk_disable_unprepare(gr2d->clk);
 
 	return 0;
diff --git a/drivers/gpu/host1x/drm/hdmi.c b/drivers/gpu/host1x/drm/hdmi.c
index a237004..f5663d1 100644
--- a/drivers/gpu/host1x/drm/hdmi.c
+++ b/drivers/gpu/host1x/drm/hdmi.c
@@ -13,13 +13,12 @@
 #include <linux/hdmi.h>
 #include <linux/regulator/consumer.h>
 
-#include "host1x_client.h"
 #include "hdmi.h"
 #include "drm.h"
 #include "dc.h"
 
 struct tegra_hdmi {
-	struct tegra_drm_client client;
+	struct host1x_client client;
 	struct tegra_output output;
 	struct device *dev;
 
@@ -43,7 +42,7 @@
 };
 
 static inline struct tegra_hdmi *
-tegra_drm_client_to_hdmi(struct tegra_drm_client *client)
+host1x_client_to_hdmi(struct host1x_client *client)
 {
 	return container_of(client, struct tegra_hdmi, client);
 }
@@ -1118,22 +1117,22 @@
 
 static int tegra_hdmi_init(struct host1x_client *client)
 {
-	struct tegra_drm_client *drm = to_tegra_drm_client(client);
-	struct tegra_hdmi *hdmi = tegra_drm_client_to_hdmi(drm);
+	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+	struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
 	int err;
 
 	hdmi->output.type = TEGRA_OUTPUT_HDMI;
 	hdmi->output.dev = client->dev;
 	hdmi->output.ops = &hdmi_ops;
 
-	err = tegra_output_init(drm->drm, &hdmi->output);
+	err = tegra_output_init(tegra->drm, &hdmi->output);
 	if (err < 0) {
 		dev_err(client->dev, "output setup failed: %d\n", err);
 		return err;
 	}
 
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		err = tegra_hdmi_debugfs_init(hdmi, drm->drm->primary);
+		err = tegra_hdmi_debugfs_init(hdmi, tegra->drm->primary);
 		if (err < 0)
 			dev_err(client->dev, "debugfs setup failed: %d\n", err);
 	}
@@ -1143,8 +1142,7 @@
 
 static int tegra_hdmi_exit(struct host1x_client *client)
 {
-	struct tegra_drm_client *drm = to_tegra_drm_client(client);
-	struct tegra_hdmi *hdmi = tegra_drm_client_to_hdmi(drm);
+	struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
 	int err;
 
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
@@ -1176,7 +1174,6 @@
 
 static int tegra_hdmi_probe(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct tegra_hdmi *hdmi;
 	struct resource *regs;
 	int err;
@@ -1247,11 +1244,11 @@
 
 	hdmi->irq = err;
 
-	INIT_LIST_HEAD(&hdmi->client.base.list);
-	hdmi->client.base.ops = &hdmi_client_ops;
-	hdmi->client.base.dev = &pdev->dev;
+	INIT_LIST_HEAD(&hdmi->client.list);
+	hdmi->client.ops = &hdmi_client_ops;
+	hdmi->client.dev = &pdev->dev;
 
-	err = host1x_register_client(tegra, &hdmi->client.base);
+	err = host1x_client_register(&hdmi->client);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
 			err);
@@ -1265,11 +1262,10 @@
 
 static int tegra_hdmi_remove(struct platform_device *pdev)
 {
-	struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
 	struct tegra_hdmi *hdmi = platform_get_drvdata(pdev);
 	int err;
 
-	err = host1x_unregister_client(tegra, &hdmi->client.base);
+	err = host1x_client_unregister(&hdmi->client);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
 			err);