0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <drm/drm_crtc.h>
0011 #include <drm/drm_crtc_helper.h>
0012 #include <drm/drm_fb_cma_helper.h>
0013 #include <drm/drm_fourcc.h>
0014 #include <drm/drm_gem_cma_helper.h>
0015 #include <drm/drm_gem_framebuffer_helper.h>
0016 #include <drm/drm_probe_helper.h>
0017
0018 #include "shmob_drm_crtc.h"
0019 #include "shmob_drm_drv.h"
0020 #include "shmob_drm_kms.h"
0021 #include "shmob_drm_regs.h"
0022
0023
0024
0025
0026
0027 static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
0028 {
0029 .fourcc = DRM_FORMAT_RGB565,
0030 .bpp = 16,
0031 .yuv = false,
0032 .lddfr = LDDFR_PKF_RGB16,
0033 }, {
0034 .fourcc = DRM_FORMAT_RGB888,
0035 .bpp = 24,
0036 .yuv = false,
0037 .lddfr = LDDFR_PKF_RGB24,
0038 }, {
0039 .fourcc = DRM_FORMAT_ARGB8888,
0040 .bpp = 32,
0041 .yuv = false,
0042 .lddfr = LDDFR_PKF_ARGB32,
0043 }, {
0044 .fourcc = DRM_FORMAT_NV12,
0045 .bpp = 12,
0046 .yuv = true,
0047 .lddfr = LDDFR_CC | LDDFR_YF_420,
0048 }, {
0049 .fourcc = DRM_FORMAT_NV21,
0050 .bpp = 12,
0051 .yuv = true,
0052 .lddfr = LDDFR_CC | LDDFR_YF_420,
0053 }, {
0054 .fourcc = DRM_FORMAT_NV16,
0055 .bpp = 16,
0056 .yuv = true,
0057 .lddfr = LDDFR_CC | LDDFR_YF_422,
0058 }, {
0059 .fourcc = DRM_FORMAT_NV61,
0060 .bpp = 16,
0061 .yuv = true,
0062 .lddfr = LDDFR_CC | LDDFR_YF_422,
0063 }, {
0064 .fourcc = DRM_FORMAT_NV24,
0065 .bpp = 24,
0066 .yuv = true,
0067 .lddfr = LDDFR_CC | LDDFR_YF_444,
0068 }, {
0069 .fourcc = DRM_FORMAT_NV42,
0070 .bpp = 24,
0071 .yuv = true,
0072 .lddfr = LDDFR_CC | LDDFR_YF_444,
0073 },
0074 };
0075
0076 const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
0077 {
0078 unsigned int i;
0079
0080 for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) {
0081 if (shmob_drm_format_infos[i].fourcc == fourcc)
0082 return &shmob_drm_format_infos[i];
0083 }
0084
0085 return NULL;
0086 }
0087
0088
0089
0090
0091
0092 static struct drm_framebuffer *
0093 shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
0094 const struct drm_mode_fb_cmd2 *mode_cmd)
0095 {
0096 const struct shmob_drm_format_info *format;
0097
0098 format = shmob_drm_format_info(mode_cmd->pixel_format);
0099 if (format == NULL) {
0100 dev_dbg(dev->dev, "unsupported pixel format %08x\n",
0101 mode_cmd->pixel_format);
0102 return ERR_PTR(-EINVAL);
0103 }
0104
0105 if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
0106 dev_dbg(dev->dev, "invalid pitch value %u\n",
0107 mode_cmd->pitches[0]);
0108 return ERR_PTR(-EINVAL);
0109 }
0110
0111 if (format->yuv) {
0112 unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
0113
0114 if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
0115 dev_dbg(dev->dev,
0116 "luma and chroma pitches do not match\n");
0117 return ERR_PTR(-EINVAL);
0118 }
0119 }
0120
0121 return drm_gem_fb_create(dev, file_priv, mode_cmd);
0122 }
0123
0124 static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
0125 .fb_create = shmob_drm_fb_create,
0126 };
0127
0128 int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
0129 {
0130 int ret;
0131
0132 ret = drmm_mode_config_init(sdev->ddev);
0133 if (ret)
0134 return ret;
0135
0136 shmob_drm_crtc_create(sdev);
0137 shmob_drm_encoder_create(sdev);
0138 shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
0139
0140 drm_kms_helper_poll_init(sdev->ddev);
0141
0142 sdev->ddev->mode_config.min_width = 0;
0143 sdev->ddev->mode_config.min_height = 0;
0144 sdev->ddev->mode_config.max_width = 4095;
0145 sdev->ddev->mode_config.max_height = 4095;
0146 sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
0147
0148 drm_helper_disable_unused_functions(sdev->ddev);
0149
0150 return 0;
0151 }