blob: 723ffa2d466d29522cf0ff16ecee7b2f7f3f1298 [file] [log] [blame]
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#ifdef MSM_BSP
#include <linux/msm_mdp.h>
#include <linux/msm_ion.h>
#endif
#include <pixelflinger/pixelflinger.h>
#include "minui.h"
#define MDP_V4_0 400
#ifdef MSM_BSP
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
typedef struct {
unsigned char *mem_buf;
int size;
int ion_fd;
int mem_fd;
struct ion_handle_data handle_data;
} memInfo;
//Left and right overlay id
static int overlayL_id = MSMFB_NEW_REQUEST;
static int overlayR_id = MSMFB_NEW_REQUEST;
static memInfo mem_info;
static int map_mdp_pixel_format()
{
int format = MDP_RGB_565;
#if defined(RECOVERY_BGRA)
format = MDP_BGRA_8888;
#elif defined(RECOVERY_RGBA)
format = MDP_RGBA_8888;
#elif defined(RECOVERY_RGBX)
format = MDP_RGBA_8888;
#endif
return format;
}
static bool overlay_supported = false;
static bool isMDP5 = false;
bool target_has_overlay(char *version)
{
int mdp_version;
if (strlen(version) >= 8) {
if(!strncmp(version, "msmfb", strlen("msmfb"))) {
char str_ver[4];
memcpy(str_ver, version + strlen("msmfb"), 3);
str_ver[3] = '\0';
mdp_version = atoi(str_ver);
if (mdp_version >= MDP_V4_0) {
overlay_supported = true;
}
} else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) {
overlay_supported = true;
isMDP5 = true;
}
}
if (overlay_supported) printf("Using qcomm overlay\n");
return overlay_supported;
}
bool isTargetMdp5()
{
if (isMDP5)
return true;
return false;
}
int free_ion_mem(void) {
if (!overlay_supported)
return -EINVAL;
int ret = 0;
if (mem_info.mem_buf)
munmap(mem_info.mem_buf, mem_info.size);
if (mem_info.ion_fd >= 0) {
ret = ioctl(mem_info.ion_fd, ION_IOC_FREE, &mem_info.handle_data);
if (ret < 0)
perror("free_mem failed ");
}
if (mem_info.mem_fd >= 0)
close(mem_info.mem_fd);
if (mem_info.ion_fd >= 0)
close(mem_info.ion_fd);
memset(&mem_info, 0, sizeof(mem_info));
mem_info.mem_fd = -1;
mem_info.ion_fd = -1;
return 0;
}
int alloc_ion_mem(unsigned int size)
{
if (!overlay_supported)
return -EINVAL;
int result;
struct ion_fd_data fd_data;
struct ion_allocation_data ionAllocData;
mem_info.ion_fd = open("/dev/ion", O_RDWR|O_DSYNC);
if (mem_info.ion_fd < 0) {
perror("ERROR: Can't open ion ");
return -errno;
}
ionAllocData.flags = 0;
ionAllocData.len = size;
ionAllocData.align = sysconf(_SC_PAGESIZE);
#ifdef NEW_ION_HEAP
ionAllocData.heap_id_mask =
#else
ionAllocData.heap_mask =
#endif
ION_HEAP(ION_IOMMU_HEAP_ID) |
ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID);
result = ioctl(mem_info.ion_fd, ION_IOC_ALLOC, &ionAllocData);
if(result){
perror("ION_IOC_ALLOC Failed ");
close(mem_info.ion_fd);
return result;
}
fd_data.handle = ionAllocData.handle;
mem_info.handle_data.handle = ionAllocData.handle;
result = ioctl(mem_info.ion_fd, ION_IOC_MAP, &fd_data);
if (result) {
perror("ION_IOC_MAP Failed ");
free_ion_mem();
return result;
}
mem_info.mem_buf = (unsigned char *)mmap(NULL, size, PROT_READ |
PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
mem_info.mem_fd = fd_data.fd;
if (!mem_info.mem_buf) {
perror("ERROR: mem_buf MAP_FAILED ");
free_ion_mem();
return -ENOMEM;
}
return 0;
}
int allocate_overlay(int fd, GGLSurface gr_fb[])
{
int ret = 0;
if (!overlay_supported)
return -EINVAL;
if (!isDisplaySplit()) {
// Check if overlay is already allocated
if (MSMFB_NEW_REQUEST == overlayL_id) {
struct mdp_overlay overlayL;
memset(&overlayL, 0 , sizeof (struct mdp_overlay));
/* Fill Overlay Data */
overlayL.src.width = ALIGN(gr_fb[0].width, 32);
overlayL.src.height = gr_fb[0].height;
overlayL.src.format = map_mdp_pixel_format();
overlayL.src_rect.w = gr_fb[0].width;
overlayL.src_rect.h = gr_fb[0].height;
overlayL.dst_rect.w = gr_fb[0].width;
overlayL.dst_rect.h = gr_fb[0].height;
overlayL.alpha = 0xFF;
overlayL.transp_mask = MDP_TRANSP_NOP;
overlayL.id = MSMFB_NEW_REQUEST;
ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
if (ret < 0) {
perror("Overlay Set Failed");
return ret;
}
overlayL_id = overlayL.id;
}
} else {
float xres = getFbXres();
int lSplit = getLeftSplit();
float lSplitRatio = lSplit / xres;
float lCropWidth = gr_fb[0].width * lSplitRatio;
int lWidth = lSplit;
int rWidth = gr_fb[0].width - lSplit;
int height = gr_fb[0].height;
if (MSMFB_NEW_REQUEST == overlayL_id) {
struct mdp_overlay overlayL;
memset(&overlayL, 0 , sizeof (struct mdp_overlay));
/* Fill OverlayL Data */
overlayL.src.width = ALIGN(gr_fb[0].width, 32);
overlayL.src.height = gr_fb[0].height;
overlayL.src.format = map_mdp_pixel_format();
overlayL.src_rect.x = 0;
overlayL.src_rect.y = 0;
overlayL.src_rect.w = lCropWidth;
overlayL.src_rect.h = gr_fb[0].height;
overlayL.dst_rect.x = 0;
overlayL.dst_rect.y = 0;
overlayL.dst_rect.w = lWidth;
overlayL.dst_rect.h = height;
overlayL.alpha = 0xFF;
overlayL.transp_mask = MDP_TRANSP_NOP;
overlayL.id = MSMFB_NEW_REQUEST;
ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
if (ret < 0) {
perror("OverlayL Set Failed");
return ret;
}
overlayL_id = overlayL.id;
}
if (MSMFB_NEW_REQUEST == overlayR_id) {
struct mdp_overlay overlayR;
memset(&overlayR, 0 , sizeof (struct mdp_overlay));
/* Fill OverlayR Data */
overlayR.src.width = ALIGN(gr_fb[0].width, 32);
overlayR.src.height = gr_fb[0].height;
overlayR.src.format = map_mdp_pixel_format();
overlayR.src_rect.x = lCropWidth;
overlayR.src_rect.y = 0;
overlayR.src_rect.w = gr_fb[0].width - lCropWidth;
overlayR.src_rect.h = gr_fb[0].height;
overlayR.dst_rect.x = 0;
overlayR.dst_rect.y = 0;
overlayR.dst_rect.w = rWidth;
overlayR.dst_rect.h = height;
overlayR.alpha = 0xFF;
overlayR.flags = MDSS_MDP_RIGHT_MIXER;
overlayR.transp_mask = MDP_TRANSP_NOP;
overlayR.id = MSMFB_NEW_REQUEST;
ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR);
if (ret < 0) {
perror("OverlayR Set Failed");
return ret;
}
overlayR_id = overlayR.id;
}
}
return 0;
}
int free_overlay(int fd)
{
if (!overlay_supported)
return -EINVAL;
int ret = 0;
struct mdp_display_commit ext_commit;
if (!isDisplaySplit()) {
if (overlayL_id != MSMFB_NEW_REQUEST) {
ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
if (ret) {
perror("Overlay Unset Failed");
overlayL_id = MSMFB_NEW_REQUEST;
return ret;
}
}
} else {
if (overlayL_id != MSMFB_NEW_REQUEST) {
ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
if (ret) {
perror("OverlayL Unset Failed");
overlayL_id = MSMFB_NEW_REQUEST;
return ret;
}
}
if (overlayR_id != MSMFB_NEW_REQUEST) {
ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id);
if (ret) {
perror("OverlayR Unset Failed");
overlayR_id = MSMFB_NEW_REQUEST;
return ret;
}
}
}
memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
ext_commit.wait_for_finish = 1;
ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
if (ret < 0) {
perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!");
overlayL_id = MSMFB_NEW_REQUEST;
overlayR_id = MSMFB_NEW_REQUEST;
return ret;
}
overlayL_id = MSMFB_NEW_REQUEST;
overlayR_id = MSMFB_NEW_REQUEST;
return 0;
}
int overlay_display_frame(int fd, GGLubyte* data, size_t size)
{
if (!overlay_supported)
return -EINVAL;
int ret = 0;
struct msmfb_overlay_data ovdataL, ovdataR;
struct mdp_display_commit ext_commit;
if (!isDisplaySplit()) {
if (overlayL_id == MSMFB_NEW_REQUEST) {
perror("display_frame failed, no overlay\n");
return -EINVAL;
}
memcpy(mem_info.mem_buf, data, size);
memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
ovdataL.id = overlayL_id;
ovdataL.data.flags = 0;
ovdataL.data.offset = 0;
ovdataL.data.memory_id = mem_info.mem_fd;
ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
if (ret < 0) {
perror("overlay_display_frame failed, overlay play Failed\n");
return ret;
}
} else {
if (overlayL_id == MSMFB_NEW_REQUEST) {
perror("display_frame failed, no overlayL \n");
return -EINVAL;
}
memcpy(mem_info.mem_buf, data, size);
memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
ovdataL.id = overlayL_id;
ovdataL.data.flags = 0;
ovdataL.data.offset = 0;
ovdataL.data.memory_id = mem_info.mem_fd;
ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
if (ret < 0) {
perror("overlay_display_frame failed, overlayL play Failed\n");
return ret;
}
if (overlayR_id == MSMFB_NEW_REQUEST) {
perror("display_frame failed, no overlayR \n");
return -EINVAL;
}
memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data));
ovdataR.id = overlayR_id;
ovdataR.data.flags = 0;
ovdataR.data.offset = 0;
ovdataR.data.memory_id = mem_info.mem_fd;
ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataR);
if (ret < 0) {
perror("overlay_display_frame failed, overlayR play Failed\n");
return ret;
}
}
memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
ext_commit.wait_for_finish = 1;
ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
if (ret < 0) {
perror("overlay_display_frame failed, overlay commit Failed\n!");
}
return ret;
}
#else
bool target_has_overlay(char *version) {
return false;
}
bool isTargetMdp5() {
return false;
}
int free_ion_mem(void) {
return -EINVAL;
}
int alloc_ion_mem(unsigned int size)
{
return -EINVAL;
}
int allocate_overlay(int fd, GGLSurface gr_fb[])
{
return -EINVAL;
}
int free_overlay(int fd)
{
return -EINVAL;
}
int overlay_display_frame(int fd, GGLubyte* data, size_t size)
{
return -EINVAL;
}
#endif //#ifdef MSM_BSP