Merge tag 'drm/tegra/for-3.17-rc1' of git://anongit.freedesktop.org/tegra/linux into...
authorDave Airlie <airlied@gmail.com>
Thu, 7 Aug 2014 09:53:22 +0000 (19:53 +1000)
committerDave Airlie <airlied@gmail.com>
Thu, 7 Aug 2014 09:53:22 +0000 (19:53 +1000)
drm/tegra: Changes for v3.17-rc1

Mostly some cleanup all over the place. Pitch alignment limitations of
the display controller are now honored and job submission is 64-bit
safe.

The SOR output (used for eDP) properly configures sync signal polarities
according to the display mode rather than hard-coding them to some value
and the number of bits per color is now taken from the panel rather than
hard-coded to properly support 24-bit vs. 18-bit panels.

The DSI controller now properly supports non-continuous clock mode.

GEM objects can now have their flags and tiling mode modified via IOCTLs
to allow buffers imported from Nouveau to be properly displayed. Newer
generations of the Tegra display controller can also detile block linear
buffers at scan-out time.

Finally the driver now properly exports MODULE_DEVICE_TABLEs to allow it
to be automatically loaded when built as a module.

* tag 'drm/tegra/for-3.17-rc1' of git://anongit.freedesktop.org/tegra/linux:
  drm/tegra: add MODULE_DEVICE_TABLEs
  drm/tegra: dc - Reset controller on driver remove
  drm/tegra: Properly align stride for framebuffers
  drm/tegra: sor - Configure proper sync polarities
  drm/tegra: sor - Use bits-per-color from panel
  drm/tegra: Make job submission 64-bit safe
  drm/tegra: Allow non-authenticated processes to create buffer objects
  drm/tegra: Add SET/GET_FLAGS IOCTLs
  drm/tegra: Add SET/GET_TILING IOCTLs
  drm/tegra: Implement more tiling modes
  drm/tegra: dsi - Handle non-continuous clock flag
  drm/tegra: sor - missing unlock on error

16 files changed:
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/dpaux.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/tegra/gem.h
drivers/gpu/drm/tegra/gr2d.c
drivers/gpu/drm/tegra/gr3d.c
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/sor.c
drivers/gpu/host1x/job.c
include/linux/host1x.h
include/uapi/drm/tegra_drm.h

index ef40381f3909e3ac20aed29eeb1266e6a8e3d5bd..6553fd238685e459deb0676114bfd9cac04f7e50 100644 (file)
@@ -18,6 +18,8 @@
 struct tegra_dc_soc_info {
        bool supports_interlacing;
        bool supports_cursor;
+       bool supports_block_linear;
+       unsigned int pitch_align;
 };
 
 struct tegra_plane {
@@ -212,15 +214,44 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
        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;
+       if (dc->soc->supports_block_linear) {
+               unsigned long height = window->tiling.value;
+
+               switch (window->tiling.mode) {
+               case TEGRA_BO_TILING_MODE_PITCH:
+                       value = DC_WINBUF_SURFACE_KIND_PITCH;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_TILED:
+                       value = DC_WINBUF_SURFACE_KIND_TILED;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_BLOCK:
+                       value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
+                               DC_WINBUF_SURFACE_KIND_BLOCK;
+                       break;
+               }
+
+               tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
        } else {
-               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
-                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
-       }
+               switch (window->tiling.mode) {
+               case TEGRA_BO_TILING_MODE_PITCH:
+                       value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
+                               DC_WIN_BUFFER_ADDR_MODE_LINEAR;
+                       break;
 
-       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+               case TEGRA_BO_TILING_MODE_TILED:
+                       value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
+                               DC_WIN_BUFFER_ADDR_MODE_TILE;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_BLOCK:
+                       DRM_ERROR("hardware doesn't support block linear mode\n");
+                       return -EINVAL;
+               }
+
+               tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+       }
 
        value = WIN_ENABLE;
 
