2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2013-12-17 18:04:46 +01:00
/*
*/
# include "bochs.h"
2019-01-11 06:37:41 +01:00
# include <drm/drm_atomic_helper.h>
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2019-01-11 06:37:41 +01:00
# include <drm/drm_atomic_uapi.h>
2019-01-11 06:37:52 +01:00
# include <drm/drm_gem_framebuffer_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2013-12-17 18:04:46 +01:00
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 " ) ;
/* ---------------------------------------------------------------------- */
2019-04-10 09:48:28 +02:00
static const uint32_t bochs_formats [ ] = {
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_BGRX8888 ,
} ;
static void bochs_plane_update ( struct bochs_device * bochs ,
struct drm_plane_state * state )
2019-01-11 06:37:40 +01:00
{
2019-05-08 10:26:22 +02:00
struct drm_gem_vram_object * gbo ;
2019-01-11 06:37:40 +01:00
2019-04-10 09:48:28 +02:00
if ( ! state - > fb | | ! bochs - > stride )
return ;
2019-05-08 10:26:22 +02:00
gbo = drm_gem_vram_of_gem ( state - > fb - > obj [ 0 ] ) ;
2019-04-10 09:48:28 +02:00
bochs_hw_setbase ( bochs ,
state - > crtc_x ,
state - > crtc_y ,
2019-05-08 10:26:22 +02:00
gbo - > bo . offset ) ;
2019-04-10 09:48:28 +02:00
bochs_hw_setformat ( bochs , state - > fb - > format ) ;
2019-01-11 06:37:40 +01:00
}
2019-04-10 09:48:28 +02:00
static void bochs_pipe_enable ( struct drm_simple_display_pipe * pipe ,
struct drm_crtc_state * crtc_state ,
struct drm_plane_state * plane_state )
2019-01-11 06:37:39 +01:00
{
2019-04-10 09:48:28 +02:00
struct bochs_device * bochs = pipe - > crtc . dev - > dev_private ;
bochs_hw_setmode ( bochs , & crtc_state - > mode ) ;
bochs_plane_update ( bochs , plane_state ) ;
2019-01-11 06:37:39 +01:00
}
2019-04-10 09:48:28 +02:00
static void bochs_pipe_update ( struct drm_simple_display_pipe * pipe ,
struct drm_plane_state * old_state )
2019-01-11 06:37:39 +01:00
{
2019-04-10 09:48:28 +02:00
struct bochs_device * bochs = pipe - > crtc . dev - > dev_private ;
struct drm_crtc * crtc = & pipe - > crtc ;
2019-01-11 06:37:39 +01:00
2019-04-10 09:48:28 +02:00
bochs_plane_update ( bochs , pipe - > plane . state ) ;
2019-01-11 06:37:39 +01:00
2019-04-10 09:48:28 +02:00
if ( crtc - > state - > event ) {
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
drm_crtc_send_vblank_event ( crtc , crtc - > state - > event ) ;
2019-01-11 06:37:39 +01:00
crtc - > state - > event = NULL ;
2019-04-10 09:48:28 +02:00
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
2019-01-11 06:37:39 +01:00
}
}
2019-04-10 09:48:28 +02:00
static int bochs_pipe_prepare_fb ( struct drm_simple_display_pipe * pipe ,
struct drm_plane_state * new_state )
2019-01-11 06:37:41 +01:00
{
2019-05-08 10:26:22 +02:00
struct drm_gem_vram_object * gbo ;
2019-01-11 06:37:41 +01:00
if ( ! new_state - > fb )
return 0 ;
2019-05-08 10:26:22 +02:00
gbo = drm_gem_vram_of_gem ( new_state - > fb - > obj [ 0 ] ) ;
return drm_gem_vram_pin ( gbo , DRM_GEM_VRAM_PL_FLAG_VRAM ) ;
2019-01-11 06:37:41 +01:00
}
2019-04-10 09:48:28 +02:00
static void bochs_pipe_cleanup_fb ( struct drm_simple_display_pipe * pipe ,
struct drm_plane_state * old_state )
2019-01-11 06:37:41 +01:00
{
2019-05-08 10:26:22 +02:00
struct drm_gem_vram_object * gbo ;
2019-01-11 06:37:41 +01:00
if ( ! old_state - > fb )
return ;
2019-05-08 10:26:22 +02:00
gbo = drm_gem_vram_of_gem ( old_state - > fb - > obj [ 0 ] ) ;
drm_gem_vram_unpin ( gbo ) ;
2019-01-11 06:37:41 +01:00
}
2019-04-10 09:48:28 +02:00
static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = {
. enable = bochs_pipe_enable ,
. update = bochs_pipe_update ,
. prepare_fb = bochs_pipe_prepare_fb ,
. cleanup_fb = bochs_pipe_cleanup_fb ,
2013-12-17 18:04:46 +01:00
} ;
2016-09-25 15:25:34 +08:00
static int bochs_connector_get_modes ( struct drm_connector * connector )
2013-12-17 18:04:46 +01:00
{
2018-10-29 21:50:48 +01:00
struct bochs_device * bochs =
container_of ( connector , struct bochs_device , connector ) ;
int count = 0 ;
if ( bochs - > edid )
count = drm_add_edid_modes ( connector , bochs - > edid ) ;
2013-12-17 18:04:46 +01:00
2018-10-29 21:50:48 +01:00
if ( ! count ) {
count = drm_add_modes_noedid ( connector , 8192 , 8192 ) ;
drm_set_preferred_mode ( connector , defx , defy ) ;
}
2013-12-17 18:04:46 +01:00
return count ;
}
2018-04-24 15:14:45 +02:00
static enum drm_mode_status bochs_connector_mode_valid ( struct drm_connector * connector ,
2013-12-17 18:04:46 +01:00
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 1600 x1200 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 ;
}
2015-12-15 12:21:01 +01:00
static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
2013-12-17 18:04:46 +01:00
. get_modes = bochs_connector_get_modes ,
. mode_valid = bochs_connector_mode_valid ,
} ;
2015-12-15 12:21:01 +01:00
static const struct drm_connector_funcs bochs_connector_connector_funcs = {
2013-12-17 18:04:46 +01:00
. dpms = drm_helper_connector_dpms ,
. fill_modes = drm_helper_probe_single_connector_modes ,
. destroy = drm_connector_cleanup ,
2019-01-11 06:37:41 +01:00
. reset = drm_atomic_helper_connector_reset ,
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
2013-12-17 18:04:46 +01:00
} ;
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 ) ;
2014-09-19 10:11:37 +02:00
drm_connector_register ( connector ) ;
2018-10-29 21:50:48 +01:00
bochs_hw_load_edid ( bochs ) ;
if ( bochs - > edid ) {
DRM_INFO ( " Found EDID data blob. \n " ) ;
drm_connector_attach_edid_property ( connector ) ;
drm_connector_update_edid_property ( connector , bochs - > edid ) ;
}
2013-12-17 18:04:46 +01:00
}
2019-01-11 06:37:52 +01:00
static struct drm_framebuffer *
bochs_gem_fb_create ( struct drm_device * dev , struct drm_file * file ,
const struct drm_mode_fb_cmd2 * mode_cmd )
{
if ( mode_cmd - > pixel_format ! = DRM_FORMAT_XRGB8888 & &
mode_cmd - > pixel_format ! = DRM_FORMAT_BGRX8888 )
return ERR_PTR ( - EINVAL ) ;
return drm_gem_fb_create ( dev , file , mode_cmd ) ;
}
const struct drm_mode_config_funcs bochs_mode_funcs = {
. fb_create = bochs_gem_fb_create ,
. atomic_check = drm_atomic_helper_check ,
. atomic_commit = drm_atomic_helper_commit ,
} ;
2013-12-17 18:04:46 +01:00
int bochs_kms_init ( struct bochs_device * bochs )
{
drm_mode_config_init ( bochs - > dev ) ;
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 ;
2018-09-21 15:47:01 +02:00
bochs - > dev - > mode_config . quirk_addfb_prefer_host_byte_order = true ;
2013-12-17 18:04:46 +01:00
2015-12-15 12:21:01 +01:00
bochs - > dev - > mode_config . funcs = & bochs_mode_funcs ;
2013-12-17 18:04:46 +01:00
bochs_connector_init ( bochs - > dev ) ;
2019-04-10 09:48:28 +02:00
drm_simple_display_pipe_init ( bochs - > dev ,
& bochs - > pipe ,
& bochs_pipe_funcs ,
bochs_formats ,
ARRAY_SIZE ( bochs_formats ) ,
NULL ,
& bochs - > connector ) ;
2013-12-17 18:04:46 +01:00
2019-01-11 06:37:41 +01:00
drm_mode_config_reset ( bochs - > dev ) ;
2013-12-17 18:04:46 +01:00
return 0 ;
}
void bochs_kms_fini ( struct bochs_device * bochs )
{
2019-04-02 11:04:58 +02:00
drm_atomic_helper_shutdown ( bochs - > dev ) ;
drm_mode_config_cleanup ( bochs - > dev ) ;
2013-12-17 18:04:46 +01:00
}