Commit a3b1097c authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm/tegra-for-3.9' of git://anongit.freedesktop.org/tegra/linux into drm-next

Thierry writes:
"Add support for 2 hardware overlays found on Tegra. These support YUV
pixel formats and can be used as video overlays. .mode_set_base() is
implemented and support for VBLANK and page-flipping is added.

A few minor bug fixes are also included and a new debugfs file allows
to inspect the framebuffers attached to the Tegra DRM device."

* 'drm/tegra-for-3.9' of git://anongit.freedesktop.org/tegra/linux:
  drm/tegra: Add list of framebuffers to debugfs
  drm/tegra: Fix color expansion
  drm/tegra: Split DC_CMD_STATE_CONTROL register write
  drm/tegra: Implement page-flipping support
  drm/tegra: Implement VBLANK support
  drm/tegra: Implement .mode_set_base()
  drm/tegra: Add plane support
  drm/tegra: Remove bogus tegra_framebuffer structure
  drm: Add consistency check for page-flipping
parents c976cb37 e450fcc6
......@@ -1160,6 +1160,12 @@ int max_width, max_height;</synopsis>
without waiting for rendering or page flip to complete and must block
any new rendering to the frame buffer until the page flip completes.
</para>
<para>
If a page flip can be successfully scheduled the driver must set the
<code>drm_crtc-&lt;fb</code> field to the new framebuffer pointed to
by <code>fb</code>. This is important so that the reference counting
on framebuffers stays balanced.
</para>
<para>
If a page flip is already pending, the
<methodname>page_flip</methodname> operation must return
......
......@@ -3792,6 +3792,13 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
/* Keep the old fb, don't unref it. */
old_fb = NULL;
} else {
/*
* Warn if the driver hasn't properly updated the crtc->fb
* field to reflect that the new framebuffer is now used.
* Failing to do so will screw with the reference counting
* on framebuffers.
*/
WARN_ON(crtc->fb != fb);
/* Unref only the old framebuffer. */
fb = NULL;
}
......
This diff is collapsed.
......@@ -58,6 +58,8 @@
#define DC_CMD_SIGNAL_RAISE3 0x03e
#define DC_CMD_STATE_ACCESS 0x040
#define READ_MUX (1 << 0)
#define WRITE_MUX (1 << 2)
#define DC_CMD_STATE_CONTROL 0x041
#define GENERAL_ACT_REQ (1 << 0)
......@@ -290,8 +292,18 @@
#define DC_DISP_SD_HW_K_VALUES 0x4dd
#define DC_DISP_SD_MAN_K_VALUES 0x4de
#define DC_WIN_CSC_YOF 0x611
#define DC_WIN_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUR 0x613
#define DC_WIN_CSC_KVR 0x614
#define DC_WIN_CSC_KUG 0x615
#define DC_WIN_CSC_KVG 0x616
#define DC_WIN_CSC_KUB 0x617
#define DC_WIN_CSC_KVB 0x618
#define DC_WIN_WIN_OPTIONS 0x700
#define COLOR_EXPAND (1 << 6)
#define CSC_ENABLE (1 << 18)
#define WIN_ENABLE (1 << 30)
#define DC_WIN_BYTE_SWAP 0x701
......@@ -359,7 +371,7 @@
#define DC_WIN_BLEND_1WIN 0x710
#define DC_WIN_BLEND_2WIN_X 0x711
#define DC_WIN_BLEND_2WIN_Y 0x712
#define DC_WIN_BLEND32WIN_XY 0x713
#define DC_WIN_BLEND_3WIN_XY 0x713
#define DC_WIN_HP_FETCH_CONTROL 0x714
......
......@@ -40,6 +40,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (err < 0)
return err;
err = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (err < 0)
return err;
err = tegra_drm_fb_init(drm);
if (err < 0)
return err;
......@@ -89,13 +93,112 @@ static const struct file_operations tegra_drm_fops = {
.llseek = noop_llseek,
};
static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
struct tegra_dc *dc = to_tegra_dc(crtc);
if (dc->pipe == pipe)
return crtc;
}
return NULL;
}
static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
{
/* TODO: implement real hardware counter using syncpoints */
return drm_vblank_count(dev, crtc);
}
static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
{
struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
struct tegra_dc *dc = to_tegra_dc(crtc);
if (!crtc)
return -ENODEV;
tegra_dc_enable_vblank(dc);
return 0;
}
static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
{
struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
struct tegra_dc *dc = to_tegra_dc(crtc);
if (crtc)
tegra_dc_disable_vblank(dc);
}
static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
tegra_dc_cancel_page_flip(crtc, file);
}
#ifdef CONFIG_DEBUG_FS
static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
{
struct drm_info_node *node = (struct drm_info_node *)s->private;
struct drm_device *drm = node->minor->dev;
struct drm_framebuffer *fb;
mutex_lock(&drm->mode_config.fb_lock);
list_for_each_entry(fb, &drm->mode_config.fb_list, head) {
seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n",
fb->base.id, fb->width, fb->height, fb->depth,
fb->bits_per_pixel,
atomic_read(&fb->refcount.refcount));
}
mutex_unlock(&drm->mode_config.fb_lock);
return 0;
}
static struct drm_info_list tegra_debugfs_list[] = {
{ "framebuffers", tegra_debugfs_framebuffers, 0 },
};
static int tegra_debugfs_init(struct drm_minor *minor)
{
return drm_debugfs_create_files(tegra_debugfs_list,
ARRAY_SIZE(tegra_debugfs_list),
minor->debugfs_root, minor);
}
static void tegra_debugfs_cleanup(struct drm_minor *minor)
{
drm_debugfs_remove_files(tegra_debugfs_list,
ARRAY_SIZE(tegra_debugfs_list), minor);
}
#endif
struct drm_driver tegra_drm_driver = {
.driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM,
.load = tegra_drm_load,
.unload = tegra_drm_unload,
.open = tegra_drm_open,
.preclose = tegra_drm_preclose,
.lastclose = tegra_drm_lastclose,
.get_vblank_counter = tegra_drm_get_vblank_counter,
.enable_vblank = tegra_drm_enable_vblank,
.disable_vblank = tegra_drm_disable_vblank,
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = tegra_debugfs_init,
.debugfs_cleanup = tegra_debugfs_cleanup,
#endif
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,
......
......@@ -18,16 +18,6 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fixed.h>
struct tegra_framebuffer {
struct drm_framebuffer base;
struct drm_gem_cma_object *obj;
};
static inline struct tegra_framebuffer *to_tegra_fb(struct drm_framebuffer *fb)
{
return container_of(fb, struct tegra_framebuffer, base);
}
struct host1x {
struct drm_device *drm;
struct device *dev;
......@@ -44,7 +34,6 @@ struct host1x {
struct list_head clients;
struct drm_fbdev_cma *fbdev;
struct tegra_framebuffer fb;
};
struct host1x_client;
......@@ -75,6 +64,7 @@ struct tegra_output;
struct tegra_dc {
struct host1x_client client;
spinlock_t lock;
struct host1x *host1x;
struct device *dev;
......@@ -94,6 +84,9 @@ struct tegra_dc {
struct drm_info_list *debugfs_files;
struct drm_minor *minor;
struct dentry *debugfs;
/* page-flip handling */
struct drm_pending_vblank_event *event;
};
static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client)
......@@ -118,6 +111,34 @@ static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
return readl(dc->regs + (reg << 2));
}
struct tegra_dc_window {
struct {
unsigned int x;
unsigned int y;
unsigned int w;
unsigned int h;
} src;
struct {
unsigned int x;
unsigned int y;
unsigned int w;
unsigned int h;
} dst;
unsigned int bits_per_pixel;
unsigned int format;
unsigned int stride[2];
unsigned long base[3];
};
/* from dc.c */
extern unsigned int tegra_dc_format(uint32_t format);
extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
const struct tegra_dc_window *window);
extern void tegra_dc_enable_vblank(struct tegra_dc *dc);
extern void tegra_dc_disable_vblank(struct tegra_dc *dc);
extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc,
struct drm_file *file);
struct tegra_output_ops {
int (*enable)(struct tegra_output *output);
int (*disable)(struct tegra_output *output);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment