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_fourcc.h> 13 #include <drm/drm_gem_dma_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 26 static 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_XRGB8888, 44 .bpp = 32, 45 .yuv = false, 46 .lddfr = LDDFR_PKF_ARGB32, 47 }, { 48 .fourcc = DRM_FORMAT_NV12, 49 .bpp = 12, 50 .yuv = true, 51 .lddfr = LDDFR_CC | LDDFR_YF_420, 52 }, { 53 .fourcc = DRM_FORMAT_NV21, 54 .bpp = 12, 55 .yuv = true, 56 .lddfr = LDDFR_CC | LDDFR_YF_420, 57 }, { 58 .fourcc = DRM_FORMAT_NV16, 59 .bpp = 16, 60 .yuv = true, 61 .lddfr = LDDFR_CC | LDDFR_YF_422, 62 }, { 63 .fourcc = DRM_FORMAT_NV61, 64 .bpp = 16, 65 .yuv = true, 66 .lddfr = LDDFR_CC | LDDFR_YF_422, 67 }, { 68 .fourcc = DRM_FORMAT_NV24, 69 .bpp = 24, 70 .yuv = true, 71 .lddfr = LDDFR_CC | LDDFR_YF_444, 72 }, { 73 .fourcc = DRM_FORMAT_NV42, 74 .bpp = 24, 75 .yuv = true, 76 .lddfr = LDDFR_CC | LDDFR_YF_444, 77 }, 78 }; 79 80 const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc) 81 { 82 unsigned int i; 83 84 for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) { 85 if (shmob_drm_format_infos[i].fourcc == fourcc) 86 return &shmob_drm_format_infos[i]; 87 } 88 89 return NULL; 90 } 91 92 /* ----------------------------------------------------------------------------- 93 * Frame buffer 94 */ 95 96 static struct drm_framebuffer * 97 shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, 98 const struct drm_mode_fb_cmd2 *mode_cmd) 99 { 100 const struct shmob_drm_format_info *format; 101 102 format = shmob_drm_format_info(mode_cmd->pixel_format); 103 if (format == NULL) { 104 dev_dbg(dev->dev, "unsupported pixel format %p4cc\n", 105 &mode_cmd->pixel_format); 106 return ERR_PTR(-EINVAL); 107 } 108 109 if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) { 110 dev_dbg(dev->dev, "invalid pitch value %u\n", 111 mode_cmd->pitches[0]); 112 return ERR_PTR(-EINVAL); 113 } 114 115 if (format->yuv) { 116 unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1; 117 118 if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) { 119 dev_dbg(dev->dev, 120 "luma and chroma pitches do not match\n"); 121 return ERR_PTR(-EINVAL); 122 } 123 } 124 125 return drm_gem_fb_create(dev, file_priv, mode_cmd); 126 } 127 128 static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = { 129 .fb_create = shmob_drm_fb_create, 130 }; 131 132 int shmob_drm_modeset_init(struct shmob_drm_device *sdev) 133 { 134 int ret; 135 136 ret = drmm_mode_config_init(sdev->ddev); 137 if (ret) 138 return ret; 139 140 shmob_drm_crtc_create(sdev); 141 shmob_drm_encoder_create(sdev); 142 shmob_drm_connector_create(sdev, &sdev->encoder.encoder); 143 144 drm_kms_helper_poll_init(sdev->ddev); 145 146 sdev->ddev->mode_config.min_width = 0; 147 sdev->ddev->mode_config.min_height = 0; 148 sdev->ddev->mode_config.max_width = 4095; 149 sdev->ddev->mode_config.max_height = 4095; 150 sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs; 151 152 drm_helper_disable_unused_functions(sdev->ddev); 153 154 return 0; 155 } 156