linux/drivers/gpu/drm/shmobile/shmob_drm_kms.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting
   4 *
   5 * Copyright (C) 2012 Renesas Electronics Corporation
   6 *
   7 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   8 */
   9
  10#include <drm/drm_crtc.h>
  11#include <drm/drm_crtc_helper.h>
  12#include <drm/drm_fb_cma_helper.h>
  13#include <drm/drm_gem_cma_helper.h>
  14#include <drm/drm_gem_framebuffer_helper.h>
  15#include <drm/drm_probe_helper.h>
  16
  17#include "shmob_drm_crtc.h"
  18#include "shmob_drm_drv.h"
  19#include "shmob_drm_kms.h"
  20#include "shmob_drm_regs.h"
  21
  22/* -----------------------------------------------------------------------------
  23 * Format helpers
  24 */
  25
  26static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
  27        {
  28                .fourcc = DRM_FORMAT_RGB565,
  29                .bpp = 16,
  30                .yuv = false,
  31                .lddfr = LDDFR_PKF_RGB16,
  32        }, {
  33                .fourcc = DRM_FORMAT_RGB888,
  34                .bpp = 24,
  35                .yuv = false,
  36                .lddfr = LDDFR_PKF_RGB24,
  37        }, {
  38                .fourcc = DRM_FORMAT_ARGB8888,
  39                .bpp = 32,
  40                .yuv = false,
  41                .lddfr = LDDFR_PKF_ARGB32,
  42        }, {
  43                .fourcc = DRM_FORMAT_NV12,
  44                .bpp = 12,
  45                .yuv = true,
  46                .lddfr = LDDFR_CC | LDDFR_YF_420,
  47        }, {
  48                .fourcc = DRM_FORMAT_NV21,
  49                .bpp = 12,
  50                .yuv = true,
  51                .lddfr = LDDFR_CC | LDDFR_YF_420,
  52        }, {
  53                .fourcc = DRM_FORMAT_NV16,
  54                .bpp = 16,
  55                .yuv = true,
  56                .lddfr = LDDFR_CC | LDDFR_YF_422,
  57        }, {
  58                .fourcc = DRM_FORMAT_NV61,
  59                .bpp = 16,
  60                .yuv = true,
  61                .lddfr = LDDFR_CC | LDDFR_YF_422,
  62        }, {
  63                .fourcc = DRM_FORMAT_NV24,
  64                .bpp = 24,
  65                .yuv = true,
  66                .lddfr = LDDFR_CC | LDDFR_YF_444,
  67        }, {
  68                .fourcc = DRM_FORMAT_NV42,
  69                .bpp = 24,
  70                .yuv = true,
  71                .lddfr = LDDFR_CC | LDDFR_YF_444,
  72        },
  73};
  74
  75const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
  76{
  77        unsigned int i;
  78
  79        for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) {
  80                if (shmob_drm_format_infos[i].fourcc == fourcc)
  81                        return &shmob_drm_format_infos[i];
  82        }
  83
  84        return NULL;
  85}
  86
  87/* -----------------------------------------------------------------------------
  88 * Frame buffer
  89 */
  90
  91static struct drm_framebuffer *
  92shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
  93                    const struct drm_mode_fb_cmd2 *mode_cmd)
  94{
  95        const struct shmob_drm_format_info *format;
  96
  97        format = shmob_drm_format_info(mode_cmd->pixel_format);
  98        if (format == NULL) {
  99                dev_dbg(dev->dev, "unsupported pixel format %08x\n",
 100                        mode_cmd->pixel_format);
 101                return ERR_PTR(-EINVAL);
 102        }
 103
 104        if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
 105                dev_dbg(dev->dev, "invalid pitch value %u\n",
 106                        mode_cmd->pitches[0]);
 107                return ERR_PTR(-EINVAL);
 108        }
 109
 110        if (format->yuv) {
 111                unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
 112
 113                if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
 114                        dev_dbg(dev->dev,
 115                                "luma and chroma pitches do not match\n");
 116                        return ERR_PTR(-EINVAL);
 117                }
 118        }
 119
 120        return drm_gem_fb_create(dev, file_priv, mode_cmd);
 121}
 122
 123static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
 124        .fb_create = shmob_drm_fb_create,
 125};
 126
 127int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
 128{
 129        int ret;
 130
 131        ret = drmm_mode_config_init(sdev->ddev);
 132        if (ret)
 133                return ret;
 134
 135        shmob_drm_crtc_create(sdev);
 136        shmob_drm_encoder_create(sdev);
 137        shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
 138
 139        drm_kms_helper_poll_init(sdev->ddev);
 140
 141        sdev->ddev->mode_config.min_width = 0;
 142        sdev->ddev->mode_config.min_height = 0;
 143        sdev->ddev->mode_config.max_width = 4095;
 144        sdev->ddev->mode_config.max_height = 4095;
 145        sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
 146
 147        drm_helper_disable_unused_functions(sdev->ddev);
 148
 149        return 0;
 150}
 151