@@ -288,6 +319,7 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        struct tegra_dc *dc = to_tegra_dc(crtc);
        struct tegra_dc_window window;
        unsigned int i;
+       int err;
 
        memset(&window, 0, sizeof(window));
        window.src.x = src_x >> 16;
@@ -301,7 +333,10 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        window.format = tegra_dc_format(fb->pixel_format, &window.swap);
        window.bits_per_pixel = fb->bits_per_pixel;
        window.bottom_up = tegra_fb_is_bottom_up(fb);
-       window.tiled = tegra_fb_is_tiled(fb);
+
+       err = tegra_fb_get_tiling(fb, &window.tiling);
+       if (err < 0)
+               return err;
 
        for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
                struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
@@ -402,8 +437,14 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
 {
        struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
        unsigned int h_offset = 0, v_offset = 0;
+       struct tegra_bo_tiling tiling;
        unsigned int format, swap;
        unsigned long value;
+       int err;
+
+       err = tegra_fb_get_tiling(fb, &tiling);
+       if (err < 0)
+               return err;
 
        tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
 
@@ -417,15 +458,44 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
        tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
 
-       if (tegra_fb_is_tiled(fb)) {
-               value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
-                       DC_WIN_BUFFER_ADDR_MODE_TILE;
+       if (dc->soc->supports_block_linear) {
+               unsigned long height = tiling.value;
+
+               switch (tiling.mode) {
+               case TEGRA_BO_TILING_MODE_PITCH:
+                       value = DC_WINBUF_SURFACE_KIND_PITCH;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_TILED:
+                       value = DC_WINBUF_SURFACE_KIND_TILED;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_BLOCK:
+                       value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
+                               DC_WINBUF_SURFACE_KIND_BLOCK;
+                       break;
+               }
+
+               tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
        } else {
-               value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
-                       DC_WIN_BUFFER_ADDR_MODE_LINEAR;
-       }
+               switch (tiling.mode) {
+               case TEGRA_BO_TILING_MODE_PITCH:
+                       value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
+                               DC_WIN_BUFFER_ADDR_MODE_LINEAR;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_TILED:
+                       value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
+                               DC_WIN_BUFFER_ADDR_MODE_TILE;
+                       break;
+
+               case TEGRA_BO_TILING_MODE_BLOCK:
+                       DRM_ERROR("hardware doesn't support block linear mode\n");
+                       return -EINVAL;
+               }
 
-       tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
+               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)) {
@@ -1214,12 +1284,20 @@ static int tegra_dc_init(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_dc *dc = host1x_client_to_dc(client);
+       struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        drm_crtc_init(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);
 
+       /*
+        * Keep track of the minimum pitch alignment across all display
+        * controllers.
+        */
+       if (dc->soc->pitch_align > tegra->pitch_align)
+               tegra->pitch_align = dc->soc->pitch_align;
+
        err = tegra_dc_rgb_init(drm, dc);
        if (err < 0 && err != -ENODEV) {
                dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
@@ -1277,16 +1355,29 @@ static const struct host1x_client_ops dc_client_ops = {
 static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
        .supports_interlacing = false,
        .supports_cursor = false,
+       .supports_block_linear = false,
+       .pitch_align = 8,
 };
 
 static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
        .supports_interlacing = false,
        .supports_cursor = false,
+       .supports_block_linear = false,
+       .pitch_align = 8,
+};
+
+static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
+       .supports_interlacing = false,
+       .supports_cursor = false,
+       .supports_block_linear = false,
+       .pitch_align = 64,
 };
 
 static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
        .supports_interlacing = true,
        .supports_cursor = true,
+       .supports_block_linear = true,
+       .pitch_align = 64,
 };
 
 static const struct of_device_id tegra_dc_of_match[] = {
@@ -1303,6 +1394,7 @@ static const struct of_device_id tegra_dc_of_match[] = {
                /* sentinel */
        }
 };
