summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/armada_drm.c79
-rw-r--r--src/armada_module.c177
-rw-r--r--src/common_drm.c90
-rw-r--r--src/common_drm.h14
4 files changed, 285 insertions, 75 deletions
diff --git a/src/armada_drm.c b/src/armada_drm.c
index 585e285..14de490 100644
--- a/src/armada_drm.c
+++ b/src/armada_drm.c
@@ -33,9 +33,6 @@
#define CURSOR_MAX_WIDTH 64
#define CURSOR_MAX_HEIGHT 32
-#define DRM_MODULE_NAMES "armada-drm", "imx-drm"
-#define DRM_DEFAULT_BUS_ID NULL
-
const OptionInfoRec armada_drm_options[] = {
{ OPTION_XV_ACCEL, "XvAccel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_XV_PREFEROVL, "XvPreferOverlay", OPTV_BOOLEAN, {0}, TRUE },
@@ -440,7 +437,7 @@ static Bool armada_drm_ScreenInit(SCREEN_INIT_ARGS_DECL)
Bool use_kms_bo;
Bool ret;
- if (drmSetMaster(drm->fd)) {
+ if (!common_drm_get_master(drm->dev)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] set master failed: %s\n", strerror(errno));
return FALSE;
@@ -572,29 +569,13 @@ static int armada_get_cap(int fd, uint64_t cap, uint64_t *val, int scrnIndex,
return err;
}
-static const char *drm_module_names[] = { DRM_MODULE_NAMES };
-
-static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
+static Bool armada_drm_alloc(ScrnInfoPtr pScrn,
+ struct common_drm_device *drm_dev)
{
struct all_drm_info *drm;
- EntityInfoPtr pEnt;
- drmSetVersion sv;
- const char *busid = DRM_DEFAULT_BUS_ID;
uint64_t val;
- unsigned i;
int err;
- pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
- if (pEnt) {
- if (pEnt->device->busID)
- busid = pEnt->device->busID;
- free(pEnt);
- }
-
- if (busid)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using BusID \"%s\"\n",
- busid);
-
drm = calloc(1, sizeof *drm);
if (!drm)
return FALSE;
@@ -602,59 +583,32 @@ static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
drm->common.cursor_max_width = CURSOR_MAX_WIDTH;
drm->common.cursor_max_height = CURSOR_MAX_HEIGHT;
drm->common.private = &drm->armada;
-
- for (i = 0; i < ARRAY_SIZE(drm_module_names); i++) {
- drm->common.fd = drmOpen(drm_module_names[i], busid);
- if (drm->common.fd >= 0)
- break;
- }
-
- if (drm->common.fd < 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] Failed to open DRM device for %s: %s\n",
- busid, strerror(errno));
- goto err_free;
- }
-
- /*
- * Check that what we opened was a master or a master-capable FD
- * by setting the version of the interface we'll use to talk to it.
- */
- sv.drm_di_major = 1;
- sv.drm_di_minor = 1;
- sv.drm_dd_major = -1;
- sv.drm_dd_minor = -1;
- err = drmSetInterfaceVersion(drm->common.fd, &sv);
- if (err) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] failed to set DRM interface version: %s\n",
- strerror(errno));
- goto err_drm_close;
- }
+ drm->common.fd = drm_dev->fd;
+ drm->common.dev = drm_dev;
if (armada_get_cap(drm->common.fd, DRM_CAP_PRIME, &val,
pScrn->scrnIndex, "DRM_CAP_PRIME"))
- goto err_drm_close;
+ goto err_free;
if (!(val & DRM_PRIME_CAP_EXPORT)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] kernel doesn't support prime export.\n");
- goto err_drm_close;
+ goto err_free;
}
if (armada_get_cap(drm->common.fd, DRM_CAP_DUMB_BUFFER, &val,
pScrn->scrnIndex, "DRM_CAP_DUMB_BUFFER"))
- goto err_drm_close;
+ goto err_free;
if (!val) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] kernel doesn't support dumb buffer.\n");
- goto err_drm_close;
+ goto err_free;
}
err = drm_armada_init(drm->common.fd, &drm->armada.bufmgr);
if (err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] failed to initialize Armada DRM manager.\n");
- goto err_drm_close;
+ goto err_free;
}
SET_DRM_INFO(pScrn, &drm->common);
@@ -666,8 +620,6 @@ static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
return TRUE;
- err_drm_close:
- drmClose(drm->common.fd);
err_free:
free(drm);
return FALSE;
@@ -691,6 +643,7 @@ static void armada_drm_FreeScreen(FREE_SCREEN_ARGS_DECL)
static Bool armada_drm_PreInit(ScrnInfoPtr pScrn, int flags)
{
+ struct common_drm_device *drm_dev;
rgb defaultWeight = { 0, 0, 0 };
int flags24;
@@ -700,11 +653,13 @@ static Bool armada_drm_PreInit(ScrnInfoPtr pScrn, int flags)
if (flags & PROBE_DETECT)
return FALSE;
- if (!armada_drm_open_master(pScrn)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Failed to become DRM master.\n");
+ /* Get the device we detected at probe time */
+ drm_dev = common_entity_get_dev(pScrn->entityList[0]);
+ if (!drm_dev)
+ return FALSE;
+
+ if (!armada_drm_alloc(pScrn, drm_dev))
return FALSE;
- }
/* Limit the maximum framebuffer size to 16MB */
pScrn->videoRam = 16 * 1048576;
diff --git a/src/armada_module.c b/src/armada_module.c
index 8b50442..eef3c75 100644
--- a/src/armada_module.c
+++ b/src/armada_module.c
@@ -8,6 +8,15 @@
#include "config.h"
#endif
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include "xf86.h"
+#ifdef XSERVER_PLATFORM_BUS
+#include "xf86platformBus.h"
+#endif
+
#include "armada_drm.h"
#include "armada_accel.h"
#include "common_drm.h"
@@ -17,6 +26,11 @@
#define ARMADA_NAME "armada"
#define ARMADA_DRIVER_NAME "armada"
+#define DRM_MODULE_NAMES "armada-drm", "imx-drm"
+#define DRM_DEFAULT_BUS_ID NULL
+
+static const char *drm_module_names[] = { DRM_MODULE_NAMES };
+
/* Supported "chipsets" */
static SymTabRec armada_chipsets[] = {
// { 0, "88AP16x" },
@@ -101,6 +115,16 @@ static void armada_identify(int flags)
ipu_chipsets);
}
+static void armada_init_screen(ScrnInfoPtr pScrn)
+{
+ pScrn->driverVersion = ARMADA_VERSION;
+ pScrn->driverName = ARMADA_DRIVER_NAME;
+ pScrn->name = ARMADA_NAME;
+ pScrn->Probe = NULL;
+
+ armada_drm_init_screen(pScrn);
+}
+
static Bool armada_probe(DriverPtr drv, int flags)
{
GDevPtr *devSections;
@@ -116,22 +140,38 @@ static Bool armada_probe(DriverPtr drv, int flags)
for (i = 0; i < numDevSections; i++) {
ScrnInfoPtr pScrn;
- int entity;
+ const char *busid = DRM_DEFAULT_BUS_ID;
+ int entity, fd, j;
+
+ if (devSections[i]->busID)
+ busid = devSections[i]->busID;
+
+ for (j = 0; j < ARRAY_SIZE(drm_module_names); j++) {
+ fd = drmOpen(drm_module_names[j], busid);
+ if (fd >= 0)
+ break;
+ }
+
+ if (fd < 0)
+ continue;
+
+ if (!common_drm_fd_is_master(fd))
+ continue;
entity = xf86ClaimNoSlot(drv, 0, devSections[i], TRUE);
+ common_alloc_dev(entity, fd, NULL, TRUE);
+
pScrn = xf86ConfigFbEntity(NULL, 0, entity,
NULL, NULL, NULL, NULL);
+ if (!pScrn)
+ continue;
- if (pScrn) {
- foundScreen = TRUE;
+ if (busid)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Using BusID \"%s\"\n", busid);
- pScrn->driverVersion = ARMADA_VERSION;
- pScrn->driverName = ARMADA_DRIVER_NAME;
- pScrn->name = ARMADA_NAME;
- pScrn->Probe = NULL;
-
- armada_drm_init_screen(pScrn);
- }
+ foundScreen = TRUE;
+ armada_init_screen(pScrn);
}
free(devSections);
@@ -166,11 +206,125 @@ armada_driver_func(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
flag = (CARD32*)ptr;
(*flag) = 0;
return TRUE;
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,0)
+ case SUPPORTS_SERVER_FDS:
+ return TRUE;
+#endif
default:
return FALSE;
}
}
+#ifdef XSERVER_PLATFORM_BUS
+static Bool armada_is_kms(int fd)
+{
+ drmVersionPtr version;
+ drmModeResPtr res;
+ Bool has_connectors;
+
+ version = drmGetVersion(fd);
+ if (!version)
+ return FALSE;
+ drmFreeVersion(version);
+
+ res = drmModeGetResources(fd);
+ if (!res)
+ return FALSE;
+
+ has_connectors = res->count_connectors > 0;
+ drmModeFreeResources(res);
+
+ return has_connectors;
+}
+
+static struct common_drm_device *armada_create_dev(int entity_num,
+ struct xf86_platform_device *dev)
+{
+ struct common_drm_device *drm_dev;
+ const char *path;
+ Bool ddx_managed_master;
+ int fd, our_fd = -1;
+
+ path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH);
+ if (!path)
+ goto err_free;
+
+#ifdef ODEV_ATTRIB_FD
+ fd = xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1);
+#else
+ fd = -1;
+#endif
+ if (fd != -1) {
+ ddx_managed_master = FALSE;
+ if (!armada_is_kms(fd))
+ goto err_free;
+ } else {
+ ddx_managed_master = TRUE;
+ our_fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (our_fd == -1)
+ goto err_free;
+
+ if (!armada_is_kms(our_fd)) {
+ close(our_fd);
+ goto err_free;
+ }
+
+ if (!common_drm_fd_is_master(our_fd)) {
+ close(our_fd);
+ goto err_free;
+ }
+
+ fd = our_fd;
+ }
+
+ /* If we're running unprivileged, don't drop master status */
+ if (geteuid())
+ ddx_managed_master = FALSE;
+
+ drm_dev = common_alloc_dev(entity_num, fd, path, ddx_managed_master);
+ if (!drm_dev && our_fd != -1)
+ close(our_fd);
+
+ return drm_dev;
+
+ err_free:
+ return NULL;
+}
+
+static int armada_create_screen(DriverPtr drv, int entity_num,
+ struct common_drm_device *drm_dev)
+{
+ ScrnInfoPtr pScrn;
+
+ pScrn = xf86AllocateScreen(drv, 0);
+ if (!pScrn)
+ return FALSE;
+
+ xf86AddEntityToScreen(pScrn, entity_num);
+
+ armada_init_screen(pScrn);
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Added screen for KMS device %s\n", drm_dev->kms_path);
+
+ return TRUE;
+}
+
+static Bool armada_platform_probe(DriverPtr drv, int entity_num, int flags,
+ struct xf86_platform_device *dev, intptr_t match_data)
+{
+ struct common_drm_device *drm_dev;
+
+ drm_dev = common_entity_get_dev(entity_num);
+ if (!drm_dev)
+ drm_dev = armada_create_dev(entity_num, dev);
+ if (!drm_dev)
+ return FALSE;
+
+ return armada_create_screen(drv, entity_num, drm_dev);
+}
+#endif
+
_X_EXPORT DriverRec armada_driver = {
.driverVersion = ARMADA_VERSION,
.driverName = ARMADA_DRIVER_NAME,
@@ -178,6 +332,9 @@ _X_EXPORT DriverRec armada_driver = {
.Probe = armada_probe,
.AvailableOptions = armada_available_options,
.driverFunc = armada_driver_func,
+#ifdef XSERVER_PLATFORM_BUS
+ .platformProbe = armada_platform_probe,
+#endif
};
#ifdef XFree86LOADER
diff --git a/src/common_drm.c b/src/common_drm.c
index b92b71c..e2468eb 100644
--- a/src/common_drm.c
+++ b/src/common_drm.c
@@ -1277,12 +1277,16 @@ Bool common_drm_EnterVT(VT_FUNC_ARGS_DECL)
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
int i;
- if (drmSetMaster(drm->fd))
+ if (!common_drm_get_master(drm->dev)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"[drm] set master failed: %s\n", strerror(errno));
+ return FALSE;
+ }
- if (!xf86SetDesiredModes(pScrn))
+ if (!xf86SetDesiredModes(pScrn)) {
+ common_drm_put_master(drm->dev);
return FALSE;
+ }
/* Disable unused CRTCs */
for (i = 0; i < xf86_config->num_crtc; i++) {
@@ -1306,7 +1310,7 @@ void common_drm_LeaveVT(VT_FUNC_ARGS_DECL)
xf86_hide_cursors(pScrn);
- drmDropMaster(drm->fd);
+ common_drm_put_master(drm->dev);
}
void common_drm_FreeScreen(FREE_SCREEN_ARGS_DECL)
@@ -1475,3 +1479,83 @@ int common_drm_vblank_wait(ScrnInfoPtr pScrn, xf86CrtcPtr crtc,
return ret;
}
+
+
+static int common_entity_key = -1;
+
+struct common_drm_device *common_entity_get_dev(int entity_num)
+{
+ if (common_entity_key == -1)
+ common_entity_key = xf86AllocateEntityPrivateIndex();
+ if (common_entity_key == -1)
+ return NULL;
+
+ return xf86GetEntityPrivate(entity_num, common_entity_key)->ptr;
+}
+
+static void common_entity_set_dev(int entity_num, struct common_drm_device *dev)
+{
+ if (common_entity_key == -1)
+ common_entity_key = xf86AllocateEntityPrivateIndex();
+
+ xf86GetEntityPrivate(entity_num, common_entity_key)->ptr = dev;
+}
+
+struct common_drm_device *common_alloc_dev(int entity_num, int fd,
+ const char *path, Bool ddx_managed_master)
+{
+ struct common_drm_device *drm_dev;
+
+ drm_dev = malloc(sizeof *drm_dev);
+ if (!drm_dev)
+ return NULL;
+
+ drm_dev->fd = fd;
+ drm_dev->master_count = !ddx_managed_master;
+
+ if (path) {
+ drm_dev->kms_path = strdup(path);
+ if (!drm_dev->kms_path) {
+ free(drm_dev);
+ return NULL;
+ }
+ } else {
+ drm_dev->kms_path = NULL;
+ }
+
+ common_entity_set_dev(entity_num, drm_dev);
+
+ return drm_dev;
+}
+
+/*
+ * Check that what we opened was a master or a master-capable FD
+ * by setting the version of the interface we'll use to talk to it.
+ */
+Bool common_drm_fd_is_master(int fd)
+{
+ drmSetVersion sv;
+
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 1;
+ sv.drm_dd_major = -1;
+ sv.drm_dd_minor = -1;
+
+ return drmSetInterfaceVersion(fd, &sv) == 0;
+}
+
+Bool common_drm_get_master(struct common_drm_device *drm_dev)
+{
+ if (drm_dev->master_count++)
+ return TRUE;
+
+ return drmSetMaster(drm_dev->fd) ? FALSE : TRUE;
+}
+
+void common_drm_put_master(struct common_drm_device *drm_dev)
+{
+ assert(drm_dev->master_count);
+
+ if (--drm_dev->master_count == 0)
+ drmDropMaster(drm_dev->fd);
+}
diff --git a/src/common_drm.h b/src/common_drm.h
index 702a920..537c88d 100644
--- a/src/common_drm.h
+++ b/src/common_drm.h
@@ -7,6 +7,12 @@
struct common_drm_event;
+struct common_drm_device {
+ int fd;
+ int master_count;
+ const char *kms_path;
+};
+
struct common_crtc_info {
int drm_fd;
unsigned num;
@@ -31,6 +37,7 @@ struct drm_udev_info {
struct common_drm_info {
int fd;
+ struct common_drm_device *dev;
uint32_t fb_id;
drmModeResPtr mode_res;
drmEventContext event_context;
@@ -110,4 +117,11 @@ void common_drm_FreeScreen(FREE_SCREEN_ARGS_DECL);
/* Present extension support */
Bool common_present_init(ScreenPtr pScreen);
+struct common_drm_device *common_entity_get_dev(int entity_num);
+struct common_drm_device *common_alloc_dev(int entity_num, int fd,
+ const char *path, Bool ddx_managed_master);
+Bool common_drm_fd_is_master(int fd);
+Bool common_drm_get_master(struct common_drm_device *drm_dev);
+void common_drm_put_master(struct common_drm_device *drm_dev);
+
#endif