Esempio n. 1
0
static int omap_modeset_init(struct drm_device *dev)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_dss_device *dssdev = NULL;
	int num_ovls = dss_feat_get_num_ovls();
	int num_mgrs = dss_feat_get_num_mgrs();
	int num_crtcs;
	int i, id = 0;

	drm_mode_config_init(dev);

	omap_drm_irq_install(dev);

	/*
	 * We usually don't want to create a CRTC for each manager, at least
	 * not until we have a way to expose private planes to userspace.
	 * Otherwise there would not be enough video pipes left for drm planes.
	 * We use the num_crtc argument to limit the number of crtcs we create.
	 */
	num_crtcs = min3(num_crtc, num_mgrs, num_ovls);

	dssdev = NULL;

	for_each_dss_dev(dssdev) {
		struct drm_connector *connector;
		struct drm_encoder *encoder;
		enum omap_channel channel;
		struct omap_overlay_manager *mgr;

		if (!omapdss_device_is_connected(dssdev))
			continue;

		encoder = omap_encoder_init(dev, dssdev);

		if (!encoder) {
			dev_err(dev->dev, "could not create encoder: %s\n",
					dssdev->name);
			return -ENOMEM;
		}

		connector = omap_connector_init(dev,
				get_connector_type(dssdev), dssdev, encoder);

		if (!connector) {
			dev_err(dev->dev, "could not create connector: %s\n",
					dssdev->name);
			return -ENOMEM;
		}

		BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders));
		BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors));

		priv->encoders[priv->num_encoders++] = encoder;
		priv->connectors[priv->num_connectors++] = connector;

		drm_mode_connector_attach_encoder(connector, encoder);

		/*
		 * if we have reached the limit of the crtcs we are allowed to
		 * create, let's not try to look for a crtc for this
		 * panel/encoder and onwards, we will, of course, populate the
		 * the possible_crtcs field for all the encoders with the final
		 * set of crtcs we create
		 */
		if (id == num_crtcs)
			continue;

		/*
		 * get the recommended DISPC channel for this encoder. For now,
		 * we only try to get create a crtc out of the recommended, the
		 * other possible channels to which the encoder can connect are
		 * not considered.
		 */

		mgr = omapdss_find_mgr_from_display(dssdev);
		channel = mgr->id;
		/*
		 * if this channel hasn't already been taken by a previously
		 * allocated crtc, we create a new crtc for it
		 */
		if (!channel_used(dev, channel)) {
			struct drm_plane *plane;
			struct drm_crtc *crtc;

			plane = omap_plane_init(dev, id, true);
			crtc = omap_crtc_init(dev, plane, channel, id);

			BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
			priv->crtcs[id] = crtc;
			priv->num_crtcs++;

			priv->planes[id] = plane;
			priv->num_planes++;

			id++;
		}
	}

	/*
	 * we have allocated crtcs according to the need of the panels/encoders,
	 * adding more crtcs here if needed
	 */
	for (; id < num_crtcs; id++) {

		/* find a free manager for this crtc */
		for (i = 0; i < num_mgrs; i++) {
			if (!channel_used(dev, i)) {
				struct drm_plane *plane;
				struct drm_crtc *crtc;

				plane = omap_plane_init(dev, id, true);
				crtc = omap_crtc_init(dev, plane, i, id);

				BUG_ON(priv->num_crtcs >=
					ARRAY_SIZE(priv->crtcs));

				priv->crtcs[id] = crtc;
				priv->num_crtcs++;

				priv->planes[id] = plane;
				priv->num_planes++;

				break;
			} else {
				continue;
			}
		}

		if (i == num_mgrs) {
			/* this shouldn't really happen */
			dev_err(dev->dev, "no managers left for crtc\n");
			return -ENOMEM;
		}
	}

	/*
	 * Create normal planes for the remaining overlays:
	 */
	for (; id < num_ovls; id++) {
		struct drm_plane *plane = omap_plane_init(dev, id, false);

		BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
		priv->planes[priv->num_planes++] = plane;
	}

	for (i = 0; i < priv->num_encoders; i++) {
		struct drm_encoder *encoder = priv->encoders[i];
		struct omap_dss_device *dssdev =
					omap_encoder_get_dssdev(encoder);
		struct omap_dss_device *output;

		output = omapdss_find_output_from_display(dssdev);

		/* figure out which crtc's we can connect the encoder to: */
		encoder->possible_crtcs = 0;
		for (id = 0; id < priv->num_crtcs; id++) {
			struct drm_crtc *crtc = priv->crtcs[id];
			enum omap_channel crtc_channel;

			crtc_channel = omap_crtc_channel(crtc);

			if (output->dispc_channel == crtc_channel) {
				encoder->possible_crtcs |= (1 << id);
				break;
			}
		}

		omap_dss_put_device(output);
	}

	DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
		priv->num_planes, priv->num_crtcs, priv->num_encoders,
		priv->num_connectors);

	dev->mode_config.min_width = 32;
	dev->mode_config.min_height = 32;

	/* note: eventually will need some cpu_is_omapXYZ() type stuff here
	 * to fill in these limits properly on different OMAP generations..
	 */
	dev->mode_config.max_width = 2048;
	dev->mode_config.max_height = 2048;

	dev->mode_config.funcs = &omap_mode_config_funcs;

	return 0;
}
Esempio n. 2
0
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
{
    struct omapfb_info *ofbi = FB2OFB(fbi);
    struct omapfb2_device *fbdev = ofbi->fbdev;
    struct omap_dss_device *display = fb2display(fbi);
    struct omap_overlay_manager *mgr;

    union {
        struct omapfb_update_window_old	uwnd_o;
        struct omapfb_update_window	uwnd;
        struct omapfb_plane_info	plane_info;
        struct omapfb_caps		caps;
        struct omapfb_mem_info          mem_info;
        struct omapfb_color_key		color_key;
        struct omapfb_ovl_colormode	ovl_colormode;
        enum omapfb_update_mode		update_mode;
        int test_num;
        struct omapfb_memory_read	memory_read;
        struct omapfb_vram_info		vram_info;
        struct omapfb_tearsync_info	tearsync_info;
        struct omapfb_display_info	display_info;
        u32				crt;
    } p;

    int r = 0;

    switch (cmd) {
    case OMAPFB_SYNC_GFX:
        DBG("ioctl SYNC_GFX\n");
        if (!display || !display->driver->sync) {
            /* DSS1 never returns an error here, so we neither */
            /*r = -EINVAL;*/
            break;
        }

        r = display->driver->sync(display);
        break;

    case OMAPFB_UPDATE_WINDOW_OLD:
        DBG("ioctl UPDATE_WINDOW_OLD\n");
        if (!display || !display->driver->update) {
            r = -EINVAL;
            break;
        }

        if (copy_from_user(&p.uwnd_o,
                           (void __user *)arg,
                           sizeof(p.uwnd_o))) {
            r = -EFAULT;
            break;
        }

        r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
                                 p.uwnd_o.width, p.uwnd_o.height);
        break;

    case OMAPFB_UPDATE_WINDOW:
        DBG("ioctl UPDATE_WINDOW\n");
        if (!display || !display->driver->update) {
            r = -EINVAL;
            break;
        }

        if (copy_from_user(&p.uwnd, (void __user *)arg,
                           sizeof(p.uwnd))) {
            r = -EFAULT;
            break;
        }

        r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
                                 p.uwnd.width, p.uwnd.height);
        break;

    case OMAPFB_SETUP_PLANE:
        DBG("ioctl SETUP_PLANE\n");
        if (copy_from_user(&p.plane_info, (void __user *)arg,
                           sizeof(p.plane_info)))
            r = -EFAULT;
        else
            r = omapfb_setup_plane(fbi, &p.plane_info);
        break;

    case OMAPFB_QUERY_PLANE:
        DBG("ioctl QUERY_PLANE\n");
        r = omapfb_query_plane(fbi, &p.plane_info);
        if (r < 0)
            break;
        if (copy_to_user((void __user *)arg, &p.plane_info,
                         sizeof(p.plane_info)))
            r = -EFAULT;
        break;

    case OMAPFB_SETUP_MEM:
        DBG("ioctl SETUP_MEM\n");
        if (copy_from_user(&p.mem_info, (void __user *)arg,
                           sizeof(p.mem_info)))
            r = -EFAULT;
        else
            r = omapfb_setup_mem(fbi, &p.mem_info);
        break;

    case OMAPFB_QUERY_MEM:
        DBG("ioctl QUERY_MEM\n");
        r = omapfb_query_mem(fbi, &p.mem_info);
        if (r < 0)
            break;
        if (copy_to_user((void __user *)arg, &p.mem_info,
                         sizeof(p.mem_info)))
            r = -EFAULT;
        break;

    case OMAPFB_GET_CAPS:
        DBG("ioctl GET_CAPS\n");
        if (!display) {
            r = -EINVAL;
            break;
        }

        memset(&p.caps, 0, sizeof(p.caps));
        if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
            p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
        if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
            p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;

        if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
            r = -EFAULT;
        break;

    case OMAPFB_GET_OVERLAY_COLORMODE:
        DBG("ioctl GET_OVERLAY_COLORMODE\n");
        if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
                           sizeof(p.ovl_colormode))) {
            r = -EFAULT;
            break;
        }
        r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
        if (r < 0)
            break;
        if (copy_to_user((void __user *)arg, &p.ovl_colormode,
                         sizeof(p.ovl_colormode)))
            r = -EFAULT;
        break;

    case OMAPFB_SET_UPDATE_MODE:
        DBG("ioctl SET_UPDATE_MODE\n");
        if (get_user(p.update_mode, (int __user *)arg))
            r = -EFAULT;
        else
            r = omapfb_set_update_mode(fbi, p.update_mode);
        break;

    case OMAPFB_GET_UPDATE_MODE:
        DBG("ioctl GET_UPDATE_MODE\n");
        r = omapfb_get_update_mode(fbi, &p.update_mode);
        if (r)
            break;
        if (put_user(p.update_mode,
                     (enum omapfb_update_mode __user *)arg))
            r = -EFAULT;
        break;

    case OMAPFB_SET_COLOR_KEY:
        DBG("ioctl SET_COLOR_KEY\n");
        if (copy_from_user(&p.color_key, (void __user *)arg,
                           sizeof(p.color_key)))
            r = -EFAULT;
        else
            r = omapfb_set_color_key(fbi, &p.color_key);
        break;

    case OMAPFB_GET_COLOR_KEY:
        DBG("ioctl GET_COLOR_KEY\n");
        r = omapfb_get_color_key(fbi, &p.color_key);
        if (r)
            break;
        if (copy_to_user((void __user *)arg, &p.color_key,
                         sizeof(p.color_key)))
            r = -EFAULT;
        break;

    case FBIO_WAITFORVSYNC:
        if (get_user(p.crt, (__u32 __user *)arg)) {
            r = -EFAULT;
            break;
        }
        if (p.crt != 0) {
            r = -ENODEV;
            break;
        }
    /* FALLTHROUGH */

    case OMAPFB_WAITFORVSYNC:
        DBG("ioctl WAITFORVSYNC\n");

        if (!display) {
            r = -EINVAL;
            break;
        }

        mgr = omapdss_find_mgr_from_display(display);
        if (!mgr) {
            r = -EINVAL;
            break;
        }

        r = mgr->wait_for_vsync(mgr);
        break;

    case OMAPFB_WAITFORGO:
        DBG("ioctl WAITFORGO\n");
        if (!display) {
            r = -EINVAL;
            break;
        }

        r = omapfb_wait_for_go(fbi);
        break;

    /* LCD and CTRL tests do the same thing for backward
     * compatibility */
    case OMAPFB_LCD_TEST:
        DBG("ioctl LCD_TEST\n");
        if (get_user(p.test_num, (int __user *)arg)) {
            r = -EFAULT;
            break;
        }
        if (!display || !display->driver->run_test) {
            r = -EINVAL;
            break;
        }

        r = display->driver->run_test(display, p.test_num);

        break;

    case OMAPFB_CTRL_TEST:
        DBG("ioctl CTRL_TEST\n");
        if (get_user(p.test_num, (int __user *)arg)) {
            r = -EFAULT;
            break;
        }
        if (!display || !display->driver->run_test) {
            r = -EINVAL;
            break;
        }

        r = display->driver->run_test(display, p.test_num);

        break;

    case OMAPFB_MEMORY_READ:
        DBG("ioctl MEMORY_READ\n");

        if (copy_from_user(&p.memory_read, (void __user *)arg,
                           sizeof(p.memory_read))) {
            r = -EFAULT;
            break;
        }

        r = omapfb_memory_read(fbi, &p.memory_read);

        break;

    case OMAPFB_GET_VRAM_INFO: {
        DBG("ioctl GET_VRAM_INFO\n");

        /*
         * We don't have the ability to get this vram info anymore.
         * Fill in something that should keep the applications working.
         */
        p.vram_info.total = SZ_1M * 64;
        p.vram_info.free = SZ_1M * 64;
        p.vram_info.largest_free_block = SZ_1M * 64;

        if (copy_to_user((void __user *)arg, &p.vram_info,
                         sizeof(p.vram_info)))
            r = -EFAULT;
        break;
    }

    case OMAPFB_SET_TEARSYNC: {
        DBG("ioctl SET_TEARSYNC\n");

        if (copy_from_user(&p.tearsync_info, (void __user *)arg,
                           sizeof(p.tearsync_info))) {
            r = -EFAULT;
            break;
        }

        if (!display || !display->driver->enable_te) {
            r = -ENODEV;
            break;
        }

        r = display->driver->enable_te(display,
                                       !!p.tearsync_info.enabled);

        break;
    }

    case OMAPFB_GET_DISPLAY_INFO: {
        u16 xres, yres;

        DBG("ioctl GET_DISPLAY_INFO\n");

        if (display == NULL) {
            r = -ENODEV;
            break;
        }

        display->driver->get_resolution(display, &xres, &yres);

        p.display_info.xres = xres;
        p.display_info.yres = yres;

        if (display->driver->get_dimensions) {
            u32 w, h;
            display->driver->get_dimensions(display, &w, &h);
            p.display_info.width = w;
            p.display_info.height = h;
        } else {
            p.display_info.width = 0;
            p.display_info.height = 0;
        }

        if (copy_to_user((void __user *)arg, &p.display_info,
                         sizeof(p.display_info)))
            r = -EFAULT;
        break;
    }

    default:
        dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
        r = -EINVAL;
    }

    if (r < 0)
        DBG("ioctl failed: %d\n", r);

    return r;
}