]> Git Repo - linux.git/blob - drivers/gpu/drm/armada/armada_fbdev.c
Merge tag 'devicetree-fixes-for-6.4-3' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / gpu / drm / armada / armada_fbdev.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2012 Russell King
4  *  Written from the i915 driver.
5  */
6
7 #include <linux/errno.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10
11 #include <drm/drm_fb_helper.h>
12 #include <drm/drm_fourcc.h>
13
14 #include "armada_crtc.h"
15 #include "armada_drm.h"
16 #include "armada_fb.h"
17 #include "armada_gem.h"
18
19 static const struct fb_ops armada_fb_ops = {
20         .owner          = THIS_MODULE,
21         DRM_FB_HELPER_DEFAULT_OPS,
22         .fb_read        = drm_fb_helper_cfb_read,
23         .fb_write       = drm_fb_helper_cfb_write,
24         .fb_fillrect    = drm_fb_helper_cfb_fillrect,
25         .fb_copyarea    = drm_fb_helper_cfb_copyarea,
26         .fb_imageblit   = drm_fb_helper_cfb_imageblit,
27 };
28
29 static int armada_fbdev_create(struct drm_fb_helper *fbh,
30         struct drm_fb_helper_surface_size *sizes)
31 {
32         struct drm_device *dev = fbh->dev;
33         struct drm_mode_fb_cmd2 mode;
34         struct armada_framebuffer *dfb;
35         struct armada_gem_object *obj;
36         struct fb_info *info;
37         int size, ret;
38         void *ptr;
39
40         memset(&mode, 0, sizeof(mode));
41         mode.width = sizes->surface_width;
42         mode.height = sizes->surface_height;
43         mode.pitches[0] = armada_pitch(mode.width, sizes->surface_bpp);
44         mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
45                                         sizes->surface_depth);
46
47         size = mode.pitches[0] * mode.height;
48         obj = armada_gem_alloc_private_object(dev, size);
49         if (!obj) {
50                 DRM_ERROR("failed to allocate fb memory\n");
51                 return -ENOMEM;
52         }
53
54         ret = armada_gem_linear_back(dev, obj);
55         if (ret) {
56                 drm_gem_object_put(&obj->obj);
57                 return ret;
58         }
59
60         ptr = armada_gem_map_object(dev, obj);
61         if (!ptr) {
62                 drm_gem_object_put(&obj->obj);
63                 return -ENOMEM;
64         }
65
66         dfb = armada_framebuffer_create(dev, &mode, obj);
67
68         /*
69          * A reference is now held by the framebuffer object if
70          * successful, otherwise this drops the ref for the error path.
71          */
72         drm_gem_object_put(&obj->obj);
73
74         if (IS_ERR(dfb))
75                 return PTR_ERR(dfb);
76
77         info = drm_fb_helper_alloc_info(fbh);
78         if (IS_ERR(info)) {
79                 ret = PTR_ERR(info);
80                 goto err_fballoc;
81         }
82
83         info->fbops = &armada_fb_ops;
84         info->fix.smem_start = obj->phys_addr;
85         info->fix.smem_len = obj->obj.size;
86         info->screen_size = obj->obj.size;
87         info->screen_base = ptr;
88         fbh->fb = &dfb->fb;
89
90         drm_fb_helper_fill_info(info, fbh, sizes);
91
92         DRM_DEBUG_KMS("allocated %dx%d %dbpp fb: 0x%08llx\n",
93                 dfb->fb.width, dfb->fb.height, dfb->fb.format->cpp[0] * 8,
94                 (unsigned long long)obj->phys_addr);
95
96         return 0;
97
98  err_fballoc:
99         dfb->fb.funcs->destroy(&dfb->fb);
100         return ret;
101 }
102
103 static int armada_fb_probe(struct drm_fb_helper *fbh,
104         struct drm_fb_helper_surface_size *sizes)
105 {
106         int ret = 0;
107
108         if (!fbh->fb) {
109                 ret = armada_fbdev_create(fbh, sizes);
110                 if (ret == 0)
111                         ret = 1;
112         }
113         return ret;
114 }
115
116 static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
117         .fb_probe       = armada_fb_probe,
118 };
119
120 int armada_fbdev_init(struct drm_device *dev)
121 {
122         struct armada_private *priv = drm_to_armada_dev(dev);
123         struct drm_fb_helper *fbh;
124         int ret;
125
126         fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL);
127         if (!fbh)
128                 return -ENOMEM;
129
130         priv->fbdev = fbh;
131
132         drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs);
133
134         ret = drm_fb_helper_init(dev, fbh);
135         if (ret) {
136                 DRM_ERROR("failed to initialize drm fb helper\n");
137                 goto err_fb_helper;
138         }
139
140         ret = drm_fb_helper_initial_config(fbh);
141         if (ret) {
142                 DRM_ERROR("failed to set initial config\n");
143                 goto err_fb_setup;
144         }
145
146         return 0;
147  err_fb_setup:
148         drm_fb_helper_fini(fbh);
149  err_fb_helper:
150         drm_fb_helper_unprepare(fbh);
151         priv->fbdev = NULL;
152         return ret;
153 }
154
155 void armada_fbdev_fini(struct drm_device *dev)
156 {
157         struct armada_private *priv = drm_to_armada_dev(dev);
158         struct drm_fb_helper *fbh = priv->fbdev;
159
160         if (fbh) {
161                 drm_fb_helper_unregister_info(fbh);
162
163                 drm_fb_helper_fini(fbh);
164
165                 if (fbh->fb)
166                         fbh->fb->funcs->destroy(fbh->fb);
167
168                 drm_fb_helper_unprepare(fbh);
169
170                 priv->fbdev = NULL;
171         }
172 }
This page took 0.043451 seconds and 4 git commands to generate.