]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'drm-next-3.13' of git://people.freedesktop.org/~agd5f/linux into drm...
authorDave Airlie <airlied@redhat.com>
Tue, 5 Nov 2013 06:22:08 +0000 (16:22 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 5 Nov 2013 06:22:08 +0000 (16:22 +1000)
Initial pull request for radeon drm-next 3.13.  Highlights:
- Enable DPM on a number of asics by default
- Enable audio by default
- Dynamically power down dGPUs on PowerXpress systems
- Lots of bug fixes
* 'drm-next-3.13' of git://people.freedesktop.org/~agd5f/linux: (36 commits)
  drm/radeon: don't share PPLLs on DCE4.1
  drm/radeon/dpm: fix typo in setting smc flag
  drm/radeon: fixup locking inversion between, mmap_sem and reservations
  drm/radeon: clear the page directory using the DMA
  drm/radeon: initially clear page tables
  drm/radeon: drop CP page table updates & cleanup v2
  drm/radeon: add vm_set_page tracepoint
  drm/radeon: rework and fix reset detection v2
  drm/radeon: don't use PACKET2 on CIK
  drm/radeon: fix UVD destroy IB size
  drm/radeon: activate UVD clocks before sending the destroy msg
  drm/radeon/si: fix define for MC_SEQ_TRAIN_WAKEUP_CNTL
  drm/radeon: fix endian handling in rlc buffer setup
  drm/radeon/dpm: retain user selected performance level across state changes
  drm/radeon: disable force performance state when thermal state is active
  drm/radeon: enable DPM by default on r7xx asics
  drm/radeon: enable DPM by default on evergreen asics
  drm/radeon: enable DPM by default on BTC asics
  drm/radeon: enable DPM by default on SI asics
  drm/radeon: enable DPM by default on SUMO/PALM APUs
  ...

56 files changed:
MAINTAINERS
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/tegra/Kconfig [moved from drivers/gpu/host1x/drm/Kconfig with 90% similarity]
drivers/gpu/drm/tegra/Makefile [new file with mode: 0644]
drivers/gpu/drm/tegra/bus.c [new file with mode: 0644]
drivers/gpu/drm/tegra/dc.c [moved from drivers/gpu/host1x/drm/dc.c with 93% similarity]
drivers/gpu/drm/tegra/dc.h [moved from drivers/gpu/host1x/drm/dc.h with 98% similarity]
drivers/gpu/drm/tegra/drm.c [moved from drivers/gpu/host1x/drm/drm.c with 50% similarity]
drivers/gpu/drm/tegra/drm.h [moved from drivers/gpu/host1x/drm/drm.h with 72% similarity]
drivers/gpu/drm/tegra/fb.c [moved from drivers/gpu/host1x/drm/fb.c with 92% similarity]
drivers/gpu/drm/tegra/gem.c [moved from drivers/gpu/host1x/drm/gem.c with 86% similarity]
drivers/gpu/drm/tegra/gem.h [moved from drivers/gpu/host1x/drm/gem.h with 84% similarity]
drivers/gpu/drm/tegra/gr2d.c [new file with mode: 0644]
drivers/gpu/drm/tegra/gr2d.h [new file with mode: 0644]
drivers/gpu/drm/tegra/gr3d.c [new file with mode: 0644]
drivers/gpu/drm/tegra/gr3d.h [new file with mode: 0644]
drivers/gpu/drm/tegra/hdmi.c [moved from drivers/gpu/host1x/drm/hdmi.c with 83% similarity]
drivers/gpu/drm/tegra/hdmi.h [moved from drivers/gpu/host1x/drm/hdmi.h with 72% similarity]
drivers/gpu/drm/tegra/output.c [moved from drivers/gpu/host1x/drm/output.c with 91% similarity]
drivers/gpu/drm/tegra/rgb.c [moved from drivers/gpu/host1x/drm/rgb.c with 96% similarity]
drivers/gpu/host1x/Kconfig
drivers/gpu/host1x/Makefile
drivers/gpu/host1x/bus.c [new file with mode: 0644]
drivers/gpu/host1x/bus.h [moved from drivers/gpu/host1x/host1x_client.h with 60% similarity]
drivers/gpu/host1x/cdma.c
drivers/gpu/host1x/channel.h
drivers/gpu/host1x/dev.c
drivers/gpu/host1x/dev.h
drivers/gpu/host1x/drm/gr2d.c [deleted file]
drivers/gpu/host1x/host1x.h [deleted file]
drivers/gpu/host1x/host1x_bo.h [deleted file]
drivers/gpu/host1x/hw/Makefile [deleted file]
drivers/gpu/host1x/hw/cdma_hw.c
drivers/gpu/host1x/hw/channel_hw.c
drivers/gpu/host1x/hw/debug_hw.c
drivers/gpu/host1x/hw/host1x01.c
drivers/gpu/host1x/hw/host1x02.c [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x02.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x01_uclass.h
drivers/gpu/host1x/hw/hw_host1x02_channel.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x02_sync.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x02_uclass.h [new file with mode: 0644]
drivers/gpu/host1x/hw/intr_hw.c
drivers/gpu/host1x/hw/syncpt_hw.c
drivers/gpu/host1x/job.c
drivers/gpu/host1x/job.h
drivers/gpu/host1x/syncpt.c
drivers/gpu/host1x/syncpt.h
drivers/video/Kconfig
include/drm/drmP.h
include/linux/host1x.h [new file with mode: 0644]
include/uapi/drm/tegra_drm.h

index 284969fa28967fc1d0b134f06efb055b6a1cbfd0..4907a747f3e02fed8cd6ded387cf430adcba0c7e 100644 (file)
@@ -2816,7 +2816,9 @@ L:        dri-devel@lists.freedesktop.org
 L:     linux-tegra@vger.kernel.org
 T:     git git://anongit.freedesktop.org/tegra/linux.git
 S:     Maintained
+F:     drivers/gpu/drm/tegra/
 F:     drivers/gpu/host1x/
+F:     include/linux/host1x.h
 F:     include/uapi/drm/tegra_drm.h
 F:     Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
 
index e41a2d0311f8b515e47b1103a1cada02bdc91212..f8642759116770afa976a23f12f14f1f42149be4 100644 (file)
@@ -189,3 +189,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig"
 source "drivers/gpu/drm/qxl/Kconfig"
 
 source "drivers/gpu/drm/msm/Kconfig"
+
+source "drivers/gpu/drm/tegra/Kconfig"
index 5266e9fae2161b6430b6d8a799834e914093f5c8..cc08b845f9655a6b8bb516dab365da2d4c829198 100644 (file)
@@ -57,4 +57,5 @@ obj-$(CONFIG_DRM_OMAP)        += omapdrm/
 obj-$(CONFIG_DRM_TILCDC)       += tilcdc/
 obj-$(CONFIG_DRM_QXL) += qxl/
 obj-$(CONFIG_DRM_MSM) += msm/
+obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-y                  += i2c/
index dbcd68709ab7ae06f5de70d7f75a147539d758af..305b4cdcfb29ce1c5bf45d0a50ad51782c897e6a 100644 (file)
@@ -567,6 +567,14 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
                                continue;
 
                        connector->encoder = NULL;
+
+                       /*
+                        * drm_helper_disable_unused_functions() ought to be
+                        * doing this, but since we've decoupled the encoder
+                        * from the connector above, the required connection
+                        * between them is henceforth no longer available.
+                        */
+                       connector->dpms = DRM_MODE_DPMS_OFF;
                }
        }
 
index b55f138bd990e5563168b82ee7ea4a3c2729f3dc..138de14134f034927b3ffb3cadf0fc466802db47 100644 (file)
@@ -396,7 +396,7 @@ long drm_ioctl(struct file *filp,
 
       err_i1:
        if (!ioctl)
-               DRM_DEBUG("invalid iotcl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
+               DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
                          task_pid_nr(current),
                          (long)old_encode_dev(file_priv->minor->device),
                          file_priv->authenticated, cmd, nr);
index 88722f233430a3d0f7eb4e8b35ad929b709c5b35..f437b30ce6896736da893c2a8651ca23e0a1ed55 100644 (file)
@@ -108,7 +108,7 @@ static void qxl_fb_dirty_flush(struct fb_info *info)
        u32 x1, x2, y1, y2;
 
        /* TODO: hard coding 32 bpp */
-       int stride = qfbdev->qfb.base.pitches[0] * 4;
+       int stride = qfbdev->qfb.base.pitches[0];
 
        x1 = qfbdev->dirty.x1;
        x2 = qfbdev->dirty.x2;
similarity index 90%
rename from drivers/gpu/host1x/drm/Kconfig
rename to drivers/gpu/drm/tegra/Kconfig
index 0f36ddd74e87ccc317924ee617f8c1150d86ed83..8961ba6a34b879246e9b90defc1b129c2ebeea0f 100644 (file)
@@ -1,6 +1,8 @@
 config DRM_TEGRA
        bool "NVIDIA Tegra DRM"
+       depends on ARCH_TEGRA || ARCH_MULTIPLATFORM
        depends on DRM
+       select TEGRA_HOST1X
        select DRM_KMS_HELPER
        select DRM_KMS_FB_HELPER
        select FB_SYS_FILLRECT
@@ -14,6 +16,11 @@ config DRM_TEGRA
 
 if DRM_TEGRA
 
+config DRM_TEGRA_DEBUG
+       bool "NVIDIA Tegra DRM debug support"
+       help
+         Say yes here to enable debugging support.
+
 config DRM_TEGRA_STAGING
        bool "Enable HOST1X interface"
        depends on STAGING
@@ -22,9 +29,4 @@ config DRM_TEGRA_STAGING
 
          If unsure, choose N.
 
-config DRM_TEGRA_DEBUG
-       bool "NVIDIA Tegra DRM debug support"
-       help
-         Say yes here to enable debugging support.
-
 endif
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
new file mode 100644 (file)
index 0000000..edc76ab
--- /dev/null
@@ -0,0 +1,15 @@
+ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
+
+tegra-drm-y := \
+       bus.o \
+       drm.o \
+       gem.o \
+       fb.o \
+       dc.o \
+       output.o \
+       rgb.o \
+       hdmi.o \
+       gr2d.o \
+       gr3d.o
+
+obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o
diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c
new file mode 100644 (file)
index 0000000..565f8f7
--- /dev/null
@@ -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);
+}
similarity index 93%
rename from drivers/gpu/host1x/drm/dc.c
rename to drivers/gpu/drm/tegra/dc.c
index b1a05ad901c3d4758f4d768efc5b276d2dc4ee8e..ae1cb31ead7e4256c32f6ea045395347780a25a8 100644 (file)
@@ -8,13 +8,9 @@
  */
 
 #include <linux/clk.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
 #include <linux/clk/tegra.h>
+#include <linux/debugfs.h>
 
-#include "host1x_client.h"
 #include "dc.h"
 #include "drm.h"
 #include "gem.h"
@@ -51,6 +47,8 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        window.dst.h = crtc_h;
        window.format = tegra_dc_format(fb->pixel_format);
        window.bits_per_pixel = fb->bits_per_pixel;
+       window.bottom_up = tegra_fb_is_bottom_up(fb);
+       window.tiled = tegra_fb_is_tiled(fb);
 
        for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
                struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
@@ -97,8 +95,11 @@ static int tegra_plane_disable(struct drm_plane *plane)
 
 static void tegra_plane_destroy(struct drm_plane *plane)
 {
+       struct tegra_plane *p = to_tegra_plane(plane);
+
        tegra_plane_disable(plane);
        drm_plane_cleanup(plane);
+       kfree(p);
 }
 
 static const struct drm_plane_funcs tegra_plane_funcs = {
@@ -124,7 +125,7 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
        for (i = 0; i < 2; i++) {
                struct tegra_plane *plane;
 
-               plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL);
+               plane = kzalloc(sizeof(*plane), GFP_KERNEL);
                if (!plane)
                        return -ENOMEM;
 
@@ -133,8 +134,10 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
                err = drm_plane_init(drm, &plane->base, 1 << dc->pipe,
                                     &tegra_plane_funcs, plane_formats,
                                     ARRAY_SIZE(plane_formats), false);
-               if (err < 0)
+               if (err < 0) {
+                       kfree(plane);
                        return err;
+               }
        }
 
        return 0;
@@ -145,6 +148,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
 {
        unsigned int format = tegra_dc_format(fb->pixel_format);
        struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
+       unsigned int h_offset = 0, v_offset = 0;
        unsigned long value;
 
        tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -156,6 +160,32 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
        tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
 
+       if (tegra_fb_is_tiled(fb)) {
+               value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_TILE;
+       } else {
+               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
+       }
+
+       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+
+       /* make sure bottom-up buffers are properly displayed */
+       if (tegra_fb_is_bottom_up(fb)) {
+               value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+               value |= INVERT_V;
+               tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+               v_offset += fb->height - 1;
+       } else {
+               value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+               value &= ~INVERT_V;
+               tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+       }
+
+       tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
+       tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
+
        value = GENERAL_UPDATE | WIN_A_UPDATE;
        tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 
@@ -255,14 +285,26 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        return 0;
 }
 
+static void drm_crtc_clear(struct drm_crtc *crtc)
+{
+       memset(crtc, 0, sizeof(*crtc));
+}
+
+static void tegra_dc_destroy(struct drm_crtc *crtc)
+{
+       drm_crtc_cleanup(crtc);
+       drm_crtc_clear(crtc);
+}
+
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
        .page_flip = tegra_dc_page_flip,
        .set_config = drm_crtc_helper_set_config,
-       .destroy = drm_crtc_cleanup,
+       .destroy = tegra_dc_destroy,
 };
 
 static void tegra_crtc_disable(struct drm_crtc *crtc)
 {
+       struct tegra_dc *dc = to_tegra_dc(crtc);
        struct drm_device *drm = crtc->dev;
        struct drm_plane *plane;
 
@@ -277,6 +319,8 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
                        }
                }
        }
+
+       drm_vblank_off(drm, dc->pipe);
 }
 
 static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -491,9 +535,22 @@ int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
                tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
        }
 
+       if (window->bottom_up)
+               v_offset += window->src.h - 1;
+
        tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
        tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
 
+       if (window->tiled) {
+               value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_TILE;
+       } else {
+               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
+                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
+       }
+
+       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+
        value = WIN_ENABLE;
 
        if (yuv) {
@@ -512,6 +569,9 @@ int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
                value |= COLOR_EXPAND;
        }
 
+       if (window->bottom_up)
+               value |= INVERT_V;
+
        tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
 
        /*
@@ -1041,30 +1101,30 @@ static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
        return 0;
 }
 
-static int tegra_dc_drm_init(struct host1x_client *client,
-                            struct drm_device *drm)
+static int tegra_dc_init(struct host1x_client *client)
 {
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
        struct tegra_dc *dc = host1x_client_to_dc(client);
        int err;
 
-       dc->pipe = drm->mode_config.num_crtc;
+       dc->pipe = tegra->drm->mode_config.num_crtc;
 
-       drm_crtc_init(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, 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, 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->primary);
+               err = tegra_dc_debugfs_init(dc, tegra->drm->primary);
                if (err < 0)
                        dev_err(dc->dev, "debugfs setup failed: %d\n", err);
        }
@@ -1080,7 +1140,7 @@ static int tegra_dc_drm_init(struct host1x_client *client,
        return 0;
 }
 
-static int tegra_dc_drm_exit(struct host1x_client *client)
+static int tegra_dc_exit(struct host1x_client *client)
 {
        struct tegra_dc *dc = host1x_client_to_dc(client);
        int err;
@@ -1103,13 +1163,12 @@ static int tegra_dc_drm_exit(struct host1x_client *client)
 }
 
 static const struct host1x_client_ops dc_client_ops = {
-       .drm_init = tegra_dc_drm_init,
-       .drm_exit = tegra_dc_drm_exit,
+       .init = tegra_dc_init,
+       .exit = tegra_dc_exit,
 };
 
 static int tegra_dc_probe(struct platform_device *pdev)
 {
-       struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
        struct resource *regs;
        struct tegra_dc *dc;
        int err;
@@ -1153,7 +1212,7 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return err;
        }
 
-       err = host1x_register_client(host1x, &dc->client);
+       err = host1x_client_register(&dc->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
                        err);
@@ -1167,17 +1226,22 @@ static int tegra_dc_probe(struct platform_device *pdev)
 
 static int tegra_dc_remove(struct platform_device *pdev)
 {
-       struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
        struct tegra_dc *dc = platform_get_drvdata(pdev);
        int err;
 
-       err = host1x_unregister_client(host1x, &dc->client);
+       err = host1x_client_unregister(&dc->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
                        err);
                return err;
        }
 
+       err = tegra_dc_rgb_remove(dc);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err);
+               return err;
+       }
+
        clk_disable_unprepare(dc->clk);
 
        return 0;
similarity index 98%
rename from drivers/gpu/host1x/drm/dc.h
rename to drivers/gpu/drm/tegra/dc.h
index 79eaec9aac7752a27bddd06a4c08cf7f2292eac8..91bbda291470c29ce3ba80a70b0e5d541b8c6556 100644 (file)
 #define DC_WIN_CSC_KVB                         0x618
 
 #define DC_WIN_WIN_OPTIONS                     0x700
+#define INVERT_V     (1 <<  2)
 #define COLOR_EXPAND (1 <<  6)
 #define CSC_ENABLE   (1 << 18)
 #define WIN_ENABLE   (1 << 30)
 #define DC_WIN_BUF_STRIDE                      0x70b
 #define DC_WIN_UV_BUF_STRIDE                   0x70c
 #define DC_WIN_BUFFER_ADDR_MODE                        0x70d
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR         (0 <<  0)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE           (1 <<  0)
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV      (0 << 16)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE_UV                (1 << 16)
 #define DC_WIN_DV_CONTROL                      0x70e
 
 #define DC_WIN_BLEND_NOKEY                     0x70f
similarity index 50%
rename from drivers/gpu/host1x/drm/drm.c
rename to drivers/gpu/drm/tegra/drm.c
index df7d90a3a4fa7a18dda505366e7e6c35ba8cfbb7..28e178137718090f317c8884da071458900cce65 100644 (file)
@@ -7,21 +7,10 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/host1x.h>
 
-#include <linux/dma-mapping.h>
-#include <asm/dma-iommu.h>
-
-#include <drm/drm.h>
-#include <drm/drmP.h>
-
-#include "host1x_client.h"
-#include "dev.h"
 #include "drm.h"
 #include "gem.h"
-#include "syncpt.h"
 
 #define DRIVER_NAME "tegra"
 #define DRIVER_DESC "NVIDIA Tegra graphics"
 #define DRIVER_MINOR 0
 #define DRIVER_PATCHLEVEL 0
 
-struct host1x_drm_client {
-       struct host1x_client *client;
-       struct device_node *np;
-       struct list_head list;
+struct tegra_drm_file {
+       struct list_head contexts;
 };
 
-static int host1x_add_drm_client(struct host1x_drm *host1x,
-                                struct device_node *np)
+static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 {
-       struct host1x_drm_client *client;
+       struct host1x_device *device = to_host1x_device(drm->dev);
+       struct tegra_drm *tegra;
+       int err;
 
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (!client)
+       tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
+       if (!tegra)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&client->list);
-       client->np = of_node_get(np);
+       dev_set_drvdata(drm->dev, tegra);
+       mutex_init(&tegra->clients_lock);
+       INIT_LIST_HEAD(&tegra->clients);
+       drm->dev_private = tegra;
+       tegra->drm = drm;
 
-       list_add_tail(&client->list, &host1x->drm_clients);
+       drm_mode_config_init(drm);
 
-       return 0;
-}
+       err = host1x_device_init(device);
+       if (err < 0)
+               return err;
 
-static int host1x_activate_drm_client(struct host1x_drm *host1x,
-                                     struct host1x_drm_client *drm,
-                                     struct host1x_client *client)
-{
-       mutex_lock(&host1x->drm_clients_lock);
-       list_del_init(&drm->list);
-       list_add_tail(&drm->list, &host1x->drm_active);
-       drm->client = client;
-       mutex_unlock(&host1x->drm_clients_lock);
+       /*
+        * We don't use the drm_irq_install() helpers provided by the DRM
+        * core, so we need to set this manually in order to allow the
+        * DRM_IOCTL_WAIT_VBLANK to operate correctly.
+        */
+       drm->irq_enabled = true;
 
-       return 0;
-}
+       err = drm_vblank_init(drm, drm->mode_config.num_crtc);
+       if (err < 0)
+               return err;
 
-static int host1x_remove_drm_client(struct host1x_drm *host1x,
-                                   struct host1x_drm_client *client)
-{
-       mutex_lock(&host1x->drm_clients_lock);
-       list_del_init(&client->list);
-       mutex_unlock(&host1x->drm_clients_lock);
+       err = tegra_drm_fb_init(drm);
+       if (err < 0)
+               return err;
 
-       of_node_put(client->np);
-       kfree(client);
+       drm_kms_helper_poll_init(drm);
 
        return 0;
 }
 
