MTK 平台lcm驱动框架分析1

           



          源码路径:

             kernel-3.18/arch/arm/boot/dts/mt6580.dtsi

              kernel-3.18/drivers/misc/mediatek/video/common/mtkfb.c

             kernel-3.18/drivers/misc/mediatek/video/mt6580/primary_display.c

             kernel-3.18/drivers/misc/mediatek/video/mt6580/disp_lcm.c

             kernel-3.18/drivers/misc/mediatek/lcm/mt65xx_lcm_list.c

           kernel-3.18/drivers/misc/mediatek/lcm/s6d77a1a01_fwvga_dsi_vdo/s6d77a1a01_fwvga_dsi_vdo.c(这个因IC而异)

一、 添加DTS节点

         

mtkfb: mtkfb@0 {
    compatible = "mediatek,mtkfb";
};

二、mtkfb驱动

/*
 * Copyright (C) 2015 MediaTek Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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.
 */

#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/suspend.h>
#include <linux/of_fdt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/dma-buf.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
#include <linux/io.h>
#include <mt-plat/dma.h>
#include <linux/compat.h>
#include <linux/dma-mapping.h>
#if defined(COMMON_DISP_LOG)
#include "disp_log.h"
#include "disp_debug.h"
#include "disp_recorder.h"
#include "mtkfb_debug.h"
#else
#include "debug.h"
#include "ddp_log.h"
#include "disp_drv_log.h"
#include "display_recorder.h"
#endif

#include "disp_assert_layer.h"
#include "ddp_hal.h"
#include "disp_lcm.h"
#include "mtkfb.h"
#include "mtkfb_console.h"
#include "mtkfb_fence.h"
#include "mtkfb_info.h"
#include "ddp_ovl.h"
#include "disp_drv_platform.h"
#include "primary_display.h"
#include "ddp_dump.h"
#include "fbconfig_kdebug.h"
#include "ddp_manager.h"
#include "mtk_ovl.h"
#include "ion_drv.h"
#include "ddp_drv.h"
#ifdef DISP_GPIO_DTS
#include "disp_dts_gpio.h" /* set gpio via DTS */
#endif
#include "disp_helper.h"

#define ALIGN_TO(x, n)	(((x) + ((n) - 1)) & ~((n) - 1))


/* xuecheng, remove this because we use session now */
/* mtk_dispif_info_t dispif_info[MTKFB_MAX_DISPLAY_COUNT]; */

struct notifier_block pm_nb;
unsigned int EnableVSyncLog = 0;

static u32 MTK_FB_XRES;
static u32 MTK_FB_YRES;
static u32 MTK_FB_BPP;
static u32 MTK_FB_PAGES;
static u32 fb_xres_update;
static u32 fb_yres_update;
static bool no_update;

#define MTK_FB_XRESV (ALIGN_TO(MTK_FB_XRES, MTK_FB_ALIGNMENT))
#define MTK_FB_YRESV (MTK_FB_YRES * MTK_FB_PAGES)	/* For page flipping */
#define MTK_FB_BYPP  ((MTK_FB_BPP + 7) >> 3)
#define MTK_FB_LINE  (ALIGN_TO(MTK_FB_XRES, MTK_FB_ALIGNMENT) * MTK_FB_BYPP)
#define MTK_FB_SIZE  (MTK_FB_LINE * MTK_FB_YRES)

#define MTK_FB_SIZEV (MTK_FB_LINE * MTK_FB_YRES * MTK_FB_PAGES)

#define CHECK_RET(expr)			\
	do {				\
		int ret = (expr);	\
		ASSERT(0 == ret);	\
	} while (0)