+MODULE_DEVICE_TABLE(of, tegra_dc_of_match);
 
 static int tegra_dc_parse_dt(struct tegra_dc *dc)
 {
@@ -1430,6 +1522,7 @@ static int tegra_dc_remove(struct platform_device *pdev)
                return err;
        }
 
+       reset_control_assert(dc->rst);
        clk_disable_unprepare(dc->clk);
 
        return 0;
index 78c5feff95d2910123c209cc212eecd1ee1d72bf..705c93b00794feb38f56a501b7546f9e6f07b1f9 100644 (file)
 #define DC_WINBUF_ADDR_V_OFFSET_NS             0x809
 
 #define DC_WINBUF_UFLOW_STATUS                 0x80a
+#define DC_WINBUF_SURFACE_KIND                 0x80b
+#define DC_WINBUF_SURFACE_KIND_PITCH   (0 << 0)
+#define DC_WINBUF_SURFACE_KIND_TILED   (1 << 0)
+#define DC_WINBUF_SURFACE_KIND_BLOCK   (2 << 0)
+#define DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
 
 #define DC_WINBUF_AD_UFLOW_STATUS              0xbca
 #define DC_WINBUF_BD_UFLOW_STATUS              0xdca
index 3f132e356e9cd393394bdce5a3594765be08d596..708f783ead47682f8ef76e17ebc435a1850f9eb6 100644 (file)
@@ -382,6 +382,7 @@ static const struct of_device_id tegra_dpaux_of_match[] = {
        { .compatible = "nvidia,tegra124-dpaux", },
        { },
 };
+MODULE_DEVICE_TABLE(of, tegra_dpaux_of_match);
 
 struct platform_driver tegra_dpaux_driver = {
        .driver = {
index fd736efd14bd963cd38571ae7de02fb54c785ce8..59736bb810cd2d4787dab77d1fea29dadcf30f9f 100644 (file)
@@ -132,6 +132,45 @@ host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
        return &bo->base;
 }
 
+static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
+                                      struct drm_tegra_reloc __user *src,
+                                      struct drm_device *drm,
+                                      struct drm_file *file)
+{
+       u32 cmdbuf, target;
+       int err;
+
+       err = get_user(cmdbuf, &src->cmdbuf.handle);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->cmdbuf.offset, &src->cmdbuf.offset);
+       if (err < 0)
+               return err;
+
+       err = get_user(target, &src->target.handle);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->target.offset, &src->cmdbuf.offset);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->shift, &src->shift);
+       if (err < 0)
+               return err;
+
+       dest->cmdbuf.bo = host1x_bo_lookup(drm, file, cmdbuf);
+       if (!dest->cmdbuf.bo)
+               return -ENOENT;
+
+       dest->target.bo = host1x_bo_lookup(drm, file, target);
+       if (!dest->target.bo)
+               return -ENOENT;
+
+       return 0;
+}
+
 int tegra_drm_submit(struct tegra_drm_context *context,
                     struct drm_tegra_submit *args, struct drm_device *drm,
                     struct drm_file *file)
@@ -184,26 +223,13 @@ int tegra_drm_submit(struct tegra_drm_context *context,
                cmdbufs++;
        }
 
-       if (copy_from_user(job->relocarray, relocs,
-                          sizeof(*relocs) * num_relocs)) {
-               err = -EFAULT;
-               goto fail;
-       }
-
+       /* copy and resolve relocations from submit */
        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;
+               err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
+                                                 &relocs[num_relocs], drm,
+                                                 file);
+               if (err < 0)
                        goto fail;