-static int host1x_parse_dt(struct host1x_drm *host1x)
+static int tegra_drm_unload(struct drm_device *drm)
 {
-       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;
+       struct host1x_device *device = to_host1x_device(drm->dev);
        int err;
 
-       for (i = 0; i < ARRAY_SIZE(compat); i++) {
-               struct device_node *np;
+       drm_kms_helper_poll_fini(drm);
+       tegra_drm_fb_exit(drm);
+       drm_vblank_cleanup(drm);
+       drm_mode_config_cleanup(drm);
 
-               for_each_child_of_node(host1x->dev->of_node, np) {
-                       if (of_device_is_compatible(np, compat[i]) &&
-                           of_device_is_available(np)) {
-                               err = host1x_add_drm_client(host1x, np);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-       }
+       err = host1x_device_exit(device);
+       if (err < 0)
+               return err;
 
        return 0;
 }
 
-int host1x_drm_alloc(struct platform_device *pdev)
+static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
 {
-       struct host1x_drm *host1x;
-       int err;
+       struct tegra_drm_file *fpriv;
 
-       host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL);
-       if (!host1x)
+       fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+       if (!fpriv)
                return -ENOMEM;
 
-       mutex_init(&host1x->drm_clients_lock);
-       INIT_LIST_HEAD(&host1x->drm_clients);
-       INIT_LIST_HEAD(&host1x->drm_active);
-       mutex_init(&host1x->clients_lock);
-       INIT_LIST_HEAD(&host1x->clients);
-       host1x->dev = &pdev->dev;
-
-       err = host1x_parse_dt(host1x);
-       if (err < 0) {
-               dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
-               return err;
-       }
-
-       host1x_set_drm_data(&pdev->dev, host1x);
+       INIT_LIST_HEAD(&fpriv->contexts);
+       filp->driver_priv = fpriv;
 
        return 0;
 }
 
-int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
+static void tegra_drm_context_free(struct tegra_drm_context *context)
 {
-       struct host1x_client *client;
-
-       mutex_lock(&host1x->clients_lock);
-
-       list_for_each_entry(client, &host1x->clients, list) {
-               if (client->ops && client->ops->drm_init) {
-                       int err = client->ops->drm_init(client, drm);
-                       if (err < 0) {
-                               dev_err(host1x->dev,
-                                       "DRM setup failed for %s: %d\n",
-                                       dev_name(client->dev), err);
-                               mutex_unlock(&host1x->clients_lock);
-                               return err;
-                       }
-               }
-       }
-
-       mutex_unlock(&host1x->clients_lock);
-
-       return 0;
+       context->client->ops->close_channel(context);
+       kfree(context);
 }
 
-int host1x_drm_exit(struct host1x_drm *host1x)
+static void tegra_drm_lastclose(struct drm_device *drm)
 {
-       struct platform_device *pdev = to_platform_device(host1x->dev);
-       struct host1x_client *client;
-
-       if (!host1x->drm)
-               return 0;
-
-       mutex_lock(&host1x->clients_lock);
+       struct tegra_drm *tegra = drm->dev_private;
 
-       list_for_each_entry_reverse(client, &host1x->clients, list) {
-               if (client->ops && client->ops->drm_exit) {
-                       int err = client->ops->drm_exit(client);
-                       if (err < 0) {
-                               dev_err(host1x->dev,
-                                       "DRM cleanup failed for %s: %d\n",
-                                       dev_name(client->dev), err);
-                               mutex_unlock(&host1x->clients_lock);
-                               return err;
-                       }
-               }
-       }
+       tegra_fbdev_restore_mode(tegra->fbdev);
+}
 
-       mutex_unlock(&host1x->clients_lock);
+static struct host1x_bo *
+host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
+{
+       struct drm_gem_object *gem;
+       struct tegra_bo *bo;
 
-       drm_platform_exit(&tegra_drm_driver, pdev);
-       host1x->drm = NULL;
+       gem = drm_gem_object_lookup(drm, file, handle);
+       if (!gem)
+               return NULL;
 
-       return 0;
-}
+       mutex_lock(&drm->struct_mutex);
+       drm_gem_object_unreference(gem);
+       mutex_unlock(&drm->struct_mutex);
 
-int host1x_register_client(struct host1x_drm *host1x,
-                          struct host1x_client *client)
-{
-       struct host1x_drm_client *drm, *tmp;
+       bo = to_tegra_bo(gem);
+       return &bo->base;
+}
+
+int tegra_drm_submit(struct tegra_drm_context *context,
+                    struct drm_tegra_submit *args, struct drm_device *drm,
+                    struct drm_file *file)
+{
+       unsigned int num_cmdbufs = args->num_cmdbufs;
+       unsigned int num_relocs = args->num_relocs;
+       unsigned int num_waitchks = args->num_waitchks;
+       struct drm_tegra_cmdbuf __user *cmdbufs =
+               (void * __user)(uintptr_t)args->cmdbufs;
+       struct drm_tegra_reloc __user *relocs =
+               (void * __user)(uintptr_t)args->relocs;
+       struct drm_tegra_waitchk __user *waitchks =
+               (void * __user)(uintptr_t)args->waitchks;
+       struct drm_tegra_syncpt syncpt;
+       struct host1x_job *job;
        int err;
 
-       mutex_lock(&host1x->clients_lock);
-       list_add_tail(&client->list, &host1x->clients);
-       mutex_unlock(&host1x->clients_lock);
+       /* We don't yet support other than one syncpt_incr struct per submit */
+       if (args->num_syncpts != 1)
+               return -EINVAL;
 
-       list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list)
-               if (drm->np == client->dev->of_node)
-                       host1x_activate_drm_client(host1x, drm, client);
+       job = host1x_job_alloc(context->channel, args->num_cmdbufs,
+                              args->num_relocs, args->num_waitchks);
+       if (!job)
+               return -ENOMEM;
 
-       if (list_empty(&host1x->drm_clients)) {
-               struct platform_device *pdev = to_platform_device(host1x->dev);
+       job->num_relocs = args->num_relocs;
+       job->num_waitchk = args->num_waitchks;
+       job->client = (u32)args->context;
+       job->class = context->client->base.class;
+       job->serialize = true;
 
-               err = drm_platform_init(&tegra_drm_driver, pdev);
-               if (err < 0) {
-                       dev_err(host1x->dev, "drm_platform_init(): %d\n", err);
-                       return err;
-               }
-       }
+       while (num_cmdbufs) {
+               struct drm_tegra_cmdbuf cmdbuf;
+               struct host1x_bo *bo;
 
-       return 0;
-}
+               err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
+               if (err)
+                       goto fail;
 
-int host1x_unregister_client(struct host1x_drm *host1x,
-                            struct host1x_client *client)
-{
-       struct host1x_drm_client *drm, *tmp;
-       int err;
-
-       list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) {
-               if (drm->client == client) {
-                       err = host1x_drm_exit(host1x);
-                       if (err < 0) {
-                               dev_err(host1x->dev, "host1x_drm_exit(): %d\n",
-                                       err);
-                               return err;
-                       }
-
-                       host1x_remove_drm_client(host1x, drm);
-                       break;
+               bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
+               if (!bo) {
+                       err = -ENOENT;
+                       goto fail;
                }
+
+               host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
+               num_cmdbufs--;
+               cmdbufs++;
        }
 
-       mutex_lock(&host1x->clients_lock);
-       list_del_init(&client->list);
-       mutex_unlock(&host1x->clients_lock);
+       err = copy_from_user(job->relocarray, relocs,
+                            sizeof(*relocs) * num_relocs);
+       if (err)
+               goto fail;
 
-       return 0;
-}
+       while (num_relocs--) {
+               struct host1x_reloc *reloc = &job->relocarray[num_relocs];
+               struct host1x_bo *cmdbuf, *target;
 
-static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
-{
-       struct host1x_drm *host1x;
-       int err;
+               cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
+               target = host1x_bo_lookup(drm, file, (u32)reloc->target);
 
-       host1x = host1x_get_drm_data(drm->dev);
-       drm->dev_private = host1x;
-       host1x->drm = drm;
+               reloc->cmdbuf = cmdbuf;
+               reloc->target = target;
 
-       drm_mode_config_init(drm);
+               if (!reloc->target || !reloc->cmdbuf) {
+                       err = -ENOENT;
+                       goto fail;
+               }
+       }
 
-       err = host1x_drm_init(host1x, drm);
-       if (err < 0)
-               return err;
+       err = copy_from_user(job->waitchk, waitchks,
+                            sizeof(*waitchks) * num_waitchks);
+       if (err)
+               goto fail;
 
-       /*
-        * We don't use the drm_irq_install() helpers provided by the DRM
-        * core, so we need to set this manually in order to allow the
-        * DRM_IOCTL_WAIT_VBLANK to operate correctly.
-        */
-       drm->irq_enabled = true;
+       err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts,
+                            sizeof(syncpt));
+       if (err)
+               goto fail;
 
-       err = drm_vblank_init(drm, drm->mode_config.num_crtc);
-       if (err < 0)
-               return err;
+       job->is_addr_reg = context->client->ops->is_addr_reg;
+       job->syncpt_incrs = syncpt.incrs;
+       job->syncpt_id = syncpt.id;
+       job->timeout = 10000;
 
-       err = tegra_drm_fb_init(drm);
-       if (err < 0)
-               return err;
+       if (args->timeout && args->timeout < 10000)
+               job->timeout = args->timeout;
 
-       drm_kms_helper_poll_init(drm);
+       err = host1x_job_pin(job, context->client->base.dev);
+       if (err)
+               goto fail;
 
-       return 0;
-}
+       err = host1x_job_submit(job);
+       if (err)
+               goto fail_submit;
 
-static int tegra_drm_unload(struct drm_device *drm)
-{
-       drm_kms_helper_poll_fini(drm);
-       tegra_drm_fb_exit(drm);
-
-       drm_mode_config_cleanup(drm);
+       args->fence = job->syncpt_end;
 
+       host1x_job_put(job);
        return 0;
-}
 
-static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
-{
-       struct host1x_drm_file *fpriv;
-
-       fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
-       if (!fpriv)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&fpriv->contexts);
-       filp->driver_priv = fpriv;
-
-       return 0;
+fail_submit:
+       host1x_job_unpin(job);
+fail:
+       host1x_job_put(job);
+       return err;
 }
 
-static void host1x_drm_context_free(struct host1x_drm_context *context)
-{
-       context->client->ops->close_channel(context);
-       kfree(context);
-}
 
-static void tegra_drm_lastclose(struct drm_device *drm)
+#ifdef CONFIG_DRM_TEGRA_STAGING
+static struct tegra_drm_context *tegra_drm_get_context(__u64 context)
 {
-       struct host1x_drm *host1x = drm->dev_private;
-
-       tegra_fbdev_restore_mode(host1x->fbdev);
+       return (struct tegra_drm_context *)(uintptr_t)context;
 }
 
-#ifdef CONFIG_DRM_TEGRA_STAGING
-static bool host1x_drm_file_owns_context(struct host1x_drm_file *file,
-                                        struct host1x_drm_context *context)
+static bool tegra_drm_file_owns_context(struct tegra_drm_file *file,
+                                       struct tegra_drm_context *context)
 {
-       struct host1x_drm_context *ctx;
+       struct tegra_drm_context *ctx;
 
        list_for_each_entry(ctx, &file->contexts, list)
                if (ctx == context)
@@ -335,7 +262,7 @@ static int tegra_gem_create(struct drm_device *drm, void *data,
        struct drm_tegra_gem_create *args = data;
        struct tegra_bo *bo;
 
-       bo = tegra_bo_create_with_handle(file, drm, args->size,
+       bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags,
                                         &args->handle);
        if (IS_ERR(bo))
                return PTR_ERR(bo);
@@ -366,10 +293,11 @@ static int tegra_gem_mmap(struct drm_device *drm, void *data,
 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;
 
@@ -380,10 +308,11 @@ static int tegra_syncpt_read(struct drm_device *drm, void *data,
 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;
 
@@ -393,10 +322,11 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data,
 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;
 
@@ -407,26 +337,26 @@ static int tegra_syncpt_wait(struct drm_device *drm, void *data,
 static int tegra_open_channel(struct drm_device *drm, void *data,
                              struct drm_file *file)
 {
+       struct tegra_drm_file *fpriv = file->driver_priv;
+       struct tegra_drm *tegra = drm->dev_private;
        struct drm_tegra_open_channel *args = data;
-       struct host1x_client *client;
-       struct host1x_drm_context *context;
-       struct host1x_drm_file *fpriv = file->driver_priv;
-       struct host1x_drm *host1x = drm->dev_private;
+       struct tegra_drm_context *context;
+       struct tegra_drm_client *client;
        int err = -ENODEV;
 
        context = kzalloc(sizeof(*context), GFP_KERNEL);
        if (!context)
                return -ENOMEM;
 
-       list_for_each_entry(client, &host1x->clients, list)
-               if (client->class == args->client) {
+       list_for_each_entry(client, &tegra->clients, list)
+               if (client->base.class == args->client) {
                        err = client->ops->open_channel(client, context);
                        if (err)
                                break;
 
-                       context->client = client;
                        list_add(&context->list, &fpriv->contexts);
                        args->context = (uintptr_t)context;
+                       context->client = client;
                        return 0;
                }
 
@@ -437,16 +367,17 @@ static int tegra_open_channel(struct drm_device *drm, void *data,
 static int tegra_close_channel(struct drm_device *drm, void *data,
                               struct drm_file *file)
 {
+       struct tegra_drm_file *fpriv = file->driver_priv;
        struct drm_tegra_close_channel *args = data;
-       struct host1x_drm_file *fpriv = file->driver_priv;
-       struct host1x_drm_context *context =
-               (struct host1x_drm_context *)(uintptr_t)args->context;
+       struct tegra_drm_context *context;
+
+       context = tegra_drm_get_context(args->context);
 
-       if (!host1x_drm_file_owns_context(fpriv, context))
+       if (!tegra_drm_file_owns_context(fpriv, context))
                return -EINVAL;
 
        list_del(&context->list);
-       host1x_drm_context_free(context);
+       tegra_drm_context_free(context);
 
        return 0;
 }
@@ -454,19 +385,20 @@ static int tegra_close_channel(struct drm_device *drm, void *data,
 static int tegra_get_syncpt(struct drm_device *drm, void *data,
                            struct drm_file *file)
 {
+       struct tegra_drm_file *fpriv = file->driver_priv;
        struct drm_tegra_get_syncpt *args = data;
-       struct host1x_drm_file *fpriv = file->driver_priv;
-       struct host1x_drm_context *context =
-               (struct host1x_drm_context *)(uintptr_t)args->context;
+       struct tegra_drm_context *context;
        struct host1x_syncpt *syncpt;
 
-       if (!host1x_drm_file_owns_context(fpriv, context))
+       context = tegra_drm_get_context(args->context);
+
+       if (!tegra_drm_file_owns_context(fpriv, context))
                return -ENODEV;
 
-       if (args->index >= context->client->num_syncpts)
+       if (args->index >= context->client->base.num_syncpts)
                return -EINVAL;
 
-       syncpt = context->client->syncpts[args->index];
+       syncpt = context->client->base.syncpts[args->index];
        args->id = host1x_syncpt_id(syncpt);
 
        return 0;
@@ -475,16 +407,45 @@ static int tegra_get_syncpt(struct drm_device *drm, void *data,
 static int tegra_submit(struct drm_device *drm, void *data,
                        struct drm_file *file)
 {
+       struct tegra_drm_file *fpriv = file->driver_priv;
        struct drm_tegra_submit *args = data;
-       struct host1x_drm_file *fpriv = file->driver_priv;
-       struct host1x_drm_context *context =
-               (struct host1x_drm_context *)(uintptr_t)args->context;
+       struct tegra_drm_context *context;
 
-       if (!host1x_drm_file_owns_context(fpriv, context))
+       context = tegra_drm_get_context(args->context);
+
+       if (!tegra_drm_file_owns_context(fpriv, context))
                return -ENODEV;
 
        return context->client->ops->submit(context, args, drm, file);
 }
+
+static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
+                                struct drm_file *file)
+{
+       struct tegra_drm_file *fpriv = file->driver_priv;
+       struct drm_tegra_get_syncpt_base *args = data;
+       struct tegra_drm_context *context;
+       struct host1x_syncpt_base *base;
+       struct host1x_syncpt *syncpt;
+
+       context = tegra_drm_get_context(args->context);
+
+       if (!tegra_drm_file_owns_context(fpriv, context))
+               return -ENODEV;
+
+       if (args->syncpt >= context->client->base.num_syncpts)
+               return -EINVAL;
+
+       syncpt = context->client->base.syncpts[args->syncpt];
+
+       base = host1x_syncpt_get_base(syncpt);
+       if (!base)
+               return -ENXIO;
+
+       args->id = host1x_syncpt_base_id(base);
+
+       return 0;
+}
 #endif
 
 static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
@@ -498,6 +459,7 @@ static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
        DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED),
 #endif
 };
 
@@ -559,15 +521,15 @@ static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
 
 static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
 {
-       struct host1x_drm_file *fpriv = file->driver_priv;
-       struct host1x_drm_context *context, *tmp;
+       struct tegra_drm_file *fpriv = file->driver_priv;
+       struct tegra_drm_context *context, *tmp;
        struct drm_crtc *crtc;
 
        list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
                tegra_dc_cancel_page_flip(crtc, file);
 
        list_for_each_entry_safe(context, tmp, &fpriv->contexts, list)
-               host1x_drm_context_free(context);
+               tegra_drm_context_free(context);
 
        kfree(fpriv);
 }
@@ -645,3 +607,108 @@ struct drm_driver tegra_drm_driver = {
        .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,tegra20-gr3d", },
+       { .compatible = "nvidia,tegra30-dc", },
+       { .compatible = "nvidia,tegra30-hdmi", },
+       { .compatible = "nvidia,tegra30-gr2d", },
+       { .compatible = "nvidia,tegra30-gr3d", },
+       { .compatible = "nvidia,tegra114-hdmi", },
+       { .compatible = "nvidia,tegra114-gr3d", },
+       { /* 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;
+
+       err = platform_driver_register(&tegra_gr3d_driver);
+       if (err < 0)
+               goto unregister_gr2d;
+
+       return 0;
+
+unregister_gr2d:
+       platform_driver_unregister(&tegra_gr2d_driver);
+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_gr3d_driver);
+       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");
similarity index 72%
rename from drivers/gpu/host1x/drm/drm.h
rename to drivers/gpu/drm/tegra/drm.h
index 02ce020f25754633bca0f9489e6e29c85ec9eea2..fdfe259ed7f8e5e403f984d533b54a3257128aef 100644 (file)
 #ifndef HOST1X_DRM_H
 #define HOST1X_DRM_H 1
 
+#include <uapi/drm/tegra_drm.h>
+#include <linux/host1x.h>
+
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fixed.h>
-#include <uapi/drm/tegra_drm.h>
-
-#include "host1x.h"
 
 struct tegra_fb {
        struct drm_framebuffer base;
@@ -30,17 +30,8 @@ struct tegra_fbdev {
        struct tegra_fb *fb;
 };
 
-struct host1x_drm {
+struct tegra_drm {
        struct drm_device *drm;
-       struct device *dev;
-       void __iomem *regs;
-       struct clk *clk;
-       int syncpt;
-       int irq;
-
-       struct mutex drm_clients_lock;
-       struct list_head drm_clients;
-       struct list_head drm_active;
 
        struct mutex clients_lock;
        struct list_head clients;
@@ -48,66 +39,60 @@ struct host1x_drm {
        struct tegra_fbdev *fbdev;
 };
 
-struct host1x_client;
+struct tegra_drm_client;
 
-struct host1x_drm_context {
-       struct host1x_client *client;
+struct tegra_drm_context {
+       struct tegra_drm_client *client;
        struct host1x_channel *channel;
        struct list_head list;
 };
 
-struct host1x_client_ops {
-       int (*drm_init)(struct host1x_client *client, struct drm_device *drm);
-       int (*drm_exit)(struct host1x_client *client);
-       int (*open_channel)(struct host1x_client *client,
-                           struct host1x_drm_context *context);
-       void (*close_channel)(struct host1x_drm_context *context);
-       int (*submit)(struct host1x_drm_context *context,
+struct tegra_drm_client_ops {
+       int (*open_channel)(struct tegra_drm_client *client,
+                           struct tegra_drm_context *context);
+       void (*close_channel)(struct tegra_drm_context *context);
+       int (*is_addr_reg)(struct device *dev, u32 class, u32 offset);
+       int (*submit)(struct tegra_drm_context *context,
                      struct drm_tegra_submit *args, struct drm_device *drm,
                      struct drm_file *file);
 };
 
-struct host1x_drm_file {
-       struct list_head contexts;
-};
-
-struct host1x_client {
-       struct host1x_drm *host1x;
-       struct device *dev;
-
-       const struct host1x_client_ops *ops;
-
-       enum host1x_class class;
-       struct host1x_channel *channel;
-
-       struct host1x_syncpt **syncpts;
-       unsigned int num_syncpts;
+int tegra_drm_submit(struct tegra_drm_context *context,
+                    struct drm_tegra_submit *args, struct drm_device *drm,
+                    struct drm_file *file);
 
+struct tegra_drm_client {
+       struct host1x_client base;
        struct list_head list;
+
+       const struct tegra_drm_client_ops *ops;
 };
 
-extern int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm);
-extern int host1x_drm_exit(struct host1x_drm *host1x);
+static inline struct tegra_drm_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 host1x_register_client(struct host1x_drm *host1x,
-                                 struct host1x_client *client);
-extern int host1x_unregister_client(struct host1x_drm *host1x,
-                                   struct host1x_client *client);
+extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
+extern int tegra_drm_exit(struct tegra_drm *tegra);
 
 struct tegra_output;
 
 struct tegra_dc {
        struct host1x_client client;
-       spinlock_t lock;
-
-       struct host1x_drm *host1x;
        struct device *dev;
+       spinlock_t lock;
 
        struct drm_crtc base;
        int pipe;
 
        struct clk *clk;
-
        void __iomem *regs;
        int irq;
 
@@ -123,7 +108,8 @@ struct tegra_dc {
        struct drm_pending_vblank_event *event;
 };
 
-static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client)
+static inline struct tegra_dc *
+host1x_client_to_dc(struct host1x_client *client)
 {
        return container_of(client, struct tegra_dc, client);
 }
@@ -162,6 +148,8 @@ struct tegra_dc_window {
        unsigned int format;
        unsigned int stride[2];
        unsigned long base[3];
+       bool bottom_up;
+       bool tiled;
 };
 
 /* from dc.c */
@@ -249,23 +237,34 @@ static inline int tegra_output_check_mode(struct tegra_output *output,
        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_remove(struct tegra_dc *dc);
 extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
 extern int tegra_dc_rgb_exit(struct tegra_dc *dc);
 
 /* from output.c */
-extern int tegra_output_parse_dt(struct tegra_output *output);
+extern int tegra_output_probe(struct tegra_output *output);
+extern int tegra_output_remove(struct tegra_output *output);
 extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
 extern int tegra_output_exit(struct tegra_output *output);
 
 /* from fb.c */
 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
                                    unsigned int index);
+bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
+bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer);
 extern int tegra_drm_fb_init(struct drm_device *drm);
 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;
+extern struct platform_driver tegra_gr3d_driver;
 
 #endif /* HOST1X_DRM_H */
similarity index 92%
rename from drivers/gpu/host1x/drm/fb.c
rename to drivers/gpu/drm/tegra/fb.c
index 979a3e32b78bbb0f5da3126b6b406eebae6ef497..490f7719e317ed80319f4961a69d3e349d1ad333 100644 (file)
@@ -10,8 +10,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-
 #include "drm.h"
 #include "gem.h"
 
@@ -36,6 +34,26 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
        return fb->planes[index];
 }
 
+bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer)
+{
+       struct tegra_fb *fb = to_tegra_fb(framebuffer);
+
+       if (fb->planes[0]->flags & TEGRA_BO_BOTTOM_UP)
+               return true;
+
+       return false;
+}
+
+bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer)
+{
+       struct tegra_fb *fb = to_tegra_fb(framebuffer);
+
+       if (fb->planes[0]->flags & TEGRA_BO_TILED)
+               return true;
+
+       return false;
+}
+
 static void tegra_fb_destroy(struct drm_framebuffer *framebuffer)
 {
        struct tegra_fb *fb = to_tegra_fb(framebuffer);
@@ -190,7 +208,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 
        size = cmd.pitches[0] * cmd.height;
 
-       bo = tegra_bo_create(drm, size);
+       bo = tegra_bo_create(drm, size, 0);
        if (IS_ERR(bo))
                return PTR_ERR(bo);
 
@@ -323,10 +341,10 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
 
 static void tegra_fb_output_poll_changed(struct drm_device *drm)
 {
-       struct host1x_drm *host1x = drm->dev_private;
+       struct tegra_drm *tegra = drm->dev_private;
 
-       if (host1x->fbdev)
-               drm_fb_helper_hotplug_event(&host1x->fbdev->base);
+       if (tegra->fbdev)
+               drm_fb_helper_hotplug_event(&tegra->fbdev->base);
 }
 
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
@@ -336,7 +354,7 @@ static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
 
 int tegra_drm_fb_init(struct drm_device *drm)
 {
-       struct host1x_drm *host1x = drm->dev_private;
+       struct tegra_drm *tegra = drm->dev_private;
        struct tegra_fbdev *fbdev;
 
        drm->mode_config.min_width = 0;
@@ -352,16 +370,16 @@ int tegra_drm_fb_init(struct drm_device *drm)
        if (IS_ERR(fbdev))
                return PTR_ERR(fbdev);
 
-       host1x->fbdev = fbdev;
+       tegra->fbdev = fbdev;
 
        return 0;
 }
 
 void tegra_drm_fb_exit(struct drm_device *drm)
 {
-       struct host1x_drm *host1x = drm->dev_private;
+       struct tegra_drm *tegra = drm->dev_private;
 
-       tegra_fbdev_free(host1x->fbdev);
+       tegra_fbdev_free(tegra->fbdev);
 }
 
 void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
similarity index 86%
rename from drivers/gpu/host1x/drm/gem.c
rename to drivers/gpu/drm/tegra/gem.c
index 59623de4ee15f3bf9a186d80481f358397fbf99e..28a9cbc07ab95f3a5873fc9aac0f008180bffca5 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/export.h>
-#include <linux/dma-mapping.h>
-
-#include <drm/drmP.h>
-#include <drm/drm.h>
+#include <drm/tegra_drm.h>
 
 #include "gem.h"
 
-static inline struct tegra_bo *host1x_to_drm_bo(struct host1x_bo *bo)
+static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
 {
        return container_of(bo, struct tegra_bo, base);
 }
 
 static void tegra_bo_put(struct host1x_bo *bo)
 {
-       struct tegra_bo *obj = host1x_to_drm_bo(bo);
+       struct tegra_bo *obj = host1x_to_tegra_bo(bo);
        struct drm_device *drm = obj->gem.dev;
 
        mutex_lock(&drm->struct_mutex);
@@ -46,7 +39,7 @@ static void tegra_bo_put(struct host1x_bo *bo)
 
 static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt)
 {
-       struct tegra_bo *obj = host1x_to_drm_bo(bo);
+       struct tegra_bo *obj = host1x_to_tegra_bo(bo);
 
        return obj->paddr;
 }
@@ -57,7 +50,7 @@ static void tegra_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt)
 
 static void *tegra_bo_mmap(struct host1x_bo *bo)
 {
-       struct tegra_bo *obj = host1x_to_drm_bo(bo);
+       struct tegra_bo *obj = host1x_to_tegra_bo(bo);
 
        return obj->vaddr;
 }
@@ -68,7 +61,7 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr)
 
 static void *tegra_bo_kmap(struct host1x_bo *bo, unsigned int page)
 {
-       struct tegra_bo *obj = host1x_to_drm_bo(bo);
+       struct tegra_bo *obj = host1x_to_tegra_bo(bo);
 
        return obj->vaddr + page * PAGE_SIZE;
 }
@@ -80,7 +73,7 @@ static void tegra_bo_kunmap(struct host1x_bo *bo, unsigned int page,
 
 static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo)
 {
-       struct tegra_bo *obj = host1x_to_drm_bo(bo);
+       struct tegra_bo *obj = host1x_to_tegra_bo(bo);
        struct drm_device *drm = obj->gem.dev;
 
        mutex_lock(&drm->struct_mutex);
@@ -106,7 +99,8 @@ static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo)
        dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr);
 }
 
-struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size)
+struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
+                                unsigned long flags)
 {
        struct tegra_bo *bo;
        int err;
@@ -135,6 +129,12 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size)
        if (err)
                goto err_mmap;
 
+       if (flags & DRM_TEGRA_GEM_CREATE_TILED)
+               bo->flags |= TEGRA_BO_TILED;
+
+       if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP)
+               bo->flags |= TEGRA_BO_BOTTOM_UP;
+
        return bo;
 
 err_mmap:
