video: tegra: add z order blending, output position, and stride to overlays

Change-Id: I7439f60bfa3264bec9b1447fd970eef9e4c089d9
Signed-off-by: Erik Gilling <konkers@android.com>
This commit is contained in:
Antti Hatala
2010-09-08 16:09:31 -07:00
committed by Colin Cross
parent 58459da41c
commit d546987a68
5 changed files with 132 additions and 69 deletions

View File

@@ -25,18 +25,6 @@
#define TEGRA_MAX_DC 2
#define DC_N_WINDOWS 3
struct tegra_dc_blend {
u32 nokey;
u32 one_win;
u32 two_win_x;
u32 two_win_y;
u32 three_win_xy;
};
#define BLEND(key, control, weight0, weight1) \
(CKEY_ ## key | BLEND_CONTROL_ ## control | \
BLEND_WEIGHT0(weight0) | BLEND_WEIGHT0(weight1))
struct tegra_dc_mode {
int pclk;
int h_ref_to_sync;
@@ -96,19 +84,27 @@ struct tegra_dc_win {
void *virt_addr;
dma_addr_t phys_addr;
unsigned stride;
unsigned x;
unsigned y;
unsigned w;
unsigned h;
unsigned out_x;
unsigned out_y;
unsigned out_w;
unsigned out_h;
unsigned z;
int dirty;
struct tegra_dc *dc;
};
#define TEGRA_WIN_FLAG_ENABLED (1 << 0)
#define TEGRA_WIN_FLAG_COLOR_EXPAND (1 << 1)
#define TEGRA_WIN_FLAG_BLEND_PREMULT (1 << 1)
#define TEGRA_WIN_FLAG_BLEND_COVERAGE (1 << 2)
#define TEGRA_WIN_BLEND_FLAGS_MASK \
(TEGRA_WIN_FLAG_BLEND_PREMULT | TEGRA_WIN_FLAG_BLEND_COVERAGE)
/* Note: These are the actual values written to the DC_WIN_COLOR_DEPTH register
* and may change in new tegra architectures.
@@ -164,9 +160,6 @@ void tegra_dc_disable(struct tegra_dc *dc);
int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n);
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
/* will probably be replaced with an interface describing the window order */
void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend);
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode);
#endif

View File

