summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Marchenko <r.marchenko@samsung.com>2015-10-26 14:49:23 +0200
committerInki Dae <inki.dae@samsung.com>2015-11-23 22:25:08 -0800
commitaff31efe4783aed70886bb69ca65e75ab212659c (patch)
tree3fe02f3961337d5bb559c11b3df2d013a8e2aa5c
parent4ad8a8eaaf0e7e9a0c9eb3b92c8f0e17a469d6d8 (diff)
downloadlibdrm-aff31efe4783aed70886bb69ca65e75ab212659c.tar.gz
libdrm-aff31efe4783aed70886bb69ca65e75ab212659c.tar.bz2
libdrm-aff31efe4783aed70886bb69ca65e75ab212659c.zip
[SPRD] Add processing drmModeSetCrtc()
Conflicts: packaging/libdrm.spec Change-Id: Ibb01aef70115566c9bebb73d5904ffe38fe7ee9d Signed-off-by: Roman Marchenko <r.marchenko@samsung.com>
-rw-r--r--packaging/libdrm.spec1
-rw-r--r--sprd/sprd_drm.c297
2 files changed, 281 insertions, 17 deletions
diff --git a/packaging/libdrm.spec b/packaging/libdrm.spec
index d38a2da2..7c95e658 100644
--- a/packaging/libdrm.spec
+++ b/packaging/libdrm.spec
@@ -11,6 +11,7 @@ Source1001: %name.manifest
BuildRequires: kernel-headers
BuildRequires: pkgconfig(pciaccess)
BuildRequires: pkgconfig(pthread-stubs)
+BuildRequires: kernel-headers-tizen-dev
%description
Direct Rendering Manager headers and kernel modules.
diff --git a/sprd/sprd_drm.c b/sprd/sprd_drm.c
index 9d3c86b7..11f65a2c 100644
--- a/sprd/sprd_drm.c
+++ b/sprd/sprd_drm.c
@@ -30,17 +30,19 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
-#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
-
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/stddef.h>
#include <linux/fb.h>
+#include <video/sprd_fb.h>
#include "xf86drm.h"
#include "xf86drmMode.h"
@@ -53,7 +55,7 @@
#define U642INTPTR(x) ( (unsigned int*) U642VOID(x) )
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
-//#define SPRD_DEBUG_MSG 0
+#define SPRD_DEBUG_MSG 0
#ifdef SPRD_DEBUG_MSG
#define SPRD_DRM_DEBUG(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
@@ -71,9 +73,15 @@
#define MAX_CRTC 1
#define MAX_PLANE 2
+#define MAX_CONNECTOR 1
+#define DEFAULT_ZPOZ SPRD_LAYERS_OSD
+
+struct sprd_drm_device;
+
struct sprd_drm_mode_mode {
+ bool b;
struct drm_mode_modeinfo drm_mode;
uint32_t mode_id; /**< Id */
@@ -91,6 +99,8 @@ struct sprd_drm_mode_connector {
drmMMListHead link;
+ struct sprd_drm_device * dev;
+
/* file descriptor of frame buffer */
int32_t fb_fd;
const char * fb_fd_name;
@@ -98,6 +108,8 @@ struct sprd_drm_mode_connector {
/* requested DPMS state */
int32_t dpms;
+ /* activated layers */
+ uint32_t activated_layers;
drmMMListHead modes;
@@ -137,6 +149,7 @@ struct sprd_drm_framebuffer {
uint32_t pitches[4];
uint32_t offsets[4];
uint32_t handles[4];
+ uint32_t names[4];
uint32_t width;
uint32_t height;
uint32_t depth;
@@ -149,6 +162,35 @@ struct sprd_drm_framebuffer {
};
/**
+ * sprd_drm_mode_set - new values for a CRTC config change
+ * @head: list management
+ * @fb: framebuffer to use for new config
+ * @crtc: CRTC whose configuration we're about to change
+ * @mode: mode timings to use
+ * @x: position of this CRTC relative to @fb
+ * @y: position of this CRTC relative to @fb
+ * @connectors: array of connectors to drive with this CRTC if possible
+ * @num_connectors: size of @connectors array
+ *
+ * Represents a single crtc the connectors that it drives with what mode
+ * and from which framebuffer it scans out from.
+ *
+ * This is used to set modes.
+ */
+struct sprd_drm_mode_set {
+ struct sprd_drm_framebuffer *fb;
+ struct sprd_drm_mode_crtc *crtc;
+// struct drm_display_mode *mode;
+
+ uint32_t x;
+ uint32_t y;
+
+ struct sprd_drm_mode_connector *connectors[MAX_CONNECTOR];
+ uint32_t num_connectors;
+};
+
+
+/**
* @drm_fd: file descriptor of drm device
* @num_fb: number of fbs available
* @fb_list: list of framebuffers available
@@ -163,7 +205,6 @@ struct sprd_drm_framebuffer {
* enumerated by the driver are added here, as are global properties. Some
* global restrictions are also here, e.g. dimension restrictions.
*/
-
struct sprd_drm_device {
drmMMListHead link;
@@ -242,7 +283,7 @@ static void sprd_drm_resource_del(int id)
* from kernel
* Original addfb only supported RGB formats, so figure out which one
*/
-uint32_t sprd_drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
+uint32_t sprd_drm_legacy_fb_format(uint32_t bpp, uint32_t depth)
{
uint32_t fmt;
@@ -455,6 +496,9 @@ static void sprd_drm_mode_connector_update_from_frame_buffer(struct sprd_drm_mod
}
_fb_var_to_drm_mode(&mode->drm_mode, &mi);
+
+ //TODO: check real state
+ conn->dpms = DRM_MODE_DPMS_OFF;
}
else
{
@@ -463,18 +507,50 @@ static void sprd_drm_mode_connector_update_from_frame_buffer(struct sprd_drm_mod
}
}
+/*
+ * Get a gem global object name from a gem object handle
+ *
+ * @fd: file descriptor of drm device
+ * @handle: a gem object handle
+ *
+ * This interface is used to get a gem global object name from a gem object
+ * handle to a buffer that wants to share it with another process
+ *
+ * If true, return gem global object name(positive) else 0
+ */
+int sprd_drm_get_name(uint32_t fd, uint32_t handle)
+{
+ struct drm_gem_flink arg;
+ int ret;
+
+ if (!handle) return -EINVAL;
+
+ char strErroBuf[256] = {0,};
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &arg);
+ if (ret) {
+ SPRD_DRM_ERROR("failed to get gem global name[%s]\n", strerror_r(errno, strErroBuf, 256));
+ return ret;
+ }
+
+ return arg.name;
+}
+
static int sprd_drm_connector_LCD_create(struct sprd_drm_device * dev, struct sprd_drm_mode_encoder * enc)
{
struct sprd_drm_mode_connector * conn;
- /*LCD*/
conn = drmMalloc(sizeof (struct sprd_drm_mode_connector));
conn->drm_conn.connector_id = sprd_drm_resource_new_id(conn);
conn->drm_conn.connector_type = DRM_MODE_CONNECTOR_LVDS;
//TODO:: unknown value;
conn->drm_conn.connector_type_id = 1;
+ conn->dev = dev;
+
//attach encoder
conn->encoder_ids[0] = enc->drm_encoder.encoder_id;
@@ -503,7 +579,16 @@ static int sprd_drm_connector_LCD_create(struct sprd_drm_device * dev, struct sp
static int32_t sprd_drm_framebuffer_create(struct sprd_drm_device * dev, struct drm_mode_fb_cmd2 * fb_cmd)
{
- struct sprd_drm_framebuffer * fb;
+ struct sprd_drm_framebuffer * fb = NULL;
+ int i;
+ int names[4];
+
+
+ for (i = 0; i < 4; i++) {
+ names[i] = sprd_drm_get_name(dev->drm_fd, fb_cmd->handles[i]);
+ if (names[i] == 0)
+ return -EACCES;
+ }
fb = drmMalloc(sizeof (struct sprd_drm_framebuffer));
fb->id = sprd_drm_resource_new_id(fb);
@@ -522,7 +607,10 @@ static int32_t sprd_drm_framebuffer_create(struct sprd_drm_device * dev, struct
memcpy(fb->handles, fb_cmd->handles, 4 * sizeof(fb->handles[0]));
memcpy(fb->pitches, fb_cmd->pitches, 4 * sizeof(fb->pitches[0]));
memcpy(fb->offsets, fb_cmd->offsets, 4 * sizeof(fb->offsets[0]));
+ memcpy(fb->names, names, 4 * sizeof(fb->names[0]));
+ //returned value
+ fb_cmd->fb_id = fb->id;
return 0;
}
@@ -563,7 +651,7 @@ static struct sprd_drm_mode_crtc * sprd_drm_crtc_create(struct sprd_drm_device *
crtc->drm_crtc.fb_id = 0;
crtc->drm_crtc.count_connectors = 0;
- crtc->drm_crtc.set_connectors_ptr = 0;
+ crtc->drm_crtc.set_connectors_ptr = VOID2U64(drmMalloc(MAX_CONNECTOR * sizeof(struct sprd_drm_mode_connector)));
crtc->drm_crtc.x = 0;
crtc->drm_crtc.y = 0;
@@ -601,6 +689,82 @@ static struct sprd_drm_mode_plane * sprd_drm_plane_create(struct sprd_drm_devic
return plane;
}
+static int sprd_drm_connector_modeset(struct sprd_drm_mode_connector * conn,
+ struct sprd_drm_mode_set * mode_set, int zpos) {
+
+ struct overlay_setting ovs = {0,};
+ struct overlay_display_setting ds = {0,};
+
+ ovs.layer_index = zpos;
+
+ if (mode_set->fb) {
+ //TODO:: support different formats
+ ovs.data_type = SPRD_DATA_FORMAT_RGB888;
+ ovs.y_endian = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovs.uv_endian = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovs.v_endian = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovs.rb_switch = 0;
+
+ //TODO:: I am not sure
+ ovs.rect.x = mode_set->x;
+ ovs.rect.y = mode_set->y;
+ ovs.rect.w = mode_set->fb->width;
+ ovs.rect.h = mode_set->fb->height;
+
+ ds.display_mode = SPRD_DISPLAY_OVERLAY_ASYNC;
+ ds.layer_index |= ovs.layer_index;
+ if (ovs.layer_index == SPRD_LAYERS_OSD) {
+ ds.osd_handle = mode_set->fb->names[0];
+ } else {
+ ds.img_handle = mode_set->fb->names[0];
+ }
+
+ if (conn->dpms != DRM_MODE_DPMS_ON) {
+ /* lcd on */
+ if (ioctl(conn->fb_fd, FBIOBLANK, FB_BLANK_UNBLANK) < 0) {
+ SPRD_DRM_ERROR("FB_BLANK_UNBLANK is failed.: %s\n",
+ strerror (errno));
+ return -EACCES;
+ }
+ }
+
+ conn->dpms = DRM_MODE_DPMS_ON;
+
+ if (ioctl(conn->fb_fd, SPRD_FB_SET_OVERLAY, &ovs) == -1) {
+ SPRD_DRM_ERROR( "error:%s Unable to set overlay: SPRD_FB_SET_OVERLAY\n",
+ strerror (errno));
+ return -EACCES;
+ }
+
+ if (ioctl(conn->fb_fd, SPRD_FB_DISPLAY_OVERLAY, &ds) == -1) {
+ SPRD_DRM_ERROR( "error:%s Unable to SPRD_FB_DISPLAY_OVERLAY layer %d\n",
+ strerror (errno), ds.layer_index);
+ return -EACCES;
+ }
+
+ conn->activated_layers |= zpos;
+ mode_set->fb->refcount++;
+ }
+ else {
+ conn->activated_layers &= ~zpos;
+
+ //TODO::disable one layer
+
+ if (!conn->activated_layers) {
+ conn->dpms = DRM_MODE_DPMS_OFF;
+ /* lcd off */
+ if (ioctl(conn->fb_fd, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
+ SPRD_DRM_ERROR("FB_BLANK_UNBLANK is failed.: %s\n", strerror (errno));
+ return -EACCES;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+
static struct sprd_drm_device * get_sprd_device(int fd)
{
struct sprd_drm_device * dev;
@@ -807,32 +971,125 @@ static int sprd_drm_mode_set_plane(int fd, void *arg)
return -1;
}
+/*
+ * We should do following:
+ IOCTL(fd,FBIOBLANK)
+ IOCTL(fd,SPRD_FB_SET_OVERLAY)
+ IOCTL(fd,SPRD_FB_DISPLAY_OVERLAY)
+*/
static int sprd_drm_mode_set_crtc(int fd, void *arg)
{
- return sprd_drm_mode_set_plane(fd, arg);
+ struct drm_mode_crtc * crtc_cmd = (struct drm_mode_crtc *) arg;
+ struct sprd_drm_mode_crtc * crtc;
+ struct sprd_drm_framebuffer * fb = NULL;
+ struct sprd_drm_mode_set mode_set;
+ int i,j;
+
+ memset(&mode_set, 0, sizeof(struct sprd_drm_mode_set));
+
+ crtc = sprd_drm_resource_get(crtc_cmd->crtc_id);
+ if (!crtc)
+ return -EINVAL;
+ mode_set.crtc = crtc;
+
+
+ if (crtc_cmd->fb_id) {
+ mode_set.fb = sprd_drm_resource_get(crtc_cmd->fb_id);
+ if (!mode_set.fb)
+ return -EINVAL;
+ }
+
+
+ //disable all connectors(and layers) witch are connected with this crtc
+ if (crtc_cmd->fb_id == 0 && crtc_cmd->count_connectors == 0) {
+ if (crtc->drm_crtc.set_connectors_ptr) {
+
+ int * ids = U642INTPTR(crtc->drm_crtc.set_connectors_ptr);
+
+ for (i = 0; i < crtc->drm_crtc.count_connectors; i++) {
+ mode_set.connectors[i] = (struct sprd_drm_mode_connector *)sprd_drm_resource_get(ids[i]);
+ if (mode_set.connectors[i])
+ mode_set.num_connectors++;
+ }
+ }
+ }
+ else if (crtc_cmd->count_connectors > 0) {
+
+ if (crtc_cmd->set_connectors_ptr == 0)
+ return -EINVAL;
+
+ int * ids = U642INTPTR(crtc_cmd->set_connectors_ptr);
+
+ for (i = 0; i < crtc_cmd->count_connectors; i++) {
+ mode_set.connectors[i] = (struct sprd_drm_mode_connector *)sprd_drm_resource_get(ids[i]);
+ if (mode_set.connectors[i] == NULL)
+ return -EINVAL;
+ mode_set.num_connectors++;
+ }
+ }
+
+ for (i = 0; i < mode_set.num_connectors; i++) {
+ if(sprd_drm_connector_modeset(mode_set.connectors[i], &mode_set, DEFAULT_ZPOZ) == 0) {
+ if (mode_set.fb) {
+ crtc->drm_crtc.fb_id = mode_set.fb->id;
+
+ //attach connector to crtc
+ int * ids = U642INTPTR(crtc->drm_crtc.set_connectors_ptr);
+ int new_connector = 1;
+ for (j = 0; j < crtc->drm_crtc.count_connectors; j++) {
+ if (ids[j] == mode_set.connectors[i]->drm_conn.connector_id)
+ new_connector = 0;
+ }
+
+ if (new_connector)
+ ids[crtc->drm_crtc.count_connectors++] = mode_set.connectors[i]->drm_conn.connector_id;
+ }
+ else
+ {
+ //detach fb from crtc
+ crtc->drm_crtc.fb_id = 0;
+
+ //detach connector from crtc
+ //TODO:: may be more then one connector, so we should use "for"
+ crtc->drm_crtc.count_connectors = 0;
+ }
+ }
+ }
+
+ return 0;
}
static int sprd_drm_mode_add_fb(int fd, void *arg)
{
struct drm_mode_fb_cmd *or = (struct drm_mode_fb_cmd *)arg;
struct drm_mode_fb_cmd2 r;
+ int res;
+
+ memset(&r, 0, sizeof(struct drm_mode_fb_cmd2));
/* Use new struct with format internally */
- r.fb_id = or->fb_id;
r.width = or->width;
r.height = or->height;
r.pitches[0] = or->pitch;
- r.pixel_format = sprd_drm_mode_legacy_fb_format(or->bpp, or->depth);
+ r.pixel_format = sprd_drm_legacy_fb_format(or->bpp, or->depth);
r.handles[0] = or->handle;
- return sprd_drm_framebuffer_create(get_sprd_device(fd), &r);
+ res = sprd_drm_framebuffer_create(get_sprd_device(fd), &r);
+
+ //returned value
+ or->fb_id = r.fb_id;
+
+ return res;
}
static int sprd_drm_mode_add_fb2(int fd, void *arg)
{
struct drm_mode_fb_cmd2 *r = (struct drm_mode_fb_cmd *)arg;
+ int res;
+
+ res = sprd_drm_framebuffer_create(get_sprd_device(fd), &r);
- return sprd_drm_framebuffer_create(get_sprd_device(fd), &r);
+ return res;
}
static int sprd_drm_mode_rem_fb(int fd, void *arg)
@@ -842,7 +1099,7 @@ static int sprd_drm_mode_rem_fb(int fd, void *arg)
fb = (struct sprd_drm_framebuffer *)sprd_drm_resource_get(id);
- if (!fb) return EINVAL;
+ if (!fb) return -EINVAL;
sprd_drm_framebuffer_remove(get_sprd_device(fd), fb);
@@ -856,7 +1113,7 @@ static int sprd_drm_mode_get_fb(int fd, void *arg)
fb = (struct sprd_drm_framebuffer *)sprd_drm_resource_get(fb_cmd->fb_id);
- if (!fb) return EINVAL;
+ if (!fb) return -EINVAL;
fb_cmd->width = fb->width;
fb_cmd->height = fb->height;
@@ -900,19 +1157,25 @@ struct _ioctl_hook _ioctl_hooks[] = {
DRM_IOCTL_MODE_ADDFB, sprd_drm_mode_add_fb,
DRM_IOCTL_MODE_ADDFB2, sprd_drm_mode_add_fb2,
DRM_IOCTL_MODE_RMFB, sprd_drm_mode_rem_fb,
- DRM_IOCTL_MODE_GETFB, sprd_drm_mode_get_fb,
+ DRM_IOCTL_MODE_GETFB, sprd_drm_mode_get_fb/*,
DRM_IOCTL_MODE_PAGE_FLIP, sprd_drm_mode_page_flip,
DRM_IOCTL_WAIT_VBLANK, sprd_drm_wait_vblank
+*/
};
static int sprd_ioctl_hook(int fd, unsigned long request, void *arg)
{
uint32_t i;
+ int32_t ret;
for (i = 0; i < sizeof(_ioctl_hooks)/sizeof (struct _ioctl_hook); i++) {
if (_ioctl_hooks[i].request == request)
return _ioctl_hooks[i].hook(fd,arg);
}
- return -1;
+
+ do {
+ ret = ioctl(fd, request, arg);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+ return ret;
}
/*