@@ -149,14 +149,15 @@ err_dma:
 }
 
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
-                                           struct drm_device *drm,
-                                           unsigned int size,
-                                           unsigned int *handle)
+                                            struct drm_device *drm,
+                                            unsigned int size,
+                                            unsigned long flags,
+                                            unsigned int *handle)
 {
        struct tegra_bo *bo;
        int ret;
 
-       bo = tegra_bo_create(drm, size);
+       bo = tegra_bo_create(drm, size, flags);
        if (IS_ERR(bo))
                return bo;
 
@@ -178,7 +179,6 @@ void tegra_bo_free_object(struct drm_gem_object *gem)
        struct tegra_bo *bo = to_tegra_bo(gem);
 
        drm_gem_free_mmap_offset(gem);
-
        drm_gem_object_release(gem);
        tegra_bo_destroy(gem->dev, bo);
 
@@ -197,8 +197,8 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
        if (args->size < args->pitch * args->height)
                args->size = args->pitch * args->height;
 
-       bo = tegra_bo_create_with_handle(file, drm, args->size,
-                                           &args->handle);
+       bo = tegra_bo_create_with_handle(file, drm, args->size, 0,
+                                        &args->handle);
        if (IS_ERR(bo))
                return PTR_ERR(bo);
 
similarity index 84%
rename from drivers/gpu/host1x/drm/gem.h
rename to drivers/gpu/drm/tegra/gem.h
index 492533a2dacb1bba249cde2ff08b63e1c855c291..7674000bf47d6696ecec6db7507926144832c772 100644 (file)
 #ifndef __HOST1X_GEM_H
 #define __HOST1X_GEM_H
 
+#include <linux/host1x.h>
+
 #include <drm/drm.h>
 #include <drm/drmP.h>
 
-#include "host1x_bo.h"
+#define TEGRA_BO_TILED     (1 << 0)
+#define TEGRA_BO_BOTTOM_UP (1 << 1)
 
 struct tegra_bo {
        struct drm_gem_object gem;
        struct host1x_bo base;
+       unsigned long flags;
        dma_addr_t paddr;
        void *vaddr;
 };
@@ -38,11 +42,13 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem)
 
 extern const struct host1x_bo_ops tegra_bo_ops;
 
-struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size);
+struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
+                                unsigned long flags);
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
-                                           struct drm_device *drm,
-                                           unsigned int size,
-                                           unsigned int *handle);
+                                            struct drm_device *drm,
+                                            unsigned int size,
+                                            unsigned long flags,
+                                            unsigned int *handle);
 void tegra_bo_free_object(struct drm_gem_object *gem);
 int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
                         struct drm_mode_create_dumb *args);
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
new file mode 100644 (file)
index 0000000..7ec4259
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2012-2013, NVIDIA Corporation.
+ *
+ * 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 <linux/clk.h>
+
+#include "drm.h"
+#include "gem.h"
+#include "gr2d.h"
+
+struct gr2d {
+       struct tegra_drm_client client;
+       struct host1x_channel *channel;
+       struct clk *clk;
+
+       DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS);
+};
+
+static inline struct gr2d *to_gr2d(struct tegra_drm_client *client)
+{
+       return container_of(client, struct gr2d, client);
+}
+
+static int gr2d_init(struct host1x_client *client)
+{
+       struct tegra_drm_client *drm = host1x_to_drm_client(client);
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+       unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
+       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, flags);
+       if (!client->syncpts[0]) {
+               host1x_channel_free(gr2d->channel);
+               return -ENOMEM;
+       }
+
+       return tegra_drm_register_client(tegra, drm);
+}
+
+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_init,
+       .exit = gr2d_exit,
+};
+
+static int gr2d_open_channel(struct tegra_drm_client *client,
+                            struct tegra_drm_context *context)
+{
+       struct gr2d *gr2d = to_gr2d(client);
+
+       context->channel = host1x_channel_get(gr2d->channel);
+       if (!context->channel)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void gr2d_close_channel(struct tegra_drm_context *context)
+{
+       host1x_channel_put(context->channel);
+}
+
+static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
+{
+       struct gr2d *gr2d = dev_get_drvdata(dev);
+
+       switch (class) {
+       case HOST1X_CLASS_HOST1X:
+               if (offset == 0x2b)
+                       return 1;
+
+               break;
+
+       case HOST1X_CLASS_GR2D:
+       case HOST1X_CLASS_GR2D_SB:
+               if (offset >= GR2D_NUM_REGS)
+                       break;
+
+               if (test_bit(offset, gr2d->addr_regs))
+                       return 1;
+
+               break;
+       }
+
+       return 0;
+}
+
+static const struct tegra_drm_client_ops gr2d_ops = {
+       .open_channel = gr2d_open_channel,
+       .close_channel = gr2d_close_channel,
+       .is_addr_reg = gr2d_is_addr_reg,
+       .submit = tegra_drm_submit,
+};
+
+static const struct of_device_id gr2d_match[] = {
+       { .compatible = "nvidia,tegra30-gr2d" },
+       { .compatible = "nvidia,tegra20-gr2d" },
+       { },
+};
+
+static const u32 gr2d_addr_regs[] = {
+       GR2D_UA_BASE_ADDR,
+       GR2D_VA_BASE_ADDR,
+       GR2D_PAT_BASE_ADDR,
+       GR2D_DSTA_BASE_ADDR,
+       GR2D_DSTB_BASE_ADDR,
+       GR2D_DSTC_BASE_ADDR,
+       GR2D_SRCA_BASE_ADDR,
+       GR2D_SRCB_BASE_ADDR,
+       GR2D_SRC_BASE_ADDR_SB,
+       GR2D_DSTA_BASE_ADDR_SB,
+       GR2D_DSTB_BASE_ADDR_SB,
+       GR2D_UA_BASE_ADDR_SB,
+       GR2D_VA_BASE_ADDR_SB,
+};
+
+static int gr2d_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct host1x_syncpt **syncpts;
+       struct gr2d *gr2d;
+       unsigned int i;
+       int err;
+
+       gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL);
+       if (!gr2d)
+               return -ENOMEM;
+
+       syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
+       if (!syncpts)
+               return -ENOMEM;
+
+       gr2d->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(gr2d->clk)) {
+               dev_err(dev, "cannot get clock\n");
+               return PTR_ERR(gr2d->clk);
+       }
+
+       err = clk_prepare_enable(gr2d->clk);
+       if (err) {
+               dev_err(dev, "cannot turn on clock\n");
+               return err;
+       }
+
+       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_client_register(&gr2d->client.base);
+       if (err < 0) {
+               dev_err(dev, "failed to register host1x client: %d\n", err);
+               clk_disable_unprepare(gr2d->clk);
+               return err;
+       }
+
+       /* initialize address register map */
+       for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++)
+               set_bit(gr2d_addr_regs[i], gr2d->addr_regs);
+
+       platform_set_drvdata(pdev, gr2d);
+
+       return 0;
+}
+
+static int gr2d_remove(struct platform_device *pdev)
+{
+       struct gr2d *gr2d = platform_get_drvdata(pdev);
+       int err;
+
+       err = host1x_client_unregister(&gr2d->client.base);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       clk_disable_unprepare(gr2d->clk);
+
+       return 0;
+}
+
+struct platform_driver tegra_gr2d_driver = {
+       .driver = {
+               .name = "tegra-gr2d",
+               .of_match_table = gr2d_match,
+       },
+       .probe = gr2d_probe,
+       .remove = gr2d_remove,
+};
diff --git a/drivers/gpu/drm/tegra/gr2d.h b/drivers/gpu/drm/tegra/gr2d.h
new file mode 100644 (file)
index 0000000..4d7304f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef TEGRA_GR2D_H
+#define TEGRA_GR2D_H
+
+#define GR2D_UA_BASE_ADDR              0x1a
+#define GR2D_VA_BASE_ADDR              0x1b
+#define GR2D_PAT_BASE_ADDR             0x26
+#define GR2D_DSTA_BASE_ADDR            0x2b
+#define GR2D_DSTB_BASE_ADDR            0x2c
+#define GR2D_DSTC_BASE_ADDR            0x2d
+#define GR2D_SRCA_BASE_ADDR            0x31
+#define GR2D_SRCB_BASE_ADDR            0x32
+#define GR2D_SRC_BASE_ADDR_SB          0x48
+#define GR2D_DSTA_BASE_ADDR_SB         0x49
+#define GR2D_DSTB_BASE_ADDR_SB         0x4a
+#define GR2D_UA_BASE_ADDR_SB           0x4b
+#define GR2D_VA_BASE_ADDR_SB           0x4c
+
+#define GR2D_NUM_REGS                  0x4d
+
+#endif
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
new file mode 100644 (file)
index 0000000..4cec8f5
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2013 Avionic Design GmbH
+ * 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 <linux/clk.h>
+#include <linux/host1x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/tegra-powergate.h>
+
+#include "drm.h"
+#include "gem.h"
+#include "gr3d.h"
+
+struct gr3d {
+       struct tegra_drm_client client;
+       struct host1x_channel *channel;
+       struct clk *clk_secondary;
+       struct clk *clk;
+
+       DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
+};
+
+static inline struct gr3d *to_gr3d(struct tegra_drm_client *client)
+{
+       return container_of(client, struct gr3d, client);
+}
+
+static int gr3d_init(struct host1x_client *client)
+{
+       struct tegra_drm_client *drm = host1x_to_drm_client(client);
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+       unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
+       struct gr3d *gr3d = to_gr3d(drm);
+
+       gr3d->channel = host1x_channel_request(client->dev);
+       if (!gr3d->channel)
+               return -ENOMEM;
+
+       client->syncpts[0] = host1x_syncpt_request(client->dev, flags);
+       if (!client->syncpts[0]) {
+               host1x_channel_free(gr3d->channel);
+               return -ENOMEM;
+       }
+
+       return tegra_drm_register_client(tegra, drm);
+}
+
+static int gr3d_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 gr3d *gr3d = to_gr3d(drm);
+       int err;
+
+       err = tegra_drm_unregister_client(tegra, drm);
+       if (err < 0)
+               return err;
+
+       host1x_syncpt_free(client->syncpts[0]);
+       host1x_channel_free(gr3d->channel);
+
+       return 0;
+}
+
+static const struct host1x_client_ops gr3d_client_ops = {
+       .init = gr3d_init,
+       .exit = gr3d_exit,
+};
+
+static int gr3d_open_channel(struct tegra_drm_client *client,
+                            struct tegra_drm_context *context)
+{
+       struct gr3d *gr3d = to_gr3d(client);
+
+       context->channel = host1x_channel_get(gr3d->channel);
+       if (!context->channel)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void gr3d_close_channel(struct tegra_drm_context *context)
+{
+       host1x_channel_put(context->channel);
+}
+
+static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset)
+{
+       struct gr3d *gr3d = dev_get_drvdata(dev);
+
+       switch (class) {
+       case HOST1X_CLASS_HOST1X:
+               if (offset == 0x2b)
+                       return 1;
+
+               break;
+
+       case HOST1X_CLASS_GR3D:
+               if (offset >= GR3D_NUM_REGS)
+                       break;
+
+               if (test_bit(offset, gr3d->addr_regs))
+                       return 1;
+
+               break;
+       }
+
+       return 0;
+}
+
+static const struct tegra_drm_client_ops gr3d_ops = {
+       .open_channel = gr3d_open_channel,
+       .close_channel = gr3d_close_channel,
+       .is_addr_reg = gr3d_is_addr_reg,
+       .submit = tegra_drm_submit,
+};
+
+static const struct of_device_id tegra_gr3d_match[] = {
+       { .compatible = "nvidia,tegra114-gr3d" },
+       { .compatible = "nvidia,tegra30-gr3d" },
+       { .compatible = "nvidia,tegra20-gr3d" },
+       { }
+};
+
+static const u32 gr3d_addr_regs[] = {
+       GR3D_IDX_ATTRIBUTE( 0),
+       GR3D_IDX_ATTRIBUTE( 1),
+       GR3D_IDX_ATTRIBUTE( 2),
+       GR3D_IDX_ATTRIBUTE( 3),
+       GR3D_IDX_ATTRIBUTE( 4),
+       GR3D_IDX_ATTRIBUTE( 5),
+       GR3D_IDX_ATTRIBUTE( 6),
+       GR3D_IDX_ATTRIBUTE( 7),
+       GR3D_IDX_ATTRIBUTE( 8),
+       GR3D_IDX_ATTRIBUTE( 9),
+       GR3D_IDX_ATTRIBUTE(10),
+       GR3D_IDX_ATTRIBUTE(11),
+       GR3D_IDX_ATTRIBUTE(12),
+       GR3D_IDX_ATTRIBUTE(13),
+       GR3D_IDX_ATTRIBUTE(14),
+       GR3D_IDX_ATTRIBUTE(15),
+       GR3D_IDX_INDEX_BASE,
+       GR3D_QR_ZTAG_ADDR,
+       GR3D_QR_CTAG_ADDR,
+       GR3D_QR_CZ_ADDR,
+       GR3D_TEX_TEX_ADDR( 0),
+       GR3D_TEX_TEX_ADDR( 1),
+       GR3D_TEX_TEX_ADDR( 2),
+       GR3D_TEX_TEX_ADDR( 3),
+       GR3D_TEX_TEX_ADDR( 4),
+       GR3D_TEX_TEX_ADDR( 5),
+       GR3D_TEX_TEX_ADDR( 6),
+       GR3D_TEX_TEX_ADDR( 7),
+       GR3D_TEX_TEX_ADDR( 8),
+       GR3D_TEX_TEX_ADDR( 9),
+       GR3D_TEX_TEX_ADDR(10),
+       GR3D_TEX_TEX_ADDR(11),
+       GR3D_TEX_TEX_ADDR(12),
+       GR3D_TEX_TEX_ADDR(13),
+       GR3D_TEX_TEX_ADDR(14),
+       GR3D_TEX_TEX_ADDR(15),
+       GR3D_DW_MEMORY_OUTPUT_ADDRESS,
+       GR3D_GLOBAL_SURFADDR( 0),
+       GR3D_GLOBAL_SURFADDR( 1),
+       GR3D_GLOBAL_SURFADDR( 2),
+       GR3D_GLOBAL_SURFADDR( 3),
+       GR3D_GLOBAL_SURFADDR( 4),
+       GR3D_GLOBAL_SURFADDR( 5),
+       GR3D_GLOBAL_SURFADDR( 6),
+       GR3D_GLOBAL_SURFADDR( 7),
+       GR3D_GLOBAL_SURFADDR( 8),
+       GR3D_GLOBAL_SURFADDR( 9),
+       GR3D_GLOBAL_SURFADDR(10),
+       GR3D_GLOBAL_SURFADDR(11),
+       GR3D_GLOBAL_SURFADDR(12),
+       GR3D_GLOBAL_SURFADDR(13),
+       GR3D_GLOBAL_SURFADDR(14),
+       GR3D_GLOBAL_SURFADDR(15),
+       GR3D_GLOBAL_SPILLSURFADDR,
+       GR3D_GLOBAL_SURFOVERADDR( 0),
+       GR3D_GLOBAL_SURFOVERADDR( 1),
+       GR3D_GLOBAL_SURFOVERADDR( 2),
+       GR3D_GLOBAL_SURFOVERADDR( 3),
+       GR3D_GLOBAL_SURFOVERADDR( 4),
+       GR3D_GLOBAL_SURFOVERADDR( 5),
+       GR3D_GLOBAL_SURFOVERADDR( 6),
+       GR3D_GLOBAL_SURFOVERADDR( 7),
+       GR3D_GLOBAL_SURFOVERADDR( 8),
+       GR3D_GLOBAL_SURFOVERADDR( 9),
+       GR3D_GLOBAL_SURFOVERADDR(10),
+       GR3D_GLOBAL_SURFOVERADDR(11),
+       GR3D_GLOBAL_SURFOVERADDR(12),
+       GR3D_GLOBAL_SURFOVERADDR(13),
+       GR3D_GLOBAL_SURFOVERADDR(14),
+       GR3D_GLOBAL_SURFOVERADDR(15),
+       GR3D_GLOBAL_SAMP01SURFADDR( 0),
+       GR3D_GLOBAL_SAMP01SURFADDR( 1),
+       GR3D_GLOBAL_SAMP01SURFADDR( 2),
+       GR3D_GLOBAL_SAMP01SURFADDR( 3),
+       GR3D_GLOBAL_SAMP01SURFADDR( 4),
+       GR3D_GLOBAL_SAMP01SURFADDR( 5),
+       GR3D_GLOBAL_SAMP01SURFADDR( 6),
+       GR3D_GLOBAL_SAMP01SURFADDR( 7),
+       GR3D_GLOBAL_SAMP01SURFADDR( 8),
+       GR3D_GLOBAL_SAMP01SURFADDR( 9),
+       GR3D_GLOBAL_SAMP01SURFADDR(10),
+       GR3D_GLOBAL_SAMP01SURFADDR(11),
+       GR3D_GLOBAL_SAMP01SURFADDR(12),
+       GR3D_GLOBAL_SAMP01SURFADDR(13),
+       GR3D_GLOBAL_SAMP01SURFADDR(14),
+       GR3D_GLOBAL_SAMP01SURFADDR(15),
+       GR3D_GLOBAL_SAMP23SURFADDR( 0),
+       GR3D_GLOBAL_SAMP23SURFADDR( 1),
+       GR3D_GLOBAL_SAMP23SURFADDR( 2),
+       GR3D_GLOBAL_SAMP23SURFADDR( 3),
+       GR3D_GLOBAL_SAMP23SURFADDR( 4),
+       GR3D_GLOBAL_SAMP23SURFADDR( 5),
+       GR3D_GLOBAL_SAMP23SURFADDR( 6),
+       GR3D_GLOBAL_SAMP23SURFADDR( 7),
+       GR3D_GLOBAL_SAMP23SURFADDR( 8),
+       GR3D_GLOBAL_SAMP23SURFADDR( 9),
+       GR3D_GLOBAL_SAMP23SURFADDR(10),
+       GR3D_GLOBAL_SAMP23SURFADDR(11),
+       GR3D_GLOBAL_SAMP23SURFADDR(12),
+       GR3D_GLOBAL_SAMP23SURFADDR(13),
+       GR3D_GLOBAL_SAMP23SURFADDR(14),
+       GR3D_GLOBAL_SAMP23SURFADDR(15),
+};
+
+static int gr3d_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct host1x_syncpt **syncpts;
+       struct gr3d *gr3d;
+       unsigned int i;
+       int err;
+
+       gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL);
+       if (!gr3d)
+               return -ENOMEM;
+
+       syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL);
+       if (!syncpts)
+               return -ENOMEM;
+
+       gr3d->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(gr3d->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return PTR_ERR(gr3d->clk);
+       }
+
+       if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) {
+               gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2");
+               if (IS_ERR(gr3d->clk)) {
+                       dev_err(&pdev->dev, "cannot get secondary clock\n");
+                       return PTR_ERR(gr3d->clk);
+               }
+       }
+
+       err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to power up 3D unit\n");
+               return err;
+       }
+
+       if (gr3d->clk_secondary) {
+               err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1,
+                                                       gr3d->clk_secondary);
+               if (err < 0) {
+                       dev_err(&pdev->dev,
+                               "failed to power up secondary 3D unit\n");
+                       return err;
+               }
+       }
+
+       INIT_LIST_HEAD(&gr3d->client.base.list);
+       gr3d->client.base.ops = &gr3d_client_ops;
+       gr3d->client.base.dev = &pdev->dev;
+       gr3d->client.base.class = HOST1X_CLASS_GR3D;
+       gr3d->client.base.syncpts = syncpts;
+       gr3d->client.base.num_syncpts = 1;
+
+       INIT_LIST_HEAD(&gr3d->client.list);
+       gr3d->client.ops = &gr3d_ops;
+
+       err = host1x_client_register(&gr3d->client.base);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to register host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       /* initialize address register map */
+       for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++)
+               set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
+
+       platform_set_drvdata(pdev, gr3d);
+
+       return 0;
+}
+
+static int gr3d_remove(struct platform_device *pdev)
+{
+       struct gr3d *gr3d = platform_get_drvdata(pdev);
+       int err;
+
+       err = host1x_client_unregister(&gr3d->client.base);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       if (gr3d->clk_secondary) {
+               tegra_powergate_power_off(TEGRA_POWERGATE_3D1);
+               clk_disable_unprepare(gr3d->clk_secondary);
+       }
+
+       tegra_powergate_power_off(TEGRA_POWERGATE_3D);
+       clk_disable_unprepare(gr3d->clk);
+
+       return 0;
+}
+
+struct platform_driver tegra_gr3d_driver = {
+       .driver = {
+               .name = "tegra-gr3d",
+               .of_match_table = tegra_gr3d_match,
+       },
+       .probe = gr3d_probe,
+       .remove = gr3d_remove,
+};
diff --git a/drivers/gpu/drm/tegra/gr3d.h b/drivers/gpu/drm/tegra/gr3d.h
new file mode 100644 (file)
index 0000000..0c30a13
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef TEGRA_GR3D_H
+#define TEGRA_GR3D_H
+
+#define GR3D_IDX_ATTRIBUTE(x)          (0x100 + (x) * 2)
+#define GR3D_IDX_INDEX_BASE            0x121
+#define GR3D_QR_ZTAG_ADDR              0x415
+#define GR3D_QR_CTAG_ADDR              0x417
+#define GR3D_QR_CZ_ADDR                        0x419
+#define GR3D_TEX_TEX_ADDR(x)           (0x710 + (x))
+#define GR3D_DW_MEMORY_OUTPUT_ADDRESS  0x904
+#define GR3D_GLOBAL_SURFADDR(x)                (0xe00 + (x))
+#define GR3D_GLOBAL_SPILLSURFADDR      0xe2a
+#define GR3D_GLOBAL_SURFOVERADDR(x)    (0xe30 + (x))
+#define GR3D_GLOBAL_SAMP01SURFADDR(x)  (0xe50 + (x))
+#define GR3D_GLOBAL_SAMP23SURFADDR(x)  (0xe60 + (x))
+
+#define GR3D_NUM_REGS                  0xe88
+
+#endif
similarity index 83%
rename from drivers/gpu/host1x/drm/hdmi.c
rename to drivers/gpu/drm/tegra/hdmi.c
index 644d95c7d489997b9305f6eced5e62b638798a54..0cd9bc2056e8c6bfe12cd15c5722c6f18d087e78 100644 (file)
@@ -8,21 +8,33 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
-#include <linux/gpio.h>
 #include <linux/hdmi.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