@@ -39,25 +39,6 @@
#include "dc_reg.h"
#include "dc_priv.h"
struct tegra_dc_blend tegra_dc_blend_modes[][DC_N_WINDOWS] = {
{{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
.one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
.two_win_x = BLEND(NOKEY, FIX, 0x00, 0x00),
.two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
.three_win_xy = BLEND(NOKEY, FIX, 0x00, 0x00)},
{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
.one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
.two_win_x = BLEND(NOKEY, FIX, 0xff, 0xff),
.two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
.three_win_xy = BLEND(NOKEY, DEPENDANT, 0x00, 0x00)},
{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
.one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
.two_win_x = BLEND(NOKEY, ALPHA, 0xff, 0xff),
.two_win_y = BLEND(NOKEY, ALPHA, 0xff, 0xff),
.three_win_xy = BLEND(NOKEY, ALPHA, 0xff, 0xff)}
}
};
struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
@@ -349,12 +330,88 @@ struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
}
EXPORT_SYMBOL(tegra_dc_get_window);
static int get_topmost_window(u32 *depths, unsigned long *wins)
{
int idx, best = -1;
for_each_set_bit(idx, wins, sizeof(*wins)) {
if (best == -1 || depths[idx] < depths[best])
best = idx;
}
clear_bit(best, wins);
return best;
}
static u32 blend_topwin(u32 flags)
{
if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
return BLEND(NOKEY, ALPHA, 0xff, 0xff);
else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT)
return BLEND(NOKEY, PREMULT, 0xff, 0xff);
else
return BLEND(NOKEY, FIX, 0xff, 0xff);
}
static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
{
int other;
for (other = 0; other < DC_N_WINDOWS; other++) {
if (other != idx && (xy-- == 0))
break;
}
if (BIT(other) & behind_mask)
return blend_topwin(flags[idx]);
else if (flags[other])
return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
else
return BLEND(NOKEY, FIX, 0x00, 0x00);
}
static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
{
unsigned long infront_mask;
infront_mask = ~(behind_mask | BIT(idx));
infront_mask &= (BIT(DC_N_WINDOWS) - 1);
if (!infront_mask)
return blend_topwin(flags[idx]);
else if (behind_mask && flags[ffs(infront_mask)])
return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
else
return BLEND(NOKEY, FIX, 0x0, 0x0);
}
static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
{
unsigned long mask = BIT(DC_N_WINDOWS) - 1;
while (mask) {
int idx = get_topmost_window(blend->z, &mask);
tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
DC_CMD_DISPLAY_WINDOW_HEADER);
tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
DC_WIN_BLEND_NOKEY);
tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
DC_WIN_BLEND_1WIN);
tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0),
DC_WIN_BLEND_2WIN_X);
tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1),
DC_WIN_BLEND_2WIN_Y);
tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags),
DC_WIN_BLEND_3WIN_XY);
}
}
/* does not support updating windows on multiple dcs in one call */
int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
{
struct tegra_dc *dc;
unsigned long update_mask = GENERAL_ACT_REQ;
unsigned long val;
bool update_blend = false;
int i;
dc = windows[0]->dc;
@@ -370,7 +427,17 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
struct tegra_dc_win *win = windows[i];
unsigned h_dda;
unsigned v_dda;
unsigned stride;
if (win->z != dc->blend.z[win->idx]) {
dc->blend.z[win->idx] = win->z;
update_blend = true;
}
if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
dc->blend.flags[win->idx]) {
dc->blend.flags[win->idx] =
win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
update_blend = true;
}
tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -385,41 +452,46 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
stride = win->w * tegra_dc_fmt_bpp(win->fmt) / 8;
/* TODO: implement filter on settings */
h_dda = (win->w * 0x1000) / (win->out_w - 1);
v_dda = (win->h * 0x1000) / (win->out_h - 1);
h_dda = (win->w * 0x1000) / max_t(int, win->out_w - 1, 1);
v_dda = (win->h * 0x1000) / max_t(int, win->out_h - 1, 1);
tegra_dc_writel(dc,
V_POSITION(win->y) | H_POSITION(win->x),
V_POSITION(win->out_y) | H_POSITION(win->out_x),
DC_WIN_POSITION);
tegra_dc_writel(dc,
V_SIZE(win->out_h) | H_SIZE(win->out_w),
DC_WIN_SIZE);
tegra_dc_writel(dc,
V_PRESCALED_SIZE(win->out_h) |
H_PRESCALED_SIZE(stride),
V_PRESCALED_SIZE(win->h) |
H_PRESCALED_SIZE(win->w*tegra_dc_fmt_bpp(win->fmt)/8),
DC_WIN_PRESCALED_SIZE);
tegra_dc_writel(dc, 0, DC_WIN_H_INITIAL_DDA);
tegra_dc_writel(dc, 0, DC_WIN_V_INITIAL_DDA);
tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
DC_WIN_DDA_INCREMENT);
tegra_dc_writel(dc, stride, DC_WIN_LINE_STRIDE);
tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
val = WIN_ENABLE;
if (win->flags & TEGRA_WIN_FLAG_COLOR_EXPAND)
if (tegra_dc_fmt_bpp(win->fmt) < 24)
val |= COLOR_EXPAND;
tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
tegra_dc_writel(dc, (unsigned long)win->phys_addr,
DC_WINBUF_START_ADDR);
tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_H_OFFSET);
tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_V_OFFSET);
tegra_dc_writel(dc, win->x, DC_WINBUF_ADDR_H_OFFSET);
tegra_dc_writel(dc, win->y, DC_WINBUF_ADDR_V_OFFSET);
win->dirty = 1;
}
if (update_blend) {
tegra_dc_set_blending(dc, &dc->blend);
for (i = 0; i < DC_N_WINDOWS; i++) {
dc->windows[i].dirty = 1;
update_mask |= WIN_A_ACT_REQ << i;
}
}
tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
@@ -468,23 +540,6 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
}
EXPORT_SYMBOL(tegra_dc_sync_windows);
void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
{
int i;
for (i = 0; i < DC_N_WINDOWS; i++) {
tegra_dc_writel(dc, WINDOW_A_SELECT << i,
DC_CMD_DISPLAY_WINDOW_HEADER);
tegra_dc_writel(dc, blend[i].nokey, DC_WIN_BLEND_NOKEY);
tegra_dc_writel(dc, blend[i].one_win, DC_WIN_BLEND_1WIN);
tegra_dc_writel(dc, blend[i].two_win_x, DC_WIN_BLEND_2WIN_X);
tegra_dc_writel(dc, blend[i].two_win_y, DC_WIN_BLEND_2WIN_Y);
tegra_dc_writel(dc, blend[i].three_win_xy,
DC_WIN_BLEND_3WIN_XY);
}
}
EXPORT_SYMBOL(tegra_dc_set_blending);
void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
{
if (dc->out->type == TEGRA_DC_OUT_HDMI) {
@@ -674,8 +729,6 @@ static void _tegra_dc_enable(struct tegra_dc *dc)
if (dc->out_ops && dc->out_ops->enable)
dc->out_ops->enable(dc);
tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
}
void tegra_dc_enable(struct tegra_dc *dc)
@@ -915,7 +968,8 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
wins[i] = &dc->windows[i];
_tegra_dc_enable(dc);
/* force a full blending update */
dc->blend.z[0] = -1;
tegra_dc_update_windows(wins, dc->n_windows);
}

