| /* |
| * 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 |
| } |