mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 05:17:10 +09:00
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:
committed by
Colin Cross
parent
58459da41c
commit
d546987a68
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user