diff options
Diffstat (limited to 'drivers/gpu/drm/bochs/bochs_kms.c')
| -rw-r--r-- | drivers/gpu/drm/bochs/bochs_kms.c | 294 | 
1 files changed, 294 insertions, 0 deletions
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c new file mode 100644 index 00000000000..dcf2e55f4ae --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -0,0 +1,294 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "bochs.h" + +static int defx = 1024; +static int defy = 768; + +module_param(defx, int, 0444); +module_param(defy, int, 0444); +MODULE_PARM_DESC(defx, "default x resolution"); +MODULE_PARM_DESC(defy, "default y resolution"); + +/* ---------------------------------------------------------------------- */ + +static void bochs_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +	switch (mode) { +	case DRM_MODE_DPMS_ON: +	case DRM_MODE_DPMS_STANDBY: +	case DRM_MODE_DPMS_SUSPEND: +	case DRM_MODE_DPMS_OFF: +	default: +		return; +	} +} + +static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc, +				  const struct drm_display_mode *mode, +				  struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, +				    struct drm_framebuffer *old_fb) +{ +	struct bochs_device *bochs = +		container_of(crtc, struct bochs_device, crtc); +	struct bochs_framebuffer *bochs_fb; +	struct bochs_bo *bo; +	u64 gpu_addr = 0; +	int ret; + +	if (old_fb) { +		bochs_fb = to_bochs_framebuffer(old_fb); +		bo = gem_to_bochs_bo(bochs_fb->obj); +		ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); +		if (ret) { +			DRM_ERROR("failed to reserve old_fb bo\n"); +		} else { +			bochs_bo_unpin(bo); +			ttm_bo_unreserve(&bo->bo); +		} +	} + +	if (WARN_ON(crtc->primary->fb == NULL)) +		return -EINVAL; + +	bochs_fb = to_bochs_framebuffer(crtc->primary->fb); +	bo = gem_to_bochs_bo(bochs_fb->obj); +	ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); +	if (ret) +		return ret; + +	ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); +	if (ret) { +		ttm_bo_unreserve(&bo->bo); +		return ret; +	} + +	ttm_bo_unreserve(&bo->bo); +	bochs_hw_setbase(bochs, x, y, gpu_addr); +	return 0; +} + +static int bochs_crtc_mode_set(struct drm_crtc *crtc, +			       struct drm_display_mode *mode, +			       struct drm_display_mode *adjusted_mode, +			       int x, int y, struct drm_framebuffer *old_fb) +{ +	struct bochs_device *bochs = +		container_of(crtc, struct bochs_device, crtc); + +	bochs_hw_setmode(bochs, mode); +	bochs_crtc_mode_set_base(crtc, x, y, old_fb); +	return 0; +} + +static void bochs_crtc_prepare(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_commit(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, +				 u16 *blue, uint32_t start, uint32_t size) +{ +} + +/* These provide the minimum set of functions required to handle a CRTC */ +static const struct drm_crtc_funcs bochs_crtc_funcs = { +	.gamma_set = bochs_crtc_gamma_set, +	.set_config = drm_crtc_helper_set_config, +	.destroy = drm_crtc_cleanup, +}; + +static const struct drm_crtc_helper_funcs bochs_helper_funcs = { +	.dpms = bochs_crtc_dpms, +	.mode_fixup = bochs_crtc_mode_fixup, +	.mode_set = bochs_crtc_mode_set, +	.mode_set_base = bochs_crtc_mode_set_base, +	.prepare = bochs_crtc_prepare, +	.commit = bochs_crtc_commit, +	.load_lut = bochs_crtc_load_lut, +}; + +static void bochs_crtc_init(struct drm_device *dev) +{ +	struct bochs_device *bochs = dev->dev_private; +	struct drm_crtc *crtc = &bochs->crtc; + +	drm_crtc_init(dev, crtc, &bochs_crtc_funcs); +	drm_mode_crtc_set_gamma_size(crtc, 256); +	drm_crtc_helper_add(crtc, &bochs_helper_funcs); +} + +static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder, +				     const struct drm_display_mode *mode, +				     struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void bochs_encoder_mode_set(struct drm_encoder *encoder, +				   struct drm_display_mode *mode, +				   struct drm_display_mode *adjusted_mode) +{ +} + +static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) +{ +} + +static void bochs_encoder_prepare(struct drm_encoder *encoder) +{ +} + +static void bochs_encoder_commit(struct drm_encoder *encoder) +{ +} + +static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { +	.dpms = bochs_encoder_dpms, +	.mode_fixup = bochs_encoder_mode_fixup, +	.mode_set = bochs_encoder_mode_set, +	.prepare = bochs_encoder_prepare, +	.commit = bochs_encoder_commit, +}; + +static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { +	.destroy = drm_encoder_cleanup, +}; + +static void bochs_encoder_init(struct drm_device *dev) +{ +	struct bochs_device *bochs = dev->dev_private; +	struct drm_encoder *encoder = &bochs->encoder; + +	encoder->possible_crtcs = 0x1; +	drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, +			 DRM_MODE_ENCODER_DAC); +	drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); +} + + +int bochs_connector_get_modes(struct drm_connector *connector) +{ +	int count; + +	count = drm_add_modes_noedid(connector, 8192, 8192); +	drm_set_preferred_mode(connector, defx, defy); +	return count; +} + +static int bochs_connector_mode_valid(struct drm_connector *connector, +				      struct drm_display_mode *mode) +{ +	struct bochs_device *bochs = +		container_of(connector, struct bochs_device, connector); +	unsigned long size = mode->hdisplay * mode->vdisplay * 4; + +	/* +	 * Make sure we can fit two framebuffers into video memory. +	 * This allows up to 1600x1200 with 16 MB (default size). +	 * If you want more try this: +	 *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs' +	 */ +	if (size * 2 > bochs->fb_size) +		return MODE_BAD; + +	return MODE_OK; +} + +static struct drm_encoder * +bochs_connector_best_encoder(struct drm_connector *connector) +{ +	int enc_id = connector->encoder_ids[0]; +	struct drm_mode_object *obj; +	struct drm_encoder *encoder; + +	/* pick the encoder ids */ +	if (enc_id) { +		obj = drm_mode_object_find(connector->dev, enc_id, +					   DRM_MODE_OBJECT_ENCODER); +		if (!obj) +			return NULL; +		encoder = obj_to_encoder(obj); +		return encoder; +	} +	return NULL; +} + +static enum drm_connector_status bochs_connector_detect(struct drm_connector +							*connector, bool force) +{ +	return connector_status_connected; +} + +struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { +	.get_modes = bochs_connector_get_modes, +	.mode_valid = bochs_connector_mode_valid, +	.best_encoder = bochs_connector_best_encoder, +}; + +struct drm_connector_funcs bochs_connector_connector_funcs = { +	.dpms = drm_helper_connector_dpms, +	.detect = bochs_connector_detect, +	.fill_modes = drm_helper_probe_single_connector_modes, +	.destroy = drm_connector_cleanup, +}; + +static void bochs_connector_init(struct drm_device *dev) +{ +	struct bochs_device *bochs = dev->dev_private; +	struct drm_connector *connector = &bochs->connector; + +	drm_connector_init(dev, connector, &bochs_connector_connector_funcs, +			   DRM_MODE_CONNECTOR_VIRTUAL); +	drm_connector_helper_add(connector, +				 &bochs_connector_connector_helper_funcs); +} + + +int bochs_kms_init(struct bochs_device *bochs) +{ +	drm_mode_config_init(bochs->dev); +	bochs->mode_config_initialized = true; + +	bochs->dev->mode_config.max_width = 8192; +	bochs->dev->mode_config.max_height = 8192; + +	bochs->dev->mode_config.fb_base = bochs->fb_base; +	bochs->dev->mode_config.preferred_depth = 24; +	bochs->dev->mode_config.prefer_shadow = 0; + +	bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs; + +	bochs_crtc_init(bochs->dev); +	bochs_encoder_init(bochs->dev); +	bochs_connector_init(bochs->dev); +	drm_mode_connector_attach_encoder(&bochs->connector, +					  &bochs->encoder); + +	return 0; +} + +void bochs_kms_fini(struct bochs_device *bochs) +{ +	if (bochs->mode_config_initialized) { +		drm_mode_config_cleanup(bochs->dev); +		bochs->mode_config_initialized = false; +	} +}  | 
