Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* exynos_drm_vidi.c
0003  *
0004  * Copyright (C) 2012 Samsung Electronics Co.Ltd
0005  * Authors:
0006  *  Inki Dae <inki.dae@samsung.com>
0007  */
0008 
0009 #include <linux/component.h>
0010 #include <linux/kernel.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/timer.h>
0013 
0014 #include <drm/drm_atomic_helper.h>
0015 #include <drm/drm_edid.h>
0016 #include <drm/drm_framebuffer.h>
0017 #include <drm/drm_probe_helper.h>
0018 #include <drm/drm_simple_kms_helper.h>
0019 #include <drm/drm_vblank.h>
0020 #include <drm/exynos_drm.h>
0021 
0022 #include "exynos_drm_crtc.h"
0023 #include "exynos_drm_drv.h"
0024 #include "exynos_drm_fb.h"
0025 #include "exynos_drm_plane.h"
0026 #include "exynos_drm_vidi.h"
0027 
0028 /* VIDI uses fixed refresh rate of 50Hz */
0029 #define VIDI_REFRESH_TIME (1000 / 50)
0030 
0031 /* vidi has totally three virtual windows. */
0032 #define WINDOWS_NR      3
0033 
0034 #define ctx_from_connector(c)   container_of(c, struct vidi_context, \
0035                     connector)
0036 
0037 struct vidi_context {
0038     struct drm_encoder      encoder;
0039     struct drm_device       *drm_dev;
0040     struct device           *dev;
0041     struct exynos_drm_crtc      *crtc;
0042     struct drm_connector        connector;
0043     struct exynos_drm_plane     planes[WINDOWS_NR];
0044     struct edid         *raw_edid;
0045     unsigned int            clkdiv;
0046     unsigned int            connected;
0047     bool                suspended;
0048     struct timer_list       timer;
0049     struct mutex            lock;
0050 };
0051 
0052 static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
0053 {
0054     return container_of(e, struct vidi_context, encoder);
0055 }
0056 
0057 static const char fake_edid_info[] = {
0058     0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
0059     0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
0060     0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
0061     0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0062     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
0063     0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
0064     0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
0065     0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0066     0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0067     0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
0068     0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
0069     0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
0070     0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
0071     0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
0072     0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
0073     0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
0074     0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
0075     0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
0076     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0077     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0078     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0079     0x00, 0x00, 0x00, 0x06
0080 };
0081 
0082 static const uint32_t formats[] = {
0083     DRM_FORMAT_XRGB8888,
0084     DRM_FORMAT_ARGB8888,
0085     DRM_FORMAT_NV12,
0086 };
0087 
0088 static const enum drm_plane_type vidi_win_types[WINDOWS_NR] = {
0089     DRM_PLANE_TYPE_PRIMARY,
0090     DRM_PLANE_TYPE_OVERLAY,
0091     DRM_PLANE_TYPE_CURSOR,
0092 };
0093 
0094 static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
0095 {
0096     struct vidi_context *ctx = crtc->ctx;
0097 
0098     if (ctx->suspended)
0099         return -EPERM;
0100 
0101     mod_timer(&ctx->timer,
0102         jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
0103 
0104     return 0;
0105 }
0106 
0107 static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
0108 {
0109 }
0110 
0111 static void vidi_update_plane(struct exynos_drm_crtc *crtc,
0112                   struct exynos_drm_plane *plane)
0113 {
0114     struct drm_plane_state *state = plane->base.state;
0115     struct vidi_context *ctx = crtc->ctx;
0116     dma_addr_t addr;
0117 
0118     if (ctx->suspended)
0119         return;
0120 
0121     addr = exynos_drm_fb_dma_addr(state->fb, 0);
0122     DRM_DEV_DEBUG_KMS(ctx->dev, "dma_addr = %pad\n", &addr);
0123 }
0124 
0125 static void vidi_atomic_enable(struct exynos_drm_crtc *crtc)
0126 {
0127     struct vidi_context *ctx = crtc->ctx;
0128 
0129     mutex_lock(&ctx->lock);
0130 
0131     ctx->suspended = false;
0132 
0133     mutex_unlock(&ctx->lock);
0134 
0135     drm_crtc_vblank_on(&crtc->base);
0136 }
0137 
0138 static void vidi_atomic_disable(struct exynos_drm_crtc *crtc)
0139 {
0140     struct vidi_context *ctx = crtc->ctx;
0141 
0142     drm_crtc_vblank_off(&crtc->base);
0143 
0144     mutex_lock(&ctx->lock);
0145 
0146     ctx->suspended = true;
0147 
0148     mutex_unlock(&ctx->lock);
0149 }
0150 
0151 static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
0152     .atomic_enable = vidi_atomic_enable,
0153     .atomic_disable = vidi_atomic_disable,
0154     .enable_vblank = vidi_enable_vblank,
0155     .disable_vblank = vidi_disable_vblank,
0156     .update_plane = vidi_update_plane,
0157     .atomic_flush = exynos_crtc_handle_event,
0158 };
0159 
0160 static void vidi_fake_vblank_timer(struct timer_list *t)
0161 {
0162     struct vidi_context *ctx = from_timer(ctx, t, timer);
0163 
0164     if (drm_crtc_handle_vblank(&ctx->crtc->base))
0165         mod_timer(&ctx->timer,
0166             jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
0167 }
0168 
0169 static ssize_t vidi_show_connection(struct device *dev,
0170                 struct device_attribute *attr, char *buf)
0171 {
0172     struct vidi_context *ctx = dev_get_drvdata(dev);
0173     int rc;
0174 
0175     mutex_lock(&ctx->lock);
0176 
0177     rc = sprintf(buf, "%d\n", ctx->connected);
0178 
0179     mutex_unlock(&ctx->lock);
0180 
0181     return rc;
0182 }
0183 
0184 static ssize_t vidi_store_connection(struct device *dev,
0185                 struct device_attribute *attr,
0186                 const char *buf, size_t len)
0187 {
0188     struct vidi_context *ctx = dev_get_drvdata(dev);
0189     int ret;
0190 
0191     ret = kstrtoint(buf, 0, &ctx->connected);
0192     if (ret)
0193         return ret;
0194 
0195     if (ctx->connected > 1)
0196         return -EINVAL;
0197 
0198     /* use fake edid data for test. */
0199     if (!ctx->raw_edid)
0200         ctx->raw_edid = (struct edid *)fake_edid_info;
0201 
0202     /* if raw_edid isn't same as fake data then it can't be tested. */
0203     if (ctx->raw_edid != (struct edid *)fake_edid_info) {
0204         DRM_DEV_DEBUG_KMS(dev, "edid data is not fake data.\n");
0205         return -EINVAL;
0206     }
0207 
0208     DRM_DEV_DEBUG_KMS(dev, "requested connection.\n");
0209 
0210     drm_helper_hpd_irq_event(ctx->drm_dev);
0211 
0212     return len;
0213 }
0214 
0215 static DEVICE_ATTR(connection, 0644, vidi_show_connection,
0216             vidi_store_connection);
0217 
0218 static struct attribute *vidi_attrs[] = {
0219     &dev_attr_connection.attr,
0220     NULL,
0221 };
0222 ATTRIBUTE_GROUPS(vidi);
0223 
0224 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
0225                 struct drm_file *file_priv)
0226 {
0227     struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
0228     struct drm_exynos_vidi_connection *vidi = data;
0229 
0230     if (!vidi) {
0231         DRM_DEV_DEBUG_KMS(ctx->dev,
0232                   "user data for vidi is null.\n");
0233         return -EINVAL;
0234     }
0235 
0236     if (vidi->connection > 1) {
0237         DRM_DEV_DEBUG_KMS(ctx->dev,
0238                   "connection should be 0 or 1.\n");
0239         return -EINVAL;
0240     }
0241 
0242     if (ctx->connected == vidi->connection) {
0243         DRM_DEV_DEBUG_KMS(ctx->dev,
0244                   "same connection request.\n");
0245         return -EINVAL;
0246     }
0247 
0248     if (vidi->connection) {
0249         struct edid *raw_edid;
0250 
0251         raw_edid = (struct edid *)(unsigned long)vidi->edid;
0252         if (!drm_edid_is_valid(raw_edid)) {
0253             DRM_DEV_DEBUG_KMS(ctx->dev,
0254                       "edid data is invalid.\n");
0255             return -EINVAL;
0256         }
0257         ctx->raw_edid = drm_edid_duplicate(raw_edid);
0258         if (!ctx->raw_edid) {
0259             DRM_DEV_DEBUG_KMS(ctx->dev,
0260                       "failed to allocate raw_edid.\n");
0261             return -ENOMEM;
0262         }
0263     } else {
0264         /*
0265          * with connection = 0, free raw_edid
0266          * only if raw edid data isn't same as fake data.
0267          */
0268         if (ctx->raw_edid && ctx->raw_edid !=
0269                 (struct edid *)fake_edid_info) {
0270             kfree(ctx->raw_edid);
0271             ctx->raw_edid = NULL;
0272         }
0273     }
0274 
0275     ctx->connected = vidi->connection;
0276     drm_helper_hpd_irq_event(ctx->drm_dev);
0277 
0278     return 0;
0279 }
0280 
0281 static enum drm_connector_status vidi_detect(struct drm_connector *connector,
0282             bool force)
0283 {
0284     struct vidi_context *ctx = ctx_from_connector(connector);
0285 
0286     /*
0287      * connection request would come from user side
0288      * to do hotplug through specific ioctl.
0289      */
0290     return ctx->connected ? connector_status_connected :
0291             connector_status_disconnected;
0292 }
0293 
0294 static void vidi_connector_destroy(struct drm_connector *connector)
0295 {
0296 }
0297 
0298 static const struct drm_connector_funcs vidi_connector_funcs = {
0299     .fill_modes = drm_helper_probe_single_connector_modes,
0300     .detect = vidi_detect,
0301     .destroy = vidi_connector_destroy,
0302     .reset = drm_atomic_helper_connector_reset,
0303     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0304     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0305 };
0306 
0307 static int vidi_get_modes(struct drm_connector *connector)
0308 {
0309     struct vidi_context *ctx = ctx_from_connector(connector);
0310     struct edid *edid;
0311     int edid_len;
0312 
0313     /*
0314      * the edid data comes from user side and it would be set
0315      * to ctx->raw_edid through specific ioctl.
0316      */
0317     if (!ctx->raw_edid) {
0318         DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n");
0319         return -EFAULT;
0320     }
0321 
0322     edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
0323     edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
0324     if (!edid) {
0325         DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n");
0326         return -ENOMEM;
0327     }
0328 
0329     drm_connector_update_edid_property(connector, edid);
0330 
0331     return drm_add_edid_modes(connector, edid);
0332 }
0333 
0334 static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
0335     .get_modes = vidi_get_modes,
0336 };
0337 
0338 static int vidi_create_connector(struct drm_encoder *encoder)
0339 {
0340     struct vidi_context *ctx = encoder_to_vidi(encoder);
0341     struct drm_connector *connector = &ctx->connector;
0342     int ret;
0343 
0344     connector->polled = DRM_CONNECTOR_POLL_HPD;
0345 
0346     ret = drm_connector_init(ctx->drm_dev, connector,
0347             &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
0348     if (ret) {
0349         DRM_DEV_ERROR(ctx->dev,
0350                   "Failed to initialize connector with drm\n");
0351         return ret;
0352     }
0353 
0354     drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
0355     drm_connector_attach_encoder(connector, encoder);
0356 
0357     return 0;
0358 }
0359 
0360 static void exynos_vidi_mode_set(struct drm_encoder *encoder,
0361                    struct drm_display_mode *mode,
0362                    struct drm_display_mode *adjusted_mode)
0363 {
0364 }
0365 
0366 static void exynos_vidi_enable(struct drm_encoder *encoder)
0367 {
0368 }
0369 
0370 static void exynos_vidi_disable(struct drm_encoder *encoder)
0371 {
0372 }
0373 
0374 static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
0375     .mode_set = exynos_vidi_mode_set,
0376     .enable = exynos_vidi_enable,
0377     .disable = exynos_vidi_disable,
0378 };
0379 
0380 static int vidi_bind(struct device *dev, struct device *master, void *data)
0381 {
0382     struct vidi_context *ctx = dev_get_drvdata(dev);
0383     struct drm_device *drm_dev = data;
0384     struct drm_encoder *encoder = &ctx->encoder;
0385     struct exynos_drm_plane *exynos_plane;
0386     struct exynos_drm_plane_config plane_config = { 0 };
0387     unsigned int i;
0388     int ret;
0389 
0390     ctx->drm_dev = drm_dev;
0391 
0392     plane_config.pixel_formats = formats;
0393     plane_config.num_pixel_formats = ARRAY_SIZE(formats);
0394 
0395     for (i = 0; i < WINDOWS_NR; i++) {
0396         plane_config.zpos = i;
0397         plane_config.type = vidi_win_types[i];
0398 
0399         ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
0400                     &plane_config);
0401         if (ret)
0402             return ret;
0403     }
0404 
0405     exynos_plane = &ctx->planes[DEFAULT_WIN];
0406     ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
0407             EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx);
0408     if (IS_ERR(ctx->crtc)) {
0409         DRM_DEV_ERROR(dev, "failed to create crtc.\n");
0410         return PTR_ERR(ctx->crtc);
0411     }
0412 
0413     drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
0414 
0415     drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
0416 
0417     ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_VIDI);
0418     if (ret < 0)
0419         return ret;
0420 
0421     ret = vidi_create_connector(encoder);
0422     if (ret) {
0423         DRM_DEV_ERROR(dev, "failed to create connector ret = %d\n",
0424                   ret);
0425         drm_encoder_cleanup(encoder);
0426         return ret;
0427     }
0428 
0429     return 0;
0430 }
0431 
0432 
0433 static void vidi_unbind(struct device *dev, struct device *master, void *data)
0434 {
0435     struct vidi_context *ctx = dev_get_drvdata(dev);
0436 
0437     del_timer_sync(&ctx->timer);
0438 }
0439 
0440 static const struct component_ops vidi_component_ops = {
0441     .bind   = vidi_bind,
0442     .unbind = vidi_unbind,
0443 };
0444 
0445 static int vidi_probe(struct platform_device *pdev)
0446 {
0447     struct vidi_context *ctx;
0448     struct device *dev = &pdev->dev;
0449 
0450     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0451     if (!ctx)
0452         return -ENOMEM;
0453 
0454     ctx->dev = dev;
0455 
0456     timer_setup(&ctx->timer, vidi_fake_vblank_timer, 0);
0457 
0458     mutex_init(&ctx->lock);
0459 
0460     platform_set_drvdata(pdev, ctx);
0461 
0462     return component_add(dev, &vidi_component_ops);
0463 }
0464 
0465 static int vidi_remove(struct platform_device *pdev)
0466 {
0467     struct vidi_context *ctx = platform_get_drvdata(pdev);
0468 
0469     if (ctx->raw_edid != (struct edid *)fake_edid_info) {
0470         kfree(ctx->raw_edid);
0471         ctx->raw_edid = NULL;
0472 
0473         return -EINVAL;
0474     }
0475 
0476     component_del(&pdev->dev, &vidi_component_ops);
0477 
0478     return 0;
0479 }
0480 
0481 struct platform_driver vidi_driver = {
0482     .probe      = vidi_probe,
0483     .remove     = vidi_remove,
0484     .driver     = {
0485         .name   = "exynos-drm-vidi",
0486         .owner  = THIS_MODULE,
0487         .dev_groups = vidi_groups,
0488     },
0489 };