Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

OMAP: DSS2: OMAPFB: Add support for switching memory regions

Separate the memory region from the framebuffer device a little bit.
It's now possible to select the memory region used by the framebuffer
device using the new mem_idx parameter of omapfb_plane_info. If the
mem_idx is specified it will be interpreted as an index into the
memory regions array, if it's not specified the framebuffer's index is
used instead. So by default each framebuffer keeps using it's own
memory region which preserves backwards compatibility.

This allows cloning the same memory region to several overlays and yet
each overlay can be controlled independently since they can be
associated with separate framebuffer devices.

Signed-off-by: Ville Syrjälä <ville.syrjala@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>

authored by

Ville Syrjälä and committed by
Tomi Valkeinen
078ff546 2ad0c50b

+186 -67
+105 -26
drivers/video/omap2/omapfb/omapfb-ioctl.c
··· 34 34 35 35 #include "omapfb.h" 36 36 37 + static u8 get_mem_idx(struct omapfb_info *ofbi) 38 + { 39 + if (ofbi->id == ofbi->region->id) 40 + return 0; 41 + 42 + return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; 43 + } 44 + 45 + static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, 46 + u8 mem_idx) 47 + { 48 + struct omapfb2_device *fbdev = ofbi->fbdev; 49 + 50 + if (mem_idx & OMAPFB_MEM_IDX_ENABLED) 51 + mem_idx &= OMAPFB_MEM_IDX_MASK; 52 + else 53 + mem_idx = ofbi->id; 54 + 55 + if (mem_idx >= fbdev->num_fbs) 56 + return NULL; 57 + 58 + return &fbdev->regions[mem_idx]; 59 + } 60 + 37 61 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 38 62 { 39 63 struct omapfb_info *ofbi = FB2OFB(fbi); 40 64 struct omapfb2_device *fbdev = ofbi->fbdev; 41 65 struct omap_overlay *ovl; 42 - struct omap_overlay_info info; 66 + struct omap_overlay_info old_info; 67 + struct omapfb2_mem_region *old_rg, *new_rg; 43 68 int r = 0; 44 69 45 70 DBG("omapfb_setup_plane\n"); ··· 77 52 /* XXX uses only the first overlay */ 78 53 ovl = ofbi->overlays[0]; 79 54 80 - if (pi->enabled && !ofbi->region.size) { 55 + old_rg = ofbi->region; 56 + new_rg = get_mem_region(ofbi, pi->mem_idx); 57 + if (!new_rg) { 58 + r = -EINVAL; 59 + goto out; 60 + } 61 + 62 + if (pi->enabled && !new_rg->size) { 81 63 /* 82 64 * This plane's memory was freed, can't enable it 83 65 * until it's reallocated. ··· 93 61 goto out; 94 62 } 95 63 96 - ovl->get_overlay_info(ovl, &info); 64 + ovl->get_overlay_info(ovl, &old_info); 97 65 98 - info.pos_x = pi->pos_x; 99 - info.pos_y = pi->pos_y; 100 - info.out_width = pi->out_width; 101 - info.out_height = pi->out_height; 102 - info.enabled = pi->enabled; 103 - 104 - r = ovl->set_overlay_info(ovl, &info); 105 - if (r) 106 - goto out; 107 - 108 - if (ovl->manager) { 109 - r = ovl->manager->apply(ovl->manager); 110 - if (r) 111 - goto out; 66 + if (old_rg != new_rg) { 67 + ofbi->region = new_rg; 68 + set_fb_fix(fbi); 112 69 } 113 70 114 - out: 115 - if (r) 116 - dev_err(fbdev->dev, "setup_plane failed\n"); 71 + if (pi->enabled) { 72 + struct omap_overlay_info info; 73 + 74 + r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, 75 + pi->out_width, pi->out_height); 76 + if (r) 77 + goto undo; 78 + 79 + ovl->get_overlay_info(ovl, &info); 80 + 81 + if (!info.enabled) { 82 + info.enabled = pi->enabled; 83 + r = ovl->set_overlay_info(ovl, &info); 84 + if (r) 85 + goto undo; 86 + } 87 + } else { 88 + struct omap_overlay_info info; 89 + 90 + ovl->get_overlay_info(ovl, &info); 91 + 92 + info.enabled = pi->enabled; 93 + info.pos_x = pi->pos_x; 94 + info.pos_y = pi->pos_y; 95 + info.out_width = pi->out_width; 96 + info.out_height = pi->out_height; 97 + 98 + r = ovl->set_overlay_info(ovl, &info); 99 + if (r) 100 + goto undo; 101 + } 102 + 103 + if (ovl->manager) 104 + ovl->manager->apply(ovl->manager); 105 + 106 + return 0; 107 + 108 + undo: 109 + if (old_rg != new_rg) { 110 + ofbi->region = old_rg; 111 + set_fb_fix(fbi); 112 + } 113 + 114 + ovl->set_overlay_info(ovl, &old_info); 115 + out: 116 + dev_err(fbdev->dev, "setup_plane failed\n"); 117 + 117 118 return r; 118 119 } 119 120 ··· 157 92 if (ofbi->num_overlays != 1) { 158 93 memset(pi, 0, sizeof(*pi)); 159 94 } else { 160 - struct omap_overlay_info *ovli; 161 95 struct omap_overlay *ovl; 96 + struct omap_overlay_info *ovli; 162 97 163 98 ovl = ofbi->overlays[0]; 164 99 ovli = &ovl->info; ··· 168 103 pi->enabled = ovli->enabled; 169 104 pi->channel_out = 0; /* xxx */ 170 105 pi->mirror = 0; 106 + pi->mem_idx = get_mem_idx(ofbi); 171 107 pi->out_width = ovli->out_width; 172 108 pi->out_height = ovli->out_height; 173 109 } ··· 189 123 190 124 size = PAGE_ALIGN(mi->size); 191 125 192 - rg = &ofbi->region; 126 + rg = ofbi->region; 193 127 194 - for (i = 0; i < ofbi->num_overlays; i++) { 195 - if (ofbi->overlays[i]->info.enabled) 196 - return -EBUSY; 128 + if (atomic_read(&rg->map_count)) 129 + return -EBUSY; 130 + 131 + for (i = 0; i < fbdev->num_fbs; i++) { 132 + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); 133 + int j; 134 + 135 + if (ofbi2->region != rg) 136 + continue; 137 + 138 + for (j = 0; j < ofbi2->num_overlays; j++) { 139 + if (ofbi2->overlays[j]->info.enabled) { 140 + r = -EBUSY; 141 + return r; 142 + } 143 + } 197 144 } 198 145 199 146 if (rg->size != size || rg->type != mi->type) { ··· 225 146 struct omapfb_info *ofbi = FB2OFB(fbi); 226 147 struct omapfb2_mem_region *rg; 227 148 228 - rg = &ofbi->region; 149 + rg = ofbi->region; 229 150 memset(mi, 0, sizeof(*mi)); 230 151 231 152 mi->size = rg->size;
+43 -28
drivers/video/omap2/omapfb/omapfb-main.c
··· 157 157 158 158 static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) 159 159 { 160 - const struct vrfb *vrfb = &ofbi->region.vrfb; 160 + const struct vrfb *vrfb = &ofbi->region->vrfb; 161 161 unsigned offset; 162 162 163 163 switch (rot) { ··· 185 185 static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) 186 186 { 187 187 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 188 - return ofbi->region.vrfb.paddr[rot] 188 + return ofbi->region->vrfb.paddr[rot] 189 189 + omapfb_get_vrfb_offset(ofbi, rot); 190 190 } else { 191 - return ofbi->region.paddr; 191 + return ofbi->region->paddr; 192 192 } 193 193 } 194 194 195 195 static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) 196 196 { 197 197 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 198 - return ofbi->region.vrfb.paddr[0]; 198 + return ofbi->region->vrfb.paddr[0]; 199 199 else 200 - return ofbi->region.paddr; 200 + return ofbi->region->paddr; 201 201 } 202 202 203 203 static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) 204 204 { 205 205 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 206 - return ofbi->region.vrfb.vaddr[0]; 206 + return ofbi->region->vrfb.vaddr[0]; 207 207 else 208 - return ofbi->region.vaddr; 208 + return ofbi->region->vaddr; 209 209 } 210 210 211 211 static struct omapfb_colormode omapfb_colormodes[] = { ··· 450 450 static int check_fb_size(const struct omapfb_info *ofbi, 451 451 struct fb_var_screeninfo *var) 452 452 { 453 - unsigned long max_frame_size = ofbi->region.size; 453 + unsigned long max_frame_size = ofbi->region->size; 454 454 int bytespp = var->bits_per_pixel >> 3; 455 455 unsigned long line_size = var->xres_virtual * bytespp; 456 456 ··· 497 497 static int setup_vrfb_rotation(struct fb_info *fbi) 498 498 { 499 499 struct omapfb_info *ofbi = FB2OFB(fbi); 500 - struct omapfb2_mem_region *rg = &ofbi->region; 500 + struct omapfb2_mem_region *rg = ofbi->region; 501 501 struct vrfb *vrfb = &rg->vrfb; 502 502 struct fb_var_screeninfo *var = &fbi->var; 503 503 struct fb_fix_screeninfo *fix = &fbi->fix; ··· 558 558 return r; 559 559 560 560 /* used by open/write in fbmem.c */ 561 - fbi->screen_base = ofbi->region.vrfb.vaddr[0]; 561 + fbi->screen_base = ofbi->region->vrfb.vaddr[0]; 562 562 563 - fix->smem_start = ofbi->region.vrfb.paddr[0]; 563 + fix->smem_start = ofbi->region->vrfb.paddr[0]; 564 564 565 565 switch (var->nonstd) { 566 566 case OMAPFB_COLOR_YUV422: ··· 599 599 struct fb_fix_screeninfo *fix = &fbi->fix; 600 600 struct fb_var_screeninfo *var = &fbi->var; 601 601 struct omapfb_info *ofbi = FB2OFB(fbi); 602 - struct omapfb2_mem_region *rg = &ofbi->region; 602 + struct omapfb2_mem_region *rg = ofbi->region; 603 603 604 604 DBG("set_fb_fix\n"); 605 605 ··· 688 688 return -EINVAL; 689 689 690 690 /* When no memory is allocated ignore the size check */ 691 - if (ofbi->region.size != 0 && check_fb_size(ofbi, var)) 691 + if (ofbi->region->size != 0 && check_fb_size(ofbi, var)) 692 692 return -EINVAL; 693 693 694 694 if (var->xres + var->xoffset > var->xres_virtual) ··· 856 856 } 857 857 858 858 /* setup overlay according to the fb */ 859 - static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 859 + int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 860 860 u16 posx, u16 posy, u16 outw, u16 outh) 861 861 { 862 862 int r = 0; ··· 892 892 yres = var->yres; 893 893 } 894 894 895 - if (ofbi->region.size) 895 + if (ofbi->region->size) 896 896 omapfb_calc_addr(ofbi, var, fix, rotation, 897 897 &data_start_p, &data_start_v); 898 898 ··· 971 971 972 972 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); 973 973 974 - if (ofbi->region.size == 0) { 974 + if (ofbi->region->size == 0) { 975 975 /* the fb is not available. disable the overlay */ 976 976 omapfb_overlay_enable(ovl, 0); 977 977 if (!init && ovl->manager) ··· 1071 1071 1072 1072 static void mmap_user_open(struct vm_area_struct *vma) 1073 1073 { 1074 - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; 1074 + struct omapfb2_mem_region *rg = vma->vm_private_data; 1075 1075 1076 - atomic_inc(&ofbi->map_count); 1076 + atomic_inc(&rg->map_count); 1077 1077 } 1078 1078 1079 1079 static void mmap_user_close(struct vm_area_struct *vma) 1080 1080 { 1081 - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; 1081 + struct omapfb2_mem_region *rg = vma->vm_private_data; 1082 1082 1083 - atomic_dec(&ofbi->map_count); 1083 + atomic_dec(&rg->map_count); 1084 1084 } 1085 1085 1086 1086 static struct vm_operations_struct mmap_user_ops = { ··· 1092 1092 { 1093 1093 struct omapfb_info *ofbi = FB2OFB(fbi); 1094 1094 struct fb_fix_screeninfo *fix = &fbi->fix; 1095 + struct omapfb2_mem_region *rg; 1095 1096 unsigned long off; 1096 1097 unsigned long start; 1097 1098 u32 len; ··· 1102 1101 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1103 1102 return -EINVAL; 1104 1103 off = vma->vm_pgoff << PAGE_SHIFT; 1104 + 1105 + rg = ofbi->region; 1105 1106 1106 1107 start = omapfb_get_region_paddr(ofbi); 1107 1108 len = fix->smem_len; ··· 1120 1117 vma->vm_flags |= VM_IO | VM_RESERVED; 1121 1118 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 1122 1119 vma->vm_ops = &mmap_user_ops; 1123 - vma->vm_private_data = ofbi; 1120 + vma->vm_private_data = rg; 1124 1121 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 1125 1122 vma->vm_end - vma->vm_start, vma->vm_page_prot)) 1126 1123 return -EAGAIN; 1127 1124 /* vm_ops.open won't be called for mmap itself. */ 1128 - atomic_inc(&ofbi->map_count); 1125 + atomic_inc(&rg->map_count); 1129 1126 return 0; 1130 1127 } 1131 1128 ··· 1315 1312 struct omapfb2_device *fbdev = ofbi->fbdev; 1316 1313 struct omapfb2_mem_region *rg; 1317 1314 1318 - rg = &ofbi->region; 1315 + rg = ofbi->region; 1316 + 1317 + WARN_ON(atomic_read(&rg->map_count)); 1319 1318 1320 1319 if (rg->paddr) 1321 1320 if (omap_vram_free(rg->paddr, rg->size)) ··· 1372 1367 void __iomem *vaddr; 1373 1368 int r; 1374 1369 1375 - rg = &ofbi->region; 1376 - memset(rg, 0, sizeof(*rg)); 1370 + rg = ofbi->region; 1371 + 1372 + rg->paddr = 0; 1373 + rg->vaddr = NULL; 1374 + memset(&rg->vrfb, 0, sizeof rg->vrfb); 1375 + rg->size = 0; 1376 + rg->type = 0; 1377 + rg->alloc = false; 1378 + rg->map = false; 1377 1379 1378 1380 size = PAGE_ALIGN(size); 1379 1381 ··· 1633 1621 for (i = 0; i < fbdev->num_fbs; i++) { 1634 1622 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1635 1623 struct omapfb2_mem_region *rg; 1636 - rg = &ofbi->region; 1624 + rg = ofbi->region; 1637 1625 1638 1626 DBG("region%d phys %08x virt %p size=%lu\n", 1639 1627 i, ··· 1650 1638 struct omapfb_info *ofbi = FB2OFB(fbi); 1651 1639 struct omapfb2_device *fbdev = ofbi->fbdev; 1652 1640 struct omap_dss_device *display = fb2display(fbi); 1653 - struct omapfb2_mem_region *rg = &ofbi->region; 1641 + struct omapfb2_mem_region *rg = ofbi->region; 1654 1642 unsigned long old_size = rg->size; 1655 1643 unsigned long old_paddr = rg->paddr; 1656 1644 int old_type = rg->type; ··· 1733 1721 fbi->flags = FBINFO_FLAG_DEFAULT; 1734 1722 fbi->pseudo_palette = fbdev->pseudo_palette; 1735 1723 1736 - if (ofbi->region.size == 0) { 1724 + if (ofbi->region->size == 0) { 1737 1725 clear_fb_info(fbi); 1738 1726 return 0; 1739 1727 } ··· 1894 1882 ofbi = FB2OFB(fbi); 1895 1883 ofbi->fbdev = fbdev; 1896 1884 ofbi->id = i; 1885 + 1886 + ofbi->region = &fbdev->regions[i]; 1887 + ofbi->region->id = i; 1897 1888 1898 1889 /* assign these early, so that fb alloc can use them */ 1899 1890 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
+27 -10
drivers/video/omap2/omapfb/omapfb-sysfs.c
··· 64 64 if (rot_type == ofbi->rotation_type) 65 65 goto out; 66 66 67 - if (ofbi->region.size) { 67 + if (ofbi->region->size) { 68 68 r = -EBUSY; 69 69 goto out; 70 70 } ··· 408 408 struct fb_info *fbi = dev_get_drvdata(dev); 409 409 struct omapfb_info *ofbi = FB2OFB(fbi); 410 410 411 - return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); 411 + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); 412 412 } 413 413 414 414 static ssize_t store_size(struct device *dev, struct device_attribute *attr, ··· 416 416 { 417 417 struct fb_info *fbi = dev_get_drvdata(dev); 418 418 struct omapfb_info *ofbi = FB2OFB(fbi); 419 + struct omapfb2_device *fbdev = ofbi->fbdev; 420 + struct omapfb2_mem_region *rg; 419 421 unsigned long size; 420 422 int r; 421 423 int i; ··· 427 425 if (!lock_fb_info(fbi)) 428 426 return -ENODEV; 429 427 430 - for (i = 0; i < ofbi->num_overlays; i++) { 431 - if (ofbi->overlays[i]->info.enabled) { 432 - r = -EBUSY; 433 - goto out; 428 + rg = ofbi->region; 429 + 430 + if (atomic_read(&rg->map_count)) { 431 + r = -EBUSY; 432 + goto out; 433 + } 434 + 435 + for (i = 0; i < fbdev->num_fbs; i++) { 436 + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); 437 + int j; 438 + 439 + if (ofbi2->region != rg) 440 + continue; 441 + 442 + for (j = 0; j < ofbi2->num_overlays; j++) { 443 + if (ofbi2->overlays[j]->info.enabled) { 444 + r = -EBUSY; 445 + goto out; 446 + } 434 447 } 435 448 } 436 449 437 - if (size != ofbi->region.size) { 438 - r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); 450 + if (size != ofbi->region->size) { 451 + r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); 439 452 if (r) { 440 453 dev_err(dev, "realloc fbmem failed\n"); 441 454 goto out; ··· 470 453 struct fb_info *fbi = dev_get_drvdata(dev); 471 454 struct omapfb_info *ofbi = FB2OFB(fbi); 472 455 473 - return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); 456 + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); 474 457 } 475 458 476 459 static ssize_t show_virt(struct device *dev, ··· 479 462 struct fb_info *fbi = dev_get_drvdata(dev); 480 463 struct omapfb_info *ofbi = FB2OFB(fbi); 481 464 482 - return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); 465 + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); 483 466 } 484 467 485 468 static struct device_attribute omapfb_attrs[] = {
+7 -2
drivers/video/omap2/omapfb/omapfb.h
··· 44 44 #define OMAPFB_MAX_OVL_PER_FB 3 45 45 46 46 struct omapfb2_mem_region { 47 + int id; 47 48 u32 paddr; 48 49 void __iomem *vaddr; 49 50 struct vrfb vrfb; ··· 52 51 u8 type; /* OMAPFB_PLANE_MEM_* */ 53 52 bool alloc; /* allocated by the driver */ 54 53 bool map; /* kernel mapped by the driver */ 54 + atomic_t map_count; 55 55 }; 56 56 57 57 /* appended to fb_info */ 58 58 struct omapfb_info { 59 59 int id; 60 - struct omapfb2_mem_region region; 61 - atomic_t map_count; 60 + struct omapfb2_mem_region *region; 62 61 int num_overlays; 63 62 struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; 64 63 struct omapfb2_device *fbdev; ··· 77 76 78 77 unsigned num_fbs; 79 78 struct fb_info *fbs[10]; 79 + struct omapfb2_mem_region regions[10]; 80 80 81 81 unsigned num_displays; 82 82 struct omap_dss_device *displays[10]; ··· 118 116 119 117 int dss_mode_to_fb_mode(enum omap_color_mode dssmode, 120 118 struct fb_var_screeninfo *var); 119 + 120 + int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 121 + u16 posx, u16 posy, u16 outw, u16 outh); 121 122 122 123 /* find the display connected to this fb, if any */ 123 124 static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
+4 -1
include/linux/omapfb.h
··· 85 85 #define OMAPFB_MEMTYPE_SRAM 1 86 86 #define OMAPFB_MEMTYPE_MAX 1 87 87 88 + #define OMAPFB_MEM_IDX_ENABLED 0x80 89 + #define OMAPFB_MEM_IDX_MASK 0x7f 90 + 88 91 enum omapfb_color_format { 89 92 OMAPFB_COLOR_RGB565 = 0, 90 93 OMAPFB_COLOR_YUV422, ··· 139 136 __u8 enabled; 140 137 __u8 channel_out; 141 138 __u8 mirror; 142 - __u8 reserved1; 139 + __u8 mem_idx; 143 140 __u32 out_width; 144 141 __u32 out_height; 145 142 __u32 reserved2[12];