blob: 9f891ba8d76efbc7e731abfbbbb6cd2bbb21c54a [file] [log] [blame]
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc. All rights reserved.
* Copyright 2017 NXP
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gstimxcommon.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#ifdef USE_ION
#include <linux/ion.h>
#endif
/* define rotate and flip glib enum for overlaysink and imxv4l2sink */
static const GEnumValue rotate_methods[] = {
{GST_IMX_ROTATION_0, "no rotation", "none"},
{GST_IMX_ROTATION_90, "Rotate clockwise 90 degrees", "rotate-90"},
{GST_IMX_ROTATION_180, "Rotate clockwise 180 degrees", "rotate-180"},
{GST_IMX_ROTATION_270, "Rotate clockwise 270 degrees", "rotate-270"},
{GST_IMX_ROTATION_HFLIP, "Flip horizontally", "horizontal-flip"},
{GST_IMX_ROTATION_VFLIP, "Flip vertically", "vertically-flip"},
{0, NULL, NULL}
};
GType
gst_imx_rotate_method_get_type()
{
static GType rotate_method_type = 0;
static volatile gsize once = 0;
if (g_once_init_enter (&once)) {
rotate_method_type = g_enum_register_static ("GstImxRotateMethod",
rotate_methods);
g_once_init_leave (&once, rotate_method_type);
}
return rotate_method_type;
}
/*=============================================================================
FUNCTION: get_chipname
DESCRIPTION: To get chipname from /proc/cpuinfo
ARGUMENTS PASSED: STR of chipname
RETURN VALUE: chip code
=============================================================================*/
//*
static CPU_INFO cpu_info[] = {
{CC_MX23, 0x23},
{CC_MX25, 0x25},
{CC_MX27, 0x27},
{CC_MX28, 0x28},
{CC_MX31, 0x31},
{CC_MX35, 0x35},
{CC_MX37, 0x37},
{CC_MX50, 0x50},
{CC_MX51, 0x51},
{CC_MX53, 0x53},
{CC_MX6Q, 0x61},
{CC_MX6Q, 0x63},
{CC_MX60, 0x60}
};
CHIP_CODE getChipCodeFromCpuinfo (void)
{
FILE *fp = NULL;
char buf[100], *p, *rev;
char chip_name[3];
int len = 0, i;
int chip_num = -1;
CHIP_CODE cc = CC_UNKN;
fp = fopen ("/proc/cpuinfo", "r");
if (fp == NULL) {
return cc;
}
while (!feof (fp)) {
p = fgets (buf, 100, fp);
p = strstr (buf, "Revision");
if (p != NULL) {
rev = index (p, ':');
if (rev != NULL) {
rev++;
chip_num = strtoul (rev, NULL, 16);
chip_num >>= 12;
break;
}
}
}
fclose (fp);
if (chip_num < 0) {
return cc;
}
int num = sizeof(cpu_info) / sizeof(CPU_INFO);
for(i=0; i<num; i++) {
if(chip_num == cpu_info[i].chip_num) {
cc = cpu_info[i].code;
break;
}
}
return cc;
}
static SOC_INFO soc_info[] = {
{CC_MX23, "i.MX23"},
{CC_MX25, "i.MX25"},
{CC_MX27, "i.MX27"},
{CC_MX28, "i.MX28"},
{CC_MX31, "i.MX31"},
{CC_MX35, "i.MX35"},
{CC_MX37, "i.MX37"},
{CC_MX50, "i.MX50"},
{CC_MX51, "i.MX51"},
{CC_MX53, "i.MX53"},
{CC_MX6Q, "i.MX6DL"},
{CC_MX6Q, "i.MX6Q"},
{CC_MX6Q, "i.MX6QP"},
{CC_MX6SL, "i.MX6SL"},
{CC_MX6SLL, "i.MX6SLL"},
{CC_MX6SX, "i.MX6SX"},
{CC_MX6UL, "i.MX6UL"},
{CC_MX6UL, "i.MX6ULL"},
{CC_MX7D, "i.MX7D"},
{CC_MX7ULP, "i.MX7ULP"},
{CC_MX8, "i.MX8DV"},
{CC_MX8QM, "i.MX8QM"},
{CC_MX8QXP, "i.MX8QXP"},
{CC_MX8M, "i.MX8MQ"},
};
CHIP_CODE getChipCodeFromSocid (void)
{
FILE *fp = NULL;
char soc_name[100];
CHIP_CODE code = CC_UNKN;
fp = fopen("/sys/devices/soc0/soc_id", "r");
if (fp == NULL) {
g_print("open /sys/devices/soc0/soc_id failed.\n");
return CC_UNKN;
}
if (fscanf(fp, "%100s", soc_name) != 1) {
g_print("fscanf soc_id failed.\n");
fclose(fp);
return CC_UNKN;
}
fclose(fp);
//GST_INFO("SOC is %s\n", soc_name);
int num = sizeof(soc_info) / sizeof(SOC_INFO);
int i;
for(i=0; i<num; i++) {
if(!strcmp(soc_name, soc_info[i].name)) {
code = soc_info[i].code;
break;
}
}
return code;
}
#define KERN_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c))
static CHIP_CODE gimx_chip_code = CC_UNKN;
CHIP_CODE imx_chip_code (void)
{
struct utsname sys_name;
int kv, kv_major, kv_minor, kv_rel;
char soc_name[255];
int rev_major, rev_minor;
int idx, num;
if (gimx_chip_code != CC_UNKN)
return gimx_chip_code;
if (uname(&sys_name) < 0) {
g_print("get kernel version via uname failed.\n");
return CC_UNKN;
}
if (sscanf(sys_name.release, "%d.%d.%d", &kv_major, &kv_minor, &kv_rel) != 3) {
g_print("sscanf kernel version failed.\n");
return CC_UNKN;
}
kv = ((kv_major << 16) + (kv_minor << 8) + kv_rel);
//GST_INFO("kernel:%s, %d.%d.%d\n", sys_name.release, kv_major, kv_minor, kv_rel);
if (kv < KERN_VER(3, 10, 0))
gimx_chip_code = getChipCodeFromCpuinfo();
else
gimx_chip_code = getChipCodeFromSocid();
return gimx_chip_code;
}
static IMXV4l2FeatureMap g_imxv4l2feature_maps[] = {
/* chip_name, g3d, g2d, ipu, pxp, vpu, dpu, dcss*/
{CC_MX6Q, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE},
{CC_MX6SL, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE},
{CC_MX6SLL, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE},
{CC_MX6SX, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE},
{CC_MX6UL, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE},
{CC_MX7D, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE},
{CC_MX7ULP, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE},
{CC_MX8, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE},
{CC_MX8QM, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE},
{CC_MX8QXP, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE},
{CC_MX8M, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE},
};
gboolean check_feature(CHIP_CODE chip_name, CHIP_FEATURE feature)
{
int i;
gboolean ret = FALSE;
for (i=0; i<sizeof(g_imxv4l2feature_maps)/sizeof(IMXV4l2FeatureMap); i++) {
if ( chip_name== g_imxv4l2feature_maps[i].chip_name) {
switch (feature) {
case G3D:
ret = g_imxv4l2feature_maps[i].g3d;
break;
case G2D:
ret = g_imxv4l2feature_maps[i].g2d;
break;
case IPU:
ret = g_imxv4l2feature_maps[i].ipu;
break;
case PXP:
ret = g_imxv4l2feature_maps[i].pxp;
break;
case VPU:
ret = g_imxv4l2feature_maps[i].vpu;
break;
case DPU:
ret = g_imxv4l2feature_maps[i].dpu;
break;
case DCSS:
ret = g_imxv4l2feature_maps[i].dcss;
break;
default:
break;
}
break;
}
}
return ret;
}
const char *dev_ion = "/dev/ion";
unsigned long phy_addr_from_fd(int dmafd)
{
#ifdef USE_ION
int ret, fd;
if (dmafd < 0)
return NULL;
fd = open(dev_ion, O_RDWR);
if(fd < 0) {
return NULL;
}
struct ion_phys_dma_data data = {
.phys = 0,
.size = 0,
.dmafd = dmafd,
};
struct ion_custom_data custom = {
.cmd = ION_IOC_PHYS_DMA,
.arg = (unsigned long)&data,
};
ret = ioctl(fd, ION_IOC_CUSTOM, &custom);
close(fd);
if (ret < 0)
return NULL;
return data.phys;
#else
return NULL;
#endif
}
unsigned long phy_addr_from_vaddr(void *vaddr, int size)
{
#ifdef USE_ION
int ret, fd;
if (!vaddr)
return NULL;
fd = open(dev_ion, O_RDWR);
if(fd < 0) {
return NULL;
}
struct ion_phys_virt_data data = {
.virt = (unsigned long)vaddr,
.phys = 0,
.size = size,
};
struct ion_custom_data custom = {
.cmd = ION_IOC_PHYS_VIRT,
.arg = (unsigned long)&data,
};
ret = ioctl(fd, ION_IOC_CUSTOM, &custom);
close(fd);
if (ret < 0)
return NULL;
return data.phys;
#else
return NULL;
#endif
}