View File

@@ -25,6 +25,11 @@
struct tegra_dc;
struct tegra_dc_blend {
unsigned z[DC_N_WINDOWS];
unsigned flags[DC_N_WINDOWS];
};
struct tegra_dc_out_ops {
/* initialize output. dc clocks are not on at this point */
int (*init)(struct tegra_dc *dc);
@@ -60,6 +65,7 @@ struct tegra_dc {
struct tegra_dc_mode mode;
struct tegra_dc_win windows[DC_N_WINDOWS];
struct tegra_dc_blend blend;
int n_windows;
wait_queue_head_t wq;

View File

@@ -377,8 +377,13 @@
#define BLEND_CONTROL_FIX (0 << 2)
#define BLEND_CONTROL_ALPHA (1 << 2)
#define BLEND_CONTROL_DEPENDANT (2 << 2)
#define BLEND_CONTROL_PREMULT (3 << 2)
#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
#define BLEND(key, control, weight0, weight1) \
(CKEY_ ## key | BLEND_CONTROL_ ## control | \
BLEND_WEIGHT0(weight0) | BLEND_WEIGHT0(weight1))
#define DC_WIN_HP_FETCH_CONTROL 0x714
#define DC_WINBUF_START_ADDR 0x800

View File

@@ -290,7 +290,8 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
struct fb_info *info;
struct tegra_fb_info *tegra_fb;
void __iomem *fb_base = NULL;
unsigned long fb_size = 0; unsigned long fb_phys = 0;
unsigned long fb_size = 0;
unsigned long fb_phys = 0;
int ret = 0;
win = tegra_dc_get_window(dc, fb_data->win);
@@ -363,11 +364,15 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
win->w = fb_data->xres;
win->h = fb_data->yres;
/* TODO: set to output res dc */
win->out_x = 0;
win->out_y = 0;
win->out_w = fb_data->xres;
win->out_h = fb_data->yres;
win->z = 0;
win->phys_addr = fb_phys;
win->virt_addr = fb_base;
win->flags = TEGRA_WIN_FLAG_ENABLED | TEGRA_WIN_FLAG_COLOR_EXPAND;
win->stride = fb_data->xres * fb_data->bits_per_pixel / 8;
win->flags = TEGRA_WIN_FLAG_ENABLED;
if (fb_mem)
tegra_fb_set_par(info);