-               }
        }
 
        if (copy_from_user(job->waitchk, waitchks,
@@ -455,11 +481,151 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
 
        return 0;
 }
+
+static int tegra_gem_set_tiling(struct drm_device *drm, void *data,
+                               struct drm_file *file)
+{
+       struct drm_tegra_gem_set_tiling *args = data;
+       enum tegra_bo_tiling_mode mode;
+       struct drm_gem_object *gem;
+       unsigned long value = 0;
+       struct tegra_bo *bo;
+
+       switch (args->mode) {
+       case DRM_TEGRA_GEM_TILING_MODE_PITCH:
+               mode = TEGRA_BO_TILING_MODE_PITCH;
+
+               if (args->value != 0)
+                       return -EINVAL;
+
+               break;
+
+       case DRM_TEGRA_GEM_TILING_MODE_TILED:
+               mode = TEGRA_BO_TILING_MODE_TILED;
+
+               if (args->value != 0)
+                       return -EINVAL;
+
+               break;
+
+       case DRM_TEGRA_GEM_TILING_MODE_BLOCK:
+               mode = TEGRA_BO_TILING_MODE_BLOCK;
+
+               if (args->value > 5)
+                       return -EINVAL;
+
+               value = args->value;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       gem = drm_gem_object_lookup(drm, file, args->handle);
+       if (!gem)
+               return -ENOENT;
+
+       bo = to_tegra_bo(gem);
+
+       bo->tiling.mode = mode;
+       bo->tiling.value = value;
+
+       drm_gem_object_unreference(gem);
+
+       return 0;
+}
+
+static int tegra_gem_get_tiling(struct drm_device *drm, void *data,
+                               struct drm_file *file)
+{
+       struct drm_tegra_gem_get_tiling *args = data;
+       struct drm_gem_object *gem;
+       struct tegra_bo *bo;
+       int err = 0;
+
+       gem = drm_gem_object_lookup(drm, file, args->handle);
+       if (!gem)
+               return -ENOENT;
+
+       bo = to_tegra_bo(gem);
+
+       switch (bo->tiling.mode) {
+       case TEGRA_BO_TILING_MODE_PITCH:
+               args->mode = DRM_TEGRA_GEM_TILING_MODE_PITCH;
+               args->value = 0;
+               break;
+
+       case TEGRA_BO_TILING_MODE_TILED:
+               args->mode = DRM_TEGRA_GEM_TILING_MODE_TILED;
+               args->value = 0;
+               break;
+
+       case TEGRA_BO_TILING_MODE_BLOCK:
+               args->mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+               args->value = bo->tiling.value;
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       drm_gem_object_unreference(gem);
+
+       return err;
+}
+
+static int tegra_gem_set_flags(struct drm_device *drm, void *data,
+                              struct drm_file *file)
+{
+       struct drm_tegra_gem_set_flags *args = data;
+       struct drm_gem_object *gem;
+       struct tegra_bo *bo;
+
+       if (args->flags & ~DRM_TEGRA_GEM_FLAGS)
+               return -EINVAL;
+
+       gem = drm_gem_object_lookup(drm, file, args->handle);
+       if (!gem)
+               return -ENOENT;
+
+       bo = to_tegra_bo(gem);
+       bo->flags = 0;
+
+       if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP)
+               bo->flags |= TEGRA_BO_BOTTOM_UP;
+
+       drm_gem_object_unreference(gem);
+
+       return 0;
+}
+
+static int tegra_gem_get_flags(struct drm_device *drm, void *data,
+                              struct drm_file *file)
+{
+       struct drm_tegra_gem_get_flags *args = data;
+       struct drm_gem_object *gem;
+       struct tegra_bo *bo;
+
+       gem = drm_gem_object_lookup(drm, file, args->handle);
+       if (!gem)
+               return -ENOENT;
+
+       bo = to_tegra_bo(gem);
+       args->flags = 0;
+
+       if (bo->flags & TEGRA_BO_BOTTOM_UP)
+               args->flags |= DRM_TEGRA_GEM_BOTTOM_UP;
+
+       drm_gem_object_unreference(gem);
+
+       return 0;
+}
 #endif
 
 static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
 #ifdef CONFIG_DRM_TEGRA_STAGING
-       DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED),
@@ -469,6 +635,10 @@ static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
        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),
