]> Git Repo - linux.git/blob - drivers/gpu/drm/armada/armada_fbdev.c
Merge tag 'asoc-fix-v4.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broon...
[linux.git] / drivers / gpu / drm / armada / armada_fbdev.c
1 /*
2  * Copyright (C) 2012 Russell King
3  *  Written from the i915 driver.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9 #include <linux/errno.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12
13 #include <drm/drmP.h>
14 #include <drm/drm_fb_helper.h>
15 #include "armada_crtc.h"
16 #include "armada_drm.h"
17 #include "armada_fb.h"
18 #include "armada_gem.h"
19
20 static /*const*/ struct fb_ops armada_fb_ops = {
21         .owner          = THIS_MODULE,
22         DRM_FB_HELPER_DEFAULT_OPS,
23         .fb_fillrect    = drm_fb_helper_cfb_fillrect,
24         .fb_copyarea    = drm_fb_helper_cfb_copyarea,
25         .fb_imageblit   = drm_fb_helper_cfb_imageblit,
26 };
27
28 static int armada_fb_create(struct drm_fb_helper *fbh,
29         struct drm_fb_helper_surface_size *sizes)
30 {
31         struct drm_device *dev = fbh->dev;
32         struct drm_mode_fb_cmd2 mode;
33         struct armada_framebuffer *dfb;
34         struct armada_gem_object *obj;
35         struct fb_info *info;
36         int size, ret;
37         void *ptr;
38
39         memset(&mode, 0, sizeof(mode));
40         mode.width = sizes->surface_width;
41         mode.height = sizes->surface_height;
42         mode.pitches[0] = armada_pitch(mode.width, sizes->surface_bpp);
43         mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
44                                         sizes->surface_depth);
45
46         size = mode.pitches[0] * mode.height;
47         obj = armada_gem_alloc_private_object(dev, size);
48         if (!obj) {
49                 DRM_ERROR("failed to allocate fb memory\n");
50                 return -ENOMEM;
51         }
52
53         ret = armada_gem_linear_back(dev, obj);
54         if (ret) {
55                 drm_gem_object_unreference_unlocked(&obj->obj);
56                 return ret;
57         }
58
59         ptr = armada_gem_map_object(dev, obj);
60         if (!ptr) {
61                 drm_gem_object_unreference_unlocked(&obj->obj);
62                 return -ENOMEM;
63         }
64
65         dfb = armada_framebuffer_create(dev, &mode, obj);
66
67         /*
68          * A reference is now held by the framebuffer object if
69          * successful, otherwise this drops the ref for the error path.
70          */
71         drm_gem_object_unreference_unlocked(&obj->obj);
72
73         if (IS_ERR(dfb))
74                 return PTR_ERR(dfb);
75
76         info = drm_fb_helper_alloc_fbi(fbh);
77         if (IS_ERR(info)) {
78                 ret = PTR_ERR(info);
79                 goto err_fballoc;
80         }
81
82         strlcpy(info->fix.id, "armada-drmfb", sizeof(info->fix.id));
83         info->par = fbh;
84         info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
85         info->fbops = &armada_fb_ops;
86         info->fix.smem_start = obj->phys_addr;
87         info->fix.smem_len = obj->obj.size;
88         info->screen_size = obj->obj.size;
89         info->screen_base = ptr;
90         fbh->fb = &dfb->fb;
91
92         drm_fb_helper_fill_fix(info, dfb->fb.pitches[0],
93                                dfb->fb.format->depth);
94         drm_fb_helper_fill_var(info, fbh, sizes->fb_width, sizes->fb_height);
95
96         DRM_DEBUG_KMS("allocated %dx%d %dbpp fb: 0x%08llx\n",
97                 dfb->fb.width, dfb->fb.height, dfb->fb.format->cpp[0] * 8,
98                 (unsigned long long)obj->phys_addr);
99
100         return 0;
101
102  err_fballoc:
103         dfb->fb.funcs->destroy(&dfb->fb);
104         return ret;
105 }
106
107 static int armada_fb_probe(struct drm_fb_helper *fbh,
108         struct drm_fb_helper_surface_size *sizes)
109 {
110         int ret = 0;
111
112         if (!fbh->fb) {
113                 ret = armada_fb_create(fbh, sizes);
114                 if (ret == 0)
115                         ret = 1;
116         }
117         return ret;
118 }
119
120 static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
121         .gamma_set      = armada_drm_crtc_gamma_set,
122         .gamma_get      = armada_drm_crtc_gamma_get,
123         .fb_probe       = armada_fb_probe,
124 };
125
126 int armada_fbdev_init(struct drm_device *dev)
127 {
128         struct armada_private *priv = dev->dev_private;
129         struct drm_fb_helper *fbh;
130         int ret;
131
132         fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL);
133         if (!fbh)
134                 return -ENOMEM;
135
136         priv->fbdev = fbh;
137
138         drm_fb_helper_prepare(dev, fbh, &armada_fb_helper_funcs);
139
140         ret = drm_fb_helper_init(dev, fbh, 1);
141         if (ret) {
142                 DRM_ERROR("failed to initialize drm fb helper\n");
143                 goto err_fb_helper;
144         }
145
146         ret = drm_fb_helper_single_add_all_connectors(fbh);
147         if (ret) {
148                 DRM_ERROR("failed to add fb connectors\n");
149                 goto err_fb_setup;
150         }
151
152         ret = drm_fb_helper_initial_config(fbh, 32);
153         if (ret) {
154                 DRM_ERROR("failed to set initial config\n");
155                 goto err_fb_setup;
156         }
157
158         return 0;
159  err_fb_setup:
160         drm_fb_helper_fini(fbh);
161  err_fb_helper:
162         priv->fbdev = NULL;
163         return ret;
164 }
165
166 void armada_fbdev_lastclose(struct drm_device *dev)
167 {
168         struct armada_private *priv = dev->dev_private;
169
170         if (priv->fbdev)
171                 drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
172 }
173
174 void armada_fbdev_fini(struct drm_device *dev)
175 {
176         struct armada_private *priv = dev->dev_private;
177         struct drm_fb_helper *fbh = priv->fbdev;
178
179         if (fbh) {
180                 drm_fb_helper_unregister_fbi(fbh);
181
182                 drm_fb_helper_fini(fbh);
183
184                 if (fbh->fb)
185                         fbh->fb->funcs->destroy(fbh->fb);
186
187                 priv->fbdev = NULL;
188         }
189 }
This page took 0.037317 seconds and 4 git commands to generate.