blob: 0cc29a365076422c31e699aa6f31b69313602ef5 [file] [log] [blame]
/*
* drivers/amlogic/media/osd_ext/osd_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. 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.
*
*/
/* Linux Headers */
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/irqreturn.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
/* Android Headers */
#include <sw_sync.h>
#include <sync.h>
/* Amlogic Headers */
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
#include <linux/amlogic/media/amports/vframe_receiver.h>
#endif
/* Local Headers */
#include <osd/osd_log.h>
#include <osd/osd_io.h>
#include <osd/osd_reg.h>
#include <osd/osd_canvas.h>
#include <osd/osd_hw.h>
#include "osd_prot.h"
#include "osd_clone.h"
#include "osd_hw_def.h"
#ifdef CONFIG_AML_VSYNC_FIQ_ENABLE
#define FIQ_VSYNC
#endif
static DECLARE_WAIT_QUEUE_HEAD(osd_ext_vsync_wq);
static bool vsync_hit;
static bool osd_ext_vf_need_update;
static struct hw_para_s *osd_hw;
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
/* add sync fence relative varible here. */
/* we will limit all fence relative code in this driver file. */
static int ext_timeline_created;
static struct sw_sync_timeline *ext_timeline;
static u32 ext_cur_streamline_val;
/* thread control part */
struct kthread_worker ext_buffer_toggle_worker;
struct task_struct *ext_buffer_toggle_thread;
struct kthread_work ext_buffer_toggle_work;
struct list_head ext_post_fence_list;
struct mutex ext_post_fence_list_lock;
static void osd_ext_pan_display_fence(struct osd_fence_map_s *fence_map);
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
#define PROVIDER_NAME "osd_ext"
static struct vframe_s vf;
static struct vframe_provider_s osd_ext_vf_prov;
static unsigned char osd_ext_vf_prov_init;
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
static int g_vf_visual_width;
static int g_vf_width;
static int g_vf_height;
#endif
static unsigned int filt_coef0[] = { /* bicubic */
0x00800000,
0x007f0100,
0xff7f0200,
0xfe7f0300,
0xfd7e0500,
0xfc7e0600,
0xfb7d0800,
0xfb7c0900,
0xfa7b0b00,
0xfa7a0dff,
0xf9790fff,
0xf97711ff,
0xf87613ff,
0xf87416fe,
0xf87218fe,
0xf8701afe,
0xf76f1dfd,
0xf76d1ffd,
0xf76b21fd,
0xf76824fd,
0xf76627fc,
0xf76429fc,
0xf7612cfc,
0xf75f2ffb,
0xf75d31fb,
0xf75a34fb,
0xf75837fa,
0xf7553afa,
0xf8523cfa,
0xf8503ff9,
0xf84d42f9,
0xf84a45f9,
0xf84848f8
};
static unsigned int filt_coef1[] = { /* 2 point bilinear */
0x00800000,
0x007e0200,
0x007c0400,
0x007a0600,
0x00780800,
0x00760a00,
0x00740c00,
0x00720e00,
0x00701000,
0x006e1200,
0x006c1400,
0x006a1600,
0x00681800,
0x00661a00,
0x00641c00,
0x00621e00,
0x00602000,
0x005e2200,
0x005c2400,
0x005a2600,
0x00582800,
0x00562a00,
0x00542c00,
0x00522e00,
0x00503000,
0x004e3200,
0x004c3400,
0x004a3600,
0x00483800,
0x00463a00,
0x00443c00,
0x00423e00,
0x00404000
};
static unsigned int filt_coef2[] = { /* 2 point bilinear, bank_length == 2 */
0x80000000,
0x7e020000,
0x7c040000,
0x7a060000,
0x78080000,
0x760a0000,
0x740c0000,
0x720e0000,
0x70100000,
0x6e120000,
0x6c140000,
0x6a160000,
0x68180000,
0x661a0000,
0x641c0000,
0x621e0000,
0x60200000,
0x5e220000,
0x5c240000,
0x5a260000,
0x58280000,
0x562a0000,
0x542c0000,
0x522e0000,
0x50300000,
0x4e320000,
0x4c340000,
0x4a360000,
0x48380000,
0x463a0000,
0x443c0000,
0x423e0000,
0x40400000
};
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
static inline int find_ext_buf_num(u32 yres, u32 yoffset)
{
int n = yres;
int i;
for (i = 0; i < OSD_MAX_BUF_NUM; i++) {
/* find current addr position. */
if (yoffset < (n))
break;
n += yres;
}
return i;
}
static void osd_ext_toggle_buffer(struct kthread_work *work)
{
struct osd_fence_map_s *data, *next;
struct list_head saved_list;
mutex_lock(&ext_post_fence_list_lock);
saved_list = ext_post_fence_list;
list_replace_init(&ext_post_fence_list, &saved_list);
mutex_unlock(&ext_post_fence_list_lock);
list_for_each_entry_safe(data, next, &saved_list, list) {
osd_ext_pan_display_fence(data);
if ((data->in_fence) && (data->in_fd > 0)) {
__close_fd(data->files, data->in_fd);
sync_fence_put(data->in_fence);
}
list_del(&data->list);
kfree(data);
}
}
static int out_ext_fence_create(int *release_fence_fd, u32 *val, u32 buf_num)
{
/* the first time create out_fence_fd==0 */
/* sw_sync_timeline_inc will release fence and it's sync point */
struct sync_pt *outer_sync_pt;
struct sync_fence *outer_fence;
int out_fence_fd = -1;
out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
/* no file descriptor could be used. Error. */
if (out_fence_fd < 0)
return -1;
if (!ext_timeline_created) { /* timeline has not been created */
ext_timeline = sw_sync_timeline_create("osd_ext_timeline");
ext_cur_streamline_val = 1;
if (ext_timeline == NULL)
return -1;
init_kthread_worker(&ext_buffer_toggle_worker);
ext_buffer_toggle_thread =
kthread_run(kthread_worker_fn,
&ext_buffer_toggle_worker,
"aml_buf_ext_toggle");
init_kthread_work(&ext_buffer_toggle_work,
osd_ext_toggle_buffer);
ext_timeline_created = 1;
}
/* install fence map; first ,the simplest. */
ext_cur_streamline_val++;
*val = ext_cur_streamline_val;
outer_sync_pt = sw_sync_pt_create(ext_timeline, *val);
if (outer_sync_pt == NULL)
goto error_ret;
outer_fence = sync_fence_create("osd_ext_fence_out", outer_sync_pt);
if (outer_fence == NULL) {
sync_pt_free(outer_sync_pt); /* free sync point. */
goto error_ret;
}
sync_fence_install(outer_fence, out_fence_fd);
osd_log_dbg(MODULE_FENCE, "---------------------------------------\n");
osd_log_dbg(MODULE_FENCE, "return out fence fd:%d\n", out_fence_fd);
*release_fence_fd = out_fence_fd;
return out_fence_fd;
error_ret:
ext_cur_streamline_val--;
/* pt or fence fail,restore timeline value. */
osd_log_err("fence obj create fail\n");
put_unused_fd(out_fence_fd);
return -1;
}
int osd_ext_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset,
s32 in_fence_fd)
{
int out_fence_fd = -1;
int buf_num = 0;
struct osd_fence_map_s *fence_map = NULL;
fence_map = kzalloc(sizeof(struct osd_fence_map_s), GFP_KERNEL);
if (!fence_map)
return -ENOMEM;
buf_num = find_ext_buf_num(yres, yoffset);
mutex_lock(&ext_post_fence_list_lock);
fence_map->fb_index = index;
fence_map->buf_num = buf_num;
fence_map->yoffset = yoffset;
fence_map->xoffset = xoffset;
fence_map->yres = yres;
fence_map->in_fd = in_fence_fd;
fence_map->in_fence = sync_fence_fdget(in_fence_fd);
fence_map->files = current->files;
fence_map->out_fd = out_ext_fence_create(&out_fence_fd, &fence_map->val,
buf_num);
list_add_tail(&fence_map->list, &ext_post_fence_list);
mutex_unlock(&ext_post_fence_list_lock);
queue_kthread_work(&ext_buffer_toggle_worker, &ext_buffer_toggle_work);
return out_fence_fd;
}
static int osd_ext_wait_buf_ready(struct osd_fence_map_s *fence_map)
{
s32 ret = -1;
struct sync_fence *buf_ready_fence = NULL;
if (fence_map->in_fd <= 0) {
ret = -1;
return ret;
}
buf_ready_fence = fence_map->in_fence;
if (buf_ready_fence == NULL) {
ret = -1;/* no fence ,output directly. */
return ret;
}
ret = sync_fence_wait(buf_ready_fence, -1);
if (ret < 0)
osd_log_err("Sync Fence wait error:%d\n", ret);
else
ret = 1;
return ret;
}
#else
int osd_ext_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset,
s32 in_fence_fd)
{
osd_log_err("osd_ext_sync_request not supported\n");
return -5566;
}
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
static struct vframe_s *osd_ext_vf_peek(void *arg)
{
if ((osd_ext_vf_need_update && (vf.width > 0) && (vf.height > 0)))
return &vf;
else
return NULL;
}
static struct vframe_s *osd_ext_vf_get(void *arg)
{
if (osd_ext_vf_need_update) {
vf_ext_light_unreg_provider(&osd_ext_vf_prov);
osd_ext_vf_need_update = false;
return &vf;
}
return NULL;
}
static const struct vframe_operations_s osd_ext_vf_provider = {
.peek = osd_ext_vf_peek,
.get = osd_ext_vf_get,
.put = NULL,
};
#endif
static inline void osd_ext_update_3d_mode(int enable_osd1, int enable_osd2)
{
if (enable_osd1)
osd1_update_disp_3d_mode();
if (enable_osd2)
osd2_update_disp_3d_mode();
}
static inline void wait_ext_vsync_wakeup(void)
{
vsync_hit = true;
wake_up_interruptible(&osd_ext_vsync_wq);
}
static inline void walk_through_update_list(void)
{
u32 i, j;
for (i = 0; i < HW_OSD_COUNT; i++) {
j = 0;
while (osd_ext_hw.updated[i] && j < 32) {
if (osd_ext_hw.updated[i] & (1 << j)) {
osd_ext_hw.reg[i][j].update_func();
remove_from_update_list(i, j);
}
j++;
}
}
}
#ifdef FIQ_VSYNC
static irqreturn_t vsync_isr(int irq, void *dev_id)
{
wait_ext_vsync_wakeup();
return IRQ_HANDLED;
}
#endif
#ifdef FIQ_VSYNC
static void osd_ext_fiq_isr(void)
#else
static irqreturn_t vsync_isr(int irq, void *dev_id)
#endif
{
#define VOUT_ENCI 1
#define VOUT_ENCP 2
#define VOUT_ENCT 3
unsigned int fb0_cfg_w0, fb1_cfg_w0;
unsigned int odd_even;
unsigned int scan_line_number = 0;
unsigned char output_type = 0;
output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0xc;
osd_ext_hw.scan_mode = SCAN_MODE_PROGRESSIVE;
switch (output_type) {
case VOUT_ENCP:
if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) /* 1080i */
osd_ext_hw.scan_mode = SCAN_MODE_INTERLACE;
break;
case VOUT_ENCI:
if (osd_reg_read(ENCI_VIDEO_EN) & 1)
osd_ext_hw.scan_mode = SCAN_MODE_INTERLACE;
break;
}
if (osd_ext_hw.free_scale_enable[OSD1])
osd_ext_hw.scan_mode = SCAN_MODE_PROGRESSIVE;
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
fb0_cfg_w0 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0);
fb1_cfg_w0 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0 + REG_OFFSET);
if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) {
/* 1080I */
scan_line_number = ((osd_reg_read(ENCP_INFO_READ))
& 0x1fff0000) >> 16;
if ((osd_ext_hw.pandata[OSD1].y_start % 2) == 0) {
if (scan_line_number >= 562) {
/* bottom field, odd lines */
odd_even = 1;
} else {
/* top field, even lines */
odd_even = 0;
}
} else {
if (scan_line_number >= 562) {
/* top field, even lines */
odd_even = 0;
} else {
/* bottom field, odd lines */
odd_even = 1;
}
}
} else {
if ((osd_ext_hw.pandata[OSD1].y_start % 2) == 0)
odd_even = osd_reg_read(ENCI_INFO_READ) & 1;
else
odd_even = !(osd_reg_read(ENCI_INFO_READ) & 1);
}
fb0_cfg_w0 &= ~1;
fb1_cfg_w0 &= ~1;
fb0_cfg_w0 |= odd_even;
fb1_cfg_w0 |= odd_even;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, fb0_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, fb0_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, fb0_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, fb0_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W0 + REG_OFFSET, fb1_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK1_CFG_W0 + REG_OFFSET, fb1_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK2_CFG_W0 + REG_OFFSET, fb1_cfg_w0);
osd_reg_write(VIU2_OSD1_BLK3_CFG_W0 + REG_OFFSET, fb1_cfg_w0);
}
/* go through update list */
walk_through_update_list();
osd_ext_update_3d_mode(osd_ext_hw.mode_3d[OSD1].enable,
osd_ext_hw.mode_3d[OSD2].enable);
if (!vsync_hit) {
#ifdef FIQ_VSYNC
fiq_bridge_pulse_trigger(&osd_ext_hw.fiq_handle_item);
#else
wait_ext_vsync_wakeup();
#endif
}
#ifndef FIQ_VSYNC
return IRQ_HANDLED;
#endif
}
void osd_ext_wait_vsync_hw(void)
{
vsync_hit = false;
wait_event_interruptible_timeout(osd_ext_vsync_wq,
vsync_hit, msecs_to_jiffies(1000));
}
s32 osd_ext_wait_vsync_event(void)
{
vsync_hit = false;
wait_event_interruptible_timeout(osd_ext_vsync_wq,
vsync_hit, msecs_to_jiffies(1000));
return 0;
}
/* the return stride unit is 128bit(16bytes) */
static u32 line_stride_calc(
u32 fmt_mode,
u32 hsize,
u32 stride_align_32bytes)
{
u32 line_stride = 0;
/* 2-bit LUT */
if (fmt_mode == 0)
line_stride = ((hsize<<1)+127)>>7;
/* 4-bit LUT */
else if (fmt_mode == 1)
line_stride = ((hsize<<2)+127)>>7;
/* 8-bit LUT */
else if (fmt_mode == 2)
line_stride = ((hsize<<3)+127)>>7;
/* 4:2:2, 32-bit per 2 pixels */
else if (fmt_mode == 3)
line_stride = ((((hsize+1)>>1)<<5)+127)>>7;
/* 16-bit LUT */
else if (fmt_mode == 4)
line_stride = ((hsize<<4)+127)>>7;
/* 32-bit LUT */
else if (fmt_mode == 5)
line_stride = ((hsize<<5)+127)>>7;
/* 24-bit LUT */
else if (fmt_mode == 7)
line_stride = ((hsize<<4)+(hsize<<3)+127)>>7;
/* need wr ddr is 32bytes aligned */
if (stride_align_32bytes)
line_stride = ((line_stride+1)>>1)<<1;
else
line_stride = line_stride;
return line_stride;
}
static void osd_ext_update_phy_addr(u32 index)
{
u32 line_stride, fmt_mode;
fmt_mode =
osd_ext_hw.color_info[index]->hw_colormat << 2;
line_stride = line_stride_calc(fmt_mode,
osd_ext_hw.fb_gem[index].width, 1);
VSYNCOSD_WR_MPEG_REG(
VIU_OSD1_BLK1_CFG_W4,
osd_ext_hw.fb_gem[index].addr);
VSYNCOSD_WR_MPEG_REG_BITS(
VIU_OSD1_BLK2_CFG_W4,
line_stride,
0, 12);
}
void osd_ext_set_gbl_alpha_hw(u32 index, u32 gbl_alpha)
{
if (osd_ext_hw.gbl_alpha[index] != gbl_alpha) {
osd_ext_hw.gbl_alpha[index] = gbl_alpha;
add_to_update_list(index, OSD_GBL_ALPHA);
osd_ext_wait_vsync_hw();
}
}
u32 osd_ext_get_gbl_alpha_hw(u32 index)
{
return osd_ext_hw.gbl_alpha[index];
}
void osd_ext_set_color_key_hw(u32 index, u32 color_index, u32 colorkey)
{
u8 r = 0, g = 0, b = 0, a = (colorkey & 0xff000000) >> 24;
u32 data32;
colorkey &= 0x00ffffff;
switch (color_index) {
case COLOR_INDEX_16_655:
r = (colorkey >> 10 & 0x3f) << 2;
g = (colorkey >> 5 & 0x1f) << 3;
b = (colorkey & 0x1f) << 3;
break;
case COLOR_INDEX_16_844:
r = colorkey >> 8 & 0xff;
g = (colorkey >> 4 & 0xf) << 4;
b = (colorkey & 0xf) << 4;
break;
case COLOR_INDEX_16_565:
r = (colorkey >> 11 & 0x1f) << 3;
g = (colorkey >> 5 & 0x3f) << 2;
b = (colorkey & 0x1f) << 3;
break;
case COLOR_INDEX_24_888_B:
b = colorkey >> 16 & 0xff;
g = colorkey >> 8 & 0xff;
r = colorkey & 0xff;
break;
case COLOR_INDEX_24_RGB:
case COLOR_INDEX_YUV_422:
r = colorkey >> 16 & 0xff;
g = colorkey >> 8 & 0xff;
b = colorkey & 0xff;
break;
}
data32 = r << 24 | g << 16 | b << 8 | a;
if (osd_ext_hw.color_key[index] != data32) {
osd_ext_hw.color_key[index] = data32;
osd_log_info("bpp:%d--r:0x%x g:0x%x b:0x%x ,a:0x%x\n",
color_index, r, g, b, a);
add_to_update_list(index, OSD_COLOR_KEY);
osd_ext_wait_vsync_hw();
}
}
void osd_ext_srckey_enable_hw(u32 index, u8 enable)
{
if (enable != osd_ext_hw.color_key_enable[index]) {
osd_ext_hw.color_key_enable[index] = enable;
add_to_update_list(index, OSD_COLOR_KEY_ENABLE);
osd_ext_wait_vsync_hw();
}
}
void osd_ext_update_disp_axis_hw(
u32 display_h_start,
u32 display_h_end,
u32 display_v_start,
u32 display_v_end,
u32 xoffset,
u32 yoffset,
u32 mode_change,
u32 index)
{
struct pandata_s disp_data;
struct pandata_s pan_data;
if (osd_ext_hw.color_info[index] == NULL)
return;
if (mode_change) /* modify pandata . */
add_to_update_list(index, OSD_COLOR_MODE);
disp_data.x_start = display_h_start;
disp_data.y_start = display_v_start;
disp_data.x_end = display_h_end;
disp_data.y_end = display_v_end;
pan_data.x_start = xoffset;
pan_data.x_end = xoffset + (display_h_end - display_h_start);
pan_data.y_start = yoffset;
pan_data.y_end = yoffset + (display_v_end - display_v_start);
/* if output mode change then reset pan ofFfset. */
memcpy(&osd_ext_hw.pandata[index], &pan_data,
sizeof(struct pandata_s));
memcpy(&osd_ext_hw.dispdata[index], &disp_data,
sizeof(struct pandata_s));
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
}
void osd_ext_setup(struct osd_ctl_s *osd_ext_ctl,
u32 xoffset,
u32 yoffset,
u32 xres,
u32 yres,
u32 xres_virtual,
u32 yres_virtual,
u32 disp_start_x,
u32 disp_start_y,
u32 disp_end_x,
u32 disp_end_y,
u32 fbmem,
const struct color_bit_define_s *color,
int index)
{
int cpu_type;
u32 w = (color->bpp * xres_virtual + 7) >> 3;
struct pandata_s disp_data;
struct pandata_s pan_data;
pan_data.x_start = xoffset;
pan_data.y_start = yoffset;
disp_data.x_start = disp_start_x;
disp_data.y_start = disp_start_y;
if (likely(osd_ext_hw.free_scale_enable[OSD1] && index == OSD1)) {
pan_data.x_end = xoffset + (disp_end_x - disp_start_x);
pan_data.y_end = yoffset + (disp_end_y - disp_start_y);
disp_data.x_end = disp_end_x;
disp_data.y_end = disp_end_y;
} else {
pan_data.x_end = xoffset + (disp_end_x - disp_start_x);
pan_data.y_end = yoffset + (disp_end_y - disp_start_y);
disp_data.x_end = disp_end_x;
disp_data.y_end = disp_end_y;
}
if (osd_ext_hw.fb_gem[index].addr != fbmem ||
osd_ext_hw.fb_gem[index].width != w
|| osd_ext_hw.fb_gem[index].height != yres_virtual) {
osd_ext_hw.fb_gem[index].addr = fbmem;
osd_ext_hw.fb_gem[index].width = w;
osd_ext_hw.fb_gem[index].height = yres_virtual;
if (color != osd_ext_hw.color_info[index]) {
osd_ext_hw.color_info[index] = color;
add_to_update_list(index, OSD_COLOR_MODE);
}
cpu_type = get_cpu_type();
if (cpu_type == MESON_CPU_MAJOR_ID_AXG)
osd_ext_update_phy_addr(0);
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
else {
if (fbmem == 0) {
canvas_config(osd_ext_hw.fb_gem[index].canvas_idx,
osd_hw->fb_gem[index].addr,
osd_ext_hw.fb_gem[index].width,
osd_ext_hw.fb_gem[index].height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
} else {
canvas_config(osd_ext_hw.fb_gem[index].canvas_idx,
osd_ext_hw.fb_gem[index].addr,
osd_ext_hw.fb_gem[index].width,
osd_ext_hw.fb_gem[index].height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
}
}
#endif
}
/* osd blank only control by /sys/class/graphcis/fbx/blank */
#if 0
if (osd_ext_hw.enable[index] == DISABLE) {
osd_ext_hw.enable[index] = ENABLE;
add_to_update_list(index, OSD_ENABLE);
}
#endif
if (memcmp(&pan_data, &osd_ext_hw.pandata[index],
sizeof(struct pandata_s)) != 0 ||
memcmp(&disp_data, &osd_ext_hw.dispdata[index],
sizeof(struct pandata_s)) != 0) {
memcpy(&osd_ext_hw.pandata[index], &pan_data,
sizeof(struct pandata_s));
memcpy(&osd_ext_hw.dispdata[index], &disp_data,
sizeof(struct pandata_s));
add_to_update_list(index, DISP_GEOMETRY);
}
osd_ext_wait_vsync_hw();
}
void osd_ext_setpal_hw(u32 index,
unsigned int regno,
unsigned int red,
unsigned int green,
unsigned int blue,
unsigned int transp)
{
if (regno < 256) {
u32 pal;
pal = ((red & 0xff) << 24) |
((green & 0xff) << 16) |
((blue & 0xff) << 8) |
(transp & 0xff);
osd_reg_write(VIU2_OSD1_COLOR_ADDR + REG_OFFSET * index, regno);
osd_reg_write(VIU2_OSD1_COLOR + REG_OFFSET * index, pal);
}
}
u32 osd_ext_get_order_hw(u32 index)
{
return osd_ext_hw.order & 0x3;
}
void osd_ext_set_order_hw(u32 index, u32 order)
{
if ((order != OSD_ORDER_01) && (order != OSD_ORDER_10))
return;
osd_ext_hw.order = order;
add_to_update_list(index, OSD_CHANGE_ORDER);
osd_ext_wait_vsync_hw();
}
void osd_ext_enable_hw(u32 index, int enable)
{
osd_ext_hw.enable[index] = enable;
add_to_update_list(index, OSD_ENABLE);
osd_ext_wait_vsync_hw();
}
/* vpu free scale mode */
static void osd_ext_set_free_scale_enable_mode0(u32 index, u32 enable)
{
static struct pandata_s save_disp_data = { 0, 0, 0, 0 };
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
int mode_changed = 0;
if ((index == OSD1) &&
(osd_ext_hw.free_scale_enable[index] != enable))
mode_changed = 1;
#endif
#endif
osd_log_info("osd%d free scale %s\n",
index, enable ? "ENABLE" : "DISABLE");
osd_ext_hw.free_scale_enable[index] = enable;
if (index == OSD1) {
if (enable) {
osd_ext_vf_need_update = true;
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
if ((osd_ext_hw.free_src_data[OSD1].x_end > 0)
&& (osd_ext_hw.free_src_data[OSD1].x_end > 0)) {
vf.width =
osd_ext_hw.free_src_data[index].x_end -
osd_ext_hw.free_src_data[index].x_start +
1;
vf.height =
osd_ext_hw.free_src_data[index].y_end -
osd_ext_hw.free_src_data[index].y_start +
1;
} else {
vf.width = osd_ext_hw.free_scale_width[OSD1];
vf.height = osd_ext_hw.free_scale_height[OSD1];
}
vf.type = (VIDTYPE_NO_VIDEO_ENABLE |
VIDTYPE_PROGRESSIVE |
VIDTYPE_VIU_FIELD |
VIDTYPE_VSCALE_DISABLE);
vf.ratio_control = DISP_RATIO_FORCECONFIG |
DISP_RATIO_NO_KEEPRATIO;
if (osd_ext_vf_prov_init == 0) {
vf_provider_init(&osd_ext_vf_prov,
PROVIDER_NAME,
&osd_ext_vf_provider,
NULL);
osd_ext_vf_prov_init = 1;
}
vf_reg_provider(&osd_ext_vf_prov);
memcpy(&save_disp_data, &osd_ext_hw.dispdata[OSD1],
sizeof(struct pandata_s));
g_vf_visual_width = vf.width - 1 -
osd_hw->dispdata[OSD1].x_start;
g_vf_width = vf.width - 1;
g_vf_height = vf.height - 1;
osd_ext_hw.dispdata[OSD1].x_end =
osd_ext_hw.dispdata[OSD1].x_start +
vf.width - 1;
osd_ext_hw.dispdata[OSD1].y_end =
osd_ext_hw.dispdata[OSD1].y_start +
vf.height - 1;
#endif
add_to_update_list(OSD1, DISP_GEOMETRY);
add_to_update_list(OSD1, OSD_COLOR_MODE);
} else {
osd_ext_vf_need_update = false;
if (save_disp_data.x_end <= save_disp_data.x_start ||
save_disp_data.y_end <= save_disp_data.y_start)
return;
memcpy(&osd_ext_hw.dispdata[OSD1], &save_disp_data,
sizeof(struct pandata_s));
add_to_update_list(OSD1, DISP_GEOMETRY);
add_to_update_list(OSD1, OSD_COLOR_MODE);
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
vf_unreg_provider(&osd_ext_vf_prov);
#endif
}
} else {
add_to_update_list(OSD2, DISP_GEOMETRY);
add_to_update_list(OSD2, OSD_COLOR_MODE);
}
osd_ext_enable_hw(osd_ext_hw.enable[index], index);
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
if (mode_changed) {
/* extern void vf_ppmgr_reset(int type); */
vf_ppmgr_reset(1);
}
#endif
#endif
}
/* osd free scale mode */
static void osd_ext_set_free_scale_enable_mode1(u32 index, u32 enable)
{
unsigned int h_enable = 0;
unsigned int v_enable = 0;
h_enable = (enable & 0xffff0000 ? 1 : 0);
v_enable = (enable & 0xffff ? 1 : 0);
osd_ext_hw.free_scale[index].h_enable = h_enable;
osd_ext_hw.free_scale[index].v_enable = v_enable;
if (h_enable || v_enable)
osd_ext_hw.free_scale_enable[index] = 1;
else if (!h_enable && !v_enable)
osd_ext_hw.free_scale_enable[index] = 0;
if (index == OSD1) {
if (osd_ext_hw.free_scale_enable[index]) {
add_to_update_list(index, OSD_COLOR_MODE);
add_to_update_list(index, OSD_FREESCALE_COEF);
add_to_update_list(index, DISP_GEOMETRY);
add_to_update_list(index, DISP_FREESCALE_ENABLE);
} else {
add_to_update_list(index, OSD_COLOR_MODE);
add_to_update_list(index, DISP_GEOMETRY);
add_to_update_list(index, DISP_FREESCALE_ENABLE);
}
} else {
add_to_update_list(OSD2, DISP_GEOMETRY);
add_to_update_list(OSD2, OSD_COLOR_MODE);
}
osd_ext_enable_hw(osd_ext_hw.enable[index], index);
}
void osd_ext_set_free_scale_enable_hw(u32 index, u32 enable)
{
if (osd_ext_hw.free_scale_mode[index])
osd_ext_set_free_scale_enable_mode1(index, enable);
else
osd_ext_set_free_scale_enable_mode0(index, enable);
}
void osd_ext_get_free_scale_enable_hw(u32 index, u32 *free_scale_enable)
{
*free_scale_enable = osd_ext_hw.free_scale_enable[index];
}
void osd_ext_get_free_scale_width_hw(u32 index, u32 *free_scale_width)
{
*free_scale_width = osd_ext_hw.free_src_data[index].x_end -
osd_ext_hw.free_src_data[index].x_start + 1;
}
void osd_ext_get_free_scale_height_hw(u32 index, u32 *free_scale_height)
{
*free_scale_height = osd_ext_hw.free_src_data[index].y_end -
osd_ext_hw.free_src_data[index].y_start + 1;
}
void osd_ext_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1,
s32 *y1)
{
*x0 = osd_ext_hw.free_src_data[index].x_start;
*y0 = osd_ext_hw.free_src_data[index].y_start;
*x1 = osd_ext_hw.free_src_data[index].x_end;
*y1 = osd_ext_hw.free_src_data[index].y_end;
}
void osd_ext_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
osd_ext_hw.free_src_data[index].x_start = x0;
osd_ext_hw.free_src_data[index].y_start = y0;
osd_ext_hw.free_src_data[index].x_end = x1;
osd_ext_hw.free_src_data[index].y_end = y1;
}
void osd_ext_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1,
s32 *y1)
{
*x0 = osd_ext_hw.scaledata[index].x_start;
*x1 = osd_ext_hw.scaledata[index].x_end;
*y0 = osd_ext_hw.scaledata[index].y_start;
*y1 = osd_ext_hw.scaledata[index].y_end;
}
void osd_ext_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
osd_ext_hw.scaledata[index].x_start = x0;
osd_ext_hw.scaledata[index].x_end = x1;
osd_ext_hw.scaledata[index].y_start = y0;
osd_ext_hw.scaledata[index].y_end = y1;
}
void osd_ext_set_free_scale_mode_hw(u32 index, u32 freescale_mode)
{
osd_ext_hw.free_scale_mode[index] = freescale_mode;
}
void osd_ext_get_free_scale_mode_hw(u32 index, u32 *freescale_mode)
{
*freescale_mode = osd_ext_hw.free_scale_mode[index];
}
void osd_ext_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1)
{
*x0 = osd_ext_hw.free_dst_data[index].x_start;
*x1 = osd_ext_hw.free_dst_data[index].x_end;
*y0 = osd_ext_hw.free_dst_data[index].y_start;
*y1 = osd_ext_hw.free_dst_data[index].y_end;
}
void osd_ext_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
osd_ext_hw.free_dst_data[index].x_start = x0;
osd_ext_hw.free_dst_data[index].x_end = x1;
osd_ext_hw.free_dst_data[index].y_start = y0;
osd_ext_hw.free_dst_data[index].y_end = y1;
}
void osd_ext_set_debug_hw(u32 index, u32 debug_flag)
{
u32 reg = 0;
u32 offset = 0;
struct pandata_s *pdata = NULL;
if (debug_flag == 1) {
pdata = &osd_ext_hw.pandata[index];
osd_log_info("pandata[%d]:\n", index);
osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n",
pdata->x_start, pdata->x_end);
osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n",
pdata->y_start, pdata->y_end);
pdata = &osd_ext_hw.dispdata[index];
osd_log_info("dispdata[%d]\n", index);
osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n",
pdata->x_start, pdata->x_end);
osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n",
pdata->y_start, pdata->y_end);
pdata = &osd_ext_hw.scaledata[index];
osd_log_info("scaledata[%d]\n", index);
osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n",
pdata->x_start, pdata->x_end);
osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n",
pdata->y_start, pdata->y_end);
} else if (debug_flag == 2) {
reg = VPU_VIU_VENC_MUX_CTRL;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = VPP_MISC;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = VIU_OSD1_CTRL_STAT;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
if (index == 1)
offset = REG_OFFSET;
reg = offset + VIU2_OSD1_BLK0_CFG_W0;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = offset + VIU2_OSD1_BLK0_CFG_W1;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = offset + VIU2_OSD1_BLK0_CFG_W2;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = offset + VIU2_OSD1_BLK0_CFG_W3;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
reg = offset + VIU2_OSD1_BLK0_CFG_W4;
osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg));
} else {
osd_log_err("argument error\n");
}
}
void osd_ext_get_block_windows_hw(u32 index, u32 *windows)
{
/* memcpy(windows, osd_ext_hw.block_windows[index],
* sizeof(osd_ext_hw.block_windows[index]));
*/
}
void osd_ext_set_block_windows_hw(u32 index, u32 *windows)
{
/* memcpy(osd_ext_hw.block_windows[index], windows,
* sizeof(osd_ext_hw.block_windows[index]));
* add_to_update_list(index, DISP_GEOMETRY);
* osd_ext_wait_vsync_hw();
*/
}
void osd_ext_get_block_mode_hw(u32 index, u32 *mode)
{
*mode = osd_ext_hw.block_mode[index];
}
void osd_ext_set_block_mode_hw(u32 index, u32 mode)
{
osd_ext_hw.block_mode[index] = mode;
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
}
void osd_ext_set_2x_scale_hw(u32 index, u16 h_scale_enable, u16 v_scale_enable)
{
osd_log_info("osd[%d] set scale, h_scale: %s, v_scale: %s\n",
index, h_scale_enable ? "ENABLE" : "DISABLE",
v_scale_enable ? "ENABLE" : "DISABLE");
osd_log_info("osd[%d].scaledata: %d %d %d %d\n",
index,
osd_ext_hw.scaledata[index].x_start,
osd_ext_hw.scaledata[index].x_end,
osd_ext_hw.scaledata[index].y_start,
osd_ext_hw.scaledata[index].y_end);
osd_log_info("osd[%d].pandata: %d %d %d %d\n",
index,
osd_ext_hw.pandata[index].x_start,
osd_ext_hw.pandata[index].x_end,
osd_ext_hw.pandata[index].y_start,
osd_ext_hw.pandata[index].y_end);
osd_ext_hw.scale[index].h_enable = h_scale_enable;
osd_ext_hw.scale[index].v_enable = v_scale_enable;
add_to_update_list(index, DISP_SCALE_ENABLE);
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
}
void osd_ext_enable_3d_mode_hw(int index, int enable)
{
spin_lock_irqsave(&osd_ext_lock, lock_flags);
osd_ext_hw.mode_3d[index].enable = enable;
spin_unlock_irqrestore(&osd_ext_lock, lock_flags);
if (enable) {
/* when disable 3d mode ,we should return to stardard state. */
osd_ext_hw.mode_3d[index].left_right = OSD_LEFT;
osd_ext_hw.mode_3d[index].l_start =
osd_ext_hw.pandata[index].x_start;
osd_ext_hw.mode_3d[index].l_end =
(osd_ext_hw.pandata[index].x_end +
osd_ext_hw.pandata[index].x_start) >> 1;
osd_ext_hw.mode_3d[index].r_start =
osd_ext_hw.mode_3d[index].l_end + 1;
osd_ext_hw.mode_3d[index].r_end =
osd_ext_hw.pandata[index].x_end;
osd_ext_hw.mode_3d[index].origin_scale.h_enable =
osd_ext_hw.scale[index].h_enable;
osd_ext_hw.mode_3d[index].origin_scale.v_enable =
osd_ext_hw.scale[index].v_enable;
osd_ext_set_2x_scale_hw(index, 1, 0);
} else {
osd_ext_set_2x_scale_hw(index,
osd_ext_hw.mode_3d[index].origin_scale.h_enable,
osd_ext_hw.mode_3d[index].origin_scale.v_enable);
}
}
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
void osd_ext_pan_display_fence(struct osd_fence_map_s *fence_map)
{
s32 ret = 1;
long diff_x, diff_y;
u32 index = fence_map->fb_index;
u32 xoffset = fence_map->xoffset;
u32 yoffset = fence_map->yoffset;
if (index >= 2)
return;
if (ext_timeline_created) { /* out fence created success. */
ret = osd_ext_wait_buf_ready(fence_map);
if (ret < 0)
osd_log_dbg(MODULE_FENCE, "fence wait ret %d\n", ret);
}
if (ret) {
if (xoffset != osd_ext_hw.pandata[index].x_start ||
yoffset != osd_ext_hw.pandata[index].y_start) {
diff_x = xoffset - osd_ext_hw.pandata[index].x_start;
diff_y = yoffset - osd_ext_hw.pandata[index].y_start;
osd_ext_hw.pandata[index].x_start += diff_x;
osd_ext_hw.pandata[index].x_end += diff_x;
osd_ext_hw.pandata[index].y_start += diff_y;
osd_ext_hw.pandata[index].y_end += diff_y;
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
}
}
if (ext_timeline_created) {
if (ret)
sw_sync_timeline_inc(ext_timeline, 1);
else
osd_log_err("------NOT signal out_fence ERROR\n");
}
osd_log_dbg(MODULE_FENCE, "offset[%d-%d]x[%d-%d]y[%d-%d]\n",
xoffset, yoffset, osd_ext_hw.pandata[index].x_start,
osd_ext_hw.pandata[index].x_end,
osd_ext_hw.pandata[index].y_start,
osd_ext_hw.pandata[index].y_end);
}
#endif
void osd_ext_pan_display_hw(u32 index, unsigned int xoffset,
unsigned int yoffset)
{
long diff_x, diff_y;
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
if (index >= 1)
#else
if (index >= 2)
#endif
return;
if (xoffset != osd_ext_hw.pandata[index].x_start ||
yoffset != osd_ext_hw.pandata[index].y_start) {
diff_x = xoffset - osd_ext_hw.pandata[index].x_start;
diff_y = yoffset - osd_ext_hw.pandata[index].y_start;
osd_ext_hw.pandata[index].x_start += diff_x;
osd_ext_hw.pandata[index].x_end += diff_x;
osd_ext_hw.pandata[index].y_start += diff_y;
osd_ext_hw.pandata[index].y_end += diff_y;
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
osd_log_info("offset[%d-%d]x[%d-%d]y[%d-%d]\n",
xoffset, yoffset,
osd_ext_hw.pandata[index].x_start,
osd_ext_hw.pandata[index].x_end,
osd_ext_hw.pandata[index].y_start,
osd_ext_hw.pandata[index].y_end);
}
}
void osd_ext_get_info(u32 index, u32 *addr, u32 *width, u32 *height)
{
*addr = osd_ext_hw.fb_gem[index].addr;
*width = osd_ext_hw.fb_gem[index].width;
*height = osd_ext_hw.fb_gem[index].height;
}
static void osd1_update_disp_scale_enable(void)
{
if (osd_ext_hw.scale[OSD1].h_enable)
osd_reg_set_mask(VIU2_OSD1_BLK0_CFG_W0, 3 << 12);
else
osd_reg_clr_mask(VIU2_OSD1_BLK0_CFG_W0, 3 << 12);
if (osd_ext_hw.scan_mode != SCAN_MODE_INTERLACE) {
if (osd_ext_hw.scale[OSD1].v_enable)
osd_reg_set_mask(VIU2_OSD1_BLK0_CFG_W0, 1 << 14);
else
osd_reg_clr_mask(VIU2_OSD1_BLK0_CFG_W0, 1 << 14);
}
}
static void osd2_update_disp_scale_enable(void)
{
if (osd_ext_hw.scale[OSD2].h_enable) {
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12);
#else
osd_reg_set_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12);
#endif
} else
osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12);
if (osd_ext_hw.scan_mode != SCAN_MODE_INTERLACE) {
if (osd_ext_hw.scale[OSD2].v_enable) {
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14);
#else
osd_reg_set_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14);
#endif
} else
osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14);
}
}
static void osd1_update_disp_freescale_enable(void)
{
int hf_phase_step, vf_phase_step;
int src_w, src_h, dst_w, dst_h;
int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
int hf_bank_len = 4;
int vf_bank_len = 4;
hsc_ini_rcv_num = hf_bank_len;
vsc_ini_rcv_num = vf_bank_len;
hsc_ini_rpt_p0_num = (hf_bank_len / 2 - 1) > 0 ?
(hf_bank_len / 2 - 1) : 0;
vsc_ini_rpt_p0_num = (vf_bank_len / 2 - 1) > 0 ?
(vf_bank_len / 2 - 1) : 0;
src_w = osd_ext_hw.free_src_data[OSD1].x_end -
osd_ext_hw.free_src_data[OSD1].x_start + 1;
src_h = osd_ext_hw.free_src_data[OSD1].y_end -
osd_ext_hw.free_src_data[OSD1].y_start + 1;
dst_w = osd_ext_hw.free_dst_data[OSD1].x_end -
osd_ext_hw.free_dst_data[OSD1].x_start + 1;
hf_phase_step = ((src_w + 1) << 18) / dst_w;
hf_phase_step = (hf_phase_step << 6);
dst_h = osd_ext_hw.free_dst_data[OSD1].y_end -
osd_ext_hw.free_dst_data[OSD1].y_start + 1;
vf_phase_step = ((src_h + 1) << 20) /
dst_h;
vf_phase_step = (vf_phase_step << 4);
osd_reg_set_bits(VPP2_OSD_SC_DUMMY_DATA, 0x00808000, 0, 32);
if (osd_ext_hw.free_scale_enable[OSD1]) {
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 1, 3, 1);
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, OSD1, 0, 2);
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 0, 4, 8);
} else
osd_reg_clr_mask(VPP2_OSD_SC_CTRL0, 1 << 3);
if (osd_ext_hw.free_scale_enable[OSD1]) {
osd_reg_set_bits(VPP2_OSD_SCI_WH_M1,
src_w, 16, 13);
osd_reg_set_bits(VPP2_OSD_SCI_WH_M1,
src_h, 0, 13);
osd_reg_set_bits(VPP2_OSD_SCO_H_START_END,
osd_ext_hw.free_dst_data[OSD1].x_start, 16, 12);
osd_reg_set_bits(VPP2_OSD_SCO_H_START_END,
osd_ext_hw.free_dst_data[OSD1].x_end, 0, 12);
osd_reg_set_bits(VPP2_OSD_SCO_V_START_END,
osd_ext_hw.free_dst_data[OSD1].y_start,
16, 12);
osd_reg_set_bits(VPP2_OSD_SCO_V_START_END,
osd_ext_hw.free_dst_data[OSD1].y_end, 0, 12);
}
if (osd_ext_hw.free_scale[OSD1].v_enable) {
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, vf_bank_len, 0, 3);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0,
vsc_ini_rcv_num, 3, 3);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0,
vsc_ini_rpt_p0_num, 8, 2);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, 1, 24, 1);
} else
osd_reg_clr_mask(VPP2_OSD_VSC_CTRL0, 1 << 24);
if (osd_ext_hw.free_scale[OSD1].h_enable) {
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, hf_bank_len, 0, 3);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0,
hsc_ini_rcv_num, 3, 3);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0,
hsc_ini_rpt_p0_num, 8, 2);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, 1, 22, 1);
} else
osd_reg_clr_mask(VPP2_OSD_HSC_CTRL0, 1 << 22);
if (osd_ext_hw.free_scale_enable[OSD1]) {
osd_reg_set_bits(VPP2_OSD_HSC_PHASE_STEP,
hf_phase_step, 0, 28);
osd_reg_set_bits(VPP2_OSD_HSC_INI_PHASE, 0, 0, 16);
osd_reg_set_bits(VPP2_OSD_VSC_PHASE_STEP,
vf_phase_step, 0, 28);
osd_reg_set_bits(VPP2_OSD_VSC_INI_PHASE, 0, 0, 16);
}
remove_from_update_list(OSD1, DISP_FREESCALE_ENABLE);
}
static void osd1_update_coef(void)
{
int hf_coef_idx = 0;
int vf_coef_idx = 0;
int *hf_coef, *vf_coef;
int i = 0;
int hf_coef_wren = 1;
int vf_coef_wren = 1;
if (vf_coef_idx == 0)
vf_coef = filt_coef0;
else if (vf_coef_idx == 1)
vf_coef = filt_coef1;
else if (vf_coef_idx == 2)
vf_coef = filt_coef2;
else
vf_coef = filt_coef0;
if (hf_coef_idx == 0)
hf_coef = filt_coef0;
else if (hf_coef_idx == 1)
hf_coef = filt_coef1;
else if (hf_coef_idx == 2)
hf_coef = filt_coef2;
else
hf_coef = filt_coef0;
if (vf_coef_wren) {
osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX,
0x0000, 0, 9);
for (i = 0; i < 33; i++)
osd_reg_write(VPP2_OSD_SCALE_COEF,
vf_coef[i]);
}
if (hf_coef_wren) {
osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX,
0x0100, 0, 9);
for (i = 0; i < 33; i++)
osd_reg_write(VPP2_OSD_SCALE_COEF, hf_coef[i]);
}
remove_from_update_list(OSD1, OSD_FREESCALE_COEF);
}
static void osd2_update_disp_freescale_enable(void)
{
int hf_phase_step, vf_phase_step;
int src_w, src_h, dst_w, dst_h;
int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
int hf_bank_len = 4;
int vf_bank_len = 4;
hsc_ini_rcv_num = hf_bank_len;
vsc_ini_rcv_num = vf_bank_len;
hsc_ini_rpt_p0_num = (hf_bank_len / 2 - 1) > 0 ?
(hf_bank_len / 2 - 1) : 0;
vsc_ini_rpt_p0_num = (vf_bank_len / 2 - 1) > 0 ?
(vf_bank_len / 2 - 1) : 0;
src_w = osd_ext_hw.free_src_data[OSD2].x_end -
osd_ext_hw.free_src_data[OSD2].x_start + 1;
src_h = osd_ext_hw.free_src_data[OSD2].y_end -
osd_ext_hw.free_src_data[OSD2].y_start + 1;
dst_w = osd_ext_hw.free_dst_data[OSD2].x_end -
osd_ext_hw.free_dst_data[OSD2].x_start + 1;
hf_phase_step =
((src_w + 1) << 18) / dst_w;
hf_phase_step = (hf_phase_step << 6);
dst_h = osd_ext_hw.free_dst_data[OSD2].y_end -
osd_ext_hw.free_dst_data[OSD2].y_start + 1;
vf_phase_step =
((src_h + 1) << 20) / dst_h;
vf_phase_step = (vf_phase_step << 4);
osd_reg_set_bits(VPP2_OSD_SC_DUMMY_DATA, 0x00808000, 0, 32);
if (osd_ext_hw.free_scale_enable[OSD2]) {
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 1, 3, 1);
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, OSD2, 0, 2);
osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 0, 4, 8);
} else
osd_reg_clr_mask(VPP2_OSD_SC_CTRL0, 1 << 3);
if (osd_ext_hw.free_scale_enable[OSD2]) {
osd_reg_set_bits(VPP2_OSD_SCI_WH_M1,
src_w, 16, 13);
osd_reg_set_bits(VPP2_OSD_SCI_WH_M1,
src_h, 0, 13);
osd_reg_set_bits(VPP2_OSD_SCO_H_START_END,
osd_ext_hw.free_dst_data[OSD2].x_start, 16, 12);
osd_reg_set_bits(VPP2_OSD_SCO_H_START_END,
osd_ext_hw.free_dst_data[OSD2].x_end, 0, 12);
osd_reg_set_bits(VPP2_OSD_SCO_V_START_END,
osd_ext_hw.free_dst_data[OSD2].y_start, 16, 12);
osd_reg_set_bits(VPP2_OSD_SCO_V_START_END,
osd_ext_hw.free_dst_data[OSD2].y_end, 0, 12);
}
if (osd_ext_hw.free_scale[OSD2].h_enable) {
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, hf_bank_len, 0, 3);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0,
hsc_ini_rcv_num, 3, 3);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0,
hsc_ini_rpt_p0_num, 8, 2);
osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, 1, 22, 1);
} else
osd_reg_clr_mask(VPP2_OSD_HSC_CTRL0, 1 << 22);
if (osd_ext_hw.free_scale[OSD2].v_enable) {
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, vf_bank_len, 0, 3);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0,
vsc_ini_rcv_num, 3, 3);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0,
vsc_ini_rpt_p0_num, 8, 2);
osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, 1, 24, 1);
} else
osd_reg_clr_mask(VPP2_OSD_VSC_CTRL0, 1 << 24);
if (osd_ext_hw.free_scale_enable[OSD2]) {
osd_reg_set_bits(VPP2_OSD_HSC_PHASE_STEP,
hf_phase_step, 0, 28);
osd_reg_set_bits(VPP2_OSD_HSC_INI_PHASE, 0, 0, 16);
osd_reg_set_bits(VPP2_OSD_VSC_PHASE_STEP,
vf_phase_step, 0, 28);
osd_reg_set_bits(VPP2_OSD_VSC_INI_PHASE, 0, 0, 16);
}
remove_from_update_list(OSD2, DISP_FREESCALE_ENABLE);
}
static void osd2_update_coef(void)
{
int hf_coef_idx = 0;
int vf_coef_idx = 0;
int *hf_coef, *vf_coef;
int i = 0;
int hf_coef_wren = 1;
int vf_coef_wren = 1;
if (vf_coef_idx == 0)
vf_coef = filt_coef0;
else if (vf_coef_idx == 1)
vf_coef = filt_coef1;
else if (vf_coef_idx == 2)
vf_coef = filt_coef2;
else
vf_coef = filt_coef0;
if (hf_coef_idx == 0)
hf_coef = filt_coef0;
else if (hf_coef_idx == 1)
hf_coef = filt_coef1;
else if (hf_coef_idx == 2)
hf_coef = filt_coef2;
else
hf_coef = filt_coef0;
if (vf_coef_wren) {
osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, 0x0000, 0, 9);
for (i = 0; i < 33; i++)
osd_reg_write(VPP2_OSD_SCALE_COEF, vf_coef[i]);
}
if (hf_coef_wren) {
osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, 0x0100, 0, 9);
for (i = 0; i < 33; i++)
osd_reg_write(VPP2_OSD_SCALE_COEF, hf_coef[i]);
}
remove_from_update_list(OSD2, OSD_FREESCALE_COEF);
}
static void osd1_update_color_mode(void)
{
u32 data32 = 0;
if (osd_ext_hw.color_info[OSD1] != NULL) {
data32 = (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0;
data32 |= osd_reg_read(VIU2_OSD1_BLK0_CFG_W0) & 0x30007040;
data32 |= osd_ext_hw.fb_gem[OSD1].canvas_idx << 16;
/* if (!osd_ext_hw.rotate[OSD1].on_off) */
data32 |= OSD_DATA_LITTLE_ENDIAN << 15;
data32 |= osd_ext_hw.color_info[OSD1]->hw_colormat << 2;
if (osd_ext_hw.color_info[OSD1]->color_index <
COLOR_INDEX_YUV_422)
data32 |= 1 << 7; /* rgb enable */
/* osd_ext_blk_mode */
data32 |= osd_ext_hw.color_info[OSD1]->hw_blkmode << 8;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, data32);
}
remove_from_update_list(OSD1, OSD_COLOR_MODE);
}
static void osd2_update_color_mode(void)
{
u32 data32 = 0;
if (osd_ext_hw.color_info[OSD2] != NULL) {
data32 = (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0;
data32 |= osd_reg_read(VIU2_OSD2_BLK0_CFG_W0) & 0x30007040;
data32 |= osd_ext_hw.fb_gem[OSD2].canvas_idx << 16;
/* if (!osd_ext_hw.rotate[OSD1].on_off) */
data32 |= OSD_DATA_LITTLE_ENDIAN << 15;
data32 |= osd_ext_hw.color_info[OSD2]->hw_colormat << 2;
if (osd_ext_hw.color_info[OSD2]->color_index <
COLOR_INDEX_YUV_422)
data32 |= 1 << 7; /* rgb enable */
/* osd_ext_blk_mode */
data32 |= osd_ext_hw.color_info[OSD2]->hw_blkmode << 8;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W0, data32);
}
remove_from_update_list(OSD2, OSD_COLOR_MODE);
}
static void osd1_update_enable(void)
{
if (osd_ext_hw.free_scale_mode[OSD1]) {
if (osd_ext_hw.enable[OSD1] == ENABLE) {
osd_reg_set_mask(VPP2_MISC, VPP_OSD1_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN);
} else
osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND);
} else {
u32 video_enable = 0;
video_enable |= osd_reg_read(VPP2_MISC) & VPP_VD1_PREBLEND;
if (osd_ext_hw.enable[OSD1] == ENABLE) {
if (osd_ext_hw.free_scale_enable[OSD1]) {
osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_OSD1_PREBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_VD1_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_PREBLEND_EN);
} else {
osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_PREBLEND);
if (!video_enable)
osd_reg_clr_mask(VPP2_MISC,
VPP_VD1_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_OSD1_POSTBLEND);
}
} else {
if (osd_ext_hw.free_scale_enable[OSD1])
osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_PREBLEND);
else
osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND);
}
}
remove_from_update_list(OSD1, OSD_ENABLE);
}
static void osd2_update_enable(void)
{
if (osd_ext_hw.free_scale_mode[OSD2]) {
if (osd_ext_hw.enable[OSD1] == ENABLE) {
osd_reg_set_mask(VPP2_MISC, VPP_OSD2_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN);
} else
osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND);
} else {
u32 video_enable = 0;
video_enable |= osd_reg_read(VPP2_MISC) & VPP_VD1_PREBLEND;
if (osd_ext_hw.enable[OSD2] == ENABLE) {
if (osd_ext_hw.free_scale_enable[OSD2]) {
osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_OSD2_PREBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_VD1_POSTBLEND);
} else {
osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_PREBLEND);
if (!video_enable)
osd_reg_clr_mask(VPP2_MISC,
VPP_VD1_POSTBLEND);
osd_reg_set_mask(VPP2_MISC, VPP_OSD2_POSTBLEND);
}
} else {
if (osd_ext_hw.free_scale_enable[OSD2])
osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_PREBLEND);
else
osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND);
}
}
remove_from_update_list(OSD2, OSD_ENABLE);
}
static void osd1_update_disp_osd_rotate(void)
{
remove_from_update_list(OSD1, DISP_OSD_ROTATE);
}
static void osd2_update_disp_osd_rotate(void)
{
remove_from_update_list(OSD2, DISP_OSD_ROTATE);
}
static void osd1_update_color_key(void)
{
osd_reg_write(VIU2_OSD1_TCOLOR_AG0, osd_ext_hw.color_key[OSD1]);
remove_from_update_list(OSD1, OSD_COLOR_KEY);
}
static void osd2_update_color_key(void)
{
osd_reg_write(VIU2_OSD2_TCOLOR_AG0, osd_ext_hw.color_key[OSD2]);
remove_from_update_list(OSD2, OSD_COLOR_KEY);
}
static void osd1_update_color_key_enable(void)
{
u32 data32;
data32 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0);
data32 &= ~(1 << 6);
data32 |= (osd_ext_hw.color_key_enable[OSD1] << 6);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, data32);
osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, data32);
remove_from_update_list(OSD1, OSD_COLOR_KEY_ENABLE);
}
static void osd2_update_color_key_enable(void)
{
u32 data32;
data32 = osd_reg_read(VIU2_OSD2_BLK0_CFG_W0);
data32 &= ~(1 << 6);
data32 |= (osd_ext_hw.color_key_enable[OSD2] << 6);
osd_reg_write(VIU2_OSD2_BLK0_CFG_W0, data32);
remove_from_update_list(OSD2, OSD_COLOR_KEY_ENABLE);
}
static void osd1_update_gbl_alpha(void)
{
u32 data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT);
data32 &= ~(0x1ff << 12);
data32 |= osd_ext_hw.gbl_alpha[OSD1] << 12;
osd_reg_write(VIU2_OSD1_CTRL_STAT, data32);
remove_from_update_list(OSD1, OSD_GBL_ALPHA);
}
static void osd2_update_gbl_alpha(void)
{
u32 data32 = osd_reg_read(VIU2_OSD2_CTRL_STAT);
data32 &= ~(0x1ff << 12);
data32 |= osd_ext_hw.gbl_alpha[OSD2] << 12;
osd_reg_write(VIU2_OSD2_CTRL_STAT, data32);
remove_from_update_list(OSD2, OSD_GBL_ALPHA);
}
static void osd2_update_order(void)
{
switch (osd_ext_hw.order) {
case OSD_ORDER_01:
osd_reg_clr_mask(VPP2_MISC,
VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
break;
case OSD_ORDER_10:
osd_reg_set_mask(VPP2_MISC,
VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
break;
default:
break;
}
remove_from_update_list(OSD2, OSD_CHANGE_ORDER);
}
static void osd1_update_order(void)
{
switch (osd_ext_hw.order) {
case OSD_ORDER_01:
osd_reg_clr_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
break;
case OSD_ORDER_10:
osd_reg_set_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
break;
default:
break;
}
remove_from_update_list(OSD1, OSD_CHANGE_ORDER);
}
#if 0
static void osd_ext_block_update_disp_geometry(u32 index)
{
u32 data32;
u32 data_w1, data_w2, data_w3, data_w4;
u32 coef[4][2] = { {0, 0}, {1, 0}, {0, 1}, {1, 1} };
u32 xoff, yoff;
u32 i;
switch (osd_ext_hw.block_mode[index] & HW_OSD_BLOCK_LAYOUT_MASK) {
case HW_OSD_BLOCK_LAYOUT_HORIZONTAL:
yoff = ((osd_ext_hw.pandata[index].y_end & 0x1fff) -
(osd_ext_hw.pandata[index].y_start & 0x1fff) + 1) >> 2;
data_w1 = (osd_ext_hw.pandata[index].x_start & 0x1fff) |
(osd_ext_hw.pandata[index].x_end & 0x1fff) << 16;
data_w3 = (osd_ext_hw.dispdata[index].x_start & 0xfff) |
(osd_ext_hw.dispdata[index].x_end & 0xfff) << 16;
for (i = 0; i < 4; i++) {
if (i == 3) {
data_w2 = ((osd_ext_hw.pandata[index].y_start +
yoff * i) & 0x1fff)
| (osd_ext_hw.pandata[index].y_end &
0x1fff) << 16;
data_w4 = ((osd_ext_hw.dispdata[index].y_start +
yoff * i) & 0xfff)
| (osd_ext_hw.dispdata[index].y_end &
0xfff) << 16;
} else {
data_w2 = ((osd_ext_hw.pandata[index].y_start +
yoff * i) & 0x1fff)
| ((osd_ext_hw.pandata[index].y_start
+ yoff * (i + 1) - 1) & 0x1fff) << 16;
data_w4 = ((osd_ext_hw.dispdata[index].y_start +
yoff * i) & 0xfff)
| ((osd_ext_hw.dispdata[index].y_start
+ yoff * (i + 1) - 1) & 0xfff) << 16;
}
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
data32 = data_w4;
data_w4 = ((data32 & 0xfff) >> 1) |
((((((data32 >> 16) & 0xfff) + 1) >>
1) - 1) << 16);
}
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4),
data_w1);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4),
data_w2);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4),
data_w3);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2),
data_w4);
osd_ext_hw.block_windows[index][i << 1] = data_w1;
osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2;
}
break;
case HW_OSD_BLOCK_LAYOUT_VERTICAL:
xoff = ((osd_ext_hw.pandata[index].x_end & 0x1fff) -
(osd_ext_hw.pandata[index].x_start & 0x1fff) + 1) >> 2;
data_w2 = (osd_ext_hw.pandata[index].y_start & 0x1fff) |
(osd_ext_hw.pandata[index].y_end & 0x1fff) << 16;
data_w4 = (osd_ext_hw.dispdata[index].y_start & 0xfff) |
(osd_ext_hw.dispdata[index].y_end & 0xfff) << 16;
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
data32 = data_w4;
data_w4 = ((data32 & 0xfff) >> 1) |
((((((data32 >> 16) & 0xfff) + 1) >> 1) - 1)
<< 16);
}
for (i = 0; i < 4; i++) {
data_w1 = ((osd_ext_hw.pandata[index].x_start +
xoff * i) & 0x1fff)
| ((osd_ext_hw.pandata[index].x_start +
xoff * (i + 1) - 1) & 0x1fff) << 16;
data_w3 = ((osd_ext_hw.dispdata[index].x_start +
xoff * i) & 0xfff)
| ((osd_ext_hw.dispdata[index].x_start +
xoff * (i + 1) - 1) & 0xfff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4),
data_w1);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4),
data_w2);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4),
data_w3);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2),
data_w4);
osd_ext_hw.block_windows[index][i << 1] = data_w1;
osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2;
}
break;
case HW_OSD_BLOCK_LAYOUT_GRID:
xoff = ((osd_ext_hw.pandata[index].x_end & 0x1fff) -
(osd_ext_hw.pandata[index].x_start & 0x1fff) + 1) >> 1;
yoff = ((osd_ext_hw.pandata[index].y_end & 0x1fff) -
(osd_ext_hw.pandata[index].y_start & 0x1fff) + 1) >> 1;
for (i = 0; i < 4; i++) {
data_w1 = ((osd_ext_hw.pandata[index].x_start +
xoff * coef[i][0]) & 0x1fff)
| ((osd_ext_hw.pandata[index].x_start +
xoff * (coef[i][0] + 1) - 1) & 0x1fff) << 16;
data_w2 = ((osd_ext_hw.pandata[index].y_start +
yoff * coef[i][1]) & 0x1fff)
| ((osd_ext_hw.pandata[index].y_start +
yoff * (coef[i][1] + 1) - 1) & 0x1fff) << 16;
data_w3 = ((osd_ext_hw.dispdata[index].x_start +
xoff * coef[i][0]) & 0xfff)
| ((osd_ext_hw.dispdata[index].x_start +
xoff * (coef[i][0] + 1) - 1) & 0xfff) << 16;
data_w4 = ((osd_ext_hw.dispdata[index].y_start +
yoff * coef[i][1]) & 0xfff)
| ((osd_ext_hw.dispdata[index].y_start +
yoff * (coef[i][1] + 1) - 1) & 0xfff) << 16;
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
data32 = data_w4;
data_w4 = ((data32 & 0xfff) >> 1) |
((((((data32 >> 16) & 0xfff) +
1) >> 1) - 1) << 16);
}
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4),
data_w1);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4),
data_w2);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4),
data_w3);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2),
data_w4);
osd_ext_hw.block_windows[index][i << 1] = data_w1;
osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2;
}
break;
case HW_OSD_BLOCK_LAYOUT_CUSTOMER:
for (i = 0; i < 4; i++) {
if (((osd_ext_hw.block_windows[index][i << 1] >> 16) &
0x1fff) > osd_ext_hw.pandata[index].x_end) {
osd_ext_hw.block_windows[index][i << 1] =
(osd_ext_hw.block_windows[index][i << 1] &
0x1fff)
| ((osd_ext_hw.pandata[index].x_end &
0x1fff) << 16);
}
data_w1 = osd_ext_hw.block_windows[index][i << 1] &
0x1fff1fff;
data_w2 = ((osd_ext_hw.pandata[index].y_start & 0x1fff)
+ (osd_ext_hw.block_windows[index][(i << 1) + 1] &
0x1fff))
| (((osd_ext_hw.pandata[index].y_start
& 0x1fff) << 16) +
(osd_ext_hw.block_windows[index][(i << 1) + 1]
& 0x1fff0000));
data_w3 = (osd_ext_hw.dispdata[index].x_start +
(data_w1 & 0xfff))
| (((osd_ext_hw.dispdata[index].x_start &
0xfff) << 16) + (data_w1 & 0xfff0000));
data_w4 = (osd_ext_hw.dispdata[index].y_start +
(osd_ext_hw.block_windows[index][(i << 1) + 1]
& 0xfff))
| (((osd_ext_hw.dispdata[index].y_start
& 0xfff) << 16) +
(osd_ext_hw.block_windows[index][(i << 1) + 1]
& 0xfff0000));
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
data32 = data_w4;
data_w4 = ((data32 & 0xfff) >> 1) |
((((((data32 >> 16) & 0xfff) + 1) >> 1)
- 1) << 16);
}
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4),
data_w1);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4),
data_w2);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4),
data_w3);
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2),
data_w4);
}
break;
default:
osd_log_err("ERROR block_mode: 0x%x\n",
osd_ext_hw.block_mode[index]);
break;
}
}
#endif
static void osd1_update_disp_geometry(void)
{
u32 dy0, sy0, sy1;
u32 data32;
/* enable osd multi block */
if (osd_ext_hw.block_mode[OSD1]) {
/* osd_ext_block_update_disp_geometry(OSD1);
* data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT);
* data32 &= 0xfffffff0;
* data32 |= (osd_ext_hw.block_mode[OSD1] &
* HW_OSD_BLOCK_ENABLE_MASK);
* osd_reg_write(VIU2_OSD1_CTRL_STAT, data32);
*/
osd_log_info(
"osd1_update_disp_geometry: not support block mode\n");
} else {
data32 = (osd_ext_hw.dispdata[OSD1].x_start & 0xfff) |
(osd_ext_hw.dispdata[OSD1].x_end & 0xfff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3, data32);
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE)
data32 = ((osd_ext_hw.dispdata[OSD1].y_start >>
1) & 0xfff)
| ((((osd_ext_hw.dispdata[OSD1].y_end +
1) >> 1) - 1) & 0xfff) << 16;
else
data32 = (osd_ext_hw.dispdata[OSD1].y_start &
0xfff)
| (osd_ext_hw.dispdata[OSD1].y_end &
0xfff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4, data32);
/* enable osd 2x scale */
if (osd_ext_hw.scale[OSD1].h_enable ||
osd_ext_hw.scale[OSD1].v_enable) {
data32 = (osd_ext_hw.scaledata[OSD1].x_start & 0x1fff) |
(osd_ext_hw.scaledata[OSD1].x_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32);
data32 = ((osd_ext_hw.scaledata[OSD1].y_start +
osd_ext_hw.pandata[OSD1].y_start) & 0x1fff)
| ((osd_ext_hw.scaledata[OSD1].y_end +
osd_ext_hw.pandata[OSD1].y_start) & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32);
/* adjust display x-axis */
if (osd_ext_hw.scale[OSD1].h_enable) {
data32 = (osd_ext_hw.dispdata[OSD1].x_start
& 0xfff)
| ((osd_ext_hw.dispdata[OSD1].x_start +
(osd_ext_hw.scaledata[OSD1].x_end -
osd_ext_hw.scaledata[OSD1].x_start) *
2 + 1) & 0xfff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W3, data32);
}
/* adjust display y-axis */
dy0 = osd_ext_hw.dispdata[OSD1].y_start;
sy0 = osd_ext_hw.scaledata[OSD1].y_start;
sy1 = osd_ext_hw.scaledata[OSD1].y_end;
if (osd_ext_hw.scale[OSD1].v_enable) {
if (osd_ext_hw.scan_mode ==
SCAN_MODE_INTERLACE) {
data32 = ((dy0 >> 1) & 0xfff)
| (((((dy0 + (sy1 - sy0) * 2)
+ 1) >> 1) - 1) & 0xfff) << 16;
} else {
data32 = (dy0 & 0xfff)
| (((dy0 + (sy1 - sy0) * 2))
& 0xfff) << 16;
}
osd_reg_write(VIU2_OSD1_BLK0_CFG_W4, data32);
}
} else if (osd_ext_hw.free_scale_enable[OSD1]
&& (osd_ext_hw.free_src_data[OSD1].x_end > 0)
&& (osd_ext_hw.free_src_data[OSD1].y_end > 0)) {
/* enable osd free scale */
data32 = (osd_ext_hw.free_src_data[OSD1].x_start
& 0x1fff)
| (osd_ext_hw.free_src_data[OSD1].x_end
& 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32);
data32 = ((osd_ext_hw.free_src_data[OSD1].y_start +
osd_ext_hw.pandata[OSD1].y_start) & 0x1fff)
| ((osd_ext_hw.free_src_data[OSD1].y_end +
osd_ext_hw.pandata[OSD1].y_start)
& 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32);
} else {
/* normal mode */
data32 =
(osd_ext_hw.pandata[OSD1].x_start & 0x1fff) |
(osd_ext_hw.pandata[OSD1].x_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32);
data32 =
(osd_ext_hw.pandata[OSD1].y_start & 0x1fff) |
(osd_ext_hw.pandata[OSD1].y_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32);
}
data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT);
data32 &= 0xfffffff0;
data32 |= HW_OSD_BLOCK_ENABLE_0;
osd_reg_write(VIU2_OSD1_CTRL_STAT, data32);
}
remove_from_update_list(OSD1, DISP_GEOMETRY);
}
static void osd2_update_disp_geometry(void)
{
u32 data32;
data32 = (osd_ext_hw.dispdata[OSD2].x_start & 0xfff) |
(osd_ext_hw.dispdata[OSD2].x_end & 0xfff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W3, data32);
if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) {
data32 = ((osd_ext_hw.dispdata[OSD2].y_start >> 1) & 0xfff)
| ((((osd_ext_hw.dispdata[OSD2].y_end + 1) >> 1) - 1)
& 0xfff) << 16;
} else
data32 = (osd_ext_hw.dispdata[OSD2].y_start & 0xfff) |
(osd_ext_hw.dispdata[OSD2].y_end & 0xfff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W4, data32);
if (osd_ext_hw.scale[OSD2].h_enable ||
osd_ext_hw.scale[OSD2].v_enable) {
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
data32 = (osd_ext_hw.pandata[OSD2].x_start & 0x1fff) |
(osd_ext_hw.pandata[OSD2].x_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32);
data32 = (osd_ext_hw.pandata[OSD2].y_start & 0x1fff) |
(osd_ext_hw.pandata[OSD2].y_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32);
#else
data32 =
(osd_ext_hw.scaledata[OSD2].x_start & 0x1fff) |
(osd_ext_hw.scaledata[OSD2].x_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32);
data32 = ((osd_ext_hw.scaledata[OSD2].y_start +
osd_ext_hw.pandata[OSD2].y_start) & 0x1fff)
| ((osd_ext_hw.scaledata[OSD2].y_end +
osd_ext_hw.pandata[OSD2].y_start)
& 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32);
#endif
} else {
data32 = (osd_ext_hw.pandata[OSD2].x_start & 0x1fff) |
(osd_ext_hw.pandata[OSD2].x_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32);
data32 = (osd_ext_hw.pandata[OSD2].y_start & 0x1fff) |
(osd_ext_hw.pandata[OSD2].y_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32);
}
remove_from_update_list(OSD2, DISP_GEOMETRY);
}
static void osd1_update_disp_3d_mode(void)
{
/*step 1 . set pan data */
u32 data32;
if (osd_ext_hw.mode_3d[OSD1].left_right == OSD_LEFT) {
data32 = (osd_ext_hw.mode_3d[OSD1].l_start & 0x1fff) |
(osd_ext_hw.mode_3d[OSD1].l_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32);
} else {
data32 = (osd_ext_hw.mode_3d[OSD1].r_start & 0x1fff) |
(osd_ext_hw.mode_3d[OSD1].r_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32);
}
osd_ext_hw.mode_3d[OSD1].left_right ^= 1;
}
static void osd2_update_disp_3d_mode(void)
{
u32 data32;
if (osd_ext_hw.mode_3d[OSD2].left_right == OSD_LEFT) {
data32 = (osd_ext_hw.mode_3d[OSD2].l_start & 0x1fff) |
(osd_ext_hw.mode_3d[OSD2].l_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32);
} else {
data32 = (osd_ext_hw.mode_3d[OSD2].r_start & 0x1fff) |
(osd_ext_hw.mode_3d[OSD2].r_end & 0x1fff) << 16;
osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32);
}
osd_ext_hw.mode_3d[OSD2].left_right ^= 1;
}
void osd_ext_init_hw(u32 logo_loaded)
{
u32 group, idx, data32;
for (group = 0; group < HW_OSD_COUNT; group++)
for (idx = 0; idx < HW_REG_INDEX_MAX; idx++)
osd_ext_hw.reg[group][idx].update_func =
hw_func_array[group][idx];
osd_ext_hw.updated[OSD1] = 0;
osd_ext_hw.updated[OSD2] = 0;
/* here we will init default value ,these value only set once . */
if (!logo_loaded) {
data32 = 1; /* Set DDR request priority to be urgent */
data32 |= 4 << 5; /* hold_fifo_lines */
data32 |= 3 << 10; /* burst_len_sel: 3=64 */
data32 |= 32 << 12; /* fifo_depth_val: 32*8=256 */
osd_reg_write(VIU2_OSD1_FIFO_CTRL_STAT, data32);
osd_reg_write(VIU2_OSD2_FIFO_CTRL_STAT, data32);
osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN);
osd_reg_clr_mask(VPP2_MISC, VPP_PREBLEND_EN);
osd_reg_clr_mask(VPP2_MISC,
VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND);
data32 = 0x1 << 0; /* osd_ext_blk_enable */
data32 |= OSD_GLOBAL_ALPHA_DEF << 12;
data32 |= (1 << 21);
osd_reg_write(VIU2_OSD1_CTRL_STAT, data32);
osd_reg_write(VIU2_OSD2_CTRL_STAT, data32);
}
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
osd_reg_set_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
osd_ext_hw.order = OSD_ORDER_10;
#else
osd_reg_clr_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
osd_ext_hw.order = OSD_ORDER_01;
#endif
osd_ext_hw.enable[OSD2] = osd_ext_hw.enable[OSD1] = DISABLE;
osd_ext_hw.fb_gem[OSD1].canvas_idx = OSD3_CANVAS_INDEX;
osd_ext_hw.fb_gem[OSD2].canvas_idx = OSD4_CANVAS_INDEX;
osd_ext_hw.gbl_alpha[OSD1] = OSD_GLOBAL_ALPHA_DEF;
osd_ext_hw.gbl_alpha[OSD2] = OSD_GLOBAL_ALPHA_DEF;
osd_ext_hw.color_info[OSD1] = NULL;
osd_ext_hw.color_info[OSD2] = NULL;
/* TODO */
/* vf.width = vf.height = 0; */
osd_ext_hw.color_key[OSD1] = osd_ext_hw.color_key[OSD2] = 0xffffffff;
osd_ext_hw.free_scale_enable[OSD1] = 0;
osd_ext_hw.free_scale_enable[OSD2] = 0;
osd_ext_hw.scale[OSD1].h_enable = osd_ext_hw.scale[OSD1].v_enable = 0;
osd_ext_hw.scale[OSD2].h_enable = osd_ext_hw.scale[OSD2].v_enable = 0;
osd_ext_hw.mode_3d[OSD2].enable = osd_ext_hw.mode_3d[OSD1].enable = 0;
osd_ext_hw.block_mode[OSD1] = osd_ext_hw.block_mode[OSD2] = 0;
/*
* osd_ext_hw.rotation_pandata[OSD1].x_start =
* osd_ext_hw.rotation_pandata[OSD1].y_start = 0;
* osd_ext_hw.rotation_pandata[OSD2].x_start =
* osd_ext_hw.rotation_pandata[OSD2].y_start = 0;
* memset(osd_ext_hw.rotate, 0, sizeof(struct osd_rotate_s));
*/
osd_get_hw_para(&osd_hw);
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
INIT_LIST_HEAD(&ext_post_fence_list);
mutex_init(&ext_post_fence_list_lock);
#endif
#ifdef FIQ_VSYNC
osd_ext_hw.fiq_handle_item.handle = vsync_isr;
osd_ext_hw.fiq_handle_item.key = (u32) vsync_isr;
osd_ext_hw.fiq_handle_item.name = "osd_ext_vsync";
if (register_fiq_bridge_handle(&osd_ext_hw.fiq_handle_item))
#else
if (request_irq(INT_VIU2_VSYNC, &vsync_isr, IRQF_SHARED,
"osd_ext_vsync", osd_ext_setup))
#endif
osd_log_err("can't request irq for vsync\n");
#ifdef FIQ_VSYNC
request_fiq(INT_VIU2_VSYNC, &osd_ext_fiq_isr);
#endif
}
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
void osd_ext_cursor_hw(s16 x, s16 y, s16 xstart, s16 ystart, u32 osd_ext_w,
u32 osd_ext_h, int index)
{
struct pandata_s disp_tmp;
if (index != 1)
return;
memcpy(&disp_tmp, &osd_ext_hw.dispdata[OSD1], sizeof(struct pandata_s));
if (osd_ext_hw.scale[OSD2].h_enable &&
(osd_ext_hw.scaledata[OSD2].x_start > 0)
&& (osd_ext_hw.scaledata[OSD2].x_end > 0)) {
x = x * osd_ext_hw.scaledata[OSD2].x_end /
osd_ext_hw.scaledata[OSD2].x_start;
if (osd_ext_hw.scaledata[OSD2].x_end >
osd_ext_hw.scaledata[OSD2].x_start) {
disp_tmp.x_start =
osd_ext_hw.dispdata[OSD1].x_start *
osd_ext_hw.scaledata[OSD2].x_end /
osd_ext_hw.scaledata[OSD2].x_start;
disp_tmp.x_end =
osd_ext_hw.dispdata[OSD1].x_end *
osd_ext_hw.scaledata[OSD2].x_end /
osd_ext_hw.scaledata[OSD2].x_start;
}
}
if (osd_ext_hw.scale[OSD2].v_enable &&
(osd_ext_hw.scaledata[OSD2].y_start > 0)
&& (osd_ext_hw.scaledata[OSD2].y_end > 0)) {
y = y * osd_ext_hw.scaledata[OSD2].y_end /
osd_ext_hw.scaledata[OSD2].y_start;
if (osd_ext_hw.scaledata[OSD2].y_end >
osd_ext_hw.scaledata[OSD2].y_start) {
disp_tmp.y_start =
osd_ext_hw.dispdata[OSD1].y_start *
osd_ext_hw.scaledata[OSD2].y_end /
osd_ext_hw.scaledata[OSD2].y_start;
disp_tmp.y_end =
osd_ext_hw.dispdata[OSD1].y_end *
osd_ext_hw.scaledata[OSD2].y_end /
osd_ext_hw.scaledata[OSD2].y_start;
}
}
x += xstart;
y += ystart;
/**
* Use pandata to show a partial cursor when it is at the edge
* because the registers can't have negative values and because we
* need to manually clip the cursor when it is past the edge.
* The edge is hardcoded to the OSD0 area.
*/
osd_ext_hw.dispdata[OSD2].x_start = x;
osd_ext_hw.dispdata[OSD2].y_start = y;
if (x < disp_tmp.x_start) {
/* if negative position, set osd to 0,y and pan. */
if ((disp_tmp.x_start - x) < osd_ext_w) {
osd_ext_hw.pandata[OSD2].x_start = disp_tmp.x_start - x;
osd_ext_hw.pandata[OSD2].x_end = osd_ext_w - 1;
}
osd_ext_hw.dispdata[OSD2].x_start = 0;
} else {
osd_ext_hw.pandata[OSD2].x_start = 0;
if (x + osd_ext_w > disp_tmp.x_end) {
/*
* if past positive edge,
* set osd to inside of the edge and pan.
*/
if (x < osd_ext_hw.dispdata[OSD1].x_end)
osd_ext_hw.pandata[OSD2].x_end =
disp_tmp.x_end - x;
} else
osd_ext_hw.pandata[OSD2].x_end = osd_ext_w - 1;
}
if (y < disp_tmp.y_start) {
if ((disp_tmp.y_start - y) < osd_ext_h) {
osd_ext_hw.pandata[OSD2].y_start = disp_tmp.y_start - y;
osd_ext_hw.pandata[OSD2].y_end = osd_ext_h - 1;
}
osd_ext_hw.dispdata[OSD2].y_start = 0;
} else {
osd_ext_hw.pandata[OSD2].y_start = 0;
if (y + osd_ext_h > disp_tmp.y_end) {
if (y < disp_tmp.y_end)
osd_ext_hw.pandata[OSD2].y_end =
disp_tmp.y_end - y;
} else
osd_ext_hw.pandata[OSD2].y_end = osd_ext_h - 1;
}
osd_ext_hw.dispdata[OSD2].x_end =
osd_ext_hw.dispdata[OSD2].x_start +
osd_ext_hw.pandata[OSD2].x_end -
osd_ext_hw.pandata[OSD2].x_start;
osd_ext_hw.dispdata[OSD2].y_end =
osd_ext_hw.dispdata[OSD2].y_start +
osd_ext_hw.pandata[OSD2].y_end -
osd_ext_hw.pandata[OSD2].y_start;
add_to_update_list(OSD2, DISP_GEOMETRY);
}
#endif /* CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR */
void osd_ext_suspend_hw(void)
{
osd_ext_hw.reg_status_save =
osd_reg_read(VPP2_MISC) & OSD_RELATIVE_BITS;
osd_reg_clr_mask(VPP2_MISC, OSD_RELATIVE_BITS);
osd_log_info("osd_ext_suspended\n");
}
void osd_ext_resume_hw(void)
{
osd_reg_set_mask(VPP2_MISC, osd_ext_hw.reg_status_save);
osd_log_info("osd_ext_resumed\n");
}
void osd_ext_clone_pan(u32 index)
{
s32 offset = 0;
s32 height_osd0 = 0;
s32 height_osd2 = 0;
u32 py0, py1;
height_osd0 = osd_hw->pandata[index].y_end -
osd_hw->pandata[index].y_start + 1;
height_osd2 = osd_ext_hw.pandata[index].y_end -
osd_ext_hw.pandata[index].y_start + 1;
py0 = osd_ext_hw.pandata[index].y_start;
py1 = osd_ext_hw.pandata[index].y_end;
if (osd_ext_hw.clone[index]) {
if (py0 < height_osd0) {
if (py0 >= height_osd2)
offset -= py1 - py0 + 1;
else
offset = 0;
} else {
if (py0 < height_osd2)
offset += py1 - py0 + 1;
else
offset = 0;
}
osd_ext_hw.pandata[index].y_start += offset;
osd_ext_hw.pandata[index].y_end += offset;
py0 = osd_ext_hw.pandata[index].y_start;
if (osd_ext_hw.angle[index])
osd_ext_clone_update_pan(py0 ? 1 : 0);
add_to_update_list(index, DISP_GEOMETRY);
osd_ext_wait_vsync_hw();
}
}
void osd_ext_get_angle_hw(u32 index, u32 *angle)
{
osd_log_info("get osd_ext[%d]->angle: %d\n",
index, osd_ext_hw.angle[index]);
*angle = osd_ext_hw.angle[index];
}
void osd_ext_set_angle_hw(u32 index, u32 angle)
{
#ifndef OSD_EXT_GE2D_CLONE_SUPPORT
osd_log_info("++ osd_clone depends on GE2D module!\n");
return;
#endif
if (angle > 4) {
osd_log_err("++ invalid angle: %d\n", angle);
return;
}
if (osd_ext_hw.clone[index] == 0) {
osd_log_info("++ set osd_ext[%d]->angle: %d->%d\n", index,
osd_ext_hw.angle[index], angle);
osd_ext_clone_set_angle(angle);
osd_ext_hw.angle[index] = angle;
} else if (!((osd_ext_hw.angle[index] == 0) || (angle == 0))) {
osd_log_info("++ set osd_ext[%d]->angle: %d->%d\n", index,
osd_ext_hw.angle[index], angle);
osd_ext_clone_set_angle(angle);
osd_ext_hw.angle[index] = angle;
osd_ext_clone_pan(index);
}
}
void osd_ext_get_clone_hw(u32 index, u32 *clone)
{
osd_log_info("get osd_ext[%d]->clone: %d\n",
index, osd_ext_hw.clone[index]);
*clone = osd_ext_hw.clone[index];
}
void osd_ext_set_clone_hw(u32 index, u32 clone)
{
static const struct color_bit_define_s *color_info[HW_OSD_COUNT] = {};
static struct pandata_s pandata[HW_OSD_COUNT] = {};
osd_log_info("++ set osd_ext[%d]->clone: %d->%d\n", index,
osd_ext_hw.clone[index], clone);
osd_ext_hw.clone[index] = clone;
if (osd_ext_hw.clone[index]) {
if (osd_ext_hw.angle[index]) {
osd_ext_hw.color_info[index] =
osd_hw->color_info[index];
osd_ext_clone_task_start();
} else {
color_info[index] = osd_ext_hw.color_info[index];
osd_ext_hw.color_info[index] =
osd_hw->color_info[index];
memcpy(&pandata, &osd_ext_hw.pandata[index],
sizeof(struct pandata_s));
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
if (cpu_type != MESON_CPU_MAJOR_ID_AXG)
canvas_update_addr(
osd_ext_hw.fb_gem[index].canvas_idx,
osd_hw->fb_gem[index].addr);
#endif
}
} else {
if (osd_ext_hw.angle[index])
osd_ext_clone_task_stop();
else {
color_info[index] = osd_ext_hw.color_info[index];
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
if (cpu_type != MESON_CPU_MAJOR_ID_AXG)
canvas_update_addr(
osd_ext_hw.fb_gem[index].canvas_idx,
osd_ext_hw.fb_gem[index].addr);
#endif
osd_ext_hw.color_info[index] = color_info[index];
memcpy(&osd_ext_hw.pandata[index], &pandata,
sizeof(struct pandata_s));
}
}
add_to_update_list(index, OSD_COLOR_MODE);
}