+       DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, DRM_UNLOCKED),
 #endif
 };
 
index 0d30689dff016f786de35e910d930961cff534bc..e89c70fa82d554f3da8fced5ae99b840e56c985f 100644 (file)
@@ -19,6 +19,8 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fixed.h>
 
+#include "gem.h"
+
 struct reset_control;
 
 struct tegra_fb {
@@ -43,6 +45,8 @@ struct tegra_drm {
 #ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_fbdev *fbdev;
 #endif
+
+       unsigned int pitch_align;
 };
 
 struct tegra_drm_client;
@@ -160,7 +164,8 @@ struct tegra_dc_window {
        unsigned int stride[2];
        unsigned long base[3];
        bool bottom_up;
-       bool tiled;
+
+       struct tegra_bo_tiling tiling;
 };
 
 /* from dc.c */
@@ -279,7 +284,8 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
 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);
+int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
+                       struct tegra_bo_tiling *tiling);
 int tegra_drm_fb_prepare(struct drm_device *drm);
 int tegra_drm_fb_init(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
index bd56f2affa7895b2d1e0fbd556e3e811f8e78f14..f7874458926a7f289d8df1a3e46ead9f066e1a82 100644 (file)
@@ -474,7 +474,8 @@ static int tegra_output_dsi_enable(struct tegra_output *output)
        tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
 
        value = tegra_dsi_readl(dsi, DSI_CONTROL);
-       value |= DSI_CONTROL_HS_CLK_CTRL;
+       if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+               value |= DSI_CONTROL_HS_CLK_CTRL;
        value &= ~DSI_CONTROL_TX_TRIG(3);
        value &= ~DSI_CONTROL_DCS_ENABLE;
        value |= DSI_CONTROL_VIDEO_ENABLE;
@@ -982,6 +983,7 @@ static const struct of_device_id tegra_dsi_of_match[] = {
        { .compatible = "nvidia,tegra114-dsi", },
        { },
 };
+MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
 
 struct platform_driver tegra_dsi_driver = {
        .driver = {
index fc1528e0bda17009eeee5c6974c1e15fb084c0c0..3513d12d5aa1447822a7ef57449799b1aff83df9 100644 (file)
@@ -46,14 +46,15 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer)
        return false;
 }
 
-bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer)
+int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
+                       struct tegra_bo_tiling *tiling)
 {
        struct tegra_fb *fb = to_tegra_fb(framebuffer);
 
-       if (fb->planes[0]->flags & TEGRA_BO_TILED)
-               return true;
+       /* TODO: handle YUV formats? */
+       *tiling = fb->planes[0]->tiling;
 
-       return false;
+       return 0;
 }
 
 static void tegra_fb_destroy(struct drm_framebuffer *framebuffer)
@@ -193,6 +194,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
                             struct drm_fb_helper_surface_size *sizes)
 {
        struct tegra_fbdev *fbdev = to_tegra_fbdev(helper);
+       struct tegra_drm *tegra = helper->dev->dev_private;
        struct drm_device *drm = helper->dev;
        struct drm_mode_fb_cmd2 cmd = { 0 };
        unsigned int bytes_per_pixel;
@@ -207,7 +209,8 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 
        cmd.width = sizes->surface_width;
        cmd.height = sizes->surface_height;
-       cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+       cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
+                                 tegra->pitch_align);
        cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
                                                     sizes->surface_depth);
 
index aa85b7b26f105e5d7528358d6c150b1cc33d8a4e..2545c7a468a2f3c316729cfa731bf238f6eac73f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/dma-buf.h>
 #include <drm/tegra_drm.h>
 
+#include "drm.h"
 #include "gem.h"
 
 static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
