shmob_drm_kms.c (3529B)
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}