static size_t mtkfb_log_on = true;
#define MTKFB_LOG(fmt, arg...)					\
	do {							\
		if (mtkfb_log_on)				\
			pr_debug("DISP/MTKFB " fmt, ##arg);	\
	} while (0)

/* always show this debug info while the global debug log is off */
#define MTKFB_LOG_DBG(fmt, arg...) \
	do { \
		if (!mtkfb_log_on) \
			DISPMSG(fmt, ##arg); \
	} while (0)

#define MTKFB_FUNC()	\
	do { \
		if (mtkfb_log_on) \
			DISPMSG("[Func]%s\n", __func__); \
	} while (0)

#define PRNWARN(fmt, args...)  pr_warn("DISP/MTKFB " fmt, ##args)
#define PRNERR(fmt, args...)  pr_err("DISP/MTKFB " fmt, ##args)

void mtkfb_log_enable(int enable)
{
	mtkfb_log_on = enable;
	MTKFB_LOG("mtkfb log %s\n", enable ? "enabled" : "disabled");
}

/* --------------------------------------------------------------------------- */
/* local variables */
/* --------------------------------------------------------------------------- */

unsigned long fb_pa = 0;

static const struct timeval FRAME_INTERVAL = { 0, 30000 };	/* 33ms */

atomic_t has_pending_update = ATOMIC_INIT(0);
struct fb_overlay_layer video_layerInfo;
uint32_t dbr_backup = 0;
uint32_t dbg_backup = 0;
uint32_t dbb_backup = 0;
bool fblayer_dither_needed = false;
bool is_ipoh_bootup = false;
struct fb_info *mtkfb_fbi;
struct fb_overlay_layer fb_layer_context;
mtk_dispif_info_t dispif_info[MTKFB_MAX_DISPLAY_COUNT];
unsigned int FB_LAYER = 2;
bool is_early_suspended = false;
char mtkfb_lcm_name[256] = { 0 };
/**
 * This mutex is used to prevent tearing due to page flipping when adbd is
 * reading the front buffer
 */
DEFINE_SEMAPHORE(sem_flipping);
DEFINE_SEMAPHORE(sem_early_suspend);
DEFINE_SEMAPHORE(sem_overlay_buffer);

DEFINE_MUTEX(OverlaySettingMutex);
atomic_t OverlaySettingDirtyFlag = ATOMIC_INIT(0);
atomic_t OverlaySettingApplied = ATOMIC_INIT(0);
unsigned int PanDispSettingPending = 0;
unsigned int PanDispSettingDirty = 0;
unsigned int PanDispSettingApplied = 0;

DECLARE_WAIT_QUEUE_HEAD(reg_update_wq);

unsigned int need_esd_check = 0;
DECLARE_WAIT_QUEUE_HEAD(esd_check_wq);

/* extern unsigned int disp_running; */
/* extern wait_queue_head_t disp_done_wq; */

DEFINE_MUTEX(ScreenCaptureMutex);

static int sem_flipping_cnt = 1;
static int sem_early_suspend_cnt = 1;
static int vsync_cnt;

/* extern BOOL is_engine_in_suspend_mode; */
/* extern BOOL is_lcm_in_suspend_mode; */

/* --------------------------------------------------------------------------- */
/* local function declarations */
/* --------------------------------------------------------------------------- */

static int init_framebuffer(struct fb_info *info);
static int mtkfb_get_overlay_layer_info(struct fb_overlay_layer_info *layerInfo);


/* --------------------------------------------------------------------------- */
/* Timer Routines */
/* --------------------------------------------------------------------------- */
unsigned int lcd_fps = 6000;
wait_queue_head_t screen_update_wq;


/*
 * ---------------------------------------------------------------------------
 * fbdev framework callbacks and the ioctl interface
 * ---------------------------------------------------------------------------
 */
/* Called each time the mtkfb device is opened */
static int mtkfb_open(struct fb_info *info, int user)
{
	/* NOT_REFERENCED(info); */
	/* NOT_REFERENCED(user); */
	/* DISPFUNC();*/
	DISPMSG("%s\n", __func__);
	MSG_FUNC_ENTER();
	MSG_FUNC_LEAVE();
	return 0;
}

/* Called when the mtkfb device is closed. We make sure that any pending
 * gfx DMA operations are ended, before we return. */
static int mtkfb_release(struct fb_info *info, int user)
{

	/* NOT_REFERENCED(info); */
	/* NOT_REFERENCED(user); */
	DISPFUNC();

	MSG_FUNC_ENTER();
	MSG_FUNC_LEAVE();
	return 0;
}

/* Store a single color palette entry into a pseudo palette or the hardware
 * palette if one is available. For now we support only 16bpp and thus store
 * the entry only to the pseudo palette.
 */
static int mtkfb_setcolreg(u_int regno, u_int red, u_int green,
			   u_int blue, u_int transp, struct fb_info *info)
{
	int r = 0;
	unsigned bpp, m;

	/* NOT_REFERENCED(transp); */

	MSG_FUNC_ENTER();

	bpp = info->var.bits_per_pixel;
	m = 1 << bpp;
	if (regno >= m) {
		r = -EINVAL;
		goto exit;
	}

	switch (bpp) {
	case 16:
		/* RGB 565 */
		((u32 *) (info->pseudo_palette))[regno] =
		    ((red & 0xF800) | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11));
		break;
	case 32:
		/* ARGB8888 */
		((u32 *) (info->pseudo_palette))[regno] =
		    (0xff000000) |
		    ((red & 0xFF00) << 8) | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
		break;

		/* TODO: RGB888, BGR888, ABGR8888 */

	default:
		ASSERT(0);
	}

exit:
	MSG_FUNC_LEAVE();
	return r;
}

int mtkfb_set_backlight_level(unsigned int level)
{
	MTKFB_FUNC();
	DISPMSG("mtkfb_set_backlight_level:%d Start\n", level);
	primary_display_setbacklight(level);
	DISPMSG("mtkfb_set_backlight_level End\n");
	return 0;
}
EXPORT_SYMBOL(mtkfb_set_backlight_level);

int mtkfb_set_backlight_mode(unsigned int mode)
{
	MTKFB_FUNC();
	if (down_interruptible(&sem_flipping)) {
		DISPERR("[FB Driver] can't get semaphore:%d\n", __LINE__);
		return -ERESTARTSYS;
	}
	sem_flipping_cnt--;
	if (down_interruptible(&sem_early_suspend)) {
		DISPERR("[FB Driver] can't get semaphore:%d\n", __LINE__);
		sem_flipping_cnt++;
		up(&sem_flipping);
		return -ERESTARTSYS;
	}

	sem_early_suspend_cnt--;
	if (primary_display_is_sleepd())
		goto End;

	/* DISP_SetBacklight_mode(mode); */
End:
	sem_flipping_cnt++;
	sem_early_suspend_cnt++;
	up(&sem_early_suspend);
	up(&sem_flipping);
	return 0;
}
EXPORT_SYMBOL(mtkfb_set_backlight_mode);

int mtkfb_set_backlight_pwm(int div)
{
	MTKFB_FUNC();
	if (down_interruptible(&sem_flipping)) {
		DISPERR("[FB Driver] can't get semaphore:%d\n", __LINE__);
		return -ERESTARTSYS;
	}
	sem_flipping_cnt--;
	if (down_interruptible(&sem_early_suspend)) {
		DISPERR("[FB Driver] can't get semaphore:%d\n", __LINE__);
		sem_flipping_cnt++;
		up(&sem_flipping);
		return -ERESTARTSYS;
	}
	sem_early_suspend_cnt--;
	if (primary_display_is_sleepd())
		goto End;
	/* DISP_SetPWM(div); */
End:
	sem_flipping_cnt++;
	sem_early_suspend_cnt++;
	up(&sem_early_suspend);
	up(&sem_flipping);
	return 0;
}
EXPORT_SYMBOL(mtkfb_set_backlight_pwm);

int mtkfb_get_backlight_pwm(int div, unsigned int *freq)
{
	/* DISP_GetPWM(div, freq); */
	return 0;
}
EXPORT_SYMBOL(mtkfb_get_backlight_pwm);

void mtkfb_waitVsync(void)
{
	if (primary_display_is_sleepd()) {
		DISPMSG("[MTKFB_VSYNC]:mtkfb has suspend, return directly\n");
		msleep(20);
		return;
	}
	vsync_cnt++;
#ifdef CONFIG_FPGA_EARLY_PORTING
	msleep(20);
#else
	primary_display_wait_for_vsync(NULL);
#endif
	vsync_cnt--;
}
EXPORT_SYMBOL(mtkfb_waitVsync);

static int _convert_fb_layer_to_disp_input(struct fb_overlay_layer *src, disp_input_config *dst)
{
	dst->layer_id = src->layer_id;
	dst->dirty_roi_num = 0;
	if (!src->layer_enable) {
		dst->layer_enable = 0;
		return 0;
	}

	switch (src->src_fmt) {
	case MTK_FB_FORMAT_YUV422:
		dst->src_fmt = DISP_FORMAT_YUV422;
		break;

	case MTK_FB_FORMAT_RGB565:
		dst->src_fmt = DISP_FORMAT_RGB565;
		break;

	case MTK_FB_FORMAT_RGB888:
		dst->src_fmt = DISP_FORMAT_RGB888;
		break;

	case MTK_FB_FORMAT_BGR888:
		dst->src_fmt = DISP_FORMAT_BGR888;
		break;

	case MTK_FB_FORMAT_ARGB8888:
		dst->src_fmt = DISP_FORMAT_ARGB8888;
		break;

	case MTK_FB_FORMAT_ABGR8888:
		dst->src_fmt = DISP_FORMAT_ABGR8888;
		break;

	case MTK_FB_FORMAT_XRGB8888:
		dst->src_fmt = DISP_FORMAT_XRGB8888;
		break;

	case MTK_FB_FORMAT_XBGR8888:
		dst->src_fmt = DISP_FORMAT_XBGR8888;
		break;

	case MTK_FB_FORMAT_UYVY:
		dst->src_fmt = DISP_FORMAT_UYVY;
		break;

	case MTK_FB_FORMAT_BGRA8888:
		dst->src_fmt = DISP_FORMAT_BGRA8888;
		break;

	case MTK_FB_FORMAT_RGBX8888:
		dst->src_fmt = DISP_FORMAT_RGBX8888;
		break;

	default:
		DISPERR("Invalid color format: 0x%x\n", src->src_fmt);
		return -1;
	}

	dst->src_base_addr = src->src_base_addr;
	dst->security = src->security;
	dst->src_phy_addr = src->src_phy_addr;
	DISPMSG("_convert_fb_layer_to_disp_input, dst->addr=0x%08lx\n",
		(unsigned long)(dst->src_phy_addr));

	dst->isTdshp = src->isTdshp;
	dst->next_buff_idx = src->next_buff_idx;
	dst->identity = src->identity;
	dst->connected_type = src->connected_type;

	/* set Alpha blending */
	dst->alpha = src->alpha;
	if (MTK_FB_FORMAT_ARGB8888 == src->src_fmt || MTK_FB_FORMAT_ABGR8888 == src->src_fmt)
		dst->alpha_enable = true;
	else
		dst->alpha_enable = false;


	/* set src width, src height */
	dst->src_offset_x = src->src_offset_x;
	dst->src_offset_y = src->src_offset_y;
	dst->src_width = src->src_width;
	dst->src_height = src->src_height;
	dst->tgt_offset_x = src->tgt_offset_x;
	dst->tgt_offset_y = src->tgt_offset_y;
	dst->tgt_width = src->tgt_width;
	dst->tgt_height = src->tgt_height;
	if (dst->tgt_width > dst->src_width)
		dst->tgt_width = dst->src_width;
	if (dst->tgt_height > dst->src_height)
		dst->tgt_height = dst->src_height;

	dst->src_pitch = src->src_pitch;

	/* set color key */
	dst->src_color_key = src->src_color_key;
	dst->src_use_color_key = src->src_use_color_key;

	/* data transferring is triggerred in MTKFB_TRIG_OVERLAY_OUT */
	dst->layer_enable = src->layer_enable;

#if 1
	DISPMSG("_convert_fb_layer_to_disp_input():id=%u, en=%u, next_idx=%u, vaddr=%p, paddr=%p,\n",
		dst->layer_id, dst->layer_enable, dst->next_buff_idx, dst->src_base_addr, dst->src_phy_addr);
	DISPMSG("src fmt=%u, dst fmt=%u, pitch=%u, xoff=%u, yoff=%u, w=%u, h=%u\n",
		src->src_fmt, dst->src_fmt, dst->src_pitch, dst->src_offset_x,
		dst->src_offset_y, dst->src_width, dst->src_height);
	DISPMSG("_convert_fb_layer_to_disp_input():target xoff=%u, target yoff=%u, target w=%u, target h=%u, aen=%u\n",
		dst->tgt_offset_x, dst->tgt_offset_y, dst->tgt_width, dst->tgt_height,
		dst->alpha_enable);
#endif

	return 0;
}

static int mtkfb_pan_display_impl(struct fb_var_screeninfo *var, struct fb_info *info)
{
	uint32_t offset = 0;
	uint32_t paStart = 0;
	char *vaStart = NULL, *vaEnd = NULL;
	int ret = 0;
	unsigned int src_pitch = 0;
	disp_session_input_config *session_input;
	disp_input_config *input;

	/* DISPFUNC(); */

	if (no_update) {
		DISPMSG("FB_ACTIVATE_NO_UPDATE flag found, ignore mtkfb_pan_display_impl\n");
		no_update = false;
		return ret;
	}

	DISPMSG("pan_display: offset(%u,%u), res(%u,%u), resv(%u,%u)\n",
		var->xoffset, var->yoffset, info->var.xres, info->var.yres, info->var.xres_virtual,
		info->var.yres_virtual);

	info->var.yoffset = var->yoffset;
	offset = var->yoffset * info->fix.line_length;
	paStart = fb_pa + offset;
	vaStart = info->screen_base + offset;
	vaEnd = vaStart + info->var.yres * info->fix.line_length;

	session_input = kzalloc(sizeof(*session_input), GFP_KERNEL);
	if (!session_input)
		ASSERT(0);

	/* pan display use layer 0 */
	input = &session_input->config[0];
	input->layer_id = 0;
	input->src_phy_addr = (void *)((unsigned long)paStart);
	input->src_base_addr = (void *)((unsigned long)vaStart);
	input->layer_id = primary_display_get_option("FB_LAYER");
	input->layer_enable = 1;
	input->src_offset_x = 0;
	input->src_offset_y = 0;
	input->src_width = var->xres;
	input->src_height = var->yres;
	input->tgt_offset_x = 0;
	input->tgt_offset_y = 0;
	input->tgt_width = var->xres;
	input->tgt_height = var->yres;

	switch (var->bits_per_pixel) {
	case 16:
		input->src_fmt = DISP_FORMAT_RGB565;
		break;
	case 24:
		input->src_fmt = DISP_FORMAT_RGB888;
		break;
	case 32:
		input->src_fmt = (0 == var->blue.offset) ? DISP_FORMAT_BGRA8888 : DISP_FORMAT_RGBX8888;
		br
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
mtk平台lcd驱动框架详解可以从Mtkfb.c文件开始解释。在该文件中,我们可以看到定义了一个名为mtkfb_driver的结构体变量,该变量是一个platform_driver结构体类型,其中包含了一些成员函数的指针,如probe、remove、suspend、resume和shutdown等。这些函数是用来处理与MTK平台上的LCD显示相关的操作。例如,当系统探测到MTK平台上的LCD设备时,probe函数会被调用来初始化LCD驱动;当系统要移除LCD设备时,remove函数会被调用来卸载LCD驱动。 除了上述的成员函数指针外,mtkfb_driver结构体变量还包含了一些其他成员,如name、pm和bus等。其中,name成员指定了驱动的名称,pm成员用于指定与电源管理相关的操作函数,而bus成员则指定了驱动所属的总线类型。 需要注意的是,以上只是mtk平台上lcd驱动框架概述,具体实现细节可能因不同的平台而有所不同。此外,本文可能存在错误或不够深入,请参考相关资料以获取更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [MTK平台LCD驱动框架详解(一)](https://blog.csdn.net/xuan_h/article/details/38519975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值