@@ -126,7 +127,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
                goto err_mmap;
 
        if (flags & DRM_TEGRA_GEM_CREATE_TILED)
-               bo->flags |= TEGRA_BO_TILED;
+               bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED;
 
        if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP)
                bo->flags |= TEGRA_BO_BOTTOM_UP;
@@ -259,8 +260,10 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
                         struct drm_mode_create_dumb *args)
 {
        int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+       struct tegra_drm *tegra = drm->dev_private;
        struct tegra_bo *bo;
 
+       min_pitch = round_up(min_pitch, tegra->pitch_align);
        if (args->pitch < min_pitch)
                args->pitch = min_pitch;
 
index 2f3fe96c5154da0bbd99f04c6b809c18bba03f32..43a25c853357d4e9b2d51b2049b8a12794bfc714 100644 (file)
 #include <drm/drm.h>
 #include <drm/drmP.h>
 
-#define TEGRA_BO_TILED     (1 << 0)
-#define TEGRA_BO_BOTTOM_UP (1 << 1)
+#define TEGRA_BO_BOTTOM_UP (1 << 0)
+
+enum tegra_bo_tiling_mode {
+       TEGRA_BO_TILING_MODE_PITCH,
+       TEGRA_BO_TILING_MODE_TILED,
+       TEGRA_BO_TILING_MODE_BLOCK,
+};
+
+struct tegra_bo_tiling {
+       enum tegra_bo_tiling_mode mode;
+       unsigned long value;
+};
 
 struct tegra_bo {
        struct drm_gem_object gem;
@@ -26,6 +36,8 @@ struct tegra_bo {
        struct sg_table *sgt;
        dma_addr_t paddr;
        void *vaddr;
+
+       struct tegra_bo_tiling tiling;
 };
 
 static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem)
index 7c53941f2a9ea347d6ff44eb1583efc629b611d7..02cd3e37a6ec3cf7d1e1d84f65387bb1c12853cc 100644 (file)
@@ -121,6 +121,7 @@ static const struct of_device_id gr2d_match[] = {
        { .compatible = "nvidia,tegra20-gr2d" },
        { },
 };
+MODULE_DEVICE_TABLE(of, gr2d_match);
 
 static const u32 gr2d_addr_regs[] = {
        GR2D_UA_BASE_ADDR,
index 30f5ba9bd6d05c508eac1306c7b1468e6c515587..2bea2b2d204e809fd4dcc0b0bbaf7427317b8198 100644 (file)
@@ -130,6 +130,7 @@ static const struct of_device_id tegra_gr3d_match[] = {
        { .compatible = "nvidia,tegra20-gr3d" },
        { }
 };
+MODULE_DEVICE_TABLE(of, tegra_gr3d_match);
 
 static const u32 gr3d_addr_regs[] = {
        GR3D_IDX_ATTRIBUTE( 0),
index ba067bb767e376ea4aaa5a7f5fe5917d1608b7c2..ffe26547328df8a352f8dca6e832912084cc7388 100644 (file)
@@ -1450,6 +1450,7 @@ static const struct of_device_id tegra_hdmi_of_match[] = {
        { .compatible = "nvidia,tegra20-hdmi", .data = &tegra20_hdmi_config },
        { },
 };
+MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match);
 
 static int tegra_hdmi_probe(struct platform_device *pdev)
 {
index 27c979b5011112182226f7a1cd4d0e1e6b54c9ed..0410e467b82836b94e1bccd459b101ec78a5ce48 100644 (file)
@@ -516,7 +516,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
                if (err < 0) {
                        dev_err(sor->dev, "failed to probe eDP link: %d\n",
                                err);
-                       return err;
+                       goto unlock;
                }
        }
 
@@ -525,7 +525,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
                dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
 
        memset(&config, 0, sizeof(config));
-       config.bits_per_pixel = 24; /* XXX: don't hardcode? */
+       config.bits_per_pixel = output->connector.display_info.bpc * 3;
 
        err = tegra_sor_calc_config(sor, mode, &config, &link);
        if (err < 0)
@@ -815,12 +815,22 @@ static int tegra_output_sor_enable(struct tegra_output *output)
         * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
         * raster, associate with display controller)
         */
-       value = SOR_STATE_ASY_VSYNCPOL |
-               SOR_STATE_ASY_HSYNCPOL |
-               SOR_STATE_ASY_PROTOCOL_DP_A |
+       value = SOR_STATE_ASY_PROTOCOL_DP_A |
                SOR_STATE_ASY_CRC_MODE_COMPLETE |
                SOR_STATE_ASY_OWNER(dc->pipe + 1);
 
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               value &= ~SOR_STATE_ASY_HSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               value |= SOR_STATE_ASY_HSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               value &= ~SOR_STATE_ASY_VSYNCPOL;
+
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               value |= SOR_STATE_ASY_VSYNCPOL;
+
        switch (config.bits_per_pixel) {
        case 24:
                value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444;
@@ -1455,6 +1465,7 @@ static const struct of_device_id tegra_sor_of_match[] = {
        { .compatible = "nvidia,tegra124-sor", },
        { },
 };
+MODULE_DEVICE_TABLE(of, tegra_sor_of_match);
 
 struct platform_driver tegra_sor_driver = {
        .driver = {
index 112f27e51bc7df81b45efcb58f7c11fc46f097e0..63bd63f3c7dfd2da2fd3d9ae58bba1473bceb70b 100644 (file)
@@ -185,16 +185,16 @@ static unsigned int pin_job(struct host1x_job *job)
                struct sg_table *sgt;
                dma_addr_t phys_addr;
 
-               reloc->target = host1x_bo_get(reloc->target);
-               if (!reloc->target)
+               reloc->target.bo = host1x_bo_get(reloc->target.bo);
+               if (!reloc->target.bo)
                        goto unpin;
 
-               phys_addr = host1x_bo_pin(reloc->target, &sgt);
+               phys_addr = host1x_bo_pin(reloc->target.bo, &sgt);
                if (!phys_addr)
                        goto unpin;
 
                job->addr_phys[job->num_unpins] = phys_addr;
-               job->unpins[job->num_unpins].bo = reloc->target;
+               job->unpins[job->num_unpins].bo = reloc->target.bo;
                job->unpins[job->num_unpins].sgt = sgt;
                job->num_unpins++;
        }
@@ -235,21 +235,21 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
        for (i = 0; i < job->num_relocs; i++) {
                struct host1x_reloc *reloc = &job->relocarray[i];
                u32 reloc_addr = (job->reloc_addr_phys[i] +
-                       reloc->target_offset) >> reloc->shift;
+                                 reloc->target.offset) >> reloc->shift;
                u32 *target;
 
                /* skip all other gathers */
-               if (cmdbuf != reloc->cmdbuf)
+               if (cmdbuf != reloc->cmdbuf.bo)
                        continue;
 
-               if (last_page != reloc->cmdbuf_offset >> PAGE_SHIFT) {
+               if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) {
                        if (cmdbuf_page_addr)
                                host1x_bo_kunmap(cmdbuf, last_page,
                                                 cmdbuf_page_addr);
 
                        cmdbuf_page_addr = host1x_bo_kmap(cmdbuf,
-                                       reloc->cmdbuf_offset >> PAGE_SHIFT);
-                       last_page = reloc->cmdbuf_offset >> PAGE_SHIFT;
+                                       reloc->cmdbuf.offset >> PAGE_SHIFT);
+                       last_page = reloc->cmdbuf.offset >> PAGE_SHIFT;
 
                        if (unlikely(!cmdbuf_page_addr)) {
                                pr_err("Could not map cmdbuf for relocation\n");
@@ -257,7 +257,7 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
                        }
                }
 
-               target = cmdbuf_page_addr + (reloc->cmdbuf_offset & ~PAGE_MASK);
+               target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK);
                *target = reloc_addr;
        }
 
