2 * drivers/staging/omapdrm/omap_fbdev.c
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob@ti.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "drm_fb_helper.h"
25 MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')");
26 static bool ywrap_enabled = true;
27 module_param_named(ywrap, ywrap_enabled, bool, 0644);
30 * fbdev funcs, to implement legacy fbdev interface on top of drm driver
33 #define to_omap_fbdev(x) container_of(x, struct omap_fbdev, base)
36 struct drm_fb_helper base;
37 struct drm_framebuffer *fb;
38 struct drm_gem_object *bo;
42 static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
43 static struct drm_fb_helper *get_fb(struct fb_info *fbi);
45 static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
46 size_t count, loff_t *ppos)
50 res = fb_sys_write(fbi, buf, count, ppos);
51 omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres);
56 static void omap_fbdev_fillrect(struct fb_info *fbi,
57 const struct fb_fillrect *rect)
59 sys_fillrect(fbi, rect);
60 omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height);
63 static void omap_fbdev_copyarea(struct fb_info *fbi,
64 const struct fb_copyarea *area)
66 sys_copyarea(fbi, area);
67 omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height);
70 static void omap_fbdev_imageblit(struct fb_info *fbi,
71 const struct fb_image *image)
73 sys_imageblit(fbi, image);
74 omap_fbdev_flush(fbi, image->dx, image->dy,
75 image->width, image->height);
78 static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
81 struct drm_fb_helper *helper = get_fb(fbi);
82 struct omap_fbdev *fbdev = to_omap_fbdev(helper);
88 if (!fbdev->ywrap_enabled)
91 /* DMM roll shifts in 4K pages: */
92 npages = fbi->fix.line_length >> PAGE_SHIFT;
93 omap_gem_roll(fbdev->bo, var->yoffset * npages);
98 return drm_fb_helper_pan_display(var, fbi);
101 static struct fb_ops omap_fb_ops = {
102 .owner = THIS_MODULE,
104 /* Note: to properly handle manual update displays, we wrap the
105 * basic fbdev ops which write to the framebuffer
107 .fb_read = fb_sys_read,
108 .fb_write = omap_fbdev_write,
109 .fb_fillrect = omap_fbdev_fillrect,
110 .fb_copyarea = omap_fbdev_copyarea,
111 .fb_imageblit = omap_fbdev_imageblit,
113 .fb_check_var = drm_fb_helper_check_var,
114 .fb_set_par = drm_fb_helper_set_par,
115 .fb_pan_display = omap_fbdev_pan_display,
116 .fb_blank = drm_fb_helper_blank,
117 .fb_setcmap = drm_fb_helper_setcmap,
119 .fb_debug_enter = drm_fb_helper_debug_enter,
120 .fb_debug_leave = drm_fb_helper_debug_leave,
123 static int omap_fbdev_create(struct drm_fb_helper *helper,
124 struct drm_fb_helper_surface_size *sizes)
126 struct omap_fbdev *fbdev = to_omap_fbdev(helper);
127 struct drm_device *dev = helper->dev;
128 struct omap_drm_private *priv = dev->dev_private;
129 struct drm_framebuffer *fb = NULL;
130 union omap_gem_size gsize;
131 struct fb_info *fbi = NULL;
132 struct drm_mode_fb_cmd mode_cmd = {0};
135 int size, screen_width;
138 /* only doing ARGB32 since this is what is needed to alpha-blend
139 * with video overlays:
141 sizes->surface_bpp = 32;
142 sizes->surface_depth = 32;
144 DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
145 sizes->surface_height, sizes->surface_bpp,
146 sizes->fb_width, sizes->fb_height);
148 mode_cmd.width = sizes->surface_width;
149 mode_cmd.height = sizes->surface_height;
151 mode_cmd.bpp = sizes->surface_bpp;
152 mode_cmd.depth = sizes->surface_depth;
154 mode_cmd.pitch = align_pitch(
155 mode_cmd.width * ((mode_cmd.bpp + 7) / 8),
156 mode_cmd.width, mode_cmd.bpp);
158 fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled;
159 if (fbdev->ywrap_enabled) {
160 /* need to align pitch to page size if using DMM scrolling */
161 mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE);
164 /* allocate backing bo */
165 gsize = (union omap_gem_size){
166 .bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height),
168 DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
169 fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
171 dev_err(dev->dev, "failed to allocate buffer object\n");
175 fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo);
177 dev_err(dev->dev, "failed to allocate fb\n");
182 mutex_lock(&dev->struct_mutex);
184 fbi = framebuffer_alloc(0, dev->dev);
186 dev_err(dev->dev, "failed to allocate fb info\n");
191 DBG("fbi=%p, dev=%p", fbi, dev);
198 fbi->flags = FBINFO_DEFAULT;
199 fbi->fbops = &omap_fb_ops;
201 strcpy(fbi->fix.id, MODULE_NAME);
203 ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
209 drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
210 drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
212 size = omap_framebuffer_get_buffer(fb, 0, 0,
213 &vaddr, &paddr, &screen_width);
215 dev->mode_config.fb_base = paddr;
217 fbi->screen_base = vaddr;
218 fbi->screen_size = size;
219 fbi->fix.smem_start = paddr;
220 fbi->fix.smem_len = size;
222 /* if we have DMM, then we can use it for scrolling by just
223 * shuffling pages around in DMM rather than doing sw blit.
225 if (fbdev->ywrap_enabled) {
226 DRM_INFO("Enabling DMM ywrap scrolling\n");
227 fbi->flags |= FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST;
228 fbi->fix.ywrapstep = 1;
232 DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
233 DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
235 mutex_unlock(&dev->struct_mutex);
240 mutex_unlock(&dev->struct_mutex);
245 framebuffer_release(fbi);
247 fb->funcs->destroy(fb);
253 static void omap_crtc_fb_gamma_set(struct drm_crtc *crtc,
254 u16 red, u16 green, u16 blue, int regno)
256 DBG("fbdev: set gamma");
259 static void omap_crtc_fb_gamma_get(struct drm_crtc *crtc,
260 u16 *red, u16 *green, u16 *blue, int regno)
262 DBG("fbdev: get gamma");
265 static int omap_fbdev_probe(struct drm_fb_helper *helper,
266 struct drm_fb_helper_surface_size *sizes)
272 ret = omap_fbdev_create(helper, sizes);
280 static struct drm_fb_helper_funcs omap_fb_helper_funcs = {
281 .gamma_set = omap_crtc_fb_gamma_set,
282 .gamma_get = omap_crtc_fb_gamma_get,
283 .fb_probe = omap_fbdev_probe,
286 static struct drm_fb_helper *get_fb(struct fb_info *fbi)
288 if (!fbi || strcmp(fbi->fix.id, MODULE_NAME)) {
289 /* these are not the fb's you're looking for */
295 /* flush an area of the framebuffer (in case of manual update display that
296 * is not automatically flushed)
298 static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h)
300 struct drm_fb_helper *helper = get_fb(fbi);
305 VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi);
307 omap_framebuffer_flush(helper->fb, x, y, w, h);
310 /* initialize fbdev helper */
311 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
313 struct omap_drm_private *priv = dev->dev_private;
314 struct omap_fbdev *fbdev = NULL;
315 struct drm_fb_helper *helper;
318 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
320 dev_err(dev->dev, "could not allocate fbdev\n");
324 helper = &fbdev->base;
326 helper->funcs = &omap_fb_helper_funcs;
328 ret = drm_fb_helper_init(dev, helper,
329 priv->num_crtcs, priv->num_connectors);
331 dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret);
335 drm_fb_helper_single_add_all_connectors(helper);
336 drm_fb_helper_initial_config(helper, 32);
338 priv->fbdev = helper;
347 void omap_fbdev_free(struct drm_device *dev)
349 struct omap_drm_private *priv = dev->dev_private;
350 struct drm_fb_helper *helper = priv->fbdev;
351 struct omap_fbdev *fbdev;
358 unregister_framebuffer(fbi);
359 framebuffer_release(fbi);
361 drm_fb_helper_fini(helper);
363 fbdev = to_omap_fbdev(priv->fbdev);
367 /* this will free the backing object */
369 fbdev->fb->funcs->destroy(fbdev->fb);