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