diff options
-rw-r--r-- | src/armada_drm.c | 79 | ||||
-rw-r--r-- | src/armada_module.c | 177 | ||||
-rw-r--r-- | src/common_drm.c | 90 | ||||
-rw-r--r-- | src/common_drm.h | 14 |
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 |