blob: 65ce4f44f4d55454aa6236449813112eedba4214 [file] [log] [blame]
/*
* drivers/amlogic/media/osd/osd_logo.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/string.h>
#include <linux/ctype.h>
#include <linux/delay.h>
/* Amlogic Headers */
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
/* Local Headers */
#include "osd_hw.h"
#include "osd_log.h"
#include "osd.h"
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static DEFINE_MUTEX(logo_lock);
struct para_pair_s {
char *name;
int value;
};
static struct para_pair_s logo_args[] = {
{"osd0", LOGO_DEV_OSD0},
{"osd1", LOGO_DEV_OSD1},
{"viu2_osd0", LOGO_DEV_VIU2_OSD0},
{"debug", LOGO_DEBUG},
{"loaded", LOGO_LOADED},
};
struct logo_info_s {
int index;
u32 vmode;
u32 debug;
u32 loaded;
u32 fb_width;
u32 fb_height;
} logo_info = {
.index = -1,
.vmode = VMODE_MAX,
.debug = 0,
.loaded = 0,
.fb_width = 1920,
.fb_height = 1080,
};
static int get_value_by_name(char *name, struct para_pair_s *pair, u32 cnt)
{
u32 i = 0;
int found = -1;
for (i = 0; i < cnt; i++, pair++) {
if (strcmp(pair->name, name) == 0) {
found = pair->value;
break;
}
}
return found;
}
static int logo_info_init(char *para)
{
u32 count = 0;
int value = -1;
count = sizeof(logo_args) / sizeof(logo_args[0]);
value = get_value_by_name(para, logo_args, count);
if (value >= 0) {
switch (value) {
case LOGO_DEV_OSD0:
logo_info.index = LOGO_DEV_OSD0;
break;
case LOGO_DEV_OSD1:
logo_info.index = LOGO_DEV_OSD1;
break;
case LOGO_DEV_VIU2_OSD0:
logo_info.index = LOGO_DEV_VIU2_OSD0;
break;
case LOGO_DEBUG:
logo_info.debug = 1;
break;
case LOGO_LOADED:
logo_info.loaded = 1;
break;
default:
break;
}
return 0;
}
return 0;
}
static int str2lower(char *str)
{
while (*str != '\0') {
*str = tolower(*str);
str++;
}
return 0;
}
static int __init logo_setup(char *str)
{
char *ptr = str;
char sep[2];
char *option;
int count = 5;
char find = 0;
if (str == NULL)
return -EINVAL;
do {
/* search for a delimiter */
if (!isalpha(*ptr) && !isdigit(*ptr) && (*ptr != '_')) {
find = 1;
break;
}
} while (*++ptr != '\0');
if (!find)
return -EINVAL;
logo_info.index = -1;
logo_info.debug = 0;
logo_info.loaded = 0;
logo_info.vmode = VMODE_MAX;
sep[0] = *ptr;
sep[1] = '\0';
while ((count--) && (option = strsep(&str, sep))) {
pr_info("%s\n", option);
str2lower(option);
logo_info_init(option);
}
return 0;
}
static int __init get_logo_width(char *str)
{
int ret;
ret = kstrtoint(str, 0, &logo_info.fb_width);
pr_info("logo_info.fb_width=%d\n", logo_info.fb_width);
return 0;
}
static int __init get_logo_height(char *str)
{
int ret;
ret = kstrtoint(str, 0, &logo_info.fb_height);
pr_info("logo_info.fb_height=%d\n", logo_info.fb_height);
return 0;
}
int set_osd_logo_freescaler(void)
{
const struct vinfo_s *vinfo;
u32 index = logo_info.index;
s32 src_x_start = 0, src_x_end = 0;
s32 src_y_start = 0, src_y_end = 0;
s32 dst_x_start = 0, dst_x_end = 0;
s32 dst_y_start = 0, dst_y_end = 0;
s32 target_x_end = 0, target_y_end = 0;
if (logo_info.loaded == 0 || logo_info.index < 0)
return 0;
if (osd_get_logo_index() != logo_info.index) {
pr_info("logo changed, return!\n");
return -1;
}
if ((osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE) && (index >= 1))
return -1;
/* for dual logo,
* if viu1 interface(such as hdmi) is unplugged when booting.
* the viu2 display device will be used for viu1 after booting.
*/
if (osd_hw.osd_meson_dev.has_viu2)
if (index >= LOGO_DEV_VIU2_OSD0)
index = LOGO_DEV_OSD0;
if (osd_get_position_from_reg(
index,
&src_x_start, &src_x_end,
&src_y_start, &src_y_end,
&dst_x_start, &dst_x_end,
&dst_y_start, &dst_y_end))
return -1;
vinfo = get_current_vinfo();
if (vinfo) {
target_x_end = vinfo->width - 1;
target_y_end = vinfo->height - 1;
} else {
target_x_end = 1919;
target_y_end = 1079;
}
if ((src_x_start == 0)
&& (src_x_end == (logo_info.fb_width - 1))
&& (src_y_start == 0)
&& (src_y_end == (logo_info.fb_height - 1))
&& (dst_x_start == 0)
&& (dst_x_end == target_x_end)
&& (dst_y_start == 0)
&& (dst_y_end == target_y_end))
return 0;
if (vinfo)
pr_info("outputmode changed to %s, reset osd%d, (%d, %d, %d, %d) -> (%d, %d, %d, %d)\n",
vinfo->name, index,
dst_x_start, dst_y_start, dst_x_end, dst_y_end,
0, 0, target_x_end, target_y_end);
else
pr_info("outputmode changed to NULL, reset osd%d, (%d, %d, %d, %d) -> (%d, %d, %d, %d)\n",
index,
dst_x_start, dst_y_start, dst_x_end, dst_y_end,
0, 0, target_x_end, target_y_end);
osd_set_free_scale_mode_hw(index, 1);
osd_set_free_scale_enable_hw(index, 0);
osd_set_free_scale_axis_hw(index, 0, 0,
logo_info.fb_width - 1, logo_info.fb_height - 1);
osd_update_disp_axis_hw(index, 0, logo_info.fb_width - 1,
0, logo_info.fb_height - 1, 0, 0, 0);
osd_set_window_axis_hw(index, 0, 0, target_x_end, target_y_end);
osd_set_free_scale_enable_hw(index, 0x10001);
osd_enable_hw(index, 1);
return 0;
}
int get_logo_loaded(void)
{
return logo_info.loaded;
}
void set_logo_loaded(void)
{
logo_info.loaded = 0;
}
__setup("logo=", logo_setup);
__setup("fb_width=", get_logo_width);
__setup("fb_height=", get_logo_height);
int logo_work_init(void)
{
if (logo_info.loaded == 0)
return -1;
osd_set_logo_index(logo_info.index);
return 0;
}