diff options
| -rw-r--r-- | drivers/gpu/drm/arm/display/komeda/Makefile | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 165 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h | 34 |
3 files changed, 201 insertions, 1 deletions
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index 394fc2aa434a..25beae900ed2 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile | |||
| @@ -8,7 +8,8 @@ komeda-y := \ | |||
| 8 | komeda_drv.o \ | 8 | komeda_drv.o \ |
| 9 | komeda_dev.o \ | 9 | komeda_dev.o \ |
| 10 | komeda_format_caps.o \ | 10 | komeda_format_caps.o \ |
| 11 | komeda_pipeline.o | 11 | komeda_pipeline.o \ |
| 12 | komeda_framebuffer.o | ||
| 12 | 13 | ||
| 13 | komeda-y += \ | 14 | komeda-y += \ |
| 14 | d71/d71_dev.o | 15 | d71/d71_dev.o |
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c new file mode 100644 index 000000000000..4ddd5314ca23 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. | ||
| 4 | * Author: James.Qian.Wang <james.qian.wang@arm.com> | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #include <drm/drm_gem.h> | ||
| 8 | #include <drm/drm_gem_framebuffer_helper.h> | ||
| 9 | #include <drm/drm_fb_cma_helper.h> | ||
| 10 | #include <drm/drm_gem_cma_helper.h> | ||
| 11 | #include "komeda_framebuffer.h" | ||
| 12 | #include "komeda_dev.h" | ||
| 13 | |||
| 14 | static void komeda_fb_destroy(struct drm_framebuffer *fb) | ||
| 15 | { | ||
| 16 | struct komeda_fb *kfb = to_kfb(fb); | ||
| 17 | u32 i; | ||
| 18 | |||
| 19 | for (i = 0; i < fb->format->num_planes; i++) | ||
| 20 | drm_gem_object_put_unlocked(fb->obj[i]); | ||
| 21 | |||
| 22 | drm_framebuffer_cleanup(fb); | ||
| 23 | kfree(kfb); | ||
| 24 | } | ||
| 25 | |||
| 26 | static int komeda_fb_create_handle(struct drm_framebuffer *fb, | ||
| 27 | struct drm_file *file, u32 *handle) | ||
| 28 | { | ||
| 29 | return drm_gem_handle_create(file, fb->obj[0], handle); | ||
| 30 | } | ||
| 31 | |||
| 32 | static const struct drm_framebuffer_funcs komeda_fb_funcs = { | ||
| 33 | .destroy = komeda_fb_destroy, | ||
| 34 | .create_handle = komeda_fb_create_handle, | ||
| 35 | }; | ||
| 36 | |||
| 37 | static int | ||
| 38 | komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb, | ||
| 39 | struct drm_file *file, | ||
| 40 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
| 41 | { | ||
| 42 | struct drm_framebuffer *fb = &kfb->base; | ||
| 43 | struct drm_gem_object *obj; | ||
| 44 | u32 min_size = 0; | ||
| 45 | u32 i; | ||
| 46 | |||
| 47 | for (i = 0; i < fb->format->num_planes; i++) { | ||
| 48 | obj = drm_gem_object_lookup(file, mode_cmd->handles[i]); | ||
| 49 | if (!obj) { | ||
| 50 | DRM_DEBUG_KMS("Failed to lookup GEM object\n"); | ||
| 51 | fb->obj[i] = NULL; | ||
| 52 | |||
| 53 | return -ENOENT; | ||
| 54 | } | ||
| 55 | |||
| 56 | kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1); | ||
| 57 | kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1); | ||
| 58 | |||
| 59 | if (fb->pitches[i] % mdev->chip.bus_width) { | ||
| 60 | DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n", | ||
| 61 | i, fb->pitches[i], mdev->chip.bus_width); | ||
| 62 | drm_gem_object_put_unlocked(obj); | ||
| 63 | fb->obj[i] = NULL; | ||
| 64 | |||
| 65 | return -EINVAL; | ||
| 66 | } | ||
| 67 | |||
| 68 | min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1) | ||
| 69 | * fb->pitches[i]) | ||
| 70 | + (kfb->aligned_w * fb->format->cpp[i] | ||
| 71 | * kfb->format_caps->tile_size) | ||
| 72 | + fb->offsets[i]; | ||
| 73 | |||
| 74 | if (obj->size < min_size) { | ||
| 75 | DRM_DEBUG_KMS("Fail to check none afbc fb size.\n"); | ||
| 76 | drm_gem_object_put_unlocked(obj); | ||
| 77 | fb->obj[i] = NULL; | ||
| 78 | |||
| 79 | return -EINVAL; | ||
| 80 | } | ||
| 81 | |||
| 82 | fb->obj[i] = obj; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (fb->format->num_planes == 3) { | ||
| 86 | if (fb->pitches[1] != fb->pitches[2]) { | ||
| 87 | DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n"); | ||
| 88 | return -EINVAL; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | struct drm_framebuffer * | ||
| 96 | komeda_fb_create(struct drm_device *dev, struct drm_file *file, | ||
| 97 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
| 98 | { | ||
| 99 | struct komeda_dev *mdev = dev->dev_private; | ||
| 100 | struct komeda_fb *kfb; | ||
| 101 | int ret = 0, i; | ||
| 102 | |||
| 103 | kfb = kzalloc(sizeof(*kfb), GFP_KERNEL); | ||
| 104 | if (!kfb) | ||
| 105 | return ERR_PTR(-ENOMEM); | ||
| 106 | |||
| 107 | kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl, | ||
| 108 | mode_cmd->pixel_format, | ||
| 109 | mode_cmd->modifier[0]); | ||
| 110 | if (!kfb->format_caps) { | ||
| 111 | DRM_DEBUG_KMS("FMT %x is not supported.\n", | ||
| 112 | mode_cmd->pixel_format); | ||
| 113 | kfree(kfb); | ||
| 114 | return ERR_PTR(-EINVAL); | ||
| 115 | } | ||
| 116 | |||
| 117 | drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd); | ||
| 118 | |||
| 119 | ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd); | ||
| 120 | if (ret < 0) | ||
| 121 | goto err_cleanup; | ||
| 122 | |||
| 123 | ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs); | ||
| 124 | if (ret < 0) { | ||
| 125 | DRM_DEBUG_KMS("failed to initialize fb\n"); | ||
| 126 | |||
| 127 | goto err_cleanup; | ||
| 128 | } | ||
| 129 | |||
| 130 | return &kfb->base; | ||
| 131 | |||
| 132 | err_cleanup: | ||
| 133 | for (i = 0; i < kfb->base.format->num_planes; i++) | ||
| 134 | drm_gem_object_put_unlocked(kfb->base.obj[i]); | ||
| 135 | |||
| 136 | kfree(kfb); | ||
| 137 | return ERR_PTR(ret); | ||
| 138 | } | ||
| 139 | |||
| 140 | dma_addr_t | ||
| 141 | komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane) | ||
| 142 | { | ||
| 143 | struct drm_framebuffer *fb = &kfb->base; | ||
| 144 | const struct drm_gem_cma_object *obj; | ||
| 145 | u32 plane_x, plane_y, cpp, pitch, offset; | ||
| 146 | |||
| 147 | if (plane > fb->format->num_planes) { | ||
| 148 | DRM_DEBUG_KMS("Out of max plane num.\n"); | ||
| 149 | return -EINVAL; | ||
| 150 | } | ||
| 151 | |||
| 152 | obj = drm_fb_cma_get_gem_obj(fb, plane); | ||
| 153 | |||
| 154 | offset = fb->offsets[plane]; | ||
| 155 | if (!fb->modifier) { | ||
| 156 | plane_x = x / (plane ? fb->format->hsub : 1); | ||
| 157 | plane_y = y / (plane ? fb->format->vsub : 1); | ||
| 158 | cpp = fb->format->cpp[plane]; | ||
| 159 | pitch = fb->pitches[plane]; | ||
| 160 | offset += plane_x * cpp * kfb->format_caps->tile_size + | ||
| 161 | (plane_y * pitch) / kfb->format_caps->tile_size; | ||
| 162 | } | ||
| 163 | |||
| 164 | return obj->paddr + offset; | ||
| 165 | } | ||
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h new file mode 100644 index 000000000000..0de2e4a2afd2 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. | ||
| 4 | * Author: James.Qian.Wang <james.qian.wang@arm.com> | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #ifndef _KOMEDA_FRAMEBUFFER_H_ | ||
| 8 | #define _KOMEDA_FRAMEBUFFER_H_ | ||
| 9 | |||
| 10 | #include <drm/drm_framebuffer.h> | ||
| 11 | #include "komeda_format_caps.h" | ||
| 12 | |||
| 13 | /** struct komeda_fb - entend drm_framebuffer with komeda attribute */ | ||
| 14 | struct komeda_fb { | ||
| 15 | /** @base: &drm_framebuffer */ | ||
| 16 | struct drm_framebuffer base; | ||
| 17 | /* @format_caps: &komeda_format_caps */ | ||
| 18 | const struct komeda_format_caps *format_caps; | ||
| 19 | /** @aligned_w: aligned frame buffer width */ | ||
| 20 | u32 aligned_w; | ||
| 21 | /** @aligned_h: aligned frame buffer height */ | ||
| 22 | u32 aligned_h; | ||
| 23 | }; | ||
| 24 | |||
| 25 | #define to_kfb(dfb) container_of(dfb, struct komeda_fb, base) | ||
| 26 | |||
| 27 | struct drm_framebuffer * | ||
| 28 | komeda_fb_create(struct drm_device *dev, struct drm_file *file, | ||
| 29 | const struct drm_mode_fb_cmd2 *mode_cmd); | ||
| 30 | dma_addr_t | ||
| 31 | komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane); | ||
| 32 | bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type); | ||
| 33 | |||
| 34 | #endif | ||
