video: tegra: host: Add gk20a platform interface
Lauri Peltonen [Fri, 3 Jan 2014 09:58:22 +0000 (11:58 +0200)]
The platform interface abstracts the nvhost interface on Tegra and
allows supporting other SoC platforms in the gk20a driver. Currently
only probe-time initialization uses the new abstraction.

Move the gk20a device declaration from the host driver to the gk20a
driver.

Bug 1434573

Change-Id: Idaa944846317362dddd7a4f85ab6cbce9a053bad
Signed-off-by: Lauri Peltonen <lpeltonen@nvidia.com>
Reviewed-on: http://git-master/r/352045
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>

drivers/video/tegra/host/gk20a/Makefile
drivers/video/tegra/host/gk20a/gk20a.c
drivers/video/tegra/host/gk20a/gk20a.h
drivers/video/tegra/host/gk20a/platform_gk20a.h [new file with mode: 0644]
drivers/video/tegra/host/gk20a/platform_gk20a_generic.c [new file with mode: 0644]
drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c [new file with mode: 0644]
drivers/video/tegra/host/t124/t124.c

index e1affc2..5de90cf 100644 (file)
@@ -25,3 +25,6 @@ obj-$(CONFIG_GK20A) += \
        gk20a_gating_reglist.o \
        gk20a_scale.o \
        gk20a_sysfs.o
+
+obj-$(CONFIG_GK20A) += platform_gk20a_generic.o
+obj-$(CONFIG_TEGRA_GK20A) += platform_gk20a_tegra.o
index d1c32b3..d3cd264 100644 (file)
@@ -61,7 +61,7 @@
 
 static inline void set_gk20a(struct platform_device *dev, struct gk20a *gk20a)
 {
-       nvhost_set_private_data(dev, gk20a);
+       gk20a_get_platform(dev)->g = gk20a;
 }
 
 /* TBD: should be able to put in the list below. */
@@ -632,7 +632,7 @@ static void gk20a_remove_support(struct platform_device *dev)
        }
 }
 
-int nvhost_init_gk20a_support(struct platform_device *dev)
+static int gk20a_init_support(struct platform_device *dev)
 {
        int err = 0;
        struct gk20a *g = get_gk20a(dev);
@@ -931,8 +931,12 @@ done:
 }
 
 static struct of_device_id tegra_gk20a_of_match[] = {
+#ifdef CONFIG_TEGRA_GK20A
        { .compatible = "nvidia,tegra124-gk20a",
-               .data = (struct nvhost_device_data *)&tegra_gk20a_info },
+               .data = &gk20a_tegra_platform },
+#endif
+       { .compatible = "nvidia,generic-gk20a",
+               .data = &gk20a_generic_platform },
        { },
 };
 
