1a61127c2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24d8d096eSAlan Cox /**************************************************************************
34d8d096eSAlan Cox  * Copyright (c) 2007-2011, Intel Corporation.
44d8d096eSAlan Cox  * All Rights Reserved.
54d8d096eSAlan Cox  *
64d8d096eSAlan Cox  **************************************************************************/
74d8d096eSAlan Cox 
8720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
9bc61c975SDaniel Stone #include <drm/drm_gem_framebuffer_helper.h>
103599dfa1SThomas Zimmermann #include <drm/drm_modeset_helper.h>
114d8d096eSAlan Cox 
124d8d096eSAlan Cox #include "framebuffer.h"
130c7b178aSSam Ravnborg #include "psb_drv.h"
144d8d096eSAlan Cox 
154d8d096eSAlan Cox static const struct drm_framebuffer_funcs psb_fb_funcs = {
16bc61c975SDaniel Stone 	.destroy = drm_gem_fb_destroy,
17bc61c975SDaniel Stone 	.create_handle = drm_gem_fb_create_handle,
184d8d096eSAlan Cox };
194d8d096eSAlan Cox 
204d8d096eSAlan Cox /**
214d8d096eSAlan Cox  *	psb_framebuffer_init	-	initialize a framebuffer
224d8d096eSAlan Cox  *	@dev: our DRM device
234d8d096eSAlan Cox  *	@fb: framebuffer to set up
244d8d096eSAlan Cox  *	@mode_cmd: mode description
25358794a2SLee Jones  *	@obj: backing object
264d8d096eSAlan Cox  *
274d8d096eSAlan Cox  *	Configure and fill in the boilerplate for our frame buffer. Return
284d8d096eSAlan Cox  *	0 on success or an error code if we fail.
294d8d096eSAlan Cox  */
psb_framebuffer_init(struct drm_device * dev,struct drm_framebuffer * fb,const struct drm_mode_fb_cmd2 * mode_cmd,struct drm_gem_object * obj)304d8d096eSAlan Cox static int psb_framebuffer_init(struct drm_device *dev,
31e18da8ceSThomas Zimmermann 					struct drm_framebuffer *fb,
321eb83451SVille Syrjälä 					const struct drm_mode_fb_cmd2 *mode_cmd,
330471c9f5SThomas Zimmermann 					struct drm_gem_object *obj)
344d8d096eSAlan Cox {
35e0f9a4abSLaurent Pinchart 	const struct drm_format_info *info;
364d8d096eSAlan Cox 	int ret;
374d8d096eSAlan Cox 
38e0f9a4abSLaurent Pinchart 	/*
39e0f9a4abSLaurent Pinchart 	 * Reject unknown formats, YUV formats, and formats with more than
40e0f9a4abSLaurent Pinchart 	 * 4 bytes per pixel.
41e0f9a4abSLaurent Pinchart 	 */
4292f08076SMaxime Ripard 	info = drm_get_format_info(dev, mode_cmd);
43e0f9a4abSLaurent Pinchart 	if (!info || !info->depth || info->cpp[0] > 4)
44e0f9a4abSLaurent Pinchart 		return -EINVAL;
45a9a644acSDave Airlie 
46a9a644acSDave Airlie 	if (mode_cmd->pitches[0] & 63)
474d8d096eSAlan Cox 		return -EINVAL;
48e0f9a4abSLaurent Pinchart 
49e18da8ceSThomas Zimmermann 	drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
500471c9f5SThomas Zimmermann 	fb->obj[0] = obj;
51e18da8ceSThomas Zimmermann 	ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs);
524d8d096eSAlan Cox 	if (ret) {
534d8d096eSAlan Cox 		dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
544d8d096eSAlan Cox 		return ret;
554d8d096eSAlan Cox 	}
564d8d096eSAlan Cox 	return 0;
574d8d096eSAlan Cox }
584d8d096eSAlan Cox 
594d8d096eSAlan Cox /**
604d8d096eSAlan Cox  *	psb_framebuffer_create	-	create a framebuffer backed by gt
614d8d096eSAlan Cox  *	@dev: our DRM device
624d8d096eSAlan Cox  *	@mode_cmd: the description of the requested mode
63358794a2SLee Jones  *	@obj: the backing object
644d8d096eSAlan Cox  *
654d8d096eSAlan Cox  *	Create a framebuffer object backed by the gt, and fill in the
664d8d096eSAlan Cox  *	boilerplate required
674d8d096eSAlan Cox  *
684d8d096eSAlan Cox  *	TODO: review object references
694d8d096eSAlan Cox  */
psb_framebuffer_create(struct drm_device * dev,const struct drm_mode_fb_cmd2 * mode_cmd,struct drm_gem_object * obj)70*b8bbbea1SThomas Zimmermann struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev,
711eb83451SVille Syrjälä 					       const struct drm_mode_fb_cmd2 *mode_cmd,
720471c9f5SThomas Zimmermann 					       struct drm_gem_object *obj)
734d8d096eSAlan Cox {
74e18da8ceSThomas Zimmermann 	struct drm_framebuffer *fb;
754d8d096eSAlan Cox 	int ret;
764d8d096eSAlan Cox 
774d8d096eSAlan Cox 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
784d8d096eSAlan Cox 	if (!fb)
794d8d096eSAlan Cox 		return ERR_PTR(-ENOMEM);
804d8d096eSAlan Cox 
810471c9f5SThomas Zimmermann 	ret = psb_framebuffer_init(dev, fb, mode_cmd, obj);
824d8d096eSAlan Cox 	if (ret) {
834d8d096eSAlan Cox 		kfree(fb);
844d8d096eSAlan Cox 		return ERR_PTR(ret);
854d8d096eSAlan Cox 	}
86e18da8ceSThomas Zimmermann 	return fb;
874d8d096eSAlan Cox }
884d8d096eSAlan Cox 
894d8d096eSAlan Cox /**
904d8d096eSAlan Cox  *	psb_user_framebuffer_create	-	create framebuffer
914d8d096eSAlan Cox  *	@dev: our DRM device
924d8d096eSAlan Cox  *	@filp: client file
934d8d096eSAlan Cox  *	@cmd: mode request
944d8d096eSAlan Cox  *
954d8d096eSAlan Cox  *	Create a new framebuffer backed by a userspace GEM object
964d8d096eSAlan Cox  */
psb_user_framebuffer_create(struct drm_device * dev,struct drm_file * filp,const struct drm_mode_fb_cmd2 * cmd)974d8d096eSAlan Cox static struct drm_framebuffer *psb_user_framebuffer_create
984d8d096eSAlan Cox 			(struct drm_device *dev, struct drm_file *filp,
991eb83451SVille Syrjälä 			 const struct drm_mode_fb_cmd2 *cmd)
1004d8d096eSAlan Cox {
1014d8d096eSAlan Cox 	struct drm_gem_object *obj;
102cd8f318fSJing Xiangfeng 	struct drm_framebuffer *fb;
1034d8d096eSAlan Cox 
1044d8d096eSAlan Cox 	/*
1054d8d096eSAlan Cox 	 *	Find the GEM object and thus the gtt range object that is
1064d8d096eSAlan Cox 	 *	to back this space
1074d8d096eSAlan Cox 	 */
108a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(filp, cmd->handles[0]);
1094d8d096eSAlan Cox 	if (obj == NULL)
1104d8d096eSAlan Cox 		return ERR_PTR(-ENOENT);
1114d8d096eSAlan Cox 
1124d8d096eSAlan Cox 	/* Let the core code do all the work */
113cd8f318fSJing Xiangfeng 	fb = psb_framebuffer_create(dev, cmd, obj);
114cd8f318fSJing Xiangfeng 	if (IS_ERR(fb))
115cd8f318fSJing Xiangfeng 		drm_gem_object_put(obj);
116cd8f318fSJing Xiangfeng 
117cd8f318fSJing Xiangfeng 	return fb;
1184d8d096eSAlan Cox }
1194d8d096eSAlan Cox 
1204d8d096eSAlan Cox static const struct drm_mode_config_funcs psb_mode_funcs = {
1214d8d096eSAlan Cox 	.fb_create = psb_user_framebuffer_create,
1224d8d096eSAlan Cox };
1234d8d096eSAlan Cox 
psb_setup_outputs(struct drm_device * dev)1244d8d096eSAlan Cox static void psb_setup_outputs(struct drm_device *dev)
1254d8d096eSAlan Cox {
126f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
127b1a7d0ddSPatrik Jakobsson 	struct drm_connector_list_iter conn_iter;
1284d8d096eSAlan Cox 	struct drm_connector *connector;
1294d8d096eSAlan Cox 
1304d8d096eSAlan Cox 	drm_mode_create_scaling_mode_property(dev);
1314d8d096eSAlan Cox 
13213619ce5SAlan Cox 	/* It is ok for this to fail - we just don't get backlight control */
13313619ce5SAlan Cox 	if (!dev_priv->backlight_property)
13413619ce5SAlan Cox 		dev_priv->backlight_property = drm_property_create_range(dev, 0,
13513619ce5SAlan Cox 							"backlight", 0, 100);
1364d8d096eSAlan Cox 	dev_priv->ops->output_init(dev);
1374d8d096eSAlan Cox 
138b1a7d0ddSPatrik Jakobsson 	drm_connector_list_iter_begin(dev, &conn_iter);
139b1a7d0ddSPatrik Jakobsson 	drm_for_each_connector_iter(connector, &conn_iter) {
140367e4408SPatrik Jakobsson 		struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
141367e4408SPatrik Jakobsson 		struct drm_encoder *encoder = &gma_encoder->base;
1424d8d096eSAlan Cox 		int crtc_mask = 0, clone_mask = 0;
1434d8d096eSAlan Cox 
1444d8d096eSAlan Cox 		/* valid crtcs */
145367e4408SPatrik Jakobsson 		switch (gma_encoder->type) {
1464d8d096eSAlan Cox 		case INTEL_OUTPUT_ANALOG:
1474d8d096eSAlan Cox 			crtc_mask = (1 << 0);
1484d8d096eSAlan Cox 			clone_mask = (1 << INTEL_OUTPUT_ANALOG);
1494d8d096eSAlan Cox 			break;
1504d8d096eSAlan Cox 		case INTEL_OUTPUT_SDVO:
151cf8efd3aSPatrik Jakobsson 			crtc_mask = dev_priv->ops->sdvo_mask;
1528a7827eeSVille Syrjälä 			clone_mask = 0;
1534d8d096eSAlan Cox 			break;
1544d8d096eSAlan Cox 		case INTEL_OUTPUT_LVDS:
155d235e64aSAlan Cox 			crtc_mask = dev_priv->ops->lvds_mask;
1568a7827eeSVille Syrjälä 			clone_mask = 0;
1574d8d096eSAlan Cox 			break;
1584d8d096eSAlan Cox 		case INTEL_OUTPUT_MIPI:
1594d8d096eSAlan Cox 			crtc_mask = (1 << 0);
1608a7827eeSVille Syrjälä 			clone_mask = 0;
1614d8d096eSAlan Cox 			break;
1624d8d096eSAlan Cox 		case INTEL_OUTPUT_MIPI2:
1634d8d096eSAlan Cox 			crtc_mask = (1 << 2);
1648a7827eeSVille Syrjälä 			clone_mask = 0;
1654d8d096eSAlan Cox 			break;
1664d8d096eSAlan Cox 		case INTEL_OUTPUT_HDMI:
167d235e64aSAlan Cox 			crtc_mask = dev_priv->ops->hdmi_mask;
1684d8d096eSAlan Cox 			clone_mask = (1 << INTEL_OUTPUT_HDMI);
1694d8d096eSAlan Cox 			break;
170220801bdSAlan Cox 		case INTEL_OUTPUT_DISPLAYPORT:
171220801bdSAlan Cox 			crtc_mask = (1 << 0) | (1 << 1);
1728a7827eeSVille Syrjälä 			clone_mask = 0;
173220801bdSAlan Cox 			break;
174d112a816SZhao Yakui 		case INTEL_OUTPUT_EDP:
175d112a816SZhao Yakui 			crtc_mask = (1 << 1);
1768a7827eeSVille Syrjälä 			clone_mask = 0;
1774d8d096eSAlan Cox 		}
1784d8d096eSAlan Cox 		encoder->possible_crtcs = crtc_mask;
1794d8d096eSAlan Cox 		encoder->possible_clones =
180a3d5d75fSPatrik Jakobsson 		    gma_connector_clones(dev, clone_mask);
1814d8d096eSAlan Cox 	}
182b1a7d0ddSPatrik Jakobsson 	drm_connector_list_iter_end(&conn_iter);
1834d8d096eSAlan Cox }
1844d8d096eSAlan Cox 
psb_modeset_init(struct drm_device * dev)1854d8d096eSAlan Cox void psb_modeset_init(struct drm_device *dev)
1864d8d096eSAlan Cox {
187f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
1884d8d096eSAlan Cox 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
1894d8d096eSAlan Cox 	int i;
1904d8d096eSAlan Cox 
191c89717bdSPatrik Jakobsson 	if (drmm_mode_config_init(dev))
192c89717bdSPatrik Jakobsson 		return;
1934d8d096eSAlan Cox 
1944d8d096eSAlan Cox 	dev->mode_config.min_width = 0;
1954d8d096eSAlan Cox 	dev->mode_config.min_height = 0;
1964d8d096eSAlan Cox 
197e6ecefaaSLaurent Pinchart 	dev->mode_config.funcs = &psb_mode_funcs;
1984d8d096eSAlan Cox 
1994d8d096eSAlan Cox 	/* num pipes is 2 for PSB but 1 for Mrst */
2004d8d096eSAlan Cox 	for (i = 0; i < dev_priv->num_pipe; i++)
2014d8d096eSAlan Cox 		psb_intel_crtc_init(dev, i, mode_dev);
2024d8d096eSAlan Cox 
203cbbd379aSPatrik Jakobsson 	dev->mode_config.max_width = 4096;
204cbbd379aSPatrik Jakobsson 	dev->mode_config.max_height = 4096;
2054d8d096eSAlan Cox 
2064d8d096eSAlan Cox 	psb_setup_outputs(dev);
207d235e64aSAlan Cox 
208d235e64aSAlan Cox 	if (dev_priv->ops->errata)
209d235e64aSAlan Cox 	        dev_priv->ops->errata(dev);
2104ab2c7f1SAlan Cox 
2114ab2c7f1SAlan Cox         dev_priv->modeset = true;
2124d8d096eSAlan Cox }
2134d8d096eSAlan Cox 
psb_modeset_cleanup(struct drm_device * dev)2144d8d096eSAlan Cox void psb_modeset_cleanup(struct drm_device *dev)
2154d8d096eSAlan Cox {
216f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
2174ab2c7f1SAlan Cox 	if (dev_priv->modeset) {
2184d8d096eSAlan Cox 		drm_kms_helper_poll_fini(dev);
2194d8d096eSAlan Cox 	}
2204ab2c7f1SAlan Cox }
221