-#include <linux/clk/tegra.h>
-
-#include <drm/drm_edid.h>
 
 #include "hdmi.h"
 #include "drm.h"
 #include "dc.h"
-#include "host1x_client.h"
+
+struct tmds_config {
+       unsigned int pclk;
+       u32 pll0;
+       u32 pll1;
+       u32 pe_current;
+       u32 drive_current;
+       u32 peak_current;
+};
+
+struct tegra_hdmi_config {
+       const struct tmds_config *tmds;
+       unsigned int num_tmds;
+
+       unsigned long fuse_override_offset;
+       unsigned long fuse_override_value;
+
+       bool has_sor_io_peak_current;
+};
 
 struct tegra_hdmi {
        struct host1x_client client;
@@ -38,6 +50,8 @@ struct tegra_hdmi {
        struct clk *clk_parent;
        struct clk *clk;
 
+       const struct tegra_hdmi_config *config;
+
        unsigned int audio_source;
        unsigned int audio_freq;
        bool stereo;
@@ -143,15 +157,7 @@ static const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = {
        {         0,     0,      0,     0 },
 };
 
-struct tmds_config {
-       unsigned int pclk;
-       u32 pll0;
-       u32 pll1;
-       u32 pe_current;
-       u32 drive_current;
-};
-
-static const struct tmds_config tegra2_tmds_config[] = {
+static const struct tmds_config tegra20_tmds_config[] = {
        { /* slow pixel clock modes */
                .pclk = 27000000,
                .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
@@ -184,7 +190,7 @@ static const struct tmds_config tegra2_tmds_config[] = {
        },
 };
 
-static const struct tmds_config tegra3_tmds_config[] = {
+static const struct tmds_config tegra30_tmds_config[] = {
        { /* 480p modes */
                .pclk = 27000000,
                .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
@@ -230,6 +236,85 @@ static const struct tmds_config tegra3_tmds_config[] = {
        },
 };
 
+static const struct tmds_config tegra114_tmds_config[] = {
+       { /* 480p/576p / 25.2MHz/27MHz modes */
+               .pclk = 27000000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(0) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_0_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 720p / 74.25MHz modes */
+               .pclk = 74250000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(1) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) |
+                       SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_15_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_15_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 1080p / 148.5MHz modes */
+               .pclk = 148500000,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(3) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) |
+                       SOR_PLL_TMDS_TERMADJ(0),
+               .pe_current = PE_CURRENT0(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_10_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_10_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_12_400_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_12_400_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA),
+       }, { /* 225/297MHz modes */
+               .pclk = UINT_MAX,
+               .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) |
+                       SOR_PLL_VCOCAP(0xf) | SOR_PLL_RESISTORSEL,
+               .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(7)
+                       | SOR_PLL_TMDS_TERM_ENABLE,
+               .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT1(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT2(PE_CURRENT_0_mA_T114) |
+                       PE_CURRENT3(PE_CURRENT_0_mA_T114),
+               .drive_current =
+                       DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_25_200_mA_T114) |
+                       DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_19_200_mA_T114),
+               .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE1(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE2(PEAK_CURRENT_3_000_mA) |
+                       PEAK_CURRENT_LANE3(PEAK_CURRENT_0_800_mA),
+       },
+};
+
 static const struct tegra_hdmi_audio_config *
 tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk)
 {
@@ -511,7 +596,7 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi)
 
        err = hdmi_audio_infoframe_init(&frame);
        if (err < 0) {
-               dev_err(hdmi->dev, "failed to initialize audio infoframe: %d\n",
+               dev_err(hdmi->dev, "failed to setup audio infoframe: %zd\n",
                        err);
                return;
        }
@@ -531,7 +616,7 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi)
         * contain 7 bytes. Including the 3 byte header only the first 10
         * bytes can be programmed.
         */
-       tegra_hdmi_write_infopack(hdmi, buffer, min(10, err));
+       tegra_hdmi_write_infopack(hdmi, buffer, min_t(size_t, 10, err));
 
        tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE,
                          HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL);
@@ -577,8 +662,28 @@ static void tegra_hdmi_setup_tmds(struct tegra_hdmi *hdmi,
        tegra_hdmi_writel(hdmi, tmds->pll1, HDMI_NV_PDISP_SOR_PLL1);
        tegra_hdmi_writel(hdmi, tmds->pe_current, HDMI_NV_PDISP_PE_CURRENT);
 
-       value = tmds->drive_current | DRIVE_CURRENT_FUSE_OVERRIDE;
-       tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT);
+       tegra_hdmi_writel(hdmi, tmds->drive_current,
+                         HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT);
+
+       value = tegra_hdmi_readl(hdmi, hdmi->config->fuse_override_offset);
+       value |= hdmi->config->fuse_override_value;
+       tegra_hdmi_writel(hdmi, value, hdmi->config->fuse_override_offset);
+
+       if (hdmi->config->has_sor_io_peak_current)
+               tegra_hdmi_writel(hdmi, tmds->peak_current,
+                                 HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT);
+}
+
+static bool tegra_output_is_hdmi(struct tegra_output *output)
+{
+       struct edid *edid;
+
+       if (!output->connector.edid_blob_ptr)
+               return false;
+
+       edid = (struct edid *)output->connector.edid_blob_ptr->data;
+
+       return drm_detect_hdmi_monitor(edid);
 }
 
 static int tegra_output_hdmi_enable(struct tegra_output *output)
@@ -589,23 +694,17 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        struct tegra_hdmi *hdmi = to_hdmi(output);
        struct device_node *node = hdmi->dev->of_node;
        unsigned int pulse_start, div82, pclk;
-       const struct tmds_config *tmds;
-       unsigned int num_tmds;
        unsigned long value;
        int retries = 1000;
        int err;
 
+       hdmi->dvi = !tegra_output_is_hdmi(output);
+
        pclk = mode->clock * 1000;
        h_sync_width = mode->hsync_end - mode->hsync_start;
        h_back_porch = mode->htotal - mode->hsync_end;
        h_front_porch = mode->hsync_start - mode->hdisplay;
 
-       err = regulator_enable(hdmi->vdd);
-       if (err < 0) {
-               dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
-               return err;
-       }
-
        err = regulator_enable(hdmi->pll);
        if (err < 0) {
                dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err);
@@ -710,17 +809,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        tegra_hdmi_setup_stereo_infoframe(hdmi);
 
        /* TMDS CONFIG */
-       if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) {
-               num_tmds = ARRAY_SIZE(tegra3_tmds_config);
-               tmds = tegra3_tmds_config;
-       } else {
-               num_tmds = ARRAY_SIZE(tegra2_tmds_config);
-               tmds = tegra2_tmds_config;
-       }
-
-       for (i = 0; i < num_tmds; i++) {
-               if (pclk <= tmds[i].pclk) {
-                       tegra_hdmi_setup_tmds(hdmi, &tmds[i]);
+       for (i = 0; i < hdmi->config->num_tmds; i++) {
+               if (pclk <= hdmi->config->tmds[i].pclk) {
+                       tegra_hdmi_setup_tmds(hdmi, &hdmi->config->tmds[i]);
                        break;
                }
        }
@@ -824,7 +915,6 @@ static int tegra_output_hdmi_disable(struct tegra_output *output)
        tegra_periph_reset_assert(hdmi->clk);
        clk_disable(hdmi->clk);
        regulator_disable(hdmi->pll);
-       regulator_disable(hdmi->vdd);
 
        return 0;
 }
@@ -1055,6 +1145,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
        DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_CNTRL0);
        DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR);
        DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE);
+       DUMP_REG(HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT);
 
 #undef DUMP_REG
 
@@ -1122,24 +1213,31 @@ static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
        return 0;
 }
 
-static int tegra_hdmi_drm_init(struct host1x_client *client,
-                              struct drm_device *drm)
+static int tegra_hdmi_init(struct host1x_client *client)
 {
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
        struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
        int err;
 
+       err = regulator_enable(hdmi->vdd);
+       if (err < 0) {
+               dev_err(client->dev, "failed to enable VDD regulator: %d\n",
+                       err);
+               return err;
+       }
+
        hdmi->output.type = TEGRA_OUTPUT_HDMI;
        hdmi->output.dev = client->dev;
        hdmi->output.ops = &hdmi_ops;
 
-       err = tegra_output_init(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->primary);
+               err = tegra_hdmi_debugfs_init(hdmi, tegra->drm->primary);
                if (err < 0)
                        dev_err(client->dev, "debugfs setup failed: %d\n", err);
        }
@@ -1147,7 +1245,7 @@ static int tegra_hdmi_drm_init(struct host1x_client *client,
        return 0;
 }
 
-static int tegra_hdmi_drm_exit(struct host1x_client *client)
+static int tegra_hdmi_exit(struct host1x_client *client)
 {
        struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
        int err;
@@ -1171,25 +1269,63 @@ static int tegra_hdmi_drm_exit(struct host1x_client *client)
                return err;
        }
 
+       regulator_disable(hdmi->vdd);
+
        return 0;
 }
 
 static const struct host1x_client_ops hdmi_client_ops = {
-       .drm_init = tegra_hdmi_drm_init,
-       .drm_exit = tegra_hdmi_drm_exit,
+       .init = tegra_hdmi_init,
+       .exit = tegra_hdmi_exit,
+};
+
+static const struct tegra_hdmi_config tegra20_hdmi_config = {
+       .tmds = tegra20_tmds_config,
+       .num_tmds = ARRAY_SIZE(tegra20_tmds_config),
+       .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT,
+       .fuse_override_value = 1 << 31,
+       .has_sor_io_peak_current = false,
+};
+
+static const struct tegra_hdmi_config tegra30_hdmi_config = {
+       .tmds = tegra30_tmds_config,
+       .num_tmds = ARRAY_SIZE(tegra30_tmds_config),
+       .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT,
+       .fuse_override_value = 1 << 31,
+       .has_sor_io_peak_current = false,
+};
+
+static const struct tegra_hdmi_config tegra114_hdmi_config = {
+       .tmds = tegra114_tmds_config,
+       .num_tmds = ARRAY_SIZE(tegra114_tmds_config),
+       .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0,
+       .fuse_override_value = 1 << 31,
+       .has_sor_io_peak_current = true,
+};
+
+static const struct of_device_id tegra_hdmi_of_match[] = {
+       { .compatible = "nvidia,tegra114-hdmi", .data = &tegra114_hdmi_config },
+       { .compatible = "nvidia,tegra30-hdmi", .data = &tegra30_hdmi_config },
+       { .compatible = "nvidia,tegra20-hdmi", .data = &tegra20_hdmi_config },
+       { },
 };
 
 static int tegra_hdmi_probe(struct platform_device *pdev)
 {
-       struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
+       const struct of_device_id *match;
        struct tegra_hdmi *hdmi;
        struct resource *regs;
        int err;
 
+       match = of_match_node(tegra_hdmi_of_match, pdev->dev.of_node);
+       if (!match)
+               return -ENODEV;
+
        hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi)
                return -ENOMEM;
 
+       hdmi->config = match->data;
        hdmi->dev = &pdev->dev;
        hdmi->audio_source = AUTO;
        hdmi->audio_freq = 44100;
@@ -1234,7 +1370,7 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
 
        hdmi->output.dev = &pdev->dev;
 
-       err = tegra_output_parse_dt(&hdmi->output);
+       err = tegra_output_probe(&hdmi->output);
        if (err < 0)
                return err;
 
@@ -1252,11 +1388,11 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
 
        hdmi->irq = err;
 
-       hdmi->client.ops = &hdmi_client_ops;
        INIT_LIST_HEAD(&hdmi->client.list);
+       hdmi->client.ops = &hdmi_client_ops;
        hdmi->client.dev = &pdev->dev;
 
-       err = host1x_register_client(host1x, &hdmi->client);
+       err = host1x_client_register(&hdmi->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
                        err);
@@ -1270,29 +1406,28 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
 
 static int tegra_hdmi_remove(struct platform_device *pdev)
 {
-       struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
        struct tegra_hdmi *hdmi = platform_get_drvdata(pdev);
        int err;
 
-       err = host1x_unregister_client(host1x, &hdmi->client);
+       err = host1x_client_unregister(&hdmi->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
                        err);
                return err;
        }
 
+       err = tegra_output_remove(&hdmi->output);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to remove output: %d\n", err);
+               return err;
+       }
+
        clk_unprepare(hdmi->clk_parent);
        clk_unprepare(hdmi->clk);
 
        return 0;
 }
 
