| /* |
| * Copyright © 2012 ARM Limited |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| */ |
| #include <stdlib.h> |
| #include <sys/mman.h> |
| #include <assert.h> |
| #include <errno.h> |
| |
| #include <xf86.h> |
| #include <xf86drm.h> |
| #include <xf86drmMode.h> |
| |
| #include "omap_dumb.h" |
| #include "omap_msg.h" |
| |
| /* device related functions: |
| */ |
| |
| struct omap_device *omap_device_new(int fd, ScrnInfoPtr pScrn) |
| { |
| struct omap_device *new_dev = calloc(1, sizeof *new_dev); |
| const struct bo_ops *bo_ops; |
| |
| if (!new_dev) |
| return NULL; |
| |
| new_dev->fd = fd; |
| new_dev->pScrn = pScrn; |
| |
| if (!bo_device_init(new_dev)) |
| goto err_free_dev; |
| |
| bo_ops = new_dev->ops; |
| |
| if (!(bo_ops->bo_create && bo_ops->bo_destroy |
| && bo_ops->bo_get_name |
| && bo_ops->bo_map |
| && bo_ops->bo_cpu_prep |
| && bo_ops->bo_cpu_fini)) { |
| ERROR_MSG("Omap Dev New Fail: bo_ops setting is Incomplete"); |
| goto err_deinit_bodev; |
| } |
| |
| return new_dev; |
| err_deinit_bodev: |
| bo_device_deinit(new_dev); |
| err_free_dev: |
| free(new_dev); |
| return NULL; |
| } |
| |
| void omap_device_del(struct omap_device *dev) |
| { |
| bo_device_deinit(dev); |
| free(dev); |
| } |
| |
| /* buffer-object related functions: |
| */ |
| |
| static struct omap_bo *omap_bo_new(struct omap_device *dev, uint32_t width, |
| uint32_t height, uint8_t depth, uint8_t bpp, |
| uint32_t pixel_format) |
| { |
| ScrnInfoPtr pScrn = dev->pScrn; |
| const struct bo_ops *bo_ops = dev->ops; |
| struct omap_bo *new_buf; |
| uint32_t pitch; |
| size_t size; |
| const uint32_t flags = 0; |
| int ret; |
| |
| new_buf = calloc(1, sizeof(*new_buf)); |
| if (!new_buf) |
| return NULL; |
| |
| /* align to 64 bytes since Mali requires it. |
| */ |
| pitch = ((((width * bpp + 7) / 8) + 63) / 64) * 64; |
| size = height * pitch; |
| |
| new_buf->priv_bo = bo_ops->bo_create(dev, size, flags, &new_buf->handle); |
| if (!new_buf->priv_bo) { |
| ERROR_MSG("PLATFORM_BO_CREATE(size: %zu flags: 0x%x) failed: %s", |
| size, flags, strerror(errno)); |
| goto free_buf; |
| } |
| |
| if (depth) { |
| ret = drmModeAddFB(dev->fd, width, height, depth, |
| bpp, pitch, new_buf->handle, |
| &new_buf->fb_id); |
| if (ret < 0) { |
| ERROR_MSG("[BO:%u] add FB {%ux%u depth: %u bpp: %u pitch: %u} failed: %s", |
| new_buf->handle, width, |
| height, depth, bpp, pitch, |
| strerror(errno)); |
| goto destroy_bo; |
| } |
| DEBUG_MSG("Created [FB:%u] {%ux%u depth: %u bpp: %u pitch: %u} using [BO:%u]", |
| new_buf->fb_id, width, height, depth, bpp, |
| pitch, new_buf->handle); |
| } else { |
| uint32_t handles[4] = { new_buf->handle }; |
| uint32_t pitches[4] = { pitch }; |
| uint32_t offsets[4] = { 0 }; |
| |
| ret = drmModeAddFB2(dev->fd, width, height, |
| pixel_format, handles, pitches, offsets, |
| &new_buf->fb_id, 0); |
| if (ret < 0) { |
| ERROR_MSG("[BO:%u] add FB {%ux%u format: %.4s pitch: %u} failed: %s", |
| new_buf->handle, width, |
| height, (char *)&pixel_format, pitch, |
| strerror(errno)); |
| goto destroy_bo; |
| } |
| /* print pixel_format as a 'four-cc' ASCII code */ |
| DEBUG_MSG("[BO:%u] [FB:%u] Added FB: {%ux%u format: %.4s pitch: %u}", |
| new_buf->handle, new_buf->fb_id, |
| width, height, (char *)&pixel_format, pitch); |
| } |
| |
| new_buf->dev = dev; |
| new_buf->width = width; |
| new_buf->height = height; |
| new_buf->pitch = pitch; |
| new_buf->depth = depth; |
| new_buf->bpp = bpp; |
| new_buf->pixel_format = pixel_format; |
| new_buf->refcnt = 1; |
| new_buf->acquired_exclusive = 0; |
| new_buf->acquire_cnt = 0; |
| new_buf->dirty = TRUE; |
| |
| return new_buf; |
| |
| destroy_bo: |
| bo_ops->bo_destroy(new_buf); |
| free_buf: |
| free(new_buf); |
| return NULL; |
| } |
| |
| struct omap_bo *omap_bo_new_with_depth(struct omap_device *dev, uint32_t width, |
| uint32_t height, uint8_t depth, uint8_t bpp) |
| { |
| return omap_bo_new(dev, width, height, depth, bpp, 0); |
| } |
| |
| struct omap_bo *omap_bo_new_with_format(struct omap_device *dev, uint32_t width, |
| uint32_t height, uint32_t pixel_format, uint8_t bpp) |
| { |
| return omap_bo_new(dev, width, height, 0, bpp, pixel_format); |
| } |
| |
| static void omap_bo_del(struct omap_bo *bo) |
| { |
| struct omap_device *dev = bo->dev; |
| ScrnInfoPtr pScrn = dev->pScrn; |
| int res; |
| |
| res = drmModeRmFB(dev->fd, bo->fb_id); |
| if (res) |
| ERROR_MSG("[BO:%u] Remove [FB:%u] failed: %s", |
| bo->handle, bo->fb_id, |
| strerror(errno)); |
| assert(res == 0); |
| dev->ops->bo_destroy(bo); |
| free(bo); |
| } |
| |
| void omap_bo_unreference(struct omap_bo *bo) |
| { |
| if (!bo) |
| return; |
| |
| assert(bo->refcnt > 0); |
| if (--bo->refcnt == 0) |
| omap_bo_del(bo); |
| } |
| |
| void omap_bo_reference(struct omap_bo *bo) |
| { |
| assert(bo->refcnt > 0); |
| bo->refcnt++; |
| } |
| |
| uint32_t omap_bo_get_name(struct omap_bo *bo) |
| { |
| struct omap_device *dev = bo->dev; |
| ScrnInfoPtr pScrn = dev->pScrn; |
| uint32_t name; |
| int ret; |
| |
| ret = dev->ops->bo_get_name(bo, &name); |
| if (ret) { |
| ERROR_MSG("[BO:%u] BO_GET_NAME failed: %s", |
| bo->handle, strerror(errno)); |
| return 0; |
| } |
| |
| DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] ", |
| bo->handle, bo->fb_id, name); |
| |
| return name; |
| } |
| |
| uint32_t omap_bo_handle(struct omap_bo *bo) |
| { |
| return bo->handle; |
| } |
| |
| uint32_t omap_bo_width(struct omap_bo *bo) |
| { |
| return bo->width; |
| } |
| |
| uint32_t omap_bo_height(struct omap_bo *bo) |
| { |
| return bo->height; |
| } |
| |
| uint32_t omap_bo_bpp(struct omap_bo *bo) |
| { |
| return bo->bpp; |
| } |
| |
| /* Bytes per pixel */ |
| uint32_t omap_bo_Bpp(struct omap_bo *bo) |
| { |
| return (bo->bpp + 7) / 8; |
| } |
| |
| uint32_t omap_bo_pitch(struct omap_bo *bo) |
| { |
| return bo->pitch; |
| } |
| |
| uint32_t omap_bo_depth(struct omap_bo *bo) |
| { |
| return bo->depth; |
| } |
| |
| uint32_t omap_bo_fb(struct omap_bo *bo) |
| { |
| return bo->fb_id; |
| } |
| |
| void *omap_bo_map(struct omap_bo *bo) |
| { |
| struct omap_device *dev = bo->dev; |
| ScrnInfoPtr pScrn = dev->pScrn; |
| void *map_addr; |
| |
| map_addr = dev->ops->bo_map(bo); |
| if (!map_addr) { |
| ERROR_MSG("[BO:%u] bo_MAP failed: %s", |
| bo->handle, strerror(errno)); |
| return NULL; |
| } |
| |
| return map_addr; |
| } |
| |
| int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op) |
| { |
| struct omap_device *dev = bo->dev; |
| ScrnInfoPtr pScrn = dev->pScrn; |
| int ret; |
| |
| if (bo->acquire_cnt) { |
| if ((op & OMAP_GEM_WRITE) && !bo->acquired_exclusive) { |
| ERROR_MSG("attempting to acquire read locked surface for write"); |
| return 1; |
| } |
| bo->acquire_cnt++; |
| return 0; |
| } |
| |
| ret = dev->ops->bo_cpu_prep(bo, op); |
| if (!ret) { |
| bo->acquired_exclusive = op & OMAP_GEM_WRITE; |
| bo->acquire_cnt++; |
| if (bo->acquired_exclusive) { |
| bo->dirty = TRUE; |
| } |
| } |
| |
| return ret; |
| } |
| |
| int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op) |
| { |
| struct omap_device *dev = bo->dev; |
| |
| assert(bo->acquire_cnt > 0); |
| |
| if (--bo->acquire_cnt != 0) { |
| return 0; |
| } |
| |
| return dev->ops->bo_cpu_fini(bo, op); |
| } |
| |
| int omap_bo_get_dirty(struct omap_bo *bo) |
| { |
| return bo->dirty; |
| } |
| |
| void omap_bo_clear_dirty(struct omap_bo *bo) |
| { |
| bo->dirty = FALSE; |
| } |
| |