1 /*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * Copyright (c) 2012, 2013, Intel Corporation. All rights reserved.
7 */
8
9 /*
10 * Copyright © 2007 David Airlie
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice (including the next
20 * paragraph) shall be included in all copies or substantial portions of the
21 * Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 *
31 * Authors:
32 * David Airlie
33 */
34
35 #include "drmP.h"
36 #include "drm.h"
37 #include "drm_crtc.h"
38 #include "drm_fb_helper.h"
39 #include "intel_drv.h"
40 #include "i915_drm.h"
41 #include "i915_drv.h"
42
intelfb_create(struct drm_fb_helper * helper,struct drm_fb_helper_surface_size * sizes)43 static int intelfb_create(struct drm_fb_helper *helper,
44 struct drm_fb_helper_surface_size *sizes)
45 {
46 struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
47 struct drm_device *dev = ifbdev->helper.dev;
48 struct drm_i915_private *dev_priv = dev->dev_private;
49 struct drm_framebuffer *fb;
50 struct drm_mode_fb_cmd2 mode_cmd;
51 struct drm_i915_gem_object *obj;
52 int size, ret;
53
54 /* we don't do packed 24bpp */
55 if (sizes->surface_bpp == 24)
56 sizes->surface_bpp = 32;
57
58 (void) memset(&mode_cmd, 0, sizeof(struct drm_mode_fb_cmd2));
59
60 mode_cmd.width = sizes->surface_width;
61 mode_cmd.height = sizes->surface_height;
62
63 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) /
64 8), 64);
65 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
66 sizes->surface_depth);
67
68 size = mode_cmd.pitches[0] * mode_cmd.height;
69 size = ALIGN(size, PAGE_SIZE);
70
71 obj = dev_priv->fbcon_obj;
72
73 if (!obj) {
74 DRM_ERROR("There is no framebuffer for console");
75 ret = -ENOMEM;
76 goto out;
77 }
78
79 mutex_lock(&dev->struct_mutex);
80
81 ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
82 if (ret)
83 goto out_unpin;
84
85 fb = &ifbdev->ifb.base;
86
87 ifbdev->helper.fb = fb;
88
89 mutex_unlock(&dev->struct_mutex);
90
91 return 0;
92
93 out_unpin:
94 i915_gem_object_unpin(obj);
95 drm_gem_object_unreference(&obj->base);
96 mutex_unlock(&dev->struct_mutex);
97 out:
98 return ret;
99 }
100
101 static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
102 .gamma_set = intel_crtc_fb_gamma_set,
103 .gamma_get = intel_crtc_fb_gamma_get,
104 .fb_probe = intelfb_create,
105 };
106
intel_fbdev_destroy(struct drm_device * dev,struct intel_fbdev * ifbdev)107 static void intel_fbdev_destroy(struct drm_device *dev,
108 struct intel_fbdev *ifbdev)
109 {
110 struct intel_framebuffer *ifb = &ifbdev->ifb;
111
112 drm_fb_helper_fini(&ifbdev->helper);
113
114 drm_framebuffer_unregister_private(&ifb->base);
115 drm_framebuffer_cleanup(&ifb->base);
116 if (ifb->obj) {
117 drm_gem_object_unreference_unlocked(&ifb->obj->base);
118 ifb->obj = NULL;
119 }
120 }
121
intel_fbdev_init(struct drm_device * dev)122 int intel_fbdev_init(struct drm_device *dev)
123 {
124 struct intel_fbdev *ifbdev;
125 struct drm_i915_private *dev_priv = dev->dev_private;
126 int ret;
127
128 ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
129 if (!ifbdev)
130 return -ENOMEM;
131
132 dev_priv->fbdev = ifbdev;
133 ifbdev->helper.funcs = &intel_fb_helper_funcs;
134
135 ret = drm_fb_helper_init(dev, &ifbdev->helper,
136 INTEL_INFO(dev)->num_pipes,
137 INTELFB_CONN_LIMIT);
138 if (ret) {
139 kfree(ifbdev, sizeof(struct intel_fbdev));
140 return ret;
141 }
142
143 (void) drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
144 return 0;
145 }
146
intel_fbdev_initial_config(struct drm_device * dev)147 void intel_fbdev_initial_config(struct drm_device *dev)
148 {
149 struct drm_i915_private *dev_priv = dev->dev_private;
150
151 /* Due to peculiar init order wrt to hpd handling this is separate. */
152 (void) drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 16);
153 }
154
intel_fbdev_fini(struct drm_device * dev)155 void intel_fbdev_fini(struct drm_device *dev)
156 {
157 struct drm_i915_private *dev_priv = dev->dev_private;
158 if (!dev_priv->fbdev)
159 return;
160
161 intel_fbdev_destroy(dev, dev_priv->fbdev);
162 kfree(dev_priv->fbdev, sizeof(struct intel_fbdev));
163 dev_priv->fbdev = NULL;
164 }
165
intel_fb_output_poll_changed(struct drm_device * dev)166 void intel_fb_output_poll_changed(struct drm_device *dev)
167 {
168 struct drm_i915_private *dev_priv = dev->dev_private;
169 if (dev_priv->fbdev != NULL)
170 (void) drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
171 }
172
intel_fb_restore_mode(struct drm_device * dev)173 void intel_fb_restore_mode(struct drm_device *dev)
174 {
175 int ret;
176 struct drm_i915_private *dev_priv = dev->dev_private;
177
178 if (INTEL_INFO(dev)->num_pipes == 0)
179 return;
180
181 drm_modeset_lock_all(dev);
182
183 ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
184 if (ret)
185 DRM_DEBUG("failed to restore crtc mode\n");
186
187 drm_modeset_unlock_all(dev);
188 }
189