rk3288 chromium: update for hdmi display

This commit is contained in:
yzq
2014-04-07 15:33:43 +08:00
parent 7b4348227c
commit a2f0216f52
19 changed files with 1301 additions and 50 deletions

View File

@@ -331,7 +331,8 @@ CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_DRM=y
CONFIG_DRM_ROCKCHIP=y
CONFIG_DRM_ROCKCHIP_DMABUF=y
CONFIG_DRM_RK_PRIMARY=y
CONFIG_DRM_ROCKCHIP_PRIMARY=y
CONFIG_DRM_ROCKCHIP_HDMI=y
CONFIG_MALI_T6XX=y
CONFIG_MALI_T6XX_DVFS=y
CONFIG_MALI_T6XX_RT_PM=y
@@ -347,6 +348,7 @@ CONFIG_BACKLIGHT_PWM=y
CONFIG_LCDC_RK3288=y
CONFIG_RK_TRSM=y
CONFIG_RK32_LVDS=y
CONFIG_RK_HDMI=y
CONFIG_ROCKCHIP_RGA2=y
# CONFIG_IEP is not set
CONFIG_LOGO=y

View File

@@ -22,13 +22,14 @@ config DRM_ROCKCHIP_DMABUF
help
Choose this option if you want to use DMABUF feature for DRM.
config DRM_RK_PRIMARY
config DRM_ROCKCHIP_PRIMARY
bool "RK DRM PRIMARY"
depends on OF && DRM_ROCKCHIP
select FB_MODE_HELPERS
select VIDEOMODE_HELPERS
help
Choose this option if you want to use Rockchip PRIMARY DISPLAY for DRM.
config DRM_ROCKCHIP_HDMI
bool "Rockchip DRM HDMI"
depends on DRM_ROCKCHIP

View File

@@ -10,10 +10,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_encoder.o rockchip_drm_connecto
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_IOMMU) += rockchip_drm_iommu.o
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_DMABUF) += rockchip_drm_dmabuf.o
rockchipdrm-$(CONFIG_DRM_RK_PRIMARY) += rockchip_drm_primary.o
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_HDMI) += rockchip_hdmi.o rockchip_mixer.o \
rockchip_ddc.o rockchip_hdmiphy.o \
rockchip_drm_hdmi.o
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_PRIMARY) += rockchip_drm_primary.o
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_HDMI) += rockchip_drm_extend.o
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_VIDI) += rockchip_drm_vidi.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o

View File