@@ -999,7 +1003,7 @@ static int gk20a_probe(struct platform_device *dev)
 {
        struct gk20a *gk20a;
        int err;
-       struct nvhost_device_data *pdata = NULL;
+       struct gk20a_platform *platform = NULL;
        struct cooling_device_gk20a *gpu_cdev = NULL;
 
        if (dev->dev.of_node) {
@@ -1007,21 +1011,18 @@ static int gk20a_probe(struct platform_device *dev)
 
                match = of_match_device(tegra_gk20a_of_match, &dev->dev);
                if (match)
-                       pdata = (struct nvhost_device_data *)match->data;
+                       platform = (struct gk20a_platform *)match->data;
        } else
-               pdata = (struct nvhost_device_data *)dev->dev.platform_data;
+               platform = (struct gk20a_platform *)dev->dev.platform_data;
 
-       if (!pdata) {
+       if (!platform) {
                dev_err(&dev->dev, "no platform data\n");
                return -ENODATA;
        }
 
        nvhost_dbg_fn("");
-       pdata->pdev = dev;
-       mutex_init(&pdata->lock);
-       platform_set_drvdata(dev, pdata);
 
-       nvhost_module_init(dev);
+       platform_set_drvdata(dev, platform);
 
        gk20a = kzalloc(sizeof(struct gk20a), GFP_KERNEL);
        if (!gk20a) {
@@ -1031,30 +1032,25 @@ static int gk20a_probe(struct platform_device *dev)
 
        set_gk20a(dev, gk20a);
        gk20a->dev = dev;
+#ifdef CONFIG_TEGRA_GK20A
        gk20a->host = nvhost_get_host(dev);
+#endif
 
-       nvhost_init_gk20a_support(dev);
-
-#ifdef CONFIG_PM_GENERIC_DOMAINS
-       pdata->pd.name = "gk20a";
+       gk20a_init_support(dev);
 
-       err = nvhost_module_add_domain(&pdata->pd, dev);
-#endif
+       /* Initialize the platform interface. */
+       err = platform->probe(dev);
+       if (err) {
+               dev_err(&dev->dev, "platform probe failed");
+               return err;
+       }
 
-       if (pdata->can_powergate) {
+       if (platform->can_powergate) {
                gk20a->system_suspend_notifier.notifier_call =
                        gk20a_suspend_notifier;
                register_pm_notifier(&gk20a->system_suspend_notifier);
        }
 
-       err = nvhost_client_device_init(dev);
-       if (err) {
-               nvhost_dbg_fn("failed to init client device for %s",
-                             dev->name);
-               pm_runtime_put(&dev->dev);
-               return err;
-       }
-
        err = nvhost_as_init_device(dev);
        if (err) {
                nvhost_dbg_fn("failed to init client address space"
@@ -1091,17 +1087,17 @@ static int gk20a_probe(struct platform_device *dev)
        gk20a->mm.ltc_enabled_debug = true;
        gk20a->debugfs_ltc_enabled =
                        debugfs_create_bool("ltc_enabled", S_IRUGO|S_IWUSR,
-                                pdata->debugfs,
+                                platform->debugfs,
                                 &gk20a->mm.ltc_enabled_debug);
        gk20a->mm.ltc_enabled_debug = true;
        gk20a->debugfs_gr_idle_timeout_default =
                        debugfs_create_u32("gr_idle_timeout_default_us",
-                                       S_IRUGO|S_IWUSR, pdata->debugfs,
+                                       S_IRUGO|S_IWUSR, platform->debugfs,
                                         &gk20a->gr_idle_timeout_default);
        gk20a->debugfs_timeouts_enabled =
                        debugfs_create_bool("timeouts_enabled",
                                        S_IRUGO|S_IWUSR,
-                                       pdata->debugfs,
+                                       platform->debugfs,
                                        &gk20a->timeouts_enabled);
        gk20a_pmu_debugfs_init(dev);
 #endif
@@ -1173,6 +1169,11 @@ static void __exit gk20a_exit(void)
        platform_driver_unregister(&gk20a_driver);
 }
 
+bool is_gk20a_module(struct platform_device *dev)
+{
+       return &gk20a_driver.driver == dev->dev.driver;
+}
+
 void gk20a_busy(struct platform_device *pdev)
 {
        struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
index 9a7df4e..3c77cb4 100644 (file)
@@ -28,6 +28,8 @@ struct channel_gk20a;
 struct gr_gk20a;
 struct sim_gk20a;
 
+#include "dev.h"
+
 #include <linux/tegra-soc.h>
 #include <linux/spinlock.h>
 #include <linux/nvhost_gpu_ioctl.h>
@@ -39,16 +41,13 @@ struct sim_gk20a;
 #include "pmu_gk20a.h"
 #include "priv_ring_gk20a.h"
 #include "therm_gk20a.h"
+#include "platform_gk20a.h"
 
 #include "../../../../../arch/arm/mach-tegra/iomap.h"
 
 extern struct platform_device tegra_gk20a_device;
-extern struct nvhost_device_data tegra_gk20a_info;
 
-static inline bool is_gk20a_module(struct platform_device *dev)
-{
-       return &tegra_gk20a_info == nvhost_get_devdata(dev);
-}
+bool is_gk20a_module(struct platform_device *dev);
 
 struct cooling_device_gk20a {
        struct thermal_cooling_device *gk20a_cooling_dev;
@@ -125,7 +124,7 @@ static inline unsigned long gk20a_get_gr_idle_timeout(struct gk20a *g)
 
 static inline struct gk20a *get_gk20a(struct platform_device *dev)
 {
-       return (struct gk20a *)nvhost_get_private_data(dev);
+       return gk20a_get_platform(dev)->g;
 }
 
 enum BAR0_DEBUG_OPERATION {
diff --git a/drivers/video/tegra/host/gk20a/platform_gk20a.h b/drivers/video/tegra/host/gk20a/platform_gk20a.h
new file mode 100644 (file)
index 0000000..3679ee7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * drivers/video/tegra/host/gk20a/soc/platform_gk20a.h
+ *
+ * GK20A Platform (SoC) Interface
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _GK20A_PLATFORM_H_
+#define _GK20A_PLATFORM_H_
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_TEGRA_GK20A
+#include <linux/nvhost.h>
+#endif
+
+struct gk20a;
+
+struct gk20a_platform {
+#ifdef CONFIG_TEGRA_GK20A
+       /* We need to have nvhost_device_data at the beginning, because
+        * nvhost assumes that it owns the platform_data. We can store
+        * gk20a platform info after that though. */
+       struct nvhost_device_data nvhost;
+#endif
+       /* Populated by the gk20a driver after probing the platform. */
+       struct gk20a *g;
+
+       /* Should be populated at probe. */
+       bool can_powergate;
+
+       /* Should be populated by probe. */
+       struct dentry *debugfs;
+
+       /* Initialize the platform interface of the gk20a driver.
+        *
+        * The platform implementation of this function must
+        *   - set the power and clocks of the gk20a device to a known
+        *     state, and
+        *   - populate the gk20a_platform structure (a pointer to the
+        *     structure can be obtained by calling gk20a_get_platform).
+        */
+       int (*probe)(struct platform_device *dev);
+};
+
+static inline struct gk20a_platform *gk20a_get_platform(
+               struct platform_device *dev)
+{
+       return (struct gk20a_platform *)platform_get_drvdata(dev);
+}
+
+extern struct gk20a_platform gk20a_generic_platform;
+#ifdef CONFIG_TEGRA_GK20A
+extern struct gk20a_platform gk20a_tegra_platform;
+#endif
+
+#endif
diff --git a/drivers/video/tegra/host/gk20a/platform_gk20a_generic.c b/drivers/video/tegra/host/gk20a/platform_gk20a_generic.c
new file mode 100644 (file)
index 0000000..7b750df
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * drivers/video/tegra/host/gk20a/platform_gk20a_generic.c
+ *
+ * GK20A Generic Platform Interface
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "platform_gk20a.h"
+
+static int gk20a_generic_probe(struct platform_device *dev)
+{
+       struct gk20a_platform *platform = gk20a_get_platform(dev);
+
+       /* TODO: Initialize clocks and power */
+       (void)platform;
+
+       return 0;
+}
+
+struct gk20a_platform gk20a_generic_platform = {
+       .probe = gk20a_generic_probe,
+};
diff --git a/drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c b/drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c
new file mode 100644 (file)
index 0000000..9db456f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c
+ *
+ * GK20A Tegra Platform Interface
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include "platform_gk20a.h"
+#include "gk20a_scale.h"
+#include "nvhost_acm.h"
+#include "bus_client.h"
+#include "class_ids.h"
+#include "t124/syncpt_t124.h"
+#include "gr3d/pod_scaling.h"
+#include "../../../../../arch/arm/mach-tegra/iomap.h"
+#include <linux/tegra-powergate.h>
+#include <linux/nvhost_ioctl.h>
+
+#include "gk20a.h"
+
+static int gk20a_tegra_probe(struct platform_device *dev)
+{
+       int err;
+       struct gk20a_platform *platform = gk20a_get_platform(dev);
+       struct nvhost_device_data *pdata = &platform->nvhost;
+
+       pdata->pdev = dev;
+       mutex_init(&pdata->lock);
+
+       /* Initialize clocks and power. */
+       err = nvhost_module_init(dev);
+       if (err)
+               return err;
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+       pdata->pd.name = "gk20a";
+
+       err = nvhost_module_add_domain(&pdata->pd, dev);
+       if (err)
+               goto fail;
+#endif
+
+       err = nvhost_client_device_init(dev);
+       if (err) {
+               nvhost_dbg_fn("failed to init client device for %s",
+                             dev->name);
+               goto fail;
+       }
+
+       platform->can_powergate = pdata->can_powergate;
+       platform->debugfs = pdata->debugfs;
+
+       return 0;
+
+fail:
+       nvhost_module_deinit(dev);
+       pdata->pdev = NULL;
+       return err;
+}
+
+static struct resource gk20a_tegra_resources[] = {
+       {
+       .start = TEGRA_GK20A_BAR0_BASE,
+       .end   = TEGRA_GK20A_BAR0_BASE + TEGRA_GK20A_BAR0_SIZE - 1,
+       .flags = IORESOURCE_MEM,
+       },
+       {
+       .start = TEGRA_GK20A_BAR1_BASE,
+       .end   = TEGRA_GK20A_BAR1_BASE + TEGRA_GK20A_BAR1_SIZE - 1,
+       .flags = IORESOURCE_MEM,
+       },
+};
+
+struct gk20a_platform gk20a_tegra_platform = {
+       .nvhost = {
+               .syncpts                = {NVSYNCPT_GK20A_BASE},
+               .syncpt_base            = NVSYNCPT_GK20A_BASE,
+               .class                  = NV_GRAPHICS_GPU_CLASS_ID,
+               .clocks                 = {{"PLLG_ref", UINT_MAX},
+                                          {"pwr", 204000000},
+                                          {"emc", UINT_MAX},
+                                          {} },
+               .powergate_ids          = { TEGRA_POWERGATE_GPU, -1 },
+               NVHOST_DEFAULT_CLOCKGATE_DELAY,
+               .powergate_delay        = 500,
+               .can_powergate          = true,
+               .alloc_hwctx_handler    = nvhost_gk20a_alloc_hwctx_handler,
+               .ctrl_ops               = &tegra_gk20a_ctrl_ops,
+               .dbg_ops                = &tegra_gk20a_dbg_gpu_ops,
+               .prof_ops               = &tegra_gk20a_prof_gpu_ops,
+               .as_ops                 = &tegra_gk20a_as_ops,
+               .moduleid               = NVHOST_MODULE_GPU,
+               .init                   = nvhost_gk20a_init,
+               .deinit                 = nvhost_gk20a_deinit,
+               .alloc_hwctx_handler    = nvhost_gk20a_alloc_hwctx_handler,
+               .prepare_poweroff       = nvhost_gk20a_prepare_poweroff,
+               .finalize_poweron       = nvhost_gk20a_finalize_poweron,
+#ifdef CONFIG_GK20A_DEVFREQ
+               .busy                   = nvhost_gk20a_scale_notify_busy,
+               .idle                   = nvhost_gk20a_scale_notify_idle,
+               .scaling_init           = nvhost_gk20a_scale_init,
+               .scaling_deinit         = nvhost_gk20a_scale_deinit,
+               .suspend_ndev           = nvhost_scale3d_suspend,
+               .devfreq_governor       = "nvhost_podgov",
+               .scaling_post_cb        = nvhost_gk20a_scale_callback,
+               .gpu_edp_device         = true,
+#endif
+       },
+       .probe = gk20a_tegra_probe,
+};
+
+struct platform_device tegra_gk20a_device = {
+       .name           = "gk20a",
+       .resource       = gk20a_tegra_resources,
+       .num_resources  = ARRAY_SIZE(gk20a_tegra_resources),
+       .dev            = {
+               .platform_data = &gk20a_tegra_platform,
+       },
+};
index db02b97..9598db3 100644 (file)
@@ -452,65 +452,6 @@ struct platform_device tegra_vic03_device = {
 };
 #endif
 
-#if defined(CONFIG_TEGRA_GK20A)
-struct resource gk20a_resources[] = {
-       {
-       .start = TEGRA_GK20A_BAR0_BASE,
-       .end   = TEGRA_GK20A_BAR0_BASE + TEGRA_GK20A_BAR0_SIZE - 1,
-       .flags = IORESOURCE_MEM,
-       },
-       {
-       .start = TEGRA_GK20A_BAR1_BASE,
-       .end   = TEGRA_GK20A_BAR1_BASE + TEGRA_GK20A_BAR1_SIZE - 1,
-       .flags = IORESOURCE_MEM,
-       },
-};
-
-struct nvhost_device_data tegra_gk20a_info = {
-       .syncpts                = {NVSYNCPT_GK20A_BASE},
-       .syncpt_base            = NVSYNCPT_GK20A_BASE,
-       .class                  = NV_GRAPHICS_GPU_CLASS_ID,
-       .clocks                 = {{"PLLG_ref", UINT_MAX},
-                                  {"pwr", 204000000},
-                                  {"emc", UINT_MAX},
-                                  {} },
-       .powergate_ids          = { TEGRA_POWERGATE_GPU, -1 },
-       NVHOST_DEFAULT_CLOCKGATE_DELAY,
-       .powergate_delay        = 500,
-       .can_powergate          = true,
-       .alloc_hwctx_handler    = nvhost_gk20a_alloc_hwctx_handler,
-       .ctrl_ops               = &tegra_gk20a_ctrl_ops,
-       .dbg_ops                = &tegra_gk20a_dbg_gpu_ops,
-       .prof_ops                = &tegra_gk20a_prof_gpu_ops,
-       .as_ops                 = &tegra_gk20a_as_ops,
-       .moduleid               = NVHOST_MODULE_GPU,
-       .init                   = nvhost_gk20a_init,
-       .deinit                 = nvhost_gk20a_deinit,
-       .alloc_hwctx_handler    = nvhost_gk20a_alloc_hwctx_handler,
-       .prepare_poweroff       = nvhost_gk20a_prepare_poweroff,
-       .finalize_poweron       = nvhost_gk20a_finalize_poweron,
-#ifdef CONFIG_GK20A_DEVFREQ
-       .busy                   = nvhost_gk20a_scale_notify_busy,
-       .idle                   = nvhost_gk20a_scale_notify_idle,
-       .scaling_init           = nvhost_gk20a_scale_init,
-       .scaling_deinit         = nvhost_gk20a_scale_deinit,
-       .suspend_ndev           = nvhost_scale3d_suspend,
-       .devfreq_governor       = "nvhost_podgov",
-       .scaling_post_cb        = nvhost_gk20a_scale_callback,
-       .gpu_edp_device         = true,
-#endif
-};
-
-struct platform_device tegra_gk20a_device = {
-       .name           = "gk20a",
-       .resource       = gk20a_resources,
-       .num_resources  = 2, /* this is num ioresource_mem, not the sum */
-       .dev            = {
-               .platform_data = &tegra_gk20a_info,
-       },
-};
-#endif
-
 static struct platform_device *t124_devices[] = {
        &tegra_isp01_device,
        &tegra_isp01b_device,