0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/console.h>
0009 #include <linux/delay.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/mm.h>
0014 #include <linux/module.h>
0015 #include <linux/pfn_t.h>
0016 #include <linux/slab.h>
0017 #include <linux/string.h>
0018 #include <linux/tty.h>
0019
0020 #include <drm/drm.h>
0021 #include <drm/drm_crtc.h>
0022 #include <drm/drm_fb_helper.h>
0023 #include <drm/drm_fourcc.h>
0024 #include <drm/drm_framebuffer.h>
0025 #include <drm/drm_gem_framebuffer_helper.h>
0026
0027 #include "framebuffer.h"
0028 #include "gem.h"
0029 #include "psb_drv.h"
0030 #include "psb_intel_drv.h"
0031 #include "psb_intel_reg.h"
0032
0033 static const struct drm_framebuffer_funcs psb_fb_funcs = {
0034 .destroy = drm_gem_fb_destroy,
0035 .create_handle = drm_gem_fb_create_handle,
0036 };
0037
0038 #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
0039
0040 static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
0041 unsigned blue, unsigned transp,
0042 struct fb_info *info)
0043 {
0044 struct drm_fb_helper *fb_helper = info->par;
0045 struct drm_framebuffer *fb = fb_helper->fb;
0046 uint32_t v;
0047
0048 if (!fb)
0049 return -ENOMEM;
0050
0051 if (regno > 255)
0052 return 1;
0053
0054 red = CMAP_TOHW(red, info->var.red.length);
0055 blue = CMAP_TOHW(blue, info->var.blue.length);
0056 green = CMAP_TOHW(green, info->var.green.length);
0057 transp = CMAP_TOHW(transp, info->var.transp.length);
0058
0059 v = (red << info->var.red.offset) |
0060 (green << info->var.green.offset) |
0061 (blue << info->var.blue.offset) |
0062 (transp << info->var.transp.offset);
0063
0064 if (regno < 16) {
0065 switch (fb->format->cpp[0] * 8) {
0066 case 16:
0067 ((uint32_t *) info->pseudo_palette)[regno] = v;
0068 break;
0069 case 24:
0070 case 32:
0071 ((uint32_t *) info->pseudo_palette)[regno] = v;
0072 break;
0073 }
0074 }
0075
0076 return 0;
0077 }
0078
0079 static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf)
0080 {
0081 struct vm_area_struct *vma = vmf->vma;
0082 struct drm_framebuffer *fb = vma->vm_private_data;
0083 struct drm_device *dev = fb->dev;
0084 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0085 struct psb_gem_object *pobj = to_psb_gem_object(fb->obj[0]);
0086 int page_num;
0087 int i;
0088 unsigned long address;
0089 vm_fault_t ret = VM_FAULT_SIGBUS;
0090 unsigned long pfn;
0091 unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + pobj->offset;
0092
0093 page_num = vma_pages(vma);
0094 address = vmf->address - (vmf->pgoff << PAGE_SHIFT);
0095
0096 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0097
0098 for (i = 0; i < page_num; i++) {
0099 pfn = (phys_addr >> PAGE_SHIFT);
0100
0101 ret = vmf_insert_mixed(vma, address,
0102 __pfn_to_pfn_t(pfn, PFN_DEV));
0103 if (unlikely(ret & VM_FAULT_ERROR))
0104 break;
0105 address += PAGE_SIZE;
0106 phys_addr += PAGE_SIZE;
0107 }
0108 return ret;
0109 }
0110
0111 static void psbfb_vm_open(struct vm_area_struct *vma)
0112 {
0113 }
0114
0115 static void psbfb_vm_close(struct vm_area_struct *vma)
0116 {
0117 }
0118
0119 static const struct vm_operations_struct psbfb_vm_ops = {
0120 .fault = psbfb_vm_fault,
0121 .open = psbfb_vm_open,
0122 .close = psbfb_vm_close
0123 };
0124
0125 static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
0126 {
0127 struct drm_fb_helper *fb_helper = info->par;
0128 struct drm_framebuffer *fb = fb_helper->fb;
0129
0130 if (vma->vm_pgoff != 0)
0131 return -EINVAL;
0132 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
0133 return -EINVAL;
0134
0135
0136
0137
0138
0139
0140 vma->vm_ops = &psbfb_vm_ops;
0141 vma->vm_private_data = (void *)fb;
0142 vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
0143 return 0;
0144 }
0145
0146 static const struct fb_ops psbfb_unaccel_ops = {
0147 .owner = THIS_MODULE,
0148 DRM_FB_HELPER_DEFAULT_OPS,
0149 .fb_setcolreg = psbfb_setcolreg,
0150 .fb_fillrect = drm_fb_helper_cfb_fillrect,
0151 .fb_copyarea = drm_fb_helper_cfb_copyarea,
0152 .fb_imageblit = drm_fb_helper_cfb_imageblit,
0153 .fb_mmap = psbfb_mmap,
0154 };
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 static int psb_framebuffer_init(struct drm_device *dev,
0167 struct drm_framebuffer *fb,
0168 const struct drm_mode_fb_cmd2 *mode_cmd,
0169 struct drm_gem_object *obj)
0170 {
0171 const struct drm_format_info *info;
0172 int ret;
0173
0174
0175
0176
0177
0178 info = drm_get_format_info(dev, mode_cmd);
0179 if (!info || !info->depth || info->cpp[0] > 4)
0180 return -EINVAL;
0181
0182 if (mode_cmd->pitches[0] & 63)
0183 return -EINVAL;
0184
0185 drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
0186 fb->obj[0] = obj;
0187 ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs);
0188 if (ret) {
0189 dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
0190 return ret;
0191 }
0192 return 0;
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 static struct drm_framebuffer *psb_framebuffer_create
0208 (struct drm_device *dev,
0209 const struct drm_mode_fb_cmd2 *mode_cmd,
0210 struct drm_gem_object *obj)
0211 {
0212 struct drm_framebuffer *fb;
0213 int ret;
0214
0215 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
0216 if (!fb)
0217 return ERR_PTR(-ENOMEM);
0218
0219 ret = psb_framebuffer_init(dev, fb, mode_cmd, obj);
0220 if (ret) {
0221 kfree(fb);
0222 return ERR_PTR(ret);
0223 }
0224 return fb;
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234 static int psbfb_create(struct drm_fb_helper *fb_helper,
0235 struct drm_fb_helper_surface_size *sizes)
0236 {
0237 struct drm_device *dev = fb_helper->dev;
0238 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0239 struct pci_dev *pdev = to_pci_dev(dev->dev);
0240 struct fb_info *info;
0241 struct drm_framebuffer *fb;
0242 struct drm_mode_fb_cmd2 mode_cmd;
0243 int size;
0244 int ret;
0245 struct psb_gem_object *backing;
0246 struct drm_gem_object *obj;
0247 u32 bpp, depth;
0248
0249 mode_cmd.width = sizes->surface_width;
0250 mode_cmd.height = sizes->surface_height;
0251 bpp = sizes->surface_bpp;
0252 depth = sizes->surface_depth;
0253
0254
0255 if (bpp == 24)
0256 bpp = 32;
0257
0258 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * DIV_ROUND_UP(bpp, 8), 64);
0259
0260 size = mode_cmd.pitches[0] * mode_cmd.height;
0261 size = ALIGN(size, PAGE_SIZE);
0262
0263
0264 backing = psb_gem_create(dev, size, "fb", true, PAGE_SIZE);
0265 if (IS_ERR(backing))
0266 return PTR_ERR(backing);
0267 obj = &backing->base;
0268
0269 memset(dev_priv->vram_addr + backing->offset, 0, size);
0270
0271 info = drm_fb_helper_alloc_fbi(fb_helper);
0272 if (IS_ERR(info)) {
0273 ret = PTR_ERR(info);
0274 goto err_drm_gem_object_put;
0275 }
0276
0277 mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
0278
0279 fb = psb_framebuffer_create(dev, &mode_cmd, obj);
0280 if (IS_ERR(fb)) {
0281 ret = PTR_ERR(fb);
0282 goto err_drm_gem_object_put;
0283 }
0284
0285 fb_helper->fb = fb;
0286
0287 info->fbops = &psbfb_unaccel_ops;
0288
0289 info->fix.smem_start = dev->mode_config.fb_base;
0290 info->fix.smem_len = size;
0291 info->fix.ywrapstep = 0;
0292 info->fix.ypanstep = 0;
0293
0294
0295 info->screen_base = dev_priv->vram_addr + backing->offset;
0296 info->screen_size = size;
0297
0298 if (dev_priv->gtt.stolen_size) {
0299 info->apertures->ranges[0].base = dev->mode_config.fb_base;
0300 info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
0301 }
0302
0303 drm_fb_helper_fill_info(info, fb_helper, sizes);
0304
0305 info->fix.mmio_start = pci_resource_start(pdev, 0);
0306 info->fix.mmio_len = pci_resource_len(pdev, 0);
0307
0308
0309
0310 dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height);
0311
0312 return 0;
0313
0314 err_drm_gem_object_put:
0315 drm_gem_object_put(obj);
0316 return ret;
0317 }
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327 static struct drm_framebuffer *psb_user_framebuffer_create
0328 (struct drm_device *dev, struct drm_file *filp,
0329 const struct drm_mode_fb_cmd2 *cmd)
0330 {
0331 struct drm_gem_object *obj;
0332 struct drm_framebuffer *fb;
0333
0334
0335
0336
0337
0338 obj = drm_gem_object_lookup(filp, cmd->handles[0]);
0339 if (obj == NULL)
0340 return ERR_PTR(-ENOENT);
0341
0342
0343 fb = psb_framebuffer_create(dev, cmd, obj);
0344 if (IS_ERR(fb))
0345 drm_gem_object_put(obj);
0346
0347 return fb;
0348 }
0349
0350 static int psbfb_probe(struct drm_fb_helper *fb_helper,
0351 struct drm_fb_helper_surface_size *sizes)
0352 {
0353 struct drm_device *dev = fb_helper->dev;
0354 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0355 unsigned int fb_size;
0356 int bytespp;
0357
0358 bytespp = sizes->surface_bpp / 8;
0359 if (bytespp == 3)
0360 bytespp = 4;
0361
0362
0363
0364
0365 fb_size = ALIGN(sizes->surface_width * bytespp, 64) *
0366 sizes->surface_height;
0367 fb_size = ALIGN(fb_size, PAGE_SIZE);
0368
0369 if (fb_size > dev_priv->vram_stolen_size) {
0370 sizes->surface_bpp = 16;
0371 sizes->surface_depth = 16;
0372 }
0373
0374 return psbfb_create(fb_helper, sizes);
0375 }
0376
0377 static const struct drm_fb_helper_funcs psb_fb_helper_funcs = {
0378 .fb_probe = psbfb_probe,
0379 };
0380
0381 static int psb_fbdev_destroy(struct drm_device *dev,
0382 struct drm_fb_helper *fb_helper)
0383 {
0384 struct drm_framebuffer *fb = fb_helper->fb;
0385
0386 drm_fb_helper_unregister_fbi(fb_helper);
0387
0388 drm_fb_helper_fini(fb_helper);
0389 drm_framebuffer_unregister_private(fb);
0390 drm_framebuffer_cleanup(fb);
0391
0392 if (fb->obj[0])
0393 drm_gem_object_put(fb->obj[0]);
0394 kfree(fb);
0395
0396 return 0;
0397 }
0398
0399 int psb_fbdev_init(struct drm_device *dev)
0400 {
0401 struct drm_fb_helper *fb_helper;
0402 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0403 int ret;
0404
0405 fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
0406 if (!fb_helper) {
0407 dev_err(dev->dev, "no memory\n");
0408 return -ENOMEM;
0409 }
0410
0411 dev_priv->fb_helper = fb_helper;
0412
0413 drm_fb_helper_prepare(dev, fb_helper, &psb_fb_helper_funcs);
0414
0415 ret = drm_fb_helper_init(dev, fb_helper);
0416 if (ret)
0417 goto free;
0418
0419
0420 drm_helper_disable_unused_functions(dev);
0421
0422 ret = drm_fb_helper_initial_config(fb_helper, 32);
0423 if (ret)
0424 goto fini;
0425
0426 return 0;
0427
0428 fini:
0429 drm_fb_helper_fini(fb_helper);
0430 free:
0431 kfree(fb_helper);
0432 return ret;
0433 }
0434
0435 static void psb_fbdev_fini(struct drm_device *dev)
0436 {
0437 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0438
0439 if (!dev_priv->fb_helper)
0440 return;
0441
0442 psb_fbdev_destroy(dev, dev_priv->fb_helper);
0443 kfree(dev_priv->fb_helper);
0444 dev_priv->fb_helper = NULL;
0445 }
0446
0447 static const struct drm_mode_config_funcs psb_mode_funcs = {
0448 .fb_create = psb_user_framebuffer_create,
0449 .output_poll_changed = drm_fb_helper_output_poll_changed,
0450 };
0451
0452 static void psb_setup_outputs(struct drm_device *dev)
0453 {
0454 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0455 struct drm_connector_list_iter conn_iter;
0456 struct drm_connector *connector;
0457
0458 drm_mode_create_scaling_mode_property(dev);
0459
0460
0461 if (!dev_priv->backlight_property)
0462 dev_priv->backlight_property = drm_property_create_range(dev, 0,
0463 "backlight", 0, 100);
0464 dev_priv->ops->output_init(dev);
0465
0466 drm_connector_list_iter_begin(dev, &conn_iter);
0467 drm_for_each_connector_iter(connector, &conn_iter) {
0468 struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
0469 struct drm_encoder *encoder = &gma_encoder->base;
0470 int crtc_mask = 0, clone_mask = 0;
0471
0472
0473 switch (gma_encoder->type) {
0474 case INTEL_OUTPUT_ANALOG:
0475 crtc_mask = (1 << 0);
0476 clone_mask = (1 << INTEL_OUTPUT_ANALOG);
0477 break;
0478 case INTEL_OUTPUT_SDVO:
0479 crtc_mask = dev_priv->ops->sdvo_mask;
0480 clone_mask = 0;
0481 break;
0482 case INTEL_OUTPUT_LVDS:
0483 crtc_mask = dev_priv->ops->lvds_mask;
0484 clone_mask = 0;
0485 break;
0486 case INTEL_OUTPUT_MIPI:
0487 crtc_mask = (1 << 0);
0488 clone_mask = 0;
0489 break;
0490 case INTEL_OUTPUT_MIPI2:
0491 crtc_mask = (1 << 2);
0492 clone_mask = 0;
0493 break;
0494 case INTEL_OUTPUT_HDMI:
0495 crtc_mask = dev_priv->ops->hdmi_mask;
0496 clone_mask = (1 << INTEL_OUTPUT_HDMI);
0497 break;
0498 case INTEL_OUTPUT_DISPLAYPORT:
0499 crtc_mask = (1 << 0) | (1 << 1);
0500 clone_mask = 0;
0501 break;
0502 case INTEL_OUTPUT_EDP:
0503 crtc_mask = (1 << 1);
0504 clone_mask = 0;
0505 }
0506 encoder->possible_crtcs = crtc_mask;
0507 encoder->possible_clones =
0508 gma_connector_clones(dev, clone_mask);
0509 }
0510 drm_connector_list_iter_end(&conn_iter);
0511 }
0512
0513 void psb_modeset_init(struct drm_device *dev)
0514 {
0515 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0516 struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
0517 struct pci_dev *pdev = to_pci_dev(dev->dev);
0518 int i;
0519
0520 if (drmm_mode_config_init(dev))
0521 return;
0522
0523 dev->mode_config.min_width = 0;
0524 dev->mode_config.min_height = 0;
0525
0526 dev->mode_config.funcs = &psb_mode_funcs;
0527
0528
0529
0530 pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev->mode_config.fb_base));
0531
0532
0533 for (i = 0; i < dev_priv->num_pipe; i++)
0534 psb_intel_crtc_init(dev, i, mode_dev);
0535
0536 dev->mode_config.max_width = 4096;
0537 dev->mode_config.max_height = 4096;
0538
0539 psb_setup_outputs(dev);
0540
0541 if (dev_priv->ops->errata)
0542 dev_priv->ops->errata(dev);
0543
0544 dev_priv->modeset = true;
0545 }
0546
0547 void psb_modeset_cleanup(struct drm_device *dev)
0548 {
0549 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0550 if (dev_priv->modeset) {
0551 drm_kms_helper_poll_fini(dev);
0552 psb_fbdev_fini(dev);
0553 }
0554 }