@@ -57,7 +57,31 @@ convert_to_display_mode(struct drm_display_mode *mode,
if (timing->vmode & FB_VMODE_DOUBLE)
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
}
static inline void
convert_fbmode_to_display_mode(struct drm_display_mode *mode,
struct fb_videomode *timing)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
mode->clock = timing->pixclock / 1000;
mode->vrefresh = timing->refresh;
mode->hdisplay = timing->xres;
mode->hsync_start = mode->hdisplay + timing->right_margin;
mode->hsync_end = mode->hsync_start + timing->hsync_len;
mode->htotal = mode->hsync_end + timing->left_margin;
mode->vdisplay = timing->yres;
mode->vsync_start = mode->vdisplay + timing->lower_margin;
mode->vsync_end = mode->vsync_start + timing->vsync_len;
mode->vtotal = mode->vsync_end + timing->upper_margin;
if (timing->vmode & FB_VMODE_INTERLACED)
mode->flags |= DRM_MODE_FLAG_INTERLACE;
if (timing->vmode & FB_VMODE_DOUBLE)
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
}
/* convert drm_display_mode to rockchip_video_timings */
static inline void
convert_to_video_timing(struct fb_videomode *timing,
@@ -130,6 +154,34 @@ static int rockchip_drm_connector_get_modes(struct drm_connector *connector)
}
drm_mode_connector_update_edid_property(connector, edid);
} else if(display_ops->get_modelist){
struct list_head *pos,*head;
struct fb_modelist *modelist;
struct fb_videomode *mode;
struct drm_display_mode *disp_mode = NULL;
count=0;
head = display_ops->get_modelist(manager->dev);
list_for_each(pos,head){
modelist = list_entry(pos, struct fb_modelist, list);
mode = &modelist->mode;
disp_mode = drm_mode_create(connector->dev);
if (!mode) {
DRM_ERROR("failed to create a new display mode.\n");
return count;
}
convert_fbmode_to_display_mode(disp_mode, mode);
if(mode->xres == 1280 && mode->yres == 720 && mode->refresh == 60)
disp_mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(disp_mode);
// snprintf(disp_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s-%d",
// disp_mode->hdisplay, disp_mode->vdisplay,
// !!(disp_mode->flags & DRM_MODE_FLAG_INTERLACE)? "i" : "p",disp_mode->vrefresh);
drm_mode_probed_add(connector, disp_mode);
count++;
}
} else {
struct rockchip_drm_panel_info *panel;
struct drm_display_mode *mode = drm_mode_create(connector->dev);

View File

@@ -28,7 +28,6 @@ static int rockchip_drm_create_enc_conn(struct drm_device *dev,
DRM_DEBUG_DRIVER("%s\n", __FILE__);
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
subdrv->manager->dev = subdrv->dev;
/* create and initialize a encoder for this sub driver. */
@@ -116,15 +115,12 @@ int rockchip_drm_device_register(struct drm_device *dev)
DRM_DEBUG_DRIVER("%s\n", __FILE__);
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
if (!dev)
return -EINVAL;
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
list_for_each_entry_safe(subdrv, n, &rockchip_drm_subdrv_list, list) {
err = rockchip_drm_subdrv_probe(dev, subdrv);
if (err) {
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
DRM_DEBUG("rockchip drm subdrv probe failed.\n");
list_del(&subdrv->list);
continue;
@@ -141,7 +137,6 @@ int rockchip_drm_device_register(struct drm_device *dev)
err = rockchip_drm_create_enc_conn(dev, subdrv);
if (err) {
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
DRM_DEBUG("failed to create encoder and connector.\n");
rockchip_drm_subdrv_remove(dev, subdrv);
list_del(&subdrv->list);
@@ -151,7 +146,6 @@ int rockchip_drm_device_register(struct drm_device *dev)
fine_cnt++;
}
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
if (!fine_cnt)
return -EINVAL;

View File

@@ -54,7 +54,7 @@ static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
// printk(KERN_ERR"crtc[%d] mode[%d]\n", crtc->base.id, mode);
if (rockchip_crtc->dpms == mode) {
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
@@ -147,11 +147,11 @@ static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
/* when framebuffer changing is requested, crtc's dpms should be on */
if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
DRM_ERROR("failed framebuffer changing request.\n");
return -EPERM;
// return -EPERM;
}
crtc_w = crtc->fb->width - x;
@@ -204,6 +204,7 @@ static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb = crtc->fb;
int ret = -EINVAL;
DRM_DEBUG_KMS("%s\n", __FILE__);
/* when the page flip is requested, crtc's dpms should be on */
@@ -370,7 +371,24 @@ int rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr)
return 0;
}
#if 0
int rockchip_get_crtc_vblank_timestamp(struct drm_device *dev, int crtc,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct rockchip_drm_private *private = dev->dev_private;
struct rockchip_drm_crtc *rockchip_crtc =
to_rockchip_crtc(private->crtc[crtc]);
if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;
rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
rockchip_get_vblank_timestamp);
}
#endif
int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
{
struct rockchip_drm_private *private = dev->dev_private;

View File

@@ -252,6 +252,7 @@ static struct drm_driver rockchip_drm_driver = {
.get_vblank_counter = drm_vblank_count,
.enable_vblank = rockchip_drm_crtc_enable_vblank,
.disable_vblank = rockchip_drm_crtc_disable_vblank,
// .get_vblank_timestamp = rockchip_get_crtc_vblank_timestamp,
.gem_init_object = rockchip_drm_gem_init_object,
.gem_free_object = rockchip_drm_gem_free_object,
.gem_vm_ops = &rockchip_drm_gem_vm_ops,
@@ -306,13 +307,20 @@ static int __init rockchip_drm_init(void)
DRM_DEBUG_DRIVER("%s\n", __FILE__);
#ifdef CONFIG_DRM_RK_PRIMARY
#ifdef CONFIG_DRM_ROCKCHIP_PRIMARY
ret = platform_driver_register(&primary_platform_driver);
if (ret < 0)
goto out_fimd;
goto out_primary;
platform_device_register_simple("primary-display", -1,
NULL, 0);
#endif
#ifdef CONFIG_DRM_ROCKCHIP_HDMI
ret = platform_driver_register(&extend_platform_driver);
if (ret < 0)
goto out_extend;
platform_device_register_simple("extend-display", -1,
NULL, 0);
#endif
ret = platform_driver_register(&rockchip_drm_platform_driver);
if (ret < 0)
@@ -331,9 +339,13 @@ static int __init rockchip_drm_init(void)
out:
platform_driver_unregister(&rockchip_drm_platform_driver);
out_drm:
#ifdef CONFIG_DRM_RK_PRIMARY
#ifdef CONFIG_DRM_ROCKCHIP_PRIMARY
platform_driver_unregister(&primary_platform_driver);
out_fimd:
out_primary:
#endif
#ifdef CONFIG_DRM_ROCKCHIP_HDMI
platform_driver_unregister(&extend_platform_driver);
out_extend:
#endif
return ret;
}

View File

@@ -117,6 +117,7 @@ struct rockchip_drm_overlay {
unsigned int mode_width;
unsigned int mode_height;
unsigned int refresh;
unsigned int pixclock;
unsigned int scan_flag;
unsigned int bpp;
unsigned int pitch;
@@ -149,6 +150,7 @@ struct rockchip_drm_display_ops {
struct edid *(*get_edid)(struct device *dev,
struct drm_connector *connector);
void *(*get_panel)(struct device *dev);
void *(*get_modelist)(struct device *dev);
int (*check_timing)(struct device *dev, void *timing);
int (*power_on)(struct device *dev, int mode);
};
@@ -338,6 +340,7 @@ int rockchip_platform_device_ipp_register(void);
void rockchip_platform_device_ipp_unregister(void);
extern struct platform_driver primary_platform_driver;
extern struct platform_driver extend_platform_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
extern struct platform_driver rockchip_drm_common_hdmi_driver;

View File

@@ -389,7 +389,34 @@ void rockchip_drm_fn_encoder(struct drm_crtc *crtc, void *data,
fn(encoder, data);
}
}
int rockchip_get_crtc_vblank_timestamp(struct drm_device *dev, int crtc,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
#if 0
ktime_t stime, etime, mono_time_offset;
struct timeval tv_etime;
struct drm_display_mode *mode;
int vbl_status, vtotal, vdisplay;
int vpos, hpos, i;
s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
bool invbl;
if (crtc < 0 || crtc >= dev->num_crtcs) {
DRM_ERROR("Invalid crtc %d\n", crtc);
return -EINVAL;
}
/* Scanout position query not supported? Should not happen. */
if (!dev->driver->get_scanout_position) {
DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
return -EIO;
}
#endif
return 0;//vbl_status;
}
void rockchip_drm_enable_vblank(struct drm_encoder *encoder, void *data)
{
struct rockchip_drm_manager *manager =

View File

@@ -0,0 +1,872 @@
/*
* rk3288_drm_fimd.c
*
* Copyright (C) ROCKCHIP, Inc.
* Author:yzq<yzq@rock-chips.com>
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <drm/drmP.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <video/of_display_timing.h>
#include <drm/rockchip_drm.h>
#include <linux/rockchip/cpu.h>
#include <linux/rockchip/iomap.h>
#include <linux/rk_fb.h>
#include <video/display_timing.h>
#include <linux/rockchip/cpu.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/grf.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_fbdev.h"
#include "rockchip_drm_crtc.h"
#include "rockchip_drm_iommu.h"
#include "rockchip_drm_extend.h"
static struct device *g_dev = NULL;
static int extend_activate(struct extend_context *ctx, bool enable);
#if 0
extern struct void *get_extend_drv(void);
#endif
#if 0
static const char fake_edid_info[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06
};
#endif
extern int primary_is_display;
extern wait_queue_head_t wait_primary_queue;
static bool extend_display_is_connected(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
DRM_DEBUG_KMS("%s\n", __FILE__);
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
return drm_disp->is_connected?true:false;
/* TODO. */
}
static void *extend_get_panel(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct list_head *pos;
struct fb_modelist *modelist;
struct fb_videomode *mode;
DRM_DEBUG_KMS("%s\n", __FILE__);
if(!drm_disp->is_connected)
return NULL;
list_for_each(pos,drm_disp->modelist){
modelist = list_entry(pos, struct fb_modelist, list);
mode = &modelist->mode;
if(mode->flag == HDMI_VIDEO_DEFAULT_MODE)
break;
}
memcpy(&ctx->panel->timing,mode,sizeof(struct fb_videomode));
return ctx->panel;
}
static void *extend_get_modelist(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
return drm_disp->modelist;
}
static int extend_check_timing(struct device *dev, void *timing)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
/* TODO. */
return 0;
}
static int extend_display_power_on(struct device *dev, int mode)
{
struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO */
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
extend_activate(ctx,mode == DRM_MODE_DPMS_ON?true:false);
return 0;
}
struct edid *extend_get_edid(struct device *dev,
struct drm_connector *connector)
{
#if 0
int i, j = 0, valid_extensions = 0;
struct hdmi *hdmi = get_extend_drv();
u8 *block, *new;
struct edid *edid = NULL;
struct edid *raw_edid = NULL;
bool print_bad_edid = !connector->bad_edid_counter;
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
return NULL;
/* base block fetch */
for (i = 0; i < 4; i++) {
if(hdmi->read_edid(hdmi, 0, block))
goto out;
if (drm_edid_block_valid(block, 0, print_bad_edid))
break;
}
if (i == 4)
goto carp;
/* if there's no extensions, we're done */
if (block[0x7e] == 0)
return block;
new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new)
goto out;
block = new;
for (j = 1; j <= block[0x7e]; j++) {
for (i = 0; i < 4; i++) {
if(hdmi->read_edid(hdmi, j, block))
goto out;
if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) {
valid_extensions++;
break;
}
}
if (i == 4 && print_bad_edid) {
dev_warn(connector->dev->dev,
"%s: Ignoring invalid EDID block %d.\n",
drm_get_connector_name(connector), j);
connector->bad_edid_counter++;
}
}
if (valid_extensions != block[0x7e]) {
block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
block[0x7e] = valid_extensions;
new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new)
goto out;
block = new;
}
edid = (struct edid *)block;
return edid;
carp:
if (print_bad_edid) {
dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
drm_get_connector_name(connector), j);
}
connector->bad_edid_counter++;
out:
kfree(block);
raw_edid = (struct edid *)fake_edid_info;
edid = kmemdup(raw_edid, (1 + raw_edid->extensions) * EDID_LENGTH, GFP_KERNEL);
if (!edid) {
DRM_DEBUG_KMS("failed to allocate edid\n");
return ERR_PTR(-ENOMEM);
}
return edid;
#endif
}
static struct rockchip_drm_display_ops extend_display_ops = {
.type = ROCKCHIP_DISPLAY_TYPE_HDMI,
.is_connected = extend_display_is_connected,
.get_panel = extend_get_panel,
.get_modelist = extend_get_modelist,
.check_timing = extend_check_timing,
.power_on = extend_display_power_on,
// .get_edid = extend_get_edid,
};
static void extend_dpms(struct device *subdrv_dev, int mode)
{
struct extend_context *ctx = get_extend_context(subdrv_dev);
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
mutex_lock(&ctx->lock);
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
switch (mode) {
case DRM_MODE_DPMS_ON:
/*
* enable primary hardware only if suspended status.
*
* P.S. extend_dpms function would be called at booting time so
* clk_enable could be called double time.
*/
if (ctx->suspended)
pm_runtime_get_sync(subdrv_dev);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (!ctx->suspended)
pm_runtime_put_sync(subdrv_dev);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
break;
}
mutex_unlock(&ctx->lock);
}
static void extend_apply(struct device *subdrv_dev)
{
struct extend_context *ctx = get_extend_context(subdrv_dev);
struct rockchip_drm_manager *mgr = ctx->subdrv.manager;
struct rockchip_drm_manager_ops *mgr_ops = mgr->ops;
struct rockchip_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
struct extend_win_data *win_data;
int i;
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
DRM_DEBUG_KMS("%s\n", __FILE__);
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (ovl_ops && ovl_ops->commit))
ovl_ops->commit(subdrv_dev, i);
}
if (mgr_ops && mgr_ops->commit)
mgr_ops->commit(subdrv_dev);
}
static void extend_commit(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct rockchip_drm_panel_info *panel = (struct rockchip_drm_panel_info *)extend_get_panel(dev);
// printk(KERN_ERR"%s %d\n", __func__,__LINE__);
if (ctx->suspended)
return;
drm_disp->mode = &panel->timing;
drm_disp->enable = true;
rk_drm_disp_handle(drm_disp,0,RK_DRM_SCREEN_SET);
}
static int extend_enable_vblank(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
if (ctx->suspended)
return -EPERM;
ctx->vblank_en = true;
return 0;
}
static void extend_disable_vblank(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
if (ctx->suspended)
return;
ctx->vblank_en = false;
}
static void extend_wait_for_vblank(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
if (ctx->suspended)
return;
#if 1
atomic_set(&ctx->wait_vsync_event, 1);
if (!wait_event_timeout(ctx->wait_vsync_queue,
!atomic_read(&ctx->wait_vsync_event),
DRM_HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n");
#endif
}
static void extend_event_call_back_handle(struct rk_drm_display *drm_disp,int win_id,int event)
{
struct extend_context *ctx = get_extend_context(g_dev);
struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
struct rockchip_drm_manager *manager = subdrv->manager;
struct drm_device *drm_dev = subdrv->drm_dev;
switch(event){
case RK_DRM_CALLBACK_VSYNC:
/* check the crtc is detached already from encoder */
if (manager->pipe < 0)
return;
drm_handle_vblank(drm_dev, manager->pipe);
rockchip_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
DRM_WAKEUP(&ctx->wait_vsync_queue);
}
break;
case RK_DRM_CALLBACK_HOTPLUG:
#if 0
if(0){//primary_is_display == 0){
printk(KERN_ERR"-->%s waitfor hotplug event %d\n",__func__,event);
int is_connected = drm_disp->is_connected;
drm_disp->is_connected = false;
if (!wait_event_timeout(wait_primary_queue,
primary_is_display,
20*1000)){
printk(KERN_ERR"-->%s waitfot hotplug event %d timeout\n",__func__,event);
}
drm_disp->is_connected = true;
}
#endif
printk(KERN_ERR"-->%s hotplug event %d\n",__func__,event);
drm_helper_hpd_irq_event(drm_dev);
break;
default:
printk(KERN_ERR"-->%s unhandle event %d\n",__func__,event);
break;
}
}
static void extend_get_max_resol(void *ctx, unsigned int *width,
unsigned int *height)
{
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
*width = MAX_HDMI_WIDTH;
*height = MAX_HDMI_HEIGHT;
}
static struct rockchip_drm_manager_ops extend_manager_ops = {
.dpms = extend_dpms,
.apply = extend_apply,
.commit = extend_commit,
.enable_vblank = extend_enable_vblank,
.disable_vblank = extend_disable_vblank,
.wait_for_vblank = extend_wait_for_vblank,
.get_max_resol = extend_get_max_resol,
};
static void extend_win_mode_set(struct device *dev,
struct rockchip_drm_overlay *overlay)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct extend_win_data *win_data;
int win;
unsigned long offset;
struct list_head *pos,*head;
struct fb_modelist *modelist;
struct fb_videomode *mode;
struct drm_display_mode *disp_mode = NULL;
DRM_DEBUG_KMS("%s\n", __FILE__);
if (!overlay) {
dev_err(dev, "overlay is NULL\n");
return;
}
win = overlay->zpos;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win > WINDOWS_NR)
return;
offset = overlay->fb_x * (overlay->bpp >> 3);
offset += overlay->fb_y * overlay->pitch;
// printk("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
// printk("crtc_x=%d crtc_y=%d crtc_width=%d crtc_height=%d\n",overlay->crtc_x,overlay->crtc_y,overlay->crtc_width,overlay->crtc_height);
// printk("fb_width=%d fb_height=%d dma_addr=%x offset=%x\n",overlay->fb_width,overlay->fb_height,overlay->dma_addr[0],offset);
win_data = &ctx->win_data[win];
win_data->offset_x = overlay->crtc_x;
win_data->offset_y = overlay->crtc_y;
win_data->ovl_width = overlay->crtc_width;
win_data->ovl_height = overlay->crtc_height;
win_data->fb_width = overlay->fb_width;
win_data->fb_height = overlay->fb_height;
win_data->dma_addr = overlay->dma_addr[0] + offset;
win_data->bpp = overlay->bpp;
win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
(overlay->bpp >> 3);
win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
head = drm_disp->modelist;
list_for_each(pos,head){
modelist = list_entry(pos, struct fb_modelist, list);
mode = &modelist->mode;
if(mode->xres == overlay->mode_width && mode->yres == overlay->mode_height
&& mode->pixclock == overlay->pixclock)
break;
}
if(drm_disp->mode != mode){
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
drm_disp->mode = mode;
printk("overlay [%dx%d-%d] mode[%dx%d-%d]\n",overlay->mode_width,overlay->mode_height,overlay->pixclock,mode->xres,mode->yres,mode->pixclock);
// printk("overlay->mode_width=%d overlay->mode_height=%d mode_width=%d mode_height=%d",overlay->mode_width,overlay->mode_height,mode->xres,mode->yres);
drm_disp->enable = true;
rk_drm_disp_handle(drm_disp,0,RK_DRM_SCREEN_SET);
}
}
static void extend_win_set_pixfmt(struct device *dev, unsigned int win)
{
struct extend_context *ctx = get_extend_context(dev);
struct extend_win_data *win_data = &ctx->win_data[win];
}
static void extend_win_set_colkey(struct device *dev, unsigned int win)
{
// struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
}
ktime_t win_start;
ktime_t win_end;
ktime_t win_start1;
ktime_t win_end1;
static void extend_win_commit(struct device *dev, int zpos)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct rk_win_data *rk_win = NULL;
struct extend_win_data *win_data;
int win = zpos;
unsigned long val, size;
u32 xpos, ypos;
//printk(KERN_ERR"%s %d\n", __func__,__LINE__);
if (ctx->suspended)
return;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win > WINDOWS_NR)
return;
if(win == 0){
win_start = ktime_get();
win_start = ktime_sub(win_start, win_end);
// printk("user flip buffer time %dms\n", (int)ktime_to_ms(win_start));
// win_start = ktime_get();
}
rk_win = &drm_disp->win[win];
win_data = &ctx->win_data[win];
switch(win_data->bpp){
case 32:
rk_win->format = ARGB888;
break;
case 24:
rk_win->format = RGB888;
break;
case 16:
rk_win->format = RGB565;
break;
default:
printk("not support format %d\n",win_data->bpp);
break;
}
rk_win->xpos = win_data->offset_x;
rk_win->ypos = win_data->offset_y;
rk_win->xact = win_data->ovl_width;
rk_win->yact = win_data->ovl_height;
rk_win->xsize = win_data->ovl_width;
rk_win->ysize = win_data->ovl_height;
rk_win->xvir = win_data->fb_width;
rk_win->yrgb_addr = win_data->dma_addr;
rk_win->enabled = true;
rk_drm_disp_handle(drm_disp,1<<win,RK_DRM_WIN_COMMIT | RK_DRM_DISPLAY_COMMIT);
win_data->enabled = true;
if(win ==0){
// win_end = ktime_get();
// win_end = ktime_sub(win_end, win_start);
// printk("flip buffer time %dus\n", (int)ktime_to_us(win_end));
win_end = ktime_get();
}
}
static void extend_win_disable(struct device *dev, int zpos)
{
struct extend_context *ctx = get_extend_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct extend_win_data *win_data;
int win = zpos;
DRM_DEBUG_KMS("%s\n", __FILE__);
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win > WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
if (ctx->suspended) {
/* do not resume this window*/
win_data->resume = false;
return;
}
drm_disp->win[win].enabled = false;
rk_drm_disp_handle(drm_disp,1<<win,RK_DRM_WIN_COMMIT | RK_DRM_DISPLAY_COMMIT);
win_data->enabled = false;
}
static struct rockchip_drm_overlay_ops extend_overlay_ops = {
.mode_set = extend_win_mode_set,
.commit = extend_win_commit,
.disable = extend_win_disable,
};
static struct rockchip_drm_manager extend_manager = {
.pipe = -1,
.ops = &extend_manager_ops,
.overlay_ops = &extend_overlay_ops,
.display_ops = &extend_display_ops,
};
#if 0
static irqreturn_t extend_irq_handler(int irq, void *dev_id)
{
struct extend_context *ctx = (struct extend_context *)dev_id;
struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
struct drm_device *drm_dev = subdrv->drm_dev;
struct rockchip_drm_manager *manager = subdrv->manager;
u32 intr0_reg;
/* check the crtc is detached already from encoder */
if (manager->pipe < 0)
goto out;
drm_handle_vblank(drm_dev, manager->pipe);
rockchip_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
DRM_WAKEUP(&ctx->wait_vsync_queue);
}
out:
return IRQ_HANDLED;
}
#endif
static int extend_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
/*
* enable drm irq mode.
* - with irq_enabled = 1, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler.
*/
drm_dev->irq_enabled = 1;
/*
* with vblank_disable_allowed = 1, vblank interrupt will be disabled
* by drm timer once a current process gives up ownership of
* vblank event.(after drm_vblank_put function is called)
*/
drm_dev->vblank_disable_allowed = 1;
/* attach this sub driver to iommu mapping if supported. */
if (is_drm_iommu_supported(drm_dev))
drm_iommu_attach_device(drm_dev, dev);
return 0;
}
static void extend_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
/* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(drm_dev))
drm_iommu_detach_device(drm_dev, dev);
}
static void extend_clear_win(struct extend_context *ctx, int win)
{
u32 val;
DRM_DEBUG_KMS("%s\n", __FILE__);
}
static void extend_window_suspend(struct device *dev)
{
struct extend_win_data *win_data = NULL;
struct extend_context *ctx = get_extend_context(dev);
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled;
extend_win_disable(dev, i);
}
extend_wait_for_vblank(dev);
}
static void extend_window_resume(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
struct extend_win_data *win_data;
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
win_data->enabled = win_data->resume;
win_data->resume = false;
}
}
static int extend_activate(struct extend_context *ctx, bool enable)
{
struct device *dev = ctx->subdrv.dev;
struct rk_drm_display *drm_disp = ctx->drm_disp;
if (enable) {
int ret;
ctx->suspended = false;
drm_disp->enable = true;
rk_drm_disp_handle(drm_disp,0,RK_DRM_SCREEN_BLANK);
/* if vblank was enabled status, enable it again. */
if (ctx->vblank_en)
extend_enable_vblank(dev);
extend_window_resume(dev);
} else {
extend_window_suspend(dev);
drm_disp->enable = false;
rk_drm_disp_handle(drm_disp,0,RK_DRM_SCREEN_BLANK);
ctx->suspended = true;
}
return 0;
}
static int extend_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct extend_context *ctx;
struct rockchip_drm_subdrv *subdrv;
struct rockchip_drm_panel_info *panel;
struct rk_drm_display *drm_display = NULL;
int ret = -EINVAL;
DRM_DEBUG_KMS("%s\n", __FILE__);
g_dev = dev;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
panel = devm_kzalloc(dev, sizeof(struct rockchip_drm_panel_info), GFP_KERNEL);
ctx->panel = panel;
drm_display = rk_drm_get_diplay(RK_DRM_EXTEND_SCREEN);
ctx->drm_disp = drm_display;
ctx->default_win = 0;
drm_display->event_call_back = extend_event_call_back_handle;
DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
subdrv = &ctx->subdrv;
subdrv->dev = dev;
subdrv->manager = &extend_manager;
subdrv->probe = extend_subdrv_probe;
subdrv->remove = extend_subdrv_remove;
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
//extend_commit(dev);
extend_activate(ctx, true);
rockchip_drm_subdrv_register(subdrv);
return 0;
}
static int extend_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct extend_context *ctx = platform_get_drvdata(pdev);
DRM_DEBUG_KMS("%s\n", __FILE__);
rockchip_drm_subdrv_unregister(&ctx->subdrv);
if (ctx->suspended)
goto out;
pm_runtime_set_suspended(dev);
pm_runtime_put_sync(dev);
out:
pm_runtime_disable(dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int extend_suspend(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
/*
* do not use pm_runtime_suspend(). if pm_runtime_suspend() is
* called here, an error would be returned by that interface
* because the usage_count of pm runtime is more than 1.
*/
if (!pm_runtime_suspended(dev))
return extend_activate(ctx, false);
return 0;
}
static int extend_resume(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
/*
* if entered to sleep when lcd panel was on, the usage_count
* of pm runtime would still be 1 so in this case, fimd driver
* should be on directly not drawing on pm runtime interface.
*/
if (!pm_runtime_suspended(dev)) {
int ret;
ret = extend_activate(ctx, true);
if (ret < 0)
return ret;
/*
* in case of dpms on(standby), extend_apply function will
* be called by encoder's dpms callback to update fimd's
* registers but in case of sleep wakeup, it's not.
* so extend_apply function should be called at here.
*/
extend_apply(dev);
}
return 0;
}
#endif
#ifdef CONFIG_PM_RUNTIME
static int extend_runtime_suspend(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
return extend_activate(ctx, false);
}
static int extend_runtime_resume(struct device *dev)
{
struct extend_context *ctx = get_extend_context(dev);
DRM_DEBUG_KMS("%s\n", __FILE__);
return extend_activate(ctx, true);
}
#endif
static const struct dev_pm_ops extend_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(extend_suspend, extend_resume)
SET_RUNTIME_PM_OPS(extend_runtime_suspend, extend_runtime_resume, NULL)
};
struct platform_driver extend_platform_driver = {
.probe = extend_probe,
.remove = extend_remove,
.driver = {
.owner = THIS_MODULE,
.name = "extend-display",
.pm = &extend_pm_ops,
},
};