@@ -272,7 +272,7 @@ static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
 {
        offset *= sizeof(u32);
 
-       if (reloc->cmdbuf != cmdbuf || reloc->cmdbuf_offset != offset)
+       if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset)
                return false;
 
        return true;
index d2b52999e7717252a743204817ef726fd94a3567..bb9840fd1e18855305241daca6cc6a68ce18a066 100644 (file)
@@ -164,12 +164,15 @@ int host1x_job_submit(struct host1x_job *job);
  */
 
 struct host1x_reloc {
-       struct host1x_bo *cmdbuf;
-       u32 cmdbuf_offset;
-       struct host1x_bo *target;
-       u32 target_offset;
-       u32 shift;
-       u32 pad;
+       struct {
+               struct host1x_bo *bo;
+               unsigned long offset;
+       } cmdbuf;
+       struct {
+               struct host1x_bo *bo;
+               unsigned long offset;
+       } target;
+       unsigned long shift;
 };
 
 struct host1x_job {
index b75482112428afa8eaab6cd266f3221d8decab28..c15d781ecc0f306ce5fd575192f547b8e756273f 100644 (file)
@@ -129,6 +129,44 @@ struct drm_tegra_submit {
        __u32 reserved[5];      /* future expansion */
 };
 
+#define DRM_TEGRA_GEM_TILING_MODE_PITCH 0
+#define DRM_TEGRA_GEM_TILING_MODE_TILED 1
+#define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2
+
+struct drm_tegra_gem_set_tiling {
+       /* input */
+       __u32 handle;
+       __u32 mode;
+       __u32 value;
+       __u32 pad;
+};
+
+struct drm_tegra_gem_get_tiling {
+       /* input */
+       __u32 handle;
+       /* output */
+       __u32 mode;
+       __u32 value;
+       __u32 pad;
+};
+
+#define DRM_TEGRA_GEM_BOTTOM_UP                (1 << 0)
+#define DRM_TEGRA_GEM_FLAGS            (DRM_TEGRA_GEM_BOTTOM_UP)
+
+struct drm_tegra_gem_set_flags {
+       /* input */
+       __u32 handle;
+       /* output */
+       __u32 flags;
+};
+
+struct drm_tegra_gem_get_flags {
+       /* input */
+       __u32 handle;
+       /* output */
+       __u32 flags;
+};
+
 #define DRM_TEGRA_GEM_CREATE           0x00
 #define DRM_TEGRA_GEM_MMAP             0x01
 #define DRM_TEGRA_SYNCPT_READ          0x02
@@ -139,6 +177,10 @@ struct drm_tegra_submit {
 #define DRM_TEGRA_GET_SYNCPT           0x07
 #define DRM_TEGRA_SUBMIT               0x08
 #define DRM_TEGRA_GET_SYNCPT_BASE      0x09
+#define DRM_TEGRA_GEM_SET_TILING       0x0a
+#define DRM_TEGRA_GEM_GET_TILING       0x0b
+#define DRM_TEGRA_GEM_SET_FLAGS                0x0c
+#define DRM_TEGRA_GEM_GET_FLAGS                0x0d
 
 #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)
@@ -150,5 +192,9 @@ struct drm_tegra_submit {
 #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)
+#define DRM_IOCTL_TEGRA_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_TILING, struct drm_tegra_gem_set_tiling)
+#define DRM_IOCTL_TEGRA_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_TILING, struct drm_tegra_gem_get_tiling)
+#define DRM_IOCTL_TEGRA_GEM_SET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_FLAGS, struct drm_tegra_gem_set_flags)
+#define DRM_IOCTL_TEGRA_GEM_GET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_FLAGS, struct drm_tegra_gem_get_flags)
 
 #endif