-static struct of_device_id tegra_hdmi_of_match[] = {
-       { .compatible = "nvidia,tegra30-hdmi", },
-       { .compatible = "nvidia,tegra20-hdmi", },
-       { },
-};
-
 struct platform_driver tegra_hdmi_driver = {
        .driver = {
                .name = "tegra-hdmi",
similarity index 72%
rename from drivers/gpu/host1x/drm/hdmi.h
rename to drivers/gpu/drm/tegra/hdmi.h
index 52ac36e08ccbef5ec14df106abeabcdd12efe6f2..0aebc485f7fa36be983a609f693bfbb06dcb0214 100644 (file)
 #define DRIVE_CURRENT_LANE1(x)      (((x) & 0x3f) <<  8)
 #define DRIVE_CURRENT_LANE2(x)      (((x) & 0x3f) << 16)
 #define DRIVE_CURRENT_LANE3(x)      (((x) & 0x3f) << 24)
-#define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31)
+#define DRIVE_CURRENT_LANE0_T114(x) (((x) & 0x7f) <<  0)
+#define DRIVE_CURRENT_LANE1_T114(x) (((x) & 0x7f) <<  8)
+#define DRIVE_CURRENT_LANE2_T114(x) (((x) & 0x7f) << 16)
+#define DRIVE_CURRENT_LANE3_T114(x) (((x) & 0x7f) << 24)
 
 #define DRIVE_CURRENT_1_500_mA  0x00
 #define DRIVE_CURRENT_1_875_mA  0x01
 #define DRIVE_CURRENT_24_375_mA 0x3d
 #define DRIVE_CURRENT_24_750_mA 0x3e
 
+#define DRIVE_CURRENT_0_000_mA_T114 0x00
+#define DRIVE_CURRENT_0_400_mA_T114 0x01
+#define DRIVE_CURRENT_0_800_mA_T114 0x02
+#define DRIVE_CURRENT_1_200_mA_T114 0x03
+#define DRIVE_CURRENT_1_600_mA_T114 0x04
+#define DRIVE_CURRENT_2_000_mA_T114 0x05
+#define DRIVE_CURRENT_2_400_mA_T114 0x06
+#define DRIVE_CURRENT_2_800_mA_T114 0x07
+#define DRIVE_CURRENT_3_200_mA_T114 0x08
+#define DRIVE_CURRENT_3_600_mA_T114 0x09
+#define DRIVE_CURRENT_4_000_mA_T114 0x0a
+#define DRIVE_CURRENT_4_400_mA_T114 0x0b
+#define DRIVE_CURRENT_4_800_mA_T114 0x0c
+#define DRIVE_CURRENT_5_200_mA_T114 0x0d
+#define DRIVE_CURRENT_5_600_mA_T114 0x0e
+#define DRIVE_CURRENT_6_000_mA_T114 0x0f
+#define DRIVE_CURRENT_6_400_mA_T114 0x10
+#define DRIVE_CURRENT_6_800_mA_T114 0x11
+#define DRIVE_CURRENT_7_200_mA_T114 0x12
+#define DRIVE_CURRENT_7_600_mA_T114 0x13
+#define DRIVE_CURRENT_8_000_mA_T114 0x14
+#define DRIVE_CURRENT_8_400_mA_T114 0x15
+#define DRIVE_CURRENT_8_800_mA_T114 0x16
+#define DRIVE_CURRENT_9_200_mA_T114 0x17
+#define DRIVE_CURRENT_9_600_mA_T114 0x18
+#define DRIVE_CURRENT_10_000_mA_T114 0x19
+#define DRIVE_CURRENT_10_400_mA_T114 0x1a
+#define DRIVE_CURRENT_10_800_mA_T114 0x1b
+#define DRIVE_CURRENT_11_200_mA_T114 0x1c
+#define DRIVE_CURRENT_11_600_mA_T114 0x1d
+#define DRIVE_CURRENT_12_000_mA_T114 0x1e
+#define DRIVE_CURRENT_12_400_mA_T114 0x1f
+#define DRIVE_CURRENT_12_800_mA_T114 0x20
+#define DRIVE_CURRENT_13_200_mA_T114 0x21
+#define DRIVE_CURRENT_13_600_mA_T114 0x22
+#define DRIVE_CURRENT_14_000_mA_T114 0x23
+#define DRIVE_CURRENT_14_400_mA_T114 0x24
+#define DRIVE_CURRENT_14_800_mA_T114 0x25
+#define DRIVE_CURRENT_15_200_mA_T114 0x26
+#define DRIVE_CURRENT_15_600_mA_T114 0x27
+#define DRIVE_CURRENT_16_000_mA_T114 0x28
+#define DRIVE_CURRENT_16_400_mA_T114 0x29
+#define DRIVE_CURRENT_16_800_mA_T114 0x2a
+#define DRIVE_CURRENT_17_200_mA_T114 0x2b
+#define DRIVE_CURRENT_17_600_mA_T114 0x2c
+#define DRIVE_CURRENT_18_000_mA_T114 0x2d
+#define DRIVE_CURRENT_18_400_mA_T114 0x2e
+#define DRIVE_CURRENT_18_800_mA_T114 0x2f
+#define DRIVE_CURRENT_19_200_mA_T114 0x30
+#define DRIVE_CURRENT_19_600_mA_T114 0x31
+#define DRIVE_CURRENT_20_000_mA_T114 0x32
+#define DRIVE_CURRENT_20_400_mA_T114 0x33
+#define DRIVE_CURRENT_20_800_mA_T114 0x34
+#define DRIVE_CURRENT_21_200_mA_T114 0x35
+#define DRIVE_CURRENT_21_600_mA_T114 0x36
+#define DRIVE_CURRENT_22_000_mA_T114 0x37
+#define DRIVE_CURRENT_22_400_mA_T114 0x38
+#define DRIVE_CURRENT_22_800_mA_T114 0x39
+#define DRIVE_CURRENT_23_200_mA_T114 0x3a
+#define DRIVE_CURRENT_23_600_mA_T114 0x3b
+#define DRIVE_CURRENT_24_000_mA_T114 0x3c
+#define DRIVE_CURRENT_24_400_mA_T114 0x3d
+#define DRIVE_CURRENT_24_800_mA_T114 0x3e
+#define DRIVE_CURRENT_25_200_mA_T114 0x3f
+#define DRIVE_CURRENT_25_400_mA_T114 0x40
+#define DRIVE_CURRENT_25_800_mA_T114 0x41
+#define DRIVE_CURRENT_26_200_mA_T114 0x42
+#define DRIVE_CURRENT_26_600_mA_T114 0x43
+#define DRIVE_CURRENT_27_000_mA_T114 0x44
+#define DRIVE_CURRENT_27_400_mA_T114 0x45
+#define DRIVE_CURRENT_27_800_mA_T114 0x46
+#define DRIVE_CURRENT_28_200_mA_T114 0x47
+
 #define HDMI_NV_PDISP_AUDIO_DEBUG0                             0x7f
 #define HDMI_NV_PDISP_AUDIO_DEBUG1                             0x80
 #define HDMI_NV_PDISP_AUDIO_DEBUG2                             0x81
 #define PE_CURRENT_7_0_mA 0xe
 #define PE_CURRENT_7_5_mA 0xf
 
+#define PE_CURRENT_0_mA_T114 0x0
+#define PE_CURRENT_1_mA_T114 0x1
+#define PE_CURRENT_2_mA_T114 0x2
+#define PE_CURRENT_3_mA_T114 0x3
+#define PE_CURRENT_4_mA_T114 0x4
+#define PE_CURRENT_5_mA_T114 0x5
+#define PE_CURRENT_6_mA_T114 0x6
+#define PE_CURRENT_7_mA_T114 0x7
+#define PE_CURRENT_8_mA_T114 0x8
+#define PE_CURRENT_9_mA_T114 0x9
+#define PE_CURRENT_10_mA_T114 0xa
+#define PE_CURRENT_11_mA_T114 0xb
+#define PE_CURRENT_12_mA_T114 0xc
+#define PE_CURRENT_13_mA_T114 0xd
+#define PE_CURRENT_14_mA_T114 0xe
+#define PE_CURRENT_15_mA_T114 0xf
+
 #define HDMI_NV_PDISP_KEY_CTRL                                 0x9a
 #define HDMI_NV_PDISP_KEY_DEBUG0                               0x9b
 #define HDMI_NV_PDISP_KEY_DEBUG1                               0x9c
 #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920    0xc5
 #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0xc5
 
+#define HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT              0xd1
+#define PEAK_CURRENT_LANE0(x) (((x) & 0x7f) <<  0)
+#define PEAK_CURRENT_LANE1(x) (((x) & 0x7f) <<  8)
+#define PEAK_CURRENT_LANE2(x) (((x) & 0x7f) << 16)
+#define PEAK_CURRENT_LANE3(x) (((x) & 0x7f) << 24)
+
+#define PEAK_CURRENT_0_000_mA 0x00
+#define PEAK_CURRENT_0_200_mA 0x01
+#define PEAK_CURRENT_0_400_mA 0x02
+#define PEAK_CURRENT_0_600_mA 0x03
+#define PEAK_CURRENT_0_800_mA 0x04
+#define PEAK_CURRENT_1_000_mA 0x05
+#define PEAK_CURRENT_1_200_mA 0x06
+#define PEAK_CURRENT_1_400_mA 0x07
+#define PEAK_CURRENT_1_600_mA 0x08
+#define PEAK_CURRENT_1_800_mA 0x09
+#define PEAK_CURRENT_2_000_mA 0x0a
+#define PEAK_CURRENT_2_200_mA 0x0b
+#define PEAK_CURRENT_2_400_mA 0x0c
+#define PEAK_CURRENT_2_600_mA 0x0d
+#define PEAK_CURRENT_2_800_mA 0x0e
+#define PEAK_CURRENT_3_000_mA 0x0f
+#define PEAK_CURRENT_3_200_mA 0x10
+#define PEAK_CURRENT_3_400_mA 0x11
+#define PEAK_CURRENT_3_600_mA 0x12
+#define PEAK_CURRENT_3_800_mA 0x13
+#define PEAK_CURRENT_4_000_mA 0x14
+#define PEAK_CURRENT_4_200_mA 0x15
+#define PEAK_CURRENT_4_400_mA 0x16
+#define PEAK_CURRENT_4_600_mA 0x17
+#define PEAK_CURRENT_4_800_mA 0x18
+#define PEAK_CURRENT_5_000_mA 0x19
+#define PEAK_CURRENT_5_200_mA 0x1a
+#define PEAK_CURRENT_5_400_mA 0x1b
+#define PEAK_CURRENT_5_600_mA 0x1c
+#define PEAK_CURRENT_5_800_mA 0x1d
+#define PEAK_CURRENT_6_000_mA 0x1e
+#define PEAK_CURRENT_6_200_mA 0x1f
+#define PEAK_CURRENT_6_400_mA 0x20
+#define PEAK_CURRENT_6_600_mA 0x21
+#define PEAK_CURRENT_6_800_mA 0x22
+#define PEAK_CURRENT_7_000_mA 0x23
+#define PEAK_CURRENT_7_200_mA 0x24
+#define PEAK_CURRENT_7_400_mA 0x25
+#define PEAK_CURRENT_7_600_mA 0x26
+#define PEAK_CURRENT_7_800_mA 0x27
+#define PEAK_CURRENT_8_000_mA 0x28
+#define PEAK_CURRENT_8_200_mA 0x29
+#define PEAK_CURRENT_8_400_mA 0x2a
+#define PEAK_CURRENT_8_600_mA 0x2b
+#define PEAK_CURRENT_8_800_mA 0x2c
+#define PEAK_CURRENT_9_000_mA 0x2d
+#define PEAK_CURRENT_9_200_mA 0x2e
+#define PEAK_CURRENT_9_400_mA 0x2f
+
+#define HDMI_NV_PDISP_SOR_PAD_CTLS0            0xd2
+
 #endif /* TEGRA_HDMI_H */
similarity index 91%
rename from drivers/gpu/host1x/drm/output.c
rename to drivers/gpu/drm/tegra/output.c
index 137ae81ab80eb164d139742b16996bca8b8922b5..2cb0065e0578f6d80da0532dad68a31e27a6924d 100644 (file)
@@ -7,9 +7,7 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
 #include <linux/of_gpio.h>
-#include <linux/i2c.h>
 
 #include "drm.h"
 
@@ -81,10 +79,16 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
        return status;
 }
 
+static void drm_connector_clear(struct drm_connector *connector)
+{
+       memset(connector, 0, sizeof(*connector));
+}
+
 static void tegra_connector_destroy(struct drm_connector *connector)
 {
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
+       drm_connector_clear(connector);
 }
 
 static const struct drm_connector_funcs connector_funcs = {
@@ -94,9 +98,15 @@ static const struct drm_connector_funcs connector_funcs = {
        .destroy = tegra_connector_destroy,
 };
 
+static void drm_encoder_clear(struct drm_encoder *encoder)
+{
+       memset(encoder, 0, sizeof(*encoder));
+}
+
 static void tegra_encoder_destroy(struct drm_encoder *encoder)
 {
        drm_encoder_cleanup(encoder);
+       drm_encoder_clear(encoder);
 }
 
 static const struct drm_encoder_funcs encoder_funcs = {
@@ -151,7 +161,7 @@ static irqreturn_t hpd_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-int tegra_output_parse_dt(struct tegra_output *output)
+int tegra_output_probe(struct tegra_output *output)
 {
        enum of_gpio_flags flags;
        struct device_node *ddc;
@@ -181,14 +191,6 @@ int tegra_output_parse_dt(struct tegra_output *output)
        output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
                                                   "nvidia,hpd-gpio", 0,
                                                   &flags);
-
-       return 0;
-}
-
-int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
-{
-       int connector, encoder, err;
-
        if (gpio_is_valid(output->hpd_gpio)) {
                unsigned long flags;
 
@@ -202,7 +204,8 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
                err = gpio_to_irq(output->hpd_gpio);
                if (err < 0) {
                        dev_err(output->dev, "gpio_to_irq(): %d\n", err);
-                       goto free_hpd;
+                       gpio_free(output->hpd_gpio);
+                       return err;
                }
 
                output->hpd_irq = err;
@@ -215,12 +218,33 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
                if (err < 0) {
                        dev_err(output->dev, "failed to request IRQ#%u: %d\n",
                                output->hpd_irq, err);
-                       goto free_hpd;
+                       gpio_free(output->hpd_gpio);
+                       return err;
                }
 
                output->connector.polled = DRM_CONNECTOR_POLL_HPD;
        }
 
+       return 0;
+}
+
+int tegra_output_remove(struct tegra_output *output)
+{
+       if (gpio_is_valid(output->hpd_gpio)) {
+               free_irq(output->hpd_irq, output);
+               gpio_free(output->hpd_gpio);
+       }
+
+       if (output->ddc)
+               put_device(&output->ddc->dev);
+
+       return 0;
+}
+
+int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
+{
+       int connector, encoder;
+
        switch (output->type) {
        case TEGRA_OUTPUT_RGB:
                connector = DRM_MODE_CONNECTOR_LVDS;
@@ -241,6 +265,7 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
        drm_connector_init(drm, &output->connector, &connector_funcs,
                           connector);
        drm_connector_helper_add(&output->connector, &connector_helper_funcs);
+       output->connector.dpms = DRM_MODE_DPMS_OFF;
 
        drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder);
        drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs);
@@ -251,22 +276,9 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
        output->encoder.possible_crtcs = 0x3;
 
        return 0;
-
-free_hpd:
-       gpio_free(output->hpd_gpio);
-
-       return err;
 }
 
 int tegra_output_exit(struct tegra_output *output)
 {
-       if (gpio_is_valid(output->hpd_gpio)) {
-               free_irq(output->hpd_irq, output);
-               gpio_free(output->hpd_gpio);
-       }
-
-       if (output->ddc)
-               put_device(&output->ddc->dev);
-
        return 0;
 }
similarity index 96%
rename from drivers/gpu/host1x/drm/rgb.c
rename to drivers/gpu/drm/tegra/rgb.c
index 5aa66ef7a946f8b1c25a4241cf39f76dad9e91b7..ba47ca4fb880cc239a9b5c454b3b6c5b5adcddc8 100644 (file)
@@ -8,9 +8,6 @@
  */
 
 #include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
 
 #include "drm.h"
 #include "dc.h"
@@ -150,7 +147,7 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
        rgb->output.dev = dc->dev;
        rgb->output.of_node = np;
 
-       err = tegra_output_parse_dt(&rgb->output);
+       err = tegra_output_probe(&rgb->output);
        if (err < 0)
                return err;
 
@@ -177,6 +174,20 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
        return 0;
 }
 