View File

@@ -0,0 +1,37 @@
#include "../../../video/rockchip/rk_drm_fb.h"
#include "../../../video/rockchip/hdmi/rk_hdmi.h"
#define WINDOWS_NR 4
#define MAX_HDMI_WIDTH 1920
#define MAX_HDMI_HEIGHT 1080
#define get_extend_context(dev) platform_get_drvdata(to_platform_device(dev))
struct extend_win_data {
unsigned int offset_x;
unsigned int offset_y;
unsigned int ovl_width;
unsigned int ovl_height;
unsigned int fb_width;
unsigned int fb_height;
unsigned int bpp;
dma_addr_t dma_addr;
unsigned int buf_offsize;
unsigned int line_size; /* bytes */
bool enabled;
bool resume;
};
struct extend_context {
struct rockchip_drm_subdrv subdrv;
int vblank_en;
struct drm_crtc *crtc;
struct rk_drm_display *drm_disp;
struct extend_win_data win_data[WINDOWS_NR];
unsigned int default_win;
bool suspended;
struct mutex lock;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
struct rockchip_drm_panel_info *panel;
};

View File

@@ -136,8 +136,10 @@ int rockchip_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
overlay->mode_width = crtc->mode.hdisplay;
overlay->mode_height = crtc->mode.vdisplay;
overlay->refresh = crtc->mode.vrefresh;
overlay->pixclock = crtc->mode.clock*1000;
overlay->scan_flag = crtc->mode.flags;
// printk("--->yzq %s crtc->mode->refresh =%d \n",__func__,crtc->mode.vrefresh);
DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
overlay->crtc_x, overlay->crtc_y,
overlay->crtc_width, overlay->crtc_height);

