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