+int tegra_dc_rgb_remove(struct tegra_dc *dc)
+{
+       int err;
+
+       if (!dc->rgb)
+               return 0;
+
+       err = tegra_output_remove(dc->rgb);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
 {
        struct tegra_rgb *rgb = to_rgb(dc->rgb);
index ccfd42b236060ffa17329d95a114029ef1faa89c..7d6bed2225422fa2413130a606d2b20fd084cfd4 100644 (file)
@@ -19,6 +19,4 @@ config TEGRA_HOST1X_FIREWALL
 
          If unsure, choose Y.
 
-source "drivers/gpu/host1x/drm/Kconfig"
-
 endif
index 3b037b6e0298454edbc44c30db4f818f3ca8cafc..afa1e9e4e51265fbdb21698072315786a6b730b7 100644 (file)
@@ -1,6 +1,5 @@
-ccflags-y = -Idrivers/gpu/host1x
-
 host1x-y = \
+       bus.o \
        syncpt.o \
        dev.o \
        intr.o \
@@ -8,13 +7,7 @@ host1x-y = \
        channel.o \
        job.o \
        debug.o \
-       hw/host1x01.o
-
-ccflags-y += -Iinclude/drm
-ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
+       hw/host1x01.o \
+       hw/host1x02.o
 
-host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o
-host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o
-host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o
-host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o
 obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
new file mode 100644 (file)
index 0000000..509383f
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2012 Avionic Design GmbH
+ * Copyright (C) 2012-2013, NVIDIA Corporation
+ *
+ * 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 <linux/host1x.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "dev.h"
+
+static DEFINE_MUTEX(clients_lock);
+static LIST_HEAD(clients);
+
+static DEFINE_MUTEX(drivers_lock);
+static LIST_HEAD(drivers);
+
+static DEFINE_MUTEX(devices_lock);
+static LIST_HEAD(devices);
+
+struct host1x_subdev {
+       struct host1x_client *client;
+       struct device_node *np;
+       struct list_head list;
+};
+
+/**
+ * host1x_subdev_add() - add a new subdevice with an associated device node
+ */
+static int host1x_subdev_add(struct host1x_device *device,
+                            struct device_node *np)
+{
+       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);
+
+       mutex_lock(&device->subdevs_lock);
+       list_add_tail(&subdev->list, &device->subdevs);
+       mutex_unlock(&device->subdevs_lock);
+
+       return 0;
+}
+
+/**
+ * host1x_subdev_del() - remove subdevice
+ */
+static void host1x_subdev_del(struct host1x_subdev *subdev)
+{
+       list_del(&subdev->list);
+       of_node_put(subdev->np);
+       kfree(subdev);
+}
+
+/**
+ * host1x_device_parse_dt() - scan device tree and add matching subdevices
+ */
+static int host1x_device_parse_dt(struct host1x_device *device)
+{
+       struct device_node *np;
+       int err;
+
+       for_each_child_of_node(device->dev.parent->of_node, np) {
+               if (of_match_node(device->driver->subdevs, np) &&
+                   of_device_is_available(np)) {
+                       err = host1x_subdev_add(device, np);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static void host1x_subdev_register(struct host1x_device *device,
+                                  struct host1x_subdev *subdev,
+                                  struct host1x_client *client)
+{
+       int err;
+
+       /*
+        * Move the subdevice to the list of active (registered) subdevices
+        * and associate it with a client. At the same time, associate the
+        * client with its parent device.
+        */
+       mutex_lock(&device->subdevs_lock);
+       mutex_lock(&device->clients_lock);
+       list_move_tail(&client->list, &device->clients);
+       list_move_tail(&subdev->list, &device->active);
+       client->parent = &device->dev;
+       subdev->client = client;
+       mutex_unlock(&device->clients_lock);
+       mutex_unlock(&device->subdevs_lock);
+
+       /*
+        * When all subdevices have been registered, the composite device is
+        * ready to be probed.
+        */
+       if (list_empty(&device->subdevs)) {
+               err = device->driver->probe(device);
+               if (err < 0)
+                       dev_err(&device->dev, "probe failed: %d\n", err);
+       }
+}
+
+static void __host1x_subdev_unregister(struct host1x_device *device,
+                                      struct host1x_subdev *subdev)
+{
+       struct host1x_client *client = subdev->client;
+       int err;
+
+       /*
+        * If all subdevices have been activated, we're about to remove the
+        * first active subdevice, so unload the driver first.
+        */
+       if (list_empty(&device->subdevs)) {
+               err = device->driver->remove(device);
+               if (err < 0)
+                       dev_err(&device->dev, "remove failed: %d\n", err);
+       }
+
+       /*
+        * Move the subdevice back to the list of idle subdevices and remove
+        * it from list of clients.
+        */
+       mutex_lock(&device->clients_lock);
+       subdev->client = NULL;
+       client->parent = NULL;
+       list_move_tail(&subdev->list, &device->subdevs);
+       /*
+        * XXX: Perhaps don't do this here, but rather explicitly remove it
+        * when the device is about to be deleted.
+        *
+        * This is somewhat complicated by the fact that this function is
+        * used to remove the subdevice when a client is unregistered but
+        * also when the composite device is about to be removed.
+        */
+       list_del_init(&client->list);
+       mutex_unlock(&device->clients_lock);
+}
+
+static void host1x_subdev_unregister(struct host1x_device *device,
+                                    struct host1x_subdev *subdev)
+{
+       mutex_lock(&device->subdevs_lock);
+       __host1x_subdev_unregister(device, subdev);
+       mutex_unlock(&device->subdevs_lock);
+}
+
+int host1x_device_init(struct host1x_device *device)
+{
+       struct host1x_client *client;
+       int err;
+
+       mutex_lock(&device->clients_lock);
+
+       list_for_each_entry(client, &device->clients, list) {
+               if (client->ops && client->ops->init) {
+                       err = client->ops->init(client);
+                       if (err < 0) {
+                               dev_err(&device->dev,
+                                       "failed to initialize %s: %d\n",
+                                       dev_name(client->dev), err);
+                               mutex_unlock(&device->clients_lock);
+                               return err;
+                       }
+               }
+       }
+
+       mutex_unlock(&device->clients_lock);
+
+       return 0;
+}
+
+int host1x_device_exit(struct host1x_device *device)
+{
+       struct host1x_client *client;
+       int err;
+
+       mutex_lock(&device->clients_lock);
+
+       list_for_each_entry_reverse(client, &device->clients, list) {
+               if (client->ops && client->ops->exit) {
+                       err = client->ops->exit(client);
+                       if (err < 0) {
+                               dev_err(&device->dev,
+                                       "failed to cleanup %s: %d\n",
+                                       dev_name(client->dev), err);
+                               mutex_unlock(&device->clients_lock);
+                               return err;
+                       }
+               }
+       }
+
+       mutex_unlock(&device->clients_lock);
+
+       return 0;
+}
+
+static int host1x_register_client(struct host1x *host1x,
+                                 struct host1x_client *client)
+{
+       struct host1x_device *device;
+       struct host1x_subdev *subdev;
+
+       mutex_lock(&host1x->devices_lock);
+
+       list_for_each_entry(device, &host1x->devices, list) {
+               list_for_each_entry(subdev, &device->subdevs, list) {
+                       if (subdev->np == client->dev->of_node) {
+                               host1x_subdev_register(device, subdev, client);
+                               mutex_unlock(&host1x->devices_lock);
+                               return 0;
+                       }
+               }
+       }
+
+       mutex_unlock(&host1x->devices_lock);
+       return -ENODEV;
+}
+
+static int host1x_unregister_client(struct host1x *host1x,
+                                   struct host1x_client *client)
+{
+       struct host1x_device *device, *dt;
+       struct host1x_subdev *subdev;
+
+       mutex_lock(&host1x->devices_lock);
+
+       list_for_each_entry_safe(device, dt, &host1x->devices, list) {
+               list_for_each_entry(subdev, &device->active, list) {
+                       if (subdev->client == client) {
+                               host1x_subdev_unregister(device, subdev);
+                               mutex_unlock(&host1x->devices_lock);
+                               return 0;
+                       }
+               }
+       }
+
+       mutex_unlock(&host1x->devices_lock);
+       return -ENODEV;
+}
+
+struct bus_type host1x_bus_type = {
+       .name = "host1x",
+};
+
+int host1x_bus_init(void)
+{
+       return bus_register(&host1x_bus_type);
+}
+
+void host1x_bus_exit(void)
+{
+       bus_unregister(&host1x_bus_type);
+}
+
+static void host1x_device_release(struct device *dev)
+{
+       struct host1x_device *device = to_host1x_device(dev);
+
+       kfree(device);
+}
+
+static int host1x_device_add(struct host1x *host1x,
+                            struct host1x_driver *driver)
+{
+       struct host1x_client *client, *tmp;
+       struct host1x_subdev *subdev;
+       struct host1x_device *device;
+       int err;
+
+       device = kzalloc(sizeof(*device), GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       mutex_init(&device->subdevs_lock);
+       INIT_LIST_HEAD(&device->subdevs);
+       INIT_LIST_HEAD(&device->active);
+       mutex_init(&device->clients_lock);
+       INIT_LIST_HEAD(&device->clients);
+       INIT_LIST_HEAD(&device->list);
+       device->driver = driver;
+
+       device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
+       device->dev.dma_mask = &device->dev.coherent_dma_mask;
+       device->dev.release = host1x_device_release;
+       dev_set_name(&device->dev, driver->name);
+       device->dev.bus = &host1x_bus_type;
+       device->dev.parent = host1x->dev;
+
+       err = device_register(&device->dev);
+       if (err < 0)
+               return err;
+
+       err = host1x_device_parse_dt(device);
+       if (err < 0) {
+               device_unregister(&device->dev);
+               return err;
+       }
+
+       mutex_lock(&host1x->devices_lock);
+       list_add_tail(&device->list, &host1x->devices);
+       mutex_unlock(&host1x->devices_lock);
+
+       mutex_lock(&clients_lock);
+
+       list_for_each_entry_safe(client, tmp, &clients, list) {
+               list_for_each_entry(subdev, &device->subdevs, list) {
+                       if (subdev->np == client->dev->of_node) {
+                               host1x_subdev_register(device, subdev, client);
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&clients_lock);
+
+       return 0;
+}
+
+/*
+ * Removes a device by first unregistering any subdevices and then removing
+ * itself from the list of devices.
+ *
+ * This function must be called with the host1x->devices_lock held.
+ */
+static void host1x_device_del(struct host1x *host1x,
+                             struct host1x_device *device)
+{
+       struct host1x_subdev *subdev, *sd;
+       struct host1x_client *client, *cl;
+
+       mutex_lock(&device->subdevs_lock);
+
+       /* unregister subdevices */
+       list_for_each_entry_safe(subdev, sd, &device->active, list) {
+               /*
+                * host1x_subdev_unregister() will remove the client from
+                * any lists, so we'll need to manually add it back to the
+                * list of idle clients.
+                *
+                * XXX: Alternatively, perhaps don't remove the client from
+                * any lists in host1x_subdev_unregister() and instead do
+                * that explicitly from host1x_unregister_client()?
+                */
+               client = subdev->client;
+
+               __host1x_subdev_unregister(device, subdev);
+
+               /* add the client to the list of idle clients */
+               mutex_lock(&clients_lock);
+               list_add_tail(&client->list, &clients);
+               mutex_unlock(&clients_lock);
+       }
+
+       /* remove subdevices */
+       list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
+               host1x_subdev_del(subdev);
+
+       mutex_unlock(&device->subdevs_lock);
+
+       /* move clients to idle list */
+       mutex_lock(&clients_lock);
+       mutex_lock(&device->clients_lock);
+
+       list_for_each_entry_safe(client, cl, &device->clients, list)
+               list_move_tail(&client->list, &clients);
+
+       mutex_unlock(&device->clients_lock);
+       mutex_unlock(&clients_lock);
+
+       /* finally remove the device */
+       list_del_init(&device->list);
+       device_unregister(&device->dev);
+}
+
+static void host1x_attach_driver(struct host1x *host1x,
+                                struct host1x_driver *driver)
+{
+       struct host1x_device *device;
+       int err;
+
+       mutex_lock(&host1x->devices_lock);
+
+       list_for_each_entry(device, &host1x->devices, list) {
+               if (device->driver == driver) {
+                       mutex_unlock(&host1x->devices_lock);
+                       return;
+               }
+       }
+
+       mutex_unlock(&host1x->devices_lock);
+
+       err = host1x_device_add(host1x, driver);
+       if (err < 0)
+               dev_err(host1x->dev, "failed to allocate device: %d\n", err);
+}
+
+static void host1x_detach_driver(struct host1x *host1x,
+                                struct host1x_driver *driver)
+{
+       struct host1x_device *device, *tmp;
+
+       mutex_lock(&host1x->devices_lock);
+
+       list_for_each_entry_safe(device, tmp, &host1x->devices, list)
+               if (device->driver == driver)
+                       host1x_device_del(host1x, device);
+
+       mutex_unlock(&host1x->devices_lock);
+}
+
+int host1x_register(struct host1x *host1x)
+{
+       struct host1x_driver *driver;
+
+       mutex_lock(&devices_lock);
+       list_add_tail(&host1x->list, &devices);
+       mutex_unlock(&devices_lock);
+
+       mutex_lock(&drivers_lock);
+
+       list_for_each_entry(driver, &drivers, list)
+               host1x_attach_driver(host1x, driver);
+
+       mutex_unlock(&drivers_lock);
+
+       return 0;
+}
+
+int host1x_unregister(struct host1x *host1x)
+{
+       struct host1x_driver *driver;
+
+       mutex_lock(&drivers_lock);
+
+       list_for_each_entry(driver, &drivers, list)
+               host1x_detach_driver(host1x, driver);
+
+       mutex_unlock(&drivers_lock);
+
+       mutex_lock(&devices_lock);
+       list_del_init(&host1x->list);
+       mutex_unlock(&devices_lock);
+
+       return 0;
+}
+
+int host1x_driver_register(struct host1x_driver *driver)
+{
+       struct host1x *host1x;
+
+       INIT_LIST_HEAD(&driver->list);
+
+       mutex_lock(&drivers_lock);
+       list_add_tail(&driver->list, &drivers);
+       mutex_unlock(&drivers_lock);
+
+       mutex_lock(&devices_lock);
+
+       list_for_each_entry(host1x, &devices, list)
+               host1x_attach_driver(host1x, driver);
+
+       mutex_unlock(&devices_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(host1x_driver_register);
+
+void host1x_driver_unregister(struct host1x_driver *driver)
+{
+       mutex_lock(&drivers_lock);
+       list_del_init(&driver->list);
+       mutex_unlock(&drivers_lock);
+}
+EXPORT_SYMBOL(host1x_driver_unregister);
+
+int host1x_client_register(struct host1x_client *client)
+{
+       struct host1x *host1x;
+       int err;
+
+       mutex_lock(&devices_lock);
+
+       list_for_each_entry(host1x, &devices, list) {
+               err = host1x_register_client(host1x, client);
+               if (!err) {
+                       mutex_unlock(&devices_lock);
+                       return 0;
+               }
+       }
+
+       mutex_unlock(&devices_lock);
+
+       mutex_lock(&clients_lock);
+       list_add_tail(&client->list, &clients);
+       mutex_unlock(&clients_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(host1x_client_register);
+
+int host1x_client_unregister(struct host1x_client *client)
+{
+       struct host1x_client *c;
+       struct host1x *host1x;
+       int err;
+
+       mutex_lock(&devices_lock);
+
+       list_for_each_entry(host1x, &devices, list) {
+               err = host1x_unregister_client(host1x, client);
+               if (!err) {
+                       mutex_unlock(&devices_lock);
+                       return 0;
+               }
+       }
+
+       mutex_unlock(&devices_lock);
+       mutex_lock(&clients_lock);
+
+       list_for_each_entry(c, &clients, list) {
+               if (c == client) {
+                       list_del_init(&c->list);
+                       break;
+               }
+       }
+
+       mutex_unlock(&clients_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(host1x_client_unregister);
similarity index 60%
rename from drivers/gpu/host1x/host1x_client.h
rename to drivers/gpu/host1x/bus.h
index 9b85f10f4a44fc9f70a45af7b40f33d95ba9942c..4099e99212c87354377d9a851d5409573792611b 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2013, NVIDIA Corporation.
+ * Copyright (C) 2012 Avionic Design GmbH
+ * Copyright (C) 2012-2013, NVIDIA Corporation
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef HOST1X_CLIENT_H
-#define HOST1X_CLIENT_H
+#ifndef HOST1X_BUS_H
+#define HOST1X_BUS_H
 
-struct device;
-struct platform_device;
+struct host1x;
 
-#ifdef CONFIG_DRM_TEGRA
-int host1x_drm_alloc(struct platform_device *pdev);
-#else
-static inline int host1x_drm_alloc(struct platform_device *pdev)
-{
-       return 0;
-}
-#endif
+int host1x_bus_init(void);
+void host1x_bus_exit(void);
 
-void host1x_set_drm_data(struct device *dev, void *data);
-void *host1x_get_drm_data(struct device *dev);
+int host1x_register(struct host1x *host1x);
+int host1x_unregister(struct host1x *host1x);
 
 #endif
index de72172d3b5fc2ac87955f3ef8b711890454434c..3995255b16c753731420cb8283992c17c33ddf2e 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/cacheflush.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/host1x.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/kfifo.h>
@@ -30,7 +31,6 @@
 #include "channel.h"
 #include "dev.h"
 #include "debug.h"
-#include "host1x_bo.h"
 #include "job.h"
 
 /*
index 48723b8eea42da33e9854a0925bbeedfa391a37a..df767cf90d51e14c2647f42ef192a7ffcf19489b 100644 (file)
@@ -40,12 +40,6 @@ struct host1x_channel {
 /* channel list operations */
 int host1x_channel_list_init(struct host1x *host);
 
-struct host1x_channel *host1x_channel_request(struct device *dev);
-void host1x_channel_free(struct host1x_channel *channel);
-struct host1x_channel *host1x_channel_get(struct host1x_channel *channel);
-void host1x_channel_put(struct host1x_channel *channel);
-int host1x_job_submit(struct host1x_job *job);
-
 #define host1x_for_each_channel(host, channel)                         \
        list_for_each_entry(channel, &host->chlist.list, list)
 
index 471630299878a88bbf300a09a0600da2c1c062eb..80da003d63de8d4b754cd37a607441c7c4901574 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/host1x.h>
 
+#include "bus.h"
 #include "dev.h"
 #include "intr.h"
 #include "channel.h"
 #include "debug.h"
 #include "hw/host1x01.h"
-#include "host1x_client.h"
-
-void host1x_set_drm_data(struct device *dev, void *data)
-{
-       struct host1x *host1x = dev_get_drvdata(dev);
-       host1x->drm_data = data;
-}
-
-void *host1x_get_drm_data(struct device *dev)
-{
-       struct host1x *host1x = dev_get_drvdata(dev);
-       return host1x ? host1x->drm_data : NULL;
-}
+#include "hw/host1x02.h"
 
 void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
 {
@@ -79,7 +68,17 @@ static const struct host1x_info host1x01_info = {
        .sync_offset    = 0x3000,
 };
 
+static const struct host1x_info host1x02_info = {
+       .nb_channels = 9,
+       .nb_pts = 32,
+       .nb_mlocks = 16,
+       .nb_bases = 12,
+       .init = host1x02_init,
+       .sync_offset = 0x3000,
+};
+
 static struct of_device_id host1x_of_match[] = {
+       { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
        { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
        { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
        { },
@@ -114,6 +113,9 @@ static int host1x_probe(struct platform_device *pdev)
        if (!host)
                return -ENOMEM;
 
+       mutex_init(&host->devices_lock);
+       INIT_LIST_HEAD(&host->devices);
+       INIT_LIST_HEAD(&host->list);
        host->dev = &pdev->dev;
        host->info = id->data;
 
@@ -152,7 +154,7 @@ static int host1x_probe(struct platform_device *pdev)
        err = host1x_syncpt_init(host);
        if (err) {
                dev_err(&pdev->dev, "failed to initialize syncpts\n");
-               return err;
+               goto fail_unprepare_disable;
        }
 
        err = host1x_intr_init(host, syncpt_irq);
@@ -163,19 +165,26 @@ static int host1x_probe(struct platform_device *pdev)
 
        host1x_debug_init(host);
 
-       host1x_drm_alloc(pdev);
+       err = host1x_register(host);
+       if (err < 0)
+               goto fail_deinit_intr;
 
        return 0;
 
+fail_deinit_intr:
+       host1x_intr_deinit(host);
 fail_deinit_syncpt:
        host1x_syncpt_deinit(host);
+fail_unprepare_disable:
+       clk_disable_unprepare(host->clk);
        return err;
 }
 
-static int __exit host1x_remove(struct platform_device *pdev)
+static int host1x_remove(struct platform_device *pdev)
 {
        struct host1x *host = platform_get_drvdata(pdev);
 
+       host1x_unregister(host);
        host1x_intr_deinit(host);
        host1x_syncpt_deinit(host);
        clk_disable_unprepare(host->clk);
@@ -184,59 +193,36 @@ static int __exit host1x_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver tegra_host1x_driver = {
-       .probe = host1x_probe,
-       .remove = __exit_p(host1x_remove),
        .driver = {
-               .owner = THIS_MODULE,
                .name = "tegra-host1x",
                .of_match_table = host1x_of_match,
        },
+       .probe = host1x_probe,
+       .remove = host1x_remove,
 };
 
 static int __init tegra_host1x_init(void)
 {
        int err;
 
-       err = platform_driver_register(&tegra_host1x_driver);
+       err = host1x_bus_init();
        if (err < 0)
                return err;
 
-#ifdef CONFIG_DRM_TEGRA
-       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;
-#endif
+       err = platform_driver_register(&tegra_host1x_driver);
+       if (err < 0) {
+               host1x_bus_exit();
+               return err;
+       }
 
        return 0;
-
-#ifdef CONFIG_DRM_TEGRA
-unregister_hdmi:
-       platform_driver_unregister(&tegra_hdmi_driver);
-unregister_dc:
-       platform_driver_unregister(&tegra_dc_driver);
-unregister_host1x:
-       platform_driver_unregister(&tegra_host1x_driver);
-       return err;
-#endif
 }
 module_init(tegra_host1x_init);
 
 static void __exit tegra_host1x_exit(void)
 {
-#ifdef CONFIG_DRM_TEGRA
-       platform_driver_unregister(&tegra_gr2d_driver);
-       platform_driver_unregister(&tegra_hdmi_driver);
-       platform_driver_unregister(&tegra_dc_driver);
-#endif
        platform_driver_unregister(&tegra_host1x_driver);
+       host1x_bus_exit();
 }
 module_exit(tegra_host1x_exit);
 
index bed90a8131be590fef951c533cbf3622708184da..a61a976e7a421a405d7fe075272228f08e3e3e6d 100644 (file)
@@ -27,6 +27,7 @@
 #include "job.h"
 
 struct host1x_syncpt;
+struct host1x_syncpt_base;
 struct host1x_channel;
 struct host1x_cdma;
 struct host1x_job;
@@ -102,6 +103,7 @@ struct host1x {
 
        void __iomem *regs;
        struct host1x_syncpt *syncpt;
+       struct host1x_syncpt_base *bases;
        struct device *dev;
        struct clk *clk;
 
@@ -125,7 +127,10 @@ struct host1x {
 
        struct dentry *debugfs;
 
-       void *drm_data;
+       struct mutex devices_lock;
+       struct list_head devices;
+
+       struct list_head list;
 };
 
 void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
@@ -301,8 +306,4 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o)
        host->debug_op->show_mlocks(host, o);
 }
 
-extern struct platform_driver tegra_dc_driver;
-extern struct platform_driver tegra_hdmi_driver;
-extern struct platform_driver tegra_gr2d_driver;
-
 #endif
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
deleted file mode 100644 (file)
index 27ffcf1..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * drivers/video/tegra/host/gr2d/gr2d.c
- *
- * Tegra Graphics 2D
- *
- * Copyright (c) 2012-2013, NVIDIA Corporation.
- *
- * 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 <linux/export.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/clk.h>
-
-#include "channel.h"
-#include "drm.h"
-#include "gem.h"
-#include "job.h"
-#include "host1x.h"
-#include "host1x_bo.h"
-#include "host1x_client.h"
-#include "syncpt.h"
-
-struct gr2d {
-       struct host1x_client client;
-       struct clk *clk;
-       struct host1x_channel *channel;
-       unsigned long *addr_regs;
-};
-
-static inline struct gr2d *to_gr2d(struct host1x_client *client)
-{
-       return container_of(client, struct gr2d, client);
-}
-
-static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg);
-
-static int gr2d_client_init(struct host1x_client *client,
-                           struct drm_device *drm)
-{
-       return 0;
-}
-
-static int gr2d_client_exit(struct host1x_client *client)
-{
-       return 0;
-}
-
-static int gr2d_open_channel(struct host1x_client *client,
-                            struct host1x_drm_context *context)
-{
-       struct gr2d *gr2d = to_gr2d(client);
-
-       context->channel = host1x_channel_get(gr2d->channel);
-
-       if (!context->channel)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void gr2d_close_channel(struct host1x_drm_context *context)
-{
-       host1x_channel_put(context->channel);
-}
-
-static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm,
-                                         struct drm_file *file,
-                                         u32 handle)
-{
-       struct drm_gem_object *gem;
-       struct tegra_bo *bo;
-
-       gem = drm_gem_object_lookup(drm, file, handle);
-       if (!gem)
-               return NULL;
-
-       mutex_lock(&drm->struct_mutex);
-       drm_gem_object_unreference(gem);
-       mutex_unlock(&drm->struct_mutex);
-
-       bo = to_tegra_bo(gem);
-       return &bo->base;
-}
-
-static int gr2d_submit(struct host1x_drm_context *context,
-                      struct drm_tegra_submit *args, struct drm_device *drm,
-                      struct drm_file *file)
-{
-       struct host1x_job *job;
-       unsigned int num_cmdbufs = args->num_cmdbufs;
-       unsigned int num_relocs = args->num_relocs;
-       unsigned int num_waitchks = args->num_waitchks;
-       struct drm_tegra_cmdbuf __user *cmdbufs =
-               (void * __user)(uintptr_t)args->cmdbufs;
-       struct drm_tegra_reloc __user *relocs =
-               (void * __user)(uintptr_t)args->relocs;
-       struct drm_tegra_waitchk __user *waitchks =
-               (void * __user)(uintptr_t)args->waitchks;
-       struct drm_tegra_syncpt syncpt;
-       int err;
-
-       /* We don't yet support other than one syncpt_incr struct per submit */
-       if (args->num_syncpts != 1)
-               return -EINVAL;
-
-       job = host1x_job_alloc(context->channel, args->num_cmdbufs,
-                              args->num_relocs, args->num_waitchks);
-       if (!job)
-               return -ENOMEM;
-
-       job->num_relocs = args->num_relocs;
-       job->num_waitchk = args->num_waitchks;
-       job->client = (u32)args->context;
-       job->class = context->client->class;
-       job->serialize = true;
-
-       while (num_cmdbufs) {
-               struct drm_tegra_cmdbuf cmdbuf;
-               struct host1x_bo *bo;
-
-               err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
-               if (err)
-                       goto fail;
-
-               bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
-               if (!bo) {
-                       err = -ENOENT;
-                       goto fail;
-               }
-
-               host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
-               num_cmdbufs--;
-               cmdbufs++;
-       }
-
-       err = copy_from_user(job->relocarray, relocs,
-                            sizeof(*relocs) * num_relocs);
-       if (err)
-               goto fail;
-
-       while (num_relocs--) {
-               struct host1x_reloc *reloc = &job->relocarray[num_relocs];
-               struct host1x_bo *cmdbuf, *target;
-
-               cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
-               target = host1x_bo_lookup(drm, file, (u32)reloc->target);
-
-               reloc->cmdbuf = cmdbuf;
-               reloc->target = target;
-
-               if (!reloc->target || !reloc->cmdbuf) {
-                       err = -ENOENT;
-                       goto fail;
-               }
-       }
-
-       err = copy_from_user(job->waitchk, waitchks,
-                            sizeof(*waitchks) * num_waitchks);
-       if (err)
-               goto fail;
-
-       err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts,
-                            sizeof(syncpt));
-       if (err)
-               goto fail;
-
-       job->syncpt_id = syncpt.id;
-       job->syncpt_incrs = syncpt.incrs;
-       job->timeout = 10000;
-       job->is_addr_reg = gr2d_is_addr_reg;
-
-       if (args->timeout && args->timeout < 10000)
-               job->timeout = args->timeout;
-
-       err = host1x_job_pin(job, context->client->dev);
-       if (err)
-               goto fail;
-
-       err = host1x_job_submit(job);
-       if (err)
-               goto fail_submit;
-
-       args->fence = job->syncpt_end;
-
-       host1x_job_put(job);
-       return 0;
-
-fail_submit:
-       host1x_job_unpin(job);
-fail:
-       host1x_job_put(job);
-       return err;
-}
-
-static struct host1x_client_ops gr2d_client_ops = {
-       .drm_init = gr2d_client_init,
-       .drm_exit = gr2d_client_exit,
-       .open_channel = gr2d_open_channel,
-       .close_channel = gr2d_close_channel,
-       .submit = gr2d_submit,
-};
-
-static void gr2d_init_addr_reg_map(struct device *dev, struct gr2d *gr2d)
-{
-       const u32 gr2d_addr_regs[] = {0x1a, 0x1b, 0x26, 0x2b, 0x2c, 0x2d, 0x31,
-                                     0x32, 0x48, 0x49, 0x4a, 0x4b, 0x4c};
-       unsigned long *bitmap;
-       int i;
-
-       bitmap = devm_kzalloc(dev, DIV_ROUND_UP(256, BITS_PER_BYTE),
-                             GFP_KERNEL);
-
-       for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); ++i) {
-               u32 reg = gr2d_addr_regs[i];
-               bitmap[BIT_WORD(reg)] |= BIT_MASK(reg);
-       }
-
-       gr2d->addr_regs = bitmap;
-}
-
-static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg)
-{
-       struct gr2d *gr2d = dev_get_drvdata(dev);
-
-       switch (class) {
-       case HOST1X_CLASS_HOST1X:
-               return reg == 0x2b;
-       case HOST1X_CLASS_GR2D:
-       case HOST1X_CLASS_GR2D_SB:
-               reg &= 0xff;
-               if (gr2d->addr_regs[BIT_WORD(reg)] & BIT_MASK(reg))
-                       return 1;
-       default:
-               return 0;
-       }
-}
-
-static const struct of_device_id gr2d_match[] = {
-       { .compatible = "nvidia,tegra30-gr2d" },
-       { .compatible = "nvidia,tegra20-gr2d" },
-       { },
-};
-
-static int gr2d_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct host1x_drm *host1x = host1x_get_drm_data(dev->parent);
-       int err;
-       struct gr2d *gr2d = NULL;
-       struct host1x_syncpt **syncpts;
-
-       gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL);
-       if (!gr2d)
-               return -ENOMEM;
-
-       syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
-       if (!syncpts)
-               return -ENOMEM;
-
-       gr2d->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(gr2d->clk)) {
-               dev_err(dev, "cannot get clock\n");
-               return PTR_ERR(gr2d->clk);
-       }
-
-       err = clk_prepare_enable(gr2d->clk);
-       if (err) {
-               dev_err(dev, "cannot turn on clock\n");
-               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;
-       }
-
-       gr2d->client.ops = &gr2d_client_ops;
-       gr2d->client.dev = dev;
-       gr2d->client.class = HOST1X_CLASS_GR2D;
-       gr2d->client.syncpts = syncpts;
-       gr2d->client.num_syncpts = 1;
-
-       err = host1x_register_client(host1x, &gr2d->client);
-       if (err < 0) {
-               dev_err(dev, "failed to register host1x client: %d\n", err);
-               return err;
-       }
-
-       gr2d_init_addr_reg_map(dev, gr2d);
-
-       platform_set_drvdata(pdev, gr2d);
-
-       return 0;
-}
-
-static int __exit gr2d_remove(struct platform_device *pdev)
-{
-       struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
-       struct gr2d *gr2d = platform_get_drvdata(pdev);
-       unsigned int i;
-       int err;
-
-       err = host1x_unregister_client(host1x, &gr2d->client);
-       if (err < 0) {
-               dev_err(&pdev->dev, "failed to unregister client: %d\n", err);
-               return err;
-       }
-
-       for (i = 0; i < gr2d->client.num_syncpts; i++)
-               host1x_syncpt_free(gr2d->client.syncpts[i]);
-
-       host1x_channel_free(gr2d->channel);
-       clk_disable_unprepare(gr2d->clk);
-
-       return 0;
-}
-
-struct platform_driver tegra_gr2d_driver = {
-       .probe = gr2d_probe,
-       .remove = __exit_p(gr2d_remove),
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "gr2d",
-               .of_match_table = gr2d_match,
-       }
-};
diff --git a/drivers/gpu/host1x/host1x.h b/drivers/gpu/host1x/host1x.h
deleted file mode 100644 (file)
index a2bc1e6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Tegra host1x driver
- *
- * Copyright (c) 2009-2013, NVIDIA Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef __LINUX_HOST1X_H
-#define __LINUX_HOST1X_H
-
-enum host1x_class {
-       HOST1X_CLASS_HOST1X     = 0x1,
-       HOST1X_CLASS_GR2D       = 0x51,
-       HOST1X_CLASS_GR2D_SB    = 0x52
-};
-
-#endif
diff --git a/drivers/gpu/host1x/host1x_bo.h b/drivers/gpu/host1x/host1x_bo.h
deleted file mode 100644 (file)
index 4c1f10b..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Tegra host1x Memory Management Abstraction header
- *
- * Copyright (c) 2012-2013, NVIDIA Corporation.
- *
- * 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/>.
- */
-
-#ifndef _HOST1X_BO_H
-#define _HOST1X_BO_H
-
-struct host1x_bo;
-
-struct host1x_bo_ops {
-       struct host1x_bo *(*get)(struct host1x_bo *bo);
-       void (*put)(struct host1x_bo *bo);
-       dma_addr_t (*pin)(struct host1x_bo *bo, struct sg_table **sgt);
-       void (*unpin)(struct host1x_bo *bo, struct sg_table *sgt);
-       void *(*mmap)(struct host1x_bo *bo);
-       void (*munmap)(struct host1x_bo *bo, void *addr);
-       void *(*kmap)(struct host1x_bo *bo, unsigned int pagenum);
-       void (*kunmap)(struct host1x_bo *bo, unsigned int pagenum, void *addr);
-};
-
-struct host1x_bo {
-       const struct host1x_bo_ops *ops;
-};
-
-static inline void host1x_bo_init(struct host1x_bo *bo,
-                                 const struct host1x_bo_ops *ops)
-{
-       bo->ops = ops;
-}
-
-static inline struct host1x_bo *host1x_bo_get(struct host1x_bo *bo)
-{
-       return bo->ops->get(bo);
-}
-
-static inline void host1x_bo_put(struct host1x_bo *bo)
-{
-       bo->ops->put(bo);
-}
-
-static inline dma_addr_t host1x_bo_pin(struct host1x_bo *bo,
-                                      struct sg_table **sgt)
-{
-       return bo->ops->pin(bo, sgt);
-}
-
-static inline void host1x_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt)
-{
-       bo->ops->unpin(bo, sgt);
-}
-
-static inline void *host1x_bo_mmap(struct host1x_bo *bo)
-{
-       return bo->ops->mmap(bo);
-}
-
-static inline void host1x_bo_munmap(struct host1x_bo *bo, void *addr)
-{
-       bo->ops->munmap(bo, addr);
-}
-
-static inline void *host1x_bo_kmap(struct host1x_bo *bo, unsigned int pagenum)
-{
-       return bo->ops->kmap(bo, pagenum);
-}
-
-static inline void host1x_bo_kunmap(struct host1x_bo *bo,
-                                   unsigned int pagenum, void *addr)
-{
-       bo->ops->kunmap(bo, pagenum, addr);
-}
-
-#endif
diff --git a/drivers/gpu/host1x/hw/Makefile b/drivers/gpu/host1x/hw/Makefile
deleted file mode 100644 (file)
index 9b50863..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ccflags-y = -Idrivers/gpu/host1x
-
-host1x-hw-objs  = \
-       host1x01.o
-
-obj-$(CONFIG_TEGRA_HOST1X) += host1x-hw.o
index 2ee4ad55c4dba344cbb28d72d8febecd7f0181ee..37e2a63241a9d6150b1554896fde15ac0294c157 100644 (file)
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 
-#include "cdma.h"
-#include "channel.h"
-#include "dev.h"
-#include "debug.h"
+#include "../cdma.h"
+#include "../channel.h"
+#include "../dev.h"
+#include "../debug.h"
 
 /*
  * Put the restart at the end of pushbuffer memor
index ee199623e36570719ad35fbe3de0d41b00744843..4608257ab65641c488f627a0789eae9a4ba90ff1 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/host1x.h>
 #include <linux/slab.h>
+
 #include <trace/events/host1x.h>
 
-#include "host1x.h"
-#include "host1x_bo.h"
-#include "channel.h"
-#include "dev.h"
-#include "intr.h"
-#include "job.h"
+#include "../channel.h"
+#include "../dev.h"
+#include "../intr.h"
+#include "../job.h"
 
 #define HOST1X_CHANNEL_SIZE 16384
 #define TRACE_MAX_LENGTH 128U
@@ -67,6 +67,22 @@ static void submit_gathers(struct host1x_job *job)
        }
 }
 
+static inline void synchronize_syncpt_base(struct host1x_job *job)
+{
+       struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
+       struct host1x_syncpt *sp = host->syncpt + job->syncpt_id;
+       u32 id, value;
+
+       value = host1x_syncpt_read_max(sp);
+       id = sp->base->id;
+
+       host1x_cdma_push(&job->channel->cdma,
+                        host1x_opcode_setclass(HOST1X_CLASS_HOST1X,
+                               HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1),
+                        HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(id) |
+                        HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value));
+}
+
 static int channel_submit(struct host1x_job *job)
 {
        struct host1x_channel *ch = job->channel;
@@ -118,6 +134,10 @@ static int channel_submit(struct host1x_job *job)
                                        host1x_syncpt_read_max(sp)));
        }
 
+       /* Synchronize base register to allow using it for relative waiting */
+       if (sp->base)
+               synchronize_syncpt_base(job);
+
        syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
 
        job->syncpt_end = syncval;
index 334c038052f582cac72c1818d30b3387aa3ae060..640c75ca5a8bbc465dcc9f1350d4f5efdd928d5d 100644 (file)
  *
  */
 
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-
-#include <linux/io.h>
-
-#include "dev.h"
-#include "debug.h"
-#include "cdma.h"
-#include "channel.h"
-#include "host1x_bo.h"
+#include "../dev.h"
+#include "../debug.h"
+#include "../cdma.h"
+#include "../channel.h"
 
 #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400
 
index a14e91cd1e58eee8e5f52db20c672076544a0439..859b73beb4d0c326fcaf24ae1086ff2bc876df09 100644 (file)
  */
 
 /* include hw specification */
-#include "hw/host1x01.h"
-#include "hw/host1x01_hardware.h"
+#include "host1x01.h"
+#include "host1x01_hardware.h"
 
 /* include code */
-#include "hw/cdma_hw.c"
-#include "hw/channel_hw.c"
-#include "hw/debug_hw.c"
-#include "hw/intr_hw.c"
-#include "hw/syncpt_hw.c"
+#include "cdma_hw.c"
+#include "channel_hw.c"
+#include "debug_hw.c"
+#include "intr_hw.c"
+#include "syncpt_hw.c"
 
-#include "dev.h"
+#include "../dev.h"
 
 int host1x01_init(struct host1x *host)
 {
diff --git a/drivers/gpu/host1x/hw/host1x02.c b/drivers/gpu/host1x/hw/host1x02.c
new file mode 100644 (file)
index 0000000..e98caca
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Host1x init for Tegra114 SoCs
+ *
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * 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 hw specification */
+#include "host1x01.h"
+#include "host1x01_hardware.h"
+
+/* include code */
+#include "cdma_hw.c"
+#include "channel_hw.c"
+#include "debug_hw.c"
+#include "intr_hw.c"
+#include "syncpt_hw.c"
+
+#include "../dev.h"
+
+int host1x02_init(struct host1x *host)
+{
+       host->channel_op = &host1x_channel_ops;
+       host->cdma_op = &host1x_cdma_ops;
+       host->cdma_pb_op = &host1x_pushbuffer_ops;
+       host->syncpt_op = &host1x_syncpt_ops;
+       host->intr_op = &host1x_intr_ops;
+       host->debug_op = &host1x_debug_ops;
+
+       return 0;
+}
diff --git a/drivers/gpu/host1x/hw/host1x02.h b/drivers/gpu/host1x/hw/host1x02.h
new file mode 100644 (file)
index 0000000..f748660
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Host1x init for Tegra114 SoCs
+ *
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * 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/>.
+ */
+
+#ifndef HOST1X_HOST1X02_H
+#define HOST1X_HOST1X02_H
+
+struct host1x;
+
+int host1x02_init(struct host1x *host);
+
+#endif
index 42f3ce19ca32bbb03147c74e11d3c1172b1e8b57..f7553599ee275c0a7c2eddb32ba4a6821fb25de9 100644 (file)
@@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
 }
 #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
        host1x_uclass_wait_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_r(void)
+{
+       return 0xb;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
+       host1x_uclass_load_syncpt_base_r()
 static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
 {
        return (v & 0xff) << 24;
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_channel.h b/drivers/gpu/host1x/hw/hw_host1x02_channel.h
new file mode 100644 (file)
index 0000000..e490bcd
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * 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/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X02_CHANNEL_H
+#define HOST1X_HW_HOST1X02_CHANNEL_H
+
+static inline u32 host1x_channel_fifostat_r(void)
+{
+       return 0x0;
+}
+#define HOST1X_CHANNEL_FIFOSTAT \
+       host1x_channel_fifostat_r()
+static inline u32 host1x_channel_fifostat_cfempty_v(u32 r)
+{
+       return (r >> 11) & 0x1;
+}
+#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \
+       host1x_channel_fifostat_cfempty_v(r)
+static inline u32 host1x_channel_dmastart_r(void)
+{
+       return 0x14;
+}
+#define HOST1X_CHANNEL_DMASTART \
+       host1x_channel_dmastart_r()
+static inline u32 host1x_channel_dmaput_r(void)
+{
+       return 0x18;
+}
+#define HOST1X_CHANNEL_DMAPUT \
+       host1x_channel_dmaput_r()
+static inline u32 host1x_channel_dmaget_r(void)
+{
+       return 0x1c;
+}
+#define HOST1X_CHANNEL_DMAGET \
+       host1x_channel_dmaget_r()
+static inline u32 host1x_channel_dmaend_r(void)
+{
+       return 0x20;
+}
+#define HOST1X_CHANNEL_DMAEND \
+       host1x_channel_dmaend_r()
+static inline u32 host1x_channel_dmactrl_r(void)
+{
+       return 0x24;
+}
+#define HOST1X_CHANNEL_DMACTRL \
+       host1x_channel_dmactrl_r()
+static inline u32 host1x_channel_dmactrl_dmastop(void)
+{
+       return 1 << 0;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP \
+       host1x_channel_dmactrl_dmastop()
+static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \
+       host1x_channel_dmactrl_dmastop_v(r)
+static inline u32 host1x_channel_dmactrl_dmagetrst(void)
+{
+       return 1 << 1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAGETRST \
+       host1x_channel_dmactrl_dmagetrst()
+static inline u32 host1x_channel_dmactrl_dmainitget(void)
+{
+       return 1 << 2;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \
+       host1x_channel_dmactrl_dmainitget()
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_sync.h b/drivers/gpu/host1x/hw/hw_host1x02_sync.h
new file mode 100644 (file)
index 0000000..4495401
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * 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/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X02_SYNC_H
+#define HOST1X_HW_HOST1X02_SYNC_H
+
+#define REGISTER_STRIDE        4
+
+static inline u32 host1x_sync_syncpt_r(unsigned int id)
+{
+       return 0x400 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT(id) \
+       host1x_sync_syncpt_r(id)
+static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id)
+{
+       return 0x40 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \
+       host1x_sync_syncpt_thresh_cpu0_int_status_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id)
+{
+       return 0x60 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \
+       host1x_sync_syncpt_thresh_int_disable_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id)
+{
+       return 0x68 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \
+       host1x_sync_syncpt_thresh_int_enable_cpu0_r(id)
+static inline u32 host1x_sync_cf_setup_r(unsigned int channel)
+{
+       return 0x80 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CF_SETUP(channel) \
+       host1x_sync_cf_setup_r(channel)
+static inline u32 host1x_sync_cf_setup_base_v(u32 r)
+{
+       return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_BASE_V(r) \
+       host1x_sync_cf_setup_base_v(r)
+static inline u32 host1x_sync_cf_setup_limit_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \
+       host1x_sync_cf_setup_limit_v(r)
+static inline u32 host1x_sync_cmdproc_stop_r(void)
+{
+       return 0xac;
+}
+#define HOST1X_SYNC_CMDPROC_STOP \
+       host1x_sync_cmdproc_stop_r()
+static inline u32 host1x_sync_ch_teardown_r(void)
+{
+       return 0xb0;
+}
+#define HOST1X_SYNC_CH_TEARDOWN \
+       host1x_sync_ch_teardown_r()
+static inline u32 host1x_sync_usec_clk_r(void)
+{
+       return 0x1a4;
+}
+#define HOST1X_SYNC_USEC_CLK \
+       host1x_sync_usec_clk_r()
+static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void)
+{
+       return 0x1a8;
+}
+#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \
+       host1x_sync_ctxsw_timeout_cfg_r()
+static inline u32 host1x_sync_ip_busy_timeout_r(void)
+{
+       return 0x1bc;
+}
+#define HOST1X_SYNC_IP_BUSY_TIMEOUT \
+       host1x_sync_ip_busy_timeout_r()
+static inline u32 host1x_sync_mlock_owner_r(unsigned int id)
+{
+       return 0x340 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_MLOCK_OWNER(id) \
+       host1x_sync_mlock_owner_r(id)
+static inline u32 host1x_sync_mlock_owner_chid_f(u32 v)
+{
+       return (v & 0xf) << 8;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \
+       host1x_sync_mlock_owner_chid_f(v)
+static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r)
+{
+       return (r >> 1) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \
+       host1x_sync_mlock_owner_cpu_owns_v(r)
+static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \
+       host1x_sync_mlock_owner_ch_owns_v(r)
+static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id)
+{
+       return 0x500 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \
+       host1x_sync_syncpt_int_thresh_r(id)
+static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
+{
+       return 0x600 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_BASE(id) \
+       host1x_sync_syncpt_base_r(id)
+static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id)
+{
+       return 0x700 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
+       host1x_sync_syncpt_cpu_incr_r(id)
+static inline u32 host1x_sync_cbread_r(unsigned int channel)
+{
+       return 0x720 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBREAD(channel) \
+       host1x_sync_cbread_r(channel)
+static inline u32 host1x_sync_cfpeek_ctrl_r(void)
+{
+       return 0x74c;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL \
+       host1x_sync_cfpeek_ctrl_r()
+static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v)
+{
+       return (v & 0x3ff) << 0;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \
+       host1x_sync_cfpeek_ctrl_addr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v)
+{
+       return (v & 0xf) << 16;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \
+       host1x_sync_cfpeek_ctrl_channr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v)
+{
+       return (v & 0x1) << 31;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \
+       host1x_sync_cfpeek_ctrl_ena_f(v)
+static inline u32 host1x_sync_cfpeek_read_r(void)
+{
+       return 0x750;
+}
+#define HOST1X_SYNC_CFPEEK_READ \
+       host1x_sync_cfpeek_read_r()
+static inline u32 host1x_sync_cfpeek_ptrs_r(void)
+{
+       return 0x754;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS \
+       host1x_sync_cfpeek_ptrs_r()
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r)
+{
+       return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \
+       host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r)
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \
+       host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r)
+static inline u32 host1x_sync_cbstat_r(unsigned int channel)
+{
+       return 0x758 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBSTAT(channel) \
+       host1x_sync_cbstat_r(channel)
+static inline u32 host1x_sync_cbstat_cboffset_v(u32 r)
+{
+       return (r >> 0) & 0xffff;
+}
+#define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \
+       host1x_sync_cbstat_cboffset_v(r)
+static inline u32 host1x_sync_cbstat_cbclass_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \
+       host1x_sync_cbstat_cbclass_v(r)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h
new file mode 100644 (file)
index 0000000..a3b3c98
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * 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/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X02_UCLASS_H
+#define HOST1X_HW_HOST1X02_UCLASS_H
+
+static inline u32 host1x_uclass_incr_syncpt_r(void)
+{
+       return 0x0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT \
+       host1x_uclass_incr_syncpt_r()
+static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
+{
+       return (v & 0xff) << 8;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
+       host1x_uclass_incr_syncpt_cond_f(v)
+static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
+       host1x_uclass_incr_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_r(void)
+{
+       return 0x8;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT \
+       host1x_uclass_wait_syncpt_r()
+static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \
+       host1x_uclass_wait_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
+       host1x_uclass_wait_syncpt_thresh_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_r(void)
+{
+       return 0x9;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
+       host1x_uclass_wait_syncpt_base_r()
+static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 16;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_wait_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_load_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \
+       host1x_uclass_load_syncpt_base_value_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_incr_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_incr_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_indoff_r(void)
+{
+       return 0x2d;
+}
+#define HOST1X_UCLASS_INDOFF \
+       host1x_uclass_indoff_r()
+static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
+{
+       return (v & 0xf) << 28;
+}
+#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \
+       host1x_uclass_indoff_indbe_f(v)
+static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
+{
+       return (v & 0x1) << 27;
+}
+#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \
+       host1x_uclass_indoff_autoinc_f(v)
+static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
+{
+       return (v & 0xff) << 18;
+}
+#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \
+       host1x_uclass_indoff_indmodid_f(v)
+static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
+{
+       return (v & 0xffff) << 2;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+static inline u32 host1x_uclass_indoff_rwn_read_v(void)
+{
+       return 1;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+
+#endif
index b592eef1efcb9babfe0355d418f4d276682a0841..b26dcc83bc1b373400d72c46aad21d04fb97f52f 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/io.h>
 #include <asm/mach/irq.h>
 
-#include "intr.h"
-#include "dev.h"
+#include "../intr.h"
+#include "../dev.h"
 
 /*
  * Sync point threshold interrupt service function
index 0cf6095d33678f51da127f4feac313f9422bc9e8..56e85395ac24112faf17b4b06a1aa950e671df0b 100644 (file)
@@ -18,8 +18,8 @@
 
 #include <linux/io.h>
 
-#include "dev.h"
-#include "syncpt.h"
+#include "../dev.h"
+#include "../syncpt.h"
 
 /*
  * Write the current syncpoint value back to hw.
index c4e1050f2252679e448e58e1c2b3edffffd08073..de5ec333ce1adc1974001d01bad56d2544d472d3 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
+#include <linux/host1x.h>
 #include <linux/kref.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
@@ -27,7 +28,6 @@
 
 #include "channel.h"
 #include "dev.h"
-#include "host1x_bo.h"
 #include "job.h"
 #include "syncpt.h"
 
@@ -264,7 +264,7 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
 }
 
 static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
-                      unsigned int offset)
+                       unsigned int offset)
 {
        offset *= sizeof(u32);
 
@@ -281,7 +281,7 @@ struct host1x_firewall {
        unsigned int num_relocs;
        struct host1x_reloc *reloc;
 
-       struct host1x_bo *cmdbuf_id;
+       struct host1x_bo *cmdbuf;
        unsigned int offset;
 
        u32 words;
@@ -291,25 +291,37 @@ struct host1x_firewall {
        u32 count;
 };
 
+static int check_register(struct host1x_firewall *fw, unsigned long offset)
+{
+       if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) {
+               if (!fw->num_relocs)
+                       return -EINVAL;
+
+               if (!check_reloc(fw->reloc, fw->cmdbuf, fw->offset))
+                       return -EINVAL;
+
+               fw->num_relocs--;
+               fw->reloc++;
+       }
+
+       return 0;
+}
+
 static int check_mask(struct host1x_firewall *fw)
 {
        u32 mask = fw->mask;
        u32 reg = fw->reg;
+       int ret;
 
        while (mask) {
                if (fw->words == 0)
                        return -EINVAL;
 
                if (mask & 1) {
-                       if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
-                               if (!fw->num_relocs)
-                                       return -EINVAL;
-                               if (!check_reloc(fw->reloc, fw->cmdbuf_id,
-                                                fw->offset))
-                                       return -EINVAL;
-                               fw->reloc++;
-                               fw->num_relocs--;
-                       }
+                       ret = check_register(fw, reg);
+                       if (ret < 0)
+                               return ret;
+
                        fw->words--;
                        fw->offset++;
                }
@@ -324,19 +336,16 @@ static int check_incr(struct host1x_firewall *fw)
 {
        u32 count = fw->count;
        u32 reg = fw->reg;
+       int ret;
 
        while (count) {
                if (fw->words == 0)
                        return -EINVAL;
 
-               if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
-                       if (!fw->num_relocs)
-                               return -EINVAL;
-                       if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
-                               return -EINVAL;
-                       fw->reloc++;
-                       fw->num_relocs--;
-               }
+               ret = check_register(fw, reg);
+               if (ret < 0)
+                       return ret;
+
                reg++;
                fw->words--;
                fw->offset++;
@@ -348,21 +357,17 @@ static int check_incr(struct host1x_firewall *fw)
 
 static int check_nonincr(struct host1x_firewall *fw)
 {
-       int is_addr_reg = fw->job->is_addr_reg(fw->dev, fw->class, fw->reg);
        u32 count = fw->count;
+       int ret;
 
        while (count) {
                if (fw->words == 0)
                        return -EINVAL;
 
-               if (is_addr_reg) {
-                       if (!fw->num_relocs)
-                               return -EINVAL;
-                       if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
-                               return -EINVAL;
-                       fw->reloc++;
-                       fw->num_relocs--;
-               }
+               ret = check_register(fw, fw->reg);
+               if (ret < 0)
+                       return ret;
+
                fw->words--;
                fw->offset++;
                count--;
@@ -381,7 +386,7 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
                return 0;
 
        fw->words = g->words;
-       fw->cmdbuf_id = g->bo;
+       fw->cmdbuf = g->bo;
        fw->offset = 0;
 
        while (fw->words && !err) {
@@ -436,10 +441,6 @@ static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
                }
        }
 
-       /* No relocs should remain at this point */
-       if (fw->num_relocs)
-               err = -EINVAL;
-
 out:
        return err;
 }
@@ -493,6 +494,10 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
                offset += g->words * sizeof(u32);
        }
 
+       /* No relocs should remain at this point */
+       if (fw.num_relocs)
+               return -EINVAL;
+
        return 0;
 }
 
index fba45f20458e2d1a4b4e83a795c2d948eaa5ea08..33a697d6dcefea290c3bac2981e2399e27f99a14 100644 (file)
@@ -34,15 +34,6 @@ struct host1x_cmdbuf {
        u32 pad;
 };
 
-struct host1x_reloc {
-       struct host1x_bo *cmdbuf;
-       u32 cmdbuf_offset;
-       struct host1x_bo *target;
-       u32 target_offset;
-       u32 shift;
-       u32 pad;
-};
-
 struct host1x_waitchk {
        struct host1x_bo *bo;
        u32 offset;
@@ -55,105 +46,6 @@ struct host1x_job_unpin_data {
        struct sg_table *sgt;
 };
 
-/*
- * Each submit is tracked as a host1x_job.
- */
-struct host1x_job {
-       /* When refcount goes to zero, job can be freed */
-       struct kref ref;
-
-       /* List entry */
-       struct list_head list;
-
-       /* Channel where job is submitted to */
-       struct host1x_channel *channel;
-
-       u32 client;
-
-       /* Gathers and their memory */
-       struct host1x_job_gather *gathers;
-       unsigned int num_gathers;
-
-       /* Wait checks to be processed at submit time */
-       struct host1x_waitchk *waitchk;
-       unsigned int num_waitchk;
-       u32 waitchk_mask;
-
-       /* Array of handles to be pinned & unpinned */
-       struct host1x_reloc *relocarray;
-       unsigned int num_relocs;
-       struct host1x_job_unpin_data *unpins;
-       unsigned int num_unpins;
-
-       dma_addr_t *addr_phys;
-       dma_addr_t *gather_addr_phys;
-       dma_addr_t *reloc_addr_phys;
-
-       /* Sync point id, number of increments and end related to the submit */
-       u32 syncpt_id;
-       u32 syncpt_incrs;
-       u32 syncpt_end;
-
-       /* Maximum time to wait for this job */
-       unsigned int timeout;
-
-       /* Index and number of slots used in the push buffer */
-       unsigned int first_get;
-       unsigned int num_slots;
-
-       /* Copy of gathers */
-       size_t gather_copy_size;
-       dma_addr_t gather_copy;
-       u8 *gather_copy_mapped;
-
-       /* Check if register is marked as an address reg */
-       int (*is_addr_reg)(struct device *dev, u32 reg, u32 class);
-
-       /* Request a SETCLASS to this class */
-       u32 class;
-
-       /* Add a channel wait for previous ops to complete */
-       bool serialize;
-};
-/*
- * Allocate memory for a job. Just enough memory will be allocated to
- * accomodate the submit.
- */
-struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,
-                                   u32 num_cmdbufs, u32 num_relocs,
-                                   u32 num_waitchks);
-
-/*
- * Add a gather to a job.
- */
-void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *mem_id,
-                          u32 words, u32 offset);
-
-/*
- * Increment reference going to host1x_job.
- */
-struct host1x_job *host1x_job_get(struct host1x_job *job);
-
-/*
- * Decrement reference job, free if goes to zero.
- */
-void host1x_job_put(struct host1x_job *job);
-
-/*
- * Pin memory related to job. This handles relocation of addresses to the
- * host1x address space. Handles both the gather memory and any other memory
- * referred to from the gather buffers.
- *
- * Handles also patching out host waits that would wait for an expired sync
- * point value.
- */
-int host1x_job_pin(struct host1x_job *job, struct device *dev);
-
-/*
- * Unpin memory related to job.
- */
-void host1x_job_unpin(struct host1x_job *job);
-
 /*
  * Dump contents of job to debug output.
  */
index 409745b949dbfa7d9ecd897409147ae0225623e3..159c479829c959d0bd898742f9bcfec54e74020e 100644 (file)
 #define SYNCPT_CHECK_PERIOD (2 * HZ)
 #define MAX_STUCK_CHECK_COUNT 15
 
-static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
-                                                 struct device *dev,
-                                                 bool client_managed)
+static struct host1x_syncpt_base *
+host1x_syncpt_base_request(struct host1x *host)
+{
+       struct host1x_syncpt_base *bases = host->bases;
+       unsigned int i;
+
+       for (i = 0; i < host->info->nb_bases; i++)
+               if (!bases[i].requested)
+                       break;
+
+       if (i >= host->info->nb_bases)
+               return NULL;
+
+       bases[i].requested = true;
+       return &bases[i];
+}
+
+static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
+{
+       if (base)
+               base->requested = false;
+}
+
+static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
+                                                struct device *dev,
+                                                unsigned long flags)
 {
        int i;
        struct host1x_syncpt *sp = host->syncpt;
@@ -44,6 +67,12 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
        if (i >= host->info->nb_pts)
                return NULL;
 
+       if (flags & HOST1X_SYNCPT_HAS_BASE) {
+               sp->base = host1x_syncpt_base_request(host);
+               if (!sp->base)
+                       return NULL;
+       }
+
        name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
                        dev ? dev_name(dev) : NULL);
        if (!name)
@@ -51,7 +80,11 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
 
        sp->dev = dev;
        sp->name = name;
-       sp->client_managed = client_managed;
+
+       if (flags & HOST1X_SYNCPT_CLIENT_MANAGED)
+               sp->client_managed = true;
+       else
+               sp->client_managed = false;
 
        return sp;
 }
@@ -303,25 +336,35 @@ int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr)
 
 int host1x_syncpt_init(struct host1x *host)
 {
+       struct host1x_syncpt_base *bases;
        struct host1x_syncpt *syncpt;
        int i;
 
        syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts,
-               GFP_KERNEL);
+                             GFP_KERNEL);
        if (!syncpt)
                return -ENOMEM;
 
-       for (i = 0; i < host->info->nb_pts; ++i) {
+       bases = devm_kzalloc(host->dev, sizeof(*bases) * host->info->nb_bases,
+                            GFP_KERNEL);
+       if (!bases)
+               return -ENOMEM;
+
+       for (i = 0; i < host->info->nb_pts; i++) {
                syncpt[i].id = i;
                syncpt[i].host = host;
        }
 
+       for (i = 0; i < host->info->nb_bases; i++)
+               bases[i].id = i;
+
        host->syncpt = syncpt;
+       host->bases = bases;
 
        host1x_syncpt_restore(host);
 
        /* Allocate sync point to use for clearing waits for expired fences */
-       host->nop_sp = _host1x_syncpt_alloc(host, NULL, false);
+       host->nop_sp = host1x_syncpt_alloc(host, NULL, 0);
        if (!host->nop_sp)
                return -ENOMEM;
 
@@ -329,10 +372,10 @@ int host1x_syncpt_init(struct host1x *host)
 }
 
 struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
-                                           bool client_managed)
+                                           unsigned long flags)
 {
        struct host1x *host = dev_get_drvdata(dev->parent);
-       return _host1x_syncpt_alloc(host, dev, client_managed);
+       return host1x_syncpt_alloc(host, dev, flags);
 }
 
 void host1x_syncpt_free(struct host1x_syncpt *sp)
@@ -340,7 +383,9 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
        if (!sp)
                return;
 
+       host1x_syncpt_base_free(sp->base);
        kfree(sp->name);
+       sp->base = NULL;
        sp->dev = NULL;
        sp->name = NULL;
        sp->client_managed = false;
@@ -354,6 +399,25 @@ void host1x_syncpt_deinit(struct host1x *host)
                kfree(sp->name);
 }
 
+/*
+ * Read max. It indicates how many operations there are in queue, either in
+ * channel or in a software thread.
+ * */
+u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
+{
+       smp_rmb();
+       return (u32)atomic_read(&sp->max_val);
+}
+
+/*
+ * Read min, which is a shadow of the current sync point value in hardware.
+ */
+u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
+{
+       smp_rmb();
+       return (u32)atomic_read(&sp->min_val);
+}
+
 int host1x_syncpt_nb_pts(struct host1x *host)
 {
        return host->info->nb_pts;
@@ -375,3 +439,13 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
                return NULL;
        return host->syncpt + id;
 }
+
+struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
+{
+       return sp ? sp->base : NULL;
+}
+
+u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
+{
+       return base->id;
+}
index 267c0b9d3647d24f2a3bf7dc81504eacaf957005..9056465ecd3f1ea88963c397b6f2fdd0ae5f407a 100644 (file)
@@ -20,6 +20,7 @@
 #define __HOST1X_SYNCPT_H
 
 #include <linux/atomic.h>
+#include <linux/host1x.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -30,6 +31,11 @@ struct host1x;
 /* Reserved for replacing an expired wait with a NOP */
 #define HOST1X_SYNCPT_RESERVED                 0
 
+struct host1x_syncpt_base {
+       unsigned int id;
+       bool requested;
+};
+
 struct host1x_syncpt {
        int id;
        atomic_t min_val;
@@ -39,6 +45,7 @@ struct host1x_syncpt {
        bool client_managed;
        struct host1x *host;
        struct device *dev;
+       struct host1x_syncpt_base *base;
 
        /* interrupt data */
        struct host1x_syncpt_intr intr;
@@ -50,25 +57,6 @@ int host1x_syncpt_init(struct host1x *host);
 /*  Free sync point array */
 void host1x_syncpt_deinit(struct host1x *host);
 
-/*
- * Read max. It indicates how many operations there are in queue, either in
- * channel or in a software thread.
- * */
-static inline u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
-{
-       smp_rmb();
-       return (u32)atomic_read(&sp->max_val);
-}
-
-/*
- * Read min, which is a shadow of the current sync point value in hardware.
- */
-static inline u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
-{
-       smp_rmb();
-       return (u32)atomic_read(&sp->min_val);
-}
-
 /* Return number of sync point supported. */
 int host1x_syncpt_nb_pts(struct host1x *host);
 
@@ -112,9 +100,6 @@ static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp)
        return (min == max);
 }
 
-/* Return pointer to struct denoting sync point id. */
-struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
-
 /* Load current value from hardware to the shadow register. */
 u32 host1x_syncpt_load(struct host1x_syncpt *sp);
 
@@ -130,16 +115,9 @@ void host1x_syncpt_restore(struct host1x *host);
 /* Read current wait base value into shadow register and return it. */
 u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp);
 
-/* Request incrementing a sync point. */
-int host1x_syncpt_incr(struct host1x_syncpt *sp);
-
 /* Indicate future operations by incrementing the sync point max. */
 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
 
-/* Wait until sync point reaches a threshold value, or a timeout. */
-int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh,
-                       long timeout, u32 *value);
-
 /* Check if sync point id is valid. */
 static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp)
 {
@@ -149,14 +127,4 @@ static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp)
 /* Patch a wait by replacing it with a wait for syncpt 0 value 0 */
 int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr);
 
-/* Return id of the sync point */
-u32 host1x_syncpt_id(struct host1x_syncpt *sp);
-
-/* Allocate a sync point for a device. */
-struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
-                                           bool client_managed);
-
-/* Free a sync point. */
-void host1x_syncpt_free(struct host1x_syncpt *sp);
-
 #endif
index 84b685f7ab6e0a3389c534b56e8f8187619e1e84..a312f048656f76f017c2a730836762cadd1e8553 100644 (file)
@@ -19,10 +19,10 @@ source "drivers/char/agp/Kconfig"
 
 source "drivers/gpu/vga/Kconfig"
 
-source "drivers/gpu/drm/Kconfig"
-
 source "drivers/gpu/host1x/Kconfig"
 
+source "drivers/gpu/drm/Kconfig"
+
 config VGASTATE
        tristate
        default n
index 7062307a4a2d7f656950a70bcd72bdf0fac4a4dc..e6d0cd9f518efa36733f5769e9836dced310e628 100644 (file)
@@ -150,6 +150,7 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_BUS_PCI 0x1
 #define DRIVER_BUS_PLATFORM 0x2
 #define DRIVER_BUS_USB 0x3
+#define DRIVER_BUS_HOST1X 0x4
 
 /***********************************************************************/
 /** \name Begin the DRM... */
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
new file mode 100644 (file)
index 0000000..f5b9b87
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2009-2013, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __LINUX_HOST1X_H
+#define __LINUX_HOST1X_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+enum host1x_class {
+       HOST1X_CLASS_HOST1X = 0x1,
+       HOST1X_CLASS_GR2D = 0x51,
+       HOST1X_CLASS_GR2D_SB = 0x52,
+       HOST1X_CLASS_GR3D = 0x60,
+};
+
+struct host1x_client;
+
+struct host1x_client_ops {
+       int (*init)(struct host1x_client *client);
+       int (*exit)(struct host1x_client *client);
+};
+
+struct host1x_client {
+       struct list_head list;
+       struct device *parent;
+       struct device *dev;
+
+       const struct host1x_client_ops *ops;
+
+       enum host1x_class class;
+       struct host1x_channel *channel;
+
+       struct host1x_syncpt **syncpts;
+       unsigned int num_syncpts;
+};
+
+/*
+ * host1x buffer objects
+ */
+
+struct host1x_bo;
+struct sg_table;
+
+struct host1x_bo_ops {
+       struct host1x_bo *(*get)(struct host1x_bo *bo);
+       void (*put)(struct host1x_bo *bo);
+       dma_addr_t (*pin)(struct host1x_bo *bo, struct sg_table **sgt);
+       void (*unpin)(struct host1x_bo *bo, struct sg_table *sgt);
+       void *(*mmap)(struct host1x_bo *bo);
+       void (*munmap)(struct host1x_bo *bo, void *addr);
+       void *(*kmap)(struct host1x_bo *bo, unsigned int pagenum);
+       void (*kunmap)(struct host1x_bo *bo, unsigned int pagenum, void *addr);
+};
+
+struct host1x_bo {
+       const struct host1x_bo_ops *ops;
+};
+
+static inline void host1x_bo_init(struct host1x_bo *bo,
+                                 const struct host1x_bo_ops *ops)
+{
+       bo->ops = ops;
+}
+
+static inline struct host1x_bo *host1x_bo_get(struct host1x_bo *bo)
+{
+       return bo->ops->get(bo);
+}
+
+static inline void host1x_bo_put(struct host1x_bo *bo)
+{
+       bo->ops->put(bo);
+}
+
+static inline dma_addr_t host1x_bo_pin(struct host1x_bo *bo,
+                                      struct sg_table **sgt)
+{
+       return bo->ops->pin(bo, sgt);
+}
+
+static inline void host1x_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt)
+{
+       bo->ops->unpin(bo, sgt);
+}
+
+static inline void *host1x_bo_mmap(struct host1x_bo *bo)
+{
+       return bo->ops->mmap(bo);
+}
+
+static inline void host1x_bo_munmap(struct host1x_bo *bo, void *addr)
+{
+       bo->ops->munmap(bo, addr);
+}
+
+static inline void *host1x_bo_kmap(struct host1x_bo *bo, unsigned int pagenum)
+{
+       return bo->ops->kmap(bo, pagenum);
+}
+
+static inline void host1x_bo_kunmap(struct host1x_bo *bo,
+                                   unsigned int pagenum, void *addr)
+{
+       bo->ops->kunmap(bo, pagenum, addr);
+}
+
+/*
+ * host1x syncpoints
+ */
+
+#define HOST1X_SYNCPT_CLIENT_MANAGED   (1 << 0)
+#define HOST1X_SYNCPT_HAS_BASE         (1 << 1)
+
+struct host1x_syncpt_base;
+struct host1x_syncpt;
+struct host1x;
+
+struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
+u32 host1x_syncpt_id(struct host1x_syncpt *sp);
+u32 host1x_syncpt_read_min(struct host1x_syncpt *sp);
+u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
+int host1x_syncpt_incr(struct host1x_syncpt *sp);
+int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
+                      u32 *value);
+struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
+                                           unsigned long flags);
+void host1x_syncpt_free(struct host1x_syncpt *sp);
+
+struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp);
+u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base);
+
+/*
+ * host1x channel
+ */
+
+struct host1x_channel;
+struct host1x_job;
+
+struct host1x_channel *host1x_channel_request(struct device *dev);
+void host1x_channel_free(struct host1x_channel *channel);
+struct host1x_channel *host1x_channel_get(struct host1x_channel *channel);
+void host1x_channel_put(struct host1x_channel *channel);
+int host1x_job_submit(struct host1x_job *job);
+
+/*
+ * host1x job
+ */
+
+struct host1x_reloc {
+       struct host1x_bo *cmdbuf;
+       u32 cmdbuf_offset;
+       struct host1x_bo *target;
+       u32 target_offset;
+       u32 shift;
+       u32 pad;
+};
+
+struct host1x_job {
+       /* When refcount goes to zero, job can be freed */
+       struct kref ref;
+
+       /* List entry */
+       struct list_head list;
+
+       /* Channel where job is submitted to */
+       struct host1x_channel *channel;
+
+       u32 client;
+
+       /* Gathers and their memory */
+       struct host1x_job_gather *gathers;
+       unsigned int num_gathers;
+
+       /* Wait checks to be processed at submit time */
+       struct host1x_waitchk *waitchk;
+       unsigned int num_waitchk;
+       u32 waitchk_mask;
+
+       /* Array of handles to be pinned & unpinned */
+       struct host1x_reloc *relocarray;
+       unsigned int num_relocs;
+       struct host1x_job_unpin_data *unpins;
+       unsigned int num_unpins;
+
+       dma_addr_t *addr_phys;
+       dma_addr_t *gather_addr_phys;
+       dma_addr_t *reloc_addr_phys;
+
+       /* Sync point id, number of increments and end related to the submit */
+       u32 syncpt_id;
+       u32 syncpt_incrs;
+       u32 syncpt_end;
+
+       /* Maximum time to wait for this job */
+       unsigned int timeout;
+
+       /* Index and number of slots used in the push buffer */
+       unsigned int first_get;
+       unsigned int num_slots;
+
+       /* Copy of gathers */
+       size_t gather_copy_size;
+       dma_addr_t gather_copy;
+       u8 *gather_copy_mapped;
+
+       /* Check if register is marked as an address reg */
+       int (*is_addr_reg)(struct device *dev, u32 reg, u32 class);
+
+       /* Request a SETCLASS to this class */
+       u32 class;
+
+       /* Add a channel wait for previous ops to complete */
+       bool serialize;
+};
+
+struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,
+                                   u32 num_cmdbufs, u32 num_relocs,
+                                   u32 num_waitchks);
+void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *mem_id,
+                          u32 words, u32 offset);
+struct host1x_job *host1x_job_get(struct host1x_job *job);
+void host1x_job_put(struct host1x_job *job);
+int host1x_job_pin(struct host1x_job *job, struct device *dev);
+void host1x_job_unpin(struct host1x_job *job);
+
+/*
+ * subdevice probe infrastructure
+ */
+
+struct host1x_device;
+
+struct host1x_driver {
+       const struct of_device_id *subdevs;
+       struct list_head list;
+       const char *name;
+
+       int (*probe)(struct host1x_device *device);
+       int (*remove)(struct host1x_device *device);
+};
+
+int host1x_driver_register(struct host1x_driver *driver);
+void host1x_driver_unregister(struct host1x_driver *driver);
+
+struct host1x_device {
+       struct host1x_driver *driver;
+       struct list_head list;
+       struct device dev;
+
+       struct mutex subdevs_lock;
+       struct list_head subdevs;
+       struct list_head active;
+
+       struct mutex clients_lock;
+       struct list_head clients;
+};
+
+static inline struct host1x_device *to_host1x_device(struct device *dev)
+{
+       return container_of(dev, struct host1x_device, dev);
+}
+
+int host1x_device_init(struct host1x_device *device);
+int host1x_device_exit(struct host1x_device *device);
+
+int host1x_client_register(struct host1x_client *client);
+int host1x_client_unregister(struct host1x_client *client);
+
+#endif
index 73bde4eaf16c2042038ce6435072ab8d39632e41..5e1ab552cbed31bacae535f03b6c43431af87d52 100644 (file)
@@ -19,6 +19,9 @@
 
 #include <drm/drm.h>
 