View File

@@ -39,11 +39,10 @@ static struct device *g_dev = NULL;
static bool primary_display_is_connected(struct device *dev)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO. */
return true;
return false;
}
static void *primary_get_panel(struct device *dev)
@@ -140,12 +139,13 @@ static void primary_commit(struct device *dev)
{
struct primary_context *ctx = get_primary_context(dev);
struct rk_drm_display *drm_disp = ctx->drm_disp;
struct rockchip_drm_panel_info *panel = (struct rockchip_drm_panel_info *)primary_get_panel(dev);
struct fb_videomode *mode;
printk(KERN_ERR"%s %d\n", __func__,__LINE__);
if (ctx->suspended)
return;
drm_disp->mode_id = drm_disp->best_mode;
drm_disp->mode = &panel->timing;
drm_disp->enable = true;
rk_drm_disp_handle(drm_disp,0,RK_DRM_SCREEN_SET);
}
@@ -201,7 +201,6 @@ static void primary_event_call_back_handle(struct rk_drm_display *drm_disp,int w
drm_handle_vblank(drm_dev, manager->pipe);
rockchip_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
@@ -280,7 +279,12 @@ static void primary_win_set_colkey(struct device *dev, unsigned int win)
DRM_DEBUG_KMS("%s\n", __FILE__);
}
#if 0
static ktime_t win_start;
static ktime_t win_end;
static ktime_t win_start1;
static ktime_t win_end1;
#endif
static void primary_win_commit(struct device *dev, int zpos)
{
struct primary_context *ctx = get_primary_context(dev);
@@ -301,6 +305,14 @@ static void primary_win_commit(struct device *dev, int zpos)
if (win < 0 || win > WINDOWS_NR)
return;
#if 0
if(win == 0){
win_start = ktime_get();
win_start = ktime_sub(win_start, win_end);
printk("user flip buffer time %dus\n", (int)ktime_to_us(win_start));
// win_start = ktime_get();
}
#endif
rk_win = &drm_disp->win[win];
win_data = &ctx->win_data[win];
switch(win_data->bpp){
@@ -331,6 +343,14 @@ static void primary_win_commit(struct device *dev, int zpos)
rk_drm_disp_handle(drm_disp,1<<win,RK_DRM_WIN_COMMIT | RK_DRM_DISPLAY_COMMIT);
win_data->enabled = true;
#if 0
if(win ==0){
// win_end = ktime_get();
// win_end = ktime_sub(win_end, win_start);
// printk("flip buffer time %dus\n", (int)ktime_to_us(win_end));
win_end = ktime_get();
}
#endif
}
@@ -513,7 +533,8 @@ static int primary_probe(struct platform_device *pdev)
struct rockchip_drm_subdrv *subdrv;
struct rockchip_drm_panel_info *panel;
struct rk_drm_display *drm_display = NULL;
int ret = -EINVAL;
struct fb_modelist *modelist;
struct fb_videomode *mode;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -528,7 +549,9 @@ static int primary_probe(struct platform_device *pdev)
drm_display = rk_drm_get_diplay(RK_DRM_PRIMARY_SCREEN);
ctx->drm_disp = drm_display;
ctx->default_win = 0;
memcpy(&panel->timing,drm_display->mode,sizeof(struct fb_videomode));
modelist = list_first_entry(drm_display->modelist, struct fb_modelist, list);
mode = &modelist->mode;
memcpy(&panel->timing,mode,sizeof(struct fb_videomode));
drm_display->event_call_back = primary_event_call_back_handle;
@@ -549,7 +572,7 @@ static int primary_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
primary_commit(dev);
//primary_commit(dev);
primary_activate(ctx, true);
rockchip_drm_subdrv_register(subdrv);

View File

@@ -1,6 +1,6 @@
menuconfig RK_HDMI
bool "Rockchip HDMI support"
depends on FB_ROCKCHIP
depends on FB_ROCKCHIP || DRM_ROCKCHIP
select FB_MODE_HELPERS
if RK_HDMI

View File

@@ -171,10 +171,16 @@ static struct rk_display_driver display_hdmi = {
};
static struct rk_display_device *display_device_hdmi = NULL;
#ifdef CONFIG_DRM_ROCKCHIP
extern void rk_drm_display_register(struct rk_display_ops *extend_ops, void *displaydata,int type);
#endif
void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent)
{
display_device_hdmi = rk_display_device_register(&display_hdmi, parent, hdmi);
#ifdef CONFIG_DRM_ROCKCHIP
rk_drm_display_register(&hdmi_display_ops,hdmi,SCREEN_HDMI);
#endif
}
void hdmi_unregister_display_sysfs(struct hdmi *hdmi)

