linux/drivers/gpu/drm/bochs/bochs_kms.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 */
   7
   8#include "bochs.h"
   9#include <drm/drm_plane_helper.h>
  10
  11static int defx = 1024;
  12static int defy = 768;
  13
  14module_param(defx, int, 0444);
  15module_param(defy, int, 0444);
  16MODULE_PARM_DESC(defx, "default x resolution");
  17MODULE_PARM_DESC(defy, "default y resolution");
  18
  19/* ---------------------------------------------------------------------- */
  20
  21static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
  22{
  23        switch (mode) {
  24        case DRM_MODE_DPMS_ON:
  25        case DRM_MODE_DPMS_STANDBY:
  26        case DRM_MODE_DPMS_SUSPEND:
  27        case DRM_MODE_DPMS_OFF:
  28        default:
  29                return;
  30        }
  31}
  32
  33static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
  34                                    struct drm_framebuffer *old_fb)
  35{
  36        struct bochs_device *bochs =
  37                container_of(crtc, struct bochs_device, crtc);
  38        struct bochs_framebuffer *bochs_fb;
  39        struct bochs_bo *bo;
  40        u64 gpu_addr = 0;
  41        int ret;
  42
  43        if (old_fb) {
  44                bochs_fb = to_bochs_framebuffer(old_fb);
  45                bo = gem_to_bochs_bo(bochs_fb->obj);
  46                ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
  47                if (ret) {
  48                        DRM_ERROR("failed to reserve old_fb bo\n");
  49                } else {
  50                        bochs_bo_unpin(bo);
  51                        ttm_bo_unreserve(&bo->bo);
  52                }
  53        }
  54
  55        if (WARN_ON(crtc->primary->fb == NULL))
  56                return -EINVAL;
  57
  58        bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
  59        bo = gem_to_bochs_bo(bochs_fb->obj);
  60        ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
  61        if (ret)
  62                return ret;
  63
  64        ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
  65        if (ret) {
  66                ttm_bo_unreserve(&bo->bo);
  67                return ret;
  68        }
  69
  70        ttm_bo_unreserve(&bo->bo);
  71        bochs_hw_setbase(bochs, x, y, gpu_addr);
  72        return 0;
  73}
  74
  75static int bochs_crtc_mode_set(struct drm_crtc *crtc,
  76                               struct drm_display_mode *mode,
  77                               struct drm_display_mode *adjusted_mode,
  78                               int x, int y, struct drm_framebuffer *old_fb)
  79{
  80        struct bochs_device *bochs =
  81                container_of(crtc, struct bochs_device, crtc);
  82
  83        bochs_hw_setmode(bochs, mode);
  84        bochs_crtc_mode_set_base(crtc, x, y, old_fb);
  85        return 0;
  86}
  87
  88static void bochs_crtc_prepare(struct drm_crtc *crtc)
  89{
  90}
  91
  92static void bochs_crtc_commit(struct drm_crtc *crtc)
  93{
  94}
  95
  96static int bochs_crtc_page_flip(struct drm_crtc *crtc,
  97                                struct drm_framebuffer *fb,
  98                                struct drm_pending_vblank_event *event,
  99                                uint32_t page_flip_flags,
 100                                struct drm_modeset_acquire_ctx *ctx)
 101{
 102        struct bochs_device *bochs =
 103                container_of(crtc, struct bochs_device, crtc);
 104        struct drm_framebuffer *old_fb = crtc->primary->fb;
 105        unsigned long irqflags;
 106
 107        crtc->primary->fb = fb;
 108        bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
 109        if (event) {
 110                spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
 111                drm_crtc_send_vblank_event(crtc, event);
 112                spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags);
 113        }
 114        return 0;
 115}
 116
 117/* These provide the minimum set of functions required to handle a CRTC */
 118static const struct drm_crtc_funcs bochs_crtc_funcs = {
 119        .set_config = drm_crtc_helper_set_config,
 120        .destroy = drm_crtc_cleanup,
 121        .page_flip = bochs_crtc_page_flip,
 122};
 123
 124static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
 125        .dpms = bochs_crtc_dpms,
 126        .mode_set = bochs_crtc_mode_set,
 127        .mode_set_base = bochs_crtc_mode_set_base,
 128        .prepare = bochs_crtc_prepare,
 129        .commit = bochs_crtc_commit,
 130};
 131
 132static void bochs_crtc_init(struct drm_device *dev)
 133{
 134        struct bochs_device *bochs = dev->dev_private;
 135        struct drm_crtc *crtc = &bochs->crtc;
 136
 137        drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
 138        drm_crtc_helper_add(crtc, &bochs_helper_funcs);
 139}
 140
 141static void bochs_encoder_mode_set(struct drm_encoder *encoder,
 142                                   struct drm_display_mode *mode,
 143                                   struct drm_display_mode *adjusted_mode)
 144{
 145}
 146
 147static void bochs_encoder_dpms(struct drm_encoder *encoder, int state)
 148{
 149}
 150
 151static void bochs_encoder_prepare(struct drm_encoder *encoder)
 152{
 153}
 154
 155static void bochs_encoder_commit(struct drm_encoder *encoder)
 156{
 157}
 158
 159static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = {
 160        .dpms = bochs_encoder_dpms,
 161        .mode_set = bochs_encoder_mode_set,
 162        .prepare = bochs_encoder_prepare,
 163        .commit = bochs_encoder_commit,
 164};
 165
 166static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = {
 167        .destroy = drm_encoder_cleanup,
 168};
 169
 170static void bochs_encoder_init(struct drm_device *dev)
 171{
 172        struct bochs_device *bochs = dev->dev_private;
 173        struct drm_encoder *encoder = &bochs->encoder;
 174
 175        encoder->possible_crtcs = 0x1;
 176        drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs,
 177                         DRM_MODE_ENCODER_DAC, NULL);
 178        drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs);
 179}
 180
 181
 182static int bochs_connector_get_modes(struct drm_connector *connector)
 183{
 184        int count;
 185
 186        count = drm_add_modes_noedid(connector, 8192, 8192);
 187        drm_set_preferred_mode(connector, defx, defy);
 188        return count;
 189}
 190
 191static int bochs_connector_mode_valid(struct drm_connector *connector,
 192                                      struct drm_display_mode *mode)
 193{
 194        struct bochs_device *bochs =
 195                container_of(connector, struct bochs_device, connector);
 196        unsigned long size = mode->hdisplay * mode->vdisplay * 4;
 197
 198        /*
 199         * Make sure we can fit two framebuffers into video memory.
 200         * This allows up to 1600x1200 with 16 MB (default size).
 201         * If you want more try this:
 202         *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
 203         */
 204        if (size * 2 > bochs->fb_size)
 205                return MODE_BAD;
 206
 207        return MODE_OK;
 208}
 209
 210static struct drm_encoder *
 211bochs_connector_best_encoder(struct drm_connector *connector)
 212{
 213        int enc_id = connector->encoder_ids[0];
 214        /* pick the encoder ids */
 215        if (enc_id)
 216                return drm_encoder_find(connector->dev, NULL, enc_id);
 217        return NULL;
 218}
 219
 220static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
 221        .get_modes = bochs_connector_get_modes,
 222        .mode_valid = bochs_connector_mode_valid,
 223        .best_encoder = bochs_connector_best_encoder,
 224};
 225
 226static const struct drm_connector_funcs bochs_connector_connector_funcs = {
 227        .dpms = drm_helper_connector_dpms,
 228        .fill_modes = drm_helper_probe_single_connector_modes,
 229        .destroy = drm_connector_cleanup,
 230};
 231
 232static void bochs_connector_init(struct drm_device *dev)
 233{
 234        struct bochs_device *bochs = dev->dev_private;
 235        struct drm_connector *connector = &bochs->connector;
 236
 237        drm_connector_init(dev, connector, &bochs_connector_connector_funcs,
 238                           DRM_MODE_CONNECTOR_VIRTUAL);
 239        drm_connector_helper_add(connector,
 240                                 &bochs_connector_connector_helper_funcs);
 241        drm_connector_register(connector);
 242}
 243
 244
 245int bochs_kms_init(struct bochs_device *bochs)
 246{
 247        drm_mode_config_init(bochs->dev);
 248        bochs->mode_config_initialized = true;
 249
 250        bochs->dev->mode_config.max_width = 8192;
 251        bochs->dev->mode_config.max_height = 8192;
 252
 253        bochs->dev->mode_config.fb_base = bochs->fb_base;
 254        bochs->dev->mode_config.preferred_depth = 24;
 255        bochs->dev->mode_config.prefer_shadow = 0;
 256
 257        bochs->dev->mode_config.funcs = &bochs_mode_funcs;
 258
 259        bochs_crtc_init(bochs->dev);
 260        bochs_encoder_init(bochs->dev);
 261        bochs_connector_init(bochs->dev);
 262        drm_mode_connector_attach_encoder(&bochs->connector,
 263                                          &bochs->encoder);
 264
 265        return 0;
 266}
 267
 268void bochs_kms_fini(struct bochs_device *bochs)
 269{
 270        if (bochs->mode_config_initialized) {
 271                drm_mode_config_cleanup(bochs->dev);
 272                bochs->mode_config_initialized = false;
 273        }
 274}
 275