+#define DRM_TEGRA_GEM_CREATE_TILED     (1 << 0)
+#define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1)
+
 struct drm_tegra_gem_create {
        __u64 size;
        __u32 flags;
@@ -65,6 +68,12 @@ struct drm_tegra_get_syncpt {
        __u32 id;
 };
 
+struct drm_tegra_get_syncpt_base {
+       __u64 context;
+       __u32 syncpt;
+       __u32 id;
+};
+
 struct drm_tegra_syncpt {
        __u32 id;
        __u32 incrs;
@@ -115,15 +124,16 @@ struct drm_tegra_submit {
        __u32 reserved[5];      /* future expansion */
 };
 
-#define DRM_TEGRA_GEM_CREATE   0x00
-#define DRM_TEGRA_GEM_MMAP     0x01
-#define DRM_TEGRA_SYNCPT_READ  0x02
-#define DRM_TEGRA_SYNCPT_INCR  0x03
-#define DRM_TEGRA_SYNCPT_WAIT  0x04
-#define DRM_TEGRA_OPEN_CHANNEL 0x05
-#define DRM_TEGRA_CLOSE_CHANNEL        0x06
-#define DRM_TEGRA_GET_SYNCPT   0x07
-#define DRM_TEGRA_SUBMIT       0x08
+#define DRM_TEGRA_GEM_CREATE           0x00
+#define DRM_TEGRA_GEM_MMAP             0x01
+#define DRM_TEGRA_SYNCPT_READ          0x02
+#define DRM_TEGRA_SYNCPT_INCR          0x03
+#define DRM_TEGRA_SYNCPT_WAIT          0x04
+#define DRM_TEGRA_OPEN_CHANNEL         0x05
+#define DRM_TEGRA_CLOSE_CHANNEL                0x06
+#define DRM_TEGRA_GET_SYNCPT           0x07
+#define DRM_TEGRA_SUBMIT               0x08
+#define DRM_TEGRA_GET_SYNCPT_BASE      0x09
 
 #define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create)
 #define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap)
@@ -134,5 +144,6 @@ struct drm_tegra_submit {
 #define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel)
 #define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt)
 #define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit)
+#define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base)
 
 #endif