View File

@@ -3144,6 +3144,9 @@ static irqreturn_t rk3288_lcdc_isr(int irq, void *dev_id)
complete(&(lcdc_dev->driver.frame_done));
spin_unlock(&(lcdc_dev->driver.cpl_lock));
}
#ifdef CONFIG_DRM_ROCKCHIP
lcdc_dev->driver.irq_call_back(&lcdc_dev->driver);
#endif
lcdc_dev->driver.vsync_info.timestamp = timestamp;
wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);

View File

@@ -29,6 +29,7 @@
#include <linux/rk_fb.h>
#include <linux/linux_logo.h>
#include <linux/dma-mapping.h>
#include <drm/drm_os_linux.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_OF
#include <linux/of.h>
@@ -38,6 +39,7 @@
#include <dt-bindings/rkfb/rk_fb.h>
#endif
#include <linux/display-sys.h>
#include "rk_drm_fb.h"
__weak int support_uboot_display(void)
{
@@ -47,6 +49,21 @@ static struct platform_device *drm_fb_pdev;
static struct rk_fb_trsm_ops *trsm_lvds_ops;
static struct rk_fb_trsm_ops *trsm_edp_ops;
static struct rk_fb_trsm_ops *trsm_mipi_ops;
static struct rk_display_device *disp_hdmi_devices;
void rk_drm_display_register(struct rk_display_ops *extend_ops, void *displaydata,int type)
{
switch(type) {
case SCREEN_HDMI:
disp_hdmi_devices = kzalloc(sizeof(struct rk_display_device), GFP_KERNEL);
disp_hdmi_devices->priv_data = displaydata;
disp_hdmi_devices->ops = extend_ops;
break;
default:
printk(KERN_WARNING "%s:un supported extend display:%d!\n",
__func__, type);
break;
}
}
int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
{
switch (type) {
@@ -70,6 +87,30 @@ int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
return 0;
}
struct rk_display_device *rk_drm_extend_display_get(int type)
{
struct rk_display_device *extend_display = NULL;
switch (type) {
case SCREEN_HDMI:
if(disp_hdmi_devices)
extend_display = disp_hdmi_devices;
else
printk(KERN_WARNING "%s:screen hdmi ops is NULL!\n",__func__);
break;
default:
printk(KERN_WARNING "%s:un supported extend display:%d!\n",
__func__, type);
break;
}
return extend_display;
}
#if 0
struct void *get_extend_drv(void)
{
struct rk_display_device *extend_display = rk_drm_extend_display_get(SCREEN_HDMI);
return extend_display->priv_data;
}
#endif
struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type)
{
struct rk_fb_trsm_ops *ops;
@@ -320,8 +361,8 @@ static int init_lcdc_device_driver(struct rk_drm_screen_private *screen_priv,
if (dev_drv->prop == PRMRY) {
rk_fb_set_prmry_screen(screen);
rk_fb_get_prmry_screen(screen);
dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type);
}
dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type);
return 0;
@@ -483,19 +524,45 @@ static int rk_fb_wait_for_vsync_thread(void *data)
int ret = wait_event_interruptible(dev_drv->vsync_info.wait,
!ktime_equal(timestamp, dev_drv->vsync_info.timestamp) &&
(dev_drv->vsync_info.active || dev_drv->vsync_info.irq_stop));
#if 1
if(atomic_read(&drm_screen_priv->wait_vsync_done)){
atomic_set(&drm_screen_priv->wait_vsync_done,0);
DRM_WAKEUP(&drm_screen_priv->wait_vsync_queue);
}
if(!ret && drm_display->event_call_back)
drm_display->event_call_back(drm_display,0,RK_DRM_CALLBACK_VSYNC);
#endif
}
return 0;
}
static void rk_drm_irq_handle(struct rk_lcdc_driver *dev_drv)
{
struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
struct rk_drm_screen_private *drm_screen_priv = NULL;
struct rk_drm_display *drm_display = NULL;
if(dev_drv->prop == PRMRY)
drm_screen_priv = &rk_drm_priv->screen_priv[0];
else if(dev_drv->prop == EXTEND)
drm_screen_priv = &rk_drm_priv->screen_priv[1];
if(drm_screen_priv == NULL)
return -1;
drm_display = &drm_screen_priv->drm_disp;
if(atomic_read(&drm_screen_priv->wait_vsync_done)){
atomic_set(&drm_screen_priv->wait_vsync_done,0);
DRM_WAKEUP(&drm_screen_priv->wait_vsync_queue);
}
if(drm_display->event_call_back)
drm_display->event_call_back(drm_display,0,RK_DRM_CALLBACK_VSYNC);
}
int rk_fb_register(struct rk_lcdc_driver *dev_drv,
struct rk_lcdc_win *win, int id)
{
struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
struct rk_drm_display *drm_display = NULL;
struct rk_win_data *win_data = NULL;
struct rk_drm_screen_private *drm_screen_priv = NULL;
int i=0;
if (rk_drm_priv->num_screen == RK30_MAX_LCDC_SUPPORT)
@@ -504,29 +571,53 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
if (!rk_drm_priv->screen_priv[i].lcdc_dev_drv)
break;
}
rk_drm_priv->num_screen++;
rk_drm_priv->screen_priv[i].lcdc_dev_drv = dev_drv;
rk_drm_priv->screen_priv[i].lcdc_dev_drv->id = id;
drm_screen_priv = &rk_drm_priv->screen_priv[i];
drm_screen_priv->lcdc_dev_drv = dev_drv;
drm_screen_priv->lcdc_dev_drv->id = id;
init_lcdc_device_driver(&rk_drm_priv->screen_priv[i],win,i);
init_lcdc_device_driver(drm_screen_priv,win,i);
dev_drv->irq_call_back = rk_drm_irq_handle;
drm_display = &rk_drm_priv->screen_priv[i].drm_disp;
drm_display = &drm_screen_priv->drm_disp;
drm_display->num_win = dev_drv->lcdc_win_num;
atomic_set(&drm_screen_priv->wait_vsync_done, 1);
DRM_INIT_WAITQUEUE(&drm_screen_priv->wait_vsync_queue);
if(dev_drv->prop == PRMRY){
struct fb_modelist *modelist_new;
struct fb_modelist *modelist;
struct fb_videomode *mode;
drm_display->modelist = kmalloc(sizeof(struct list_head),GFP_KERNEL);
INIT_LIST_HEAD(drm_display->modelist);
modelist_new = kmalloc(sizeof(struct fb_modelist),
GFP_KERNEL);
drm_display->screen_type = RK_DRM_PRIMARY_SCREEN;
drm_display->num_videomode = 1;
drm_display->best_mode = 0;
drm_display->is_connected = 1;
drm_display->mode = &dev_drv->cur_screen->mode;
printk("----->yzq mode dclk=%d\n",drm_display->mode->pixclock);
memcpy(&modelist_new->mode,&dev_drv->cur_screen->mode,sizeof(struct fb_videomode));
// printk("---->yzq mode xres=%d yres=%d \n",modelist_new->mode.xres,modelist_new->mode.yres);
list_add_tail(&modelist_new->list,drm_display->modelist);
modelist = list_first_entry(drm_display->modelist, struct fb_modelist, list);
mode=&modelist->mode;
// printk("---->yzq 1mode xres=%d yres=%d \n",mode->xres,mode->yres);
}else if(dev_drv->prop == EXTEND){
struct list_head *modelist;
drm_screen_priv->ex_display = rk_drm_extend_display_get(SCREEN_HDMI);
// printk("------>yzq ex_display=%x\n",drm_screen_priv->ex_display);
drm_display->screen_type = RK_DRM_EXTEND_SCREEN;
drm_display->num_videomode = 1;
drm_display->best_mode = 0;
drm_display->is_connected = 0;
#if 0
drm_screen_priv->ex_display->ops->getmodelist(drm_screen_priv->ex_display,&modelist);
memcpy(&drm_display->modelist,modelist,sizeof(struct list_head));
drm_display->is_connected = drm_screen_priv->ex_display->ops->getstatus(drm_screen_priv->ex_display);
#endif
}
if (dev_drv->prop == PRMRY) {
if (1){//dev_drv->prop == PRMRY) {
init_waitqueue_head(&dev_drv->vsync_info.wait);
dev_drv->vsync_info.thread = kthread_run(rk_fb_wait_for_vsync_thread,
dev_drv, "fb-vsync");
@@ -593,6 +684,80 @@ static int rk_drm_screen_blank(struct rk_drm_display *drm_disp)
return 0;
}
int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id)
{
return 0;
}
/**********************************************************************
this is for hdmi
name: lcdc device name ,lcdc0 , lcdc1
***********************************************************************/
struct rk_lcdc_driver *rk_get_lcdc_drv(char *name)
{
struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
int i = 0;
for (i = 0; i < rk_drm_priv->num_screen; i++) {
if (!strcmp(rk_drm_priv->screen_priv[i].lcdc_dev_drv->name, name))
break;
}
return rk_drm_priv->screen_priv[i].lcdc_dev_drv;
}
int rk_fb_switch_screen(struct rk_screen *screen , int enable, int lcdc_id)
{
struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
struct rk_lcdc_driver *dev_drv = NULL;
struct rk_drm_display *drm_disp = NULL;
char name[6];
int i;
sprintf(name, "lcdc%d", lcdc_id);
if (rk_drm_priv->disp_mode != DUAL) {
dev_drv = rk_drm_priv->screen_priv[0].lcdc_dev_drv;
} else {
for (i = 0; i < rk_drm_priv->num_screen; i++) {
if (rk_drm_priv->screen_priv[i].lcdc_dev_drv->prop == EXTEND) {
drm_disp = &rk_drm_priv->screen_priv[i].drm_disp;
dev_drv = rk_drm_priv->screen_priv[i].lcdc_dev_drv;
break;
}
}
if (i == rk_drm_priv->num_screen) {
printk(KERN_ERR "%s driver not found!", name);
return -ENODEV;
}
}
printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from", dev_drv->id);
if(enable && !drm_disp->is_connected ){
struct list_head *modelist;
struct fb_modelist *modelist1;
struct fb_videomode *mode;
struct rk_display_device *ex_display = rk_drm_priv->screen_priv[i].ex_display;
memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen));
if(ex_display == NULL)
ex_display = rk_drm_extend_display_get(SCREEN_HDMI);
rk_drm_priv->screen_priv[i].ex_display = ex_display;
ex_display->ops->getmodelist(ex_display,&modelist);
drm_disp->modelist = modelist;
drm_disp->is_connected = true;
drm_disp->event_call_back(drm_disp,0,RK_DRM_CALLBACK_HOTPLUG);
}else{
// printk("----->yzq %s %d \n",__func__,__LINE__);
drm_disp->is_connected = false;
drm_disp->event_call_back(drm_disp,0,RK_DRM_CALLBACK_HOTPLUG);
// printk("----->yzq %s %d \n",__func__,__LINE__);
}
}
static int rk_drm_screen_videomode_set(struct rk_drm_display *drm_disp)
{
// struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
@@ -605,14 +770,29 @@ static int rk_drm_screen_videomode_set(struct rk_drm_display *drm_disp)
return -1;
}
if(mode != &lcdc_dev->cur_screen->mode)
memcpy(&lcdc_dev->cur_screen->mode,mode,sizeof(struct fb_videomode));
// printk("----->yzq %s %d xres=%d yres=%d refresh=%d \n",__func__,__LINE__,mode->xres,mode->yres,mode->refresh);
if(lcdc_dev->prop == PRMRY){
if(mode != &lcdc_dev->cur_screen->mode)
memcpy(&lcdc_dev->cur_screen->mode,mode,sizeof(struct fb_videomode));
}else{
struct rk_display_device *ex_display = drm_screen_priv->ex_display;
if(ex_display == NULL)
ex_display = rk_drm_extend_display_get(SCREEN_HDMI);
// printk("------>yzq ex_display=%x\n",ex_display);
if(ex_display == NULL){
printk(KERN_ERR"-->%s can not find extend display ops\n",__func__);
return -1;
}
ex_display->ops->setmode(ex_display, mode);
}
if(!lcdc_dev->atv_layer_cnt)
lcdc_dev->ops->open(lcdc_dev, 0,true);
lcdc_dev->ops->ovl_mgr(lcdc_dev, 3210, 1);
lcdc_dev->ops->load_screen(lcdc_dev,1);
return 0;
}
@@ -664,9 +844,12 @@ static int rk_drm_display_commit(struct rk_drm_display *drm_disp)
lcdc_dev->ops->lcdc_reg_update(lcdc_dev);
return 0;
}
int rk_drm_disp_handle(struct rk_drm_display *drm_disp,unsigned int win_id,unsigned int cmd_id)
{
// struct rk_drm_private *rk_drm_priv = platform_get_drvdata(drm_fb_pdev);
struct rk_drm_screen_private *drm_screen_priv =
container_of(drm_disp, struct rk_drm_screen_private, drm_disp);
int i=0;
for( i=1; i<RK_DRM_CMD_MASK; i=i<<1){
switch(i&cmd_id){
@@ -680,8 +863,17 @@ int rk_drm_disp_handle(struct rk_drm_display *drm_disp,unsigned int win_id,unsig
rk_drm_win_commit(drm_disp, win_id);
break;
case RK_DRM_DISPLAY_COMMIT:
if(win_id & i){
if (!wait_event_timeout(drm_screen_priv->wait_vsync_queue,
!atomic_read(&drm_screen_priv->wait_vsync_done),
DRM_HZ/20))
printk("wait frame timed out.\n");
}
rk_drm_display_commit(drm_disp);
break;
if(win_id & i){
atomic_set(&drm_screen_priv->wait_vsync_done,1);
}
}
}

View File

@@ -3,7 +3,8 @@
#define RK_DRM_WIN_MASK 0x7fff
#define RK_DRM_CMD_MASK 0x7fff
#define RK_DRM_CALLBACK_VSYNC 0x1
#define RK_DRM_CALLBACK_VSYNC 0x1
#define RK_DRM_CALLBACK_HOTPLUG 0x2
#define RK_DRM_SCREEN_SET 1<<0
#define RK_DRM_SCREEN_BLANK 1<<1
@@ -35,13 +36,14 @@ struct rk_win_data {
struct rk_drm_display {
/***** hardware define *****/
enum drm_screen_type screen_type;
struct fb_videomode *mode;
struct list_head *modelist;
int num_videomode;
int best_mode;
bool is_connected;
/***** user fill info *****/
int mode_id;
struct fb_videomode *mode;
bool enable;
struct rk_win_data win[RK30_MAX_LAYER_SUPPORT];
int num_win;
@@ -52,8 +54,12 @@ struct rk_drm_display {
struct rk_drm_screen_private {
struct rk_drm_display drm_disp;
struct rk_screen screen;
atomic_t wait_vsync_done;
wait_queue_head_t wait_vsync_queue;
struct rk_fb_trsm_ops *trsm_ops;
struct rk_lcdc_driver *lcdc_dev_drv;
struct rk_display_device *ex_display;
};
struct rk_drm_private {
struct rk_drm_screen_private screen_priv[RK_DRM_MAX_SCREEN_NUM];

View File

@@ -515,6 +515,9 @@ struct rk_lcdc_driver {
struct list_head pwrlist_head;
struct rk_lcdc_drv_ops *ops;
struct rk_fb_trsm_ops *trsm_ops;
#ifdef CONFIG_DRM_ROCKCHIP
void (*irq_call_back)(struct rk_lcdc_driver *driver);
#endif
};