2019-05-31 01:09:37 -07:00
/* SPDX-License-Identifier: GPL-2.0-only */
2012-04-17 15:01:25 +01:00
/*
* Copyright 2010 Matt Turner .
2019-05-08 10:26:24 +02:00
* Copyright 2012 Red Hat
2012-04-17 15:01:25 +01:00
*
* Authors : Matthew Garrett
* Matt Turner
* Dave Airlie
*/
# ifndef __MGAG200_DRV_H__
# define __MGAG200_DRV_H__
2019-06-23 12:35:42 +02:00
# include <linux/i2c-algo-bit.h>
# include <linux/i2c.h>
2012-04-17 15:01:25 +01:00
# include <video/vga.h>
2022-07-28 14:40:56 +02:00
# include <drm/drm_connector.h>
# include <drm/drm_crtc.h>
2016-11-28 20:51:09 +02:00
# include <drm/drm_encoder.h>
2014-09-23 15:46:53 +02:00
# include <drm/drm_gem.h>
2020-05-15 10:32:33 +02:00
# include <drm/drm_gem_shmem_helper.h>
2022-07-28 14:40:56 +02:00
# include <drm/drm_plane.h>
2019-05-08 10:26:25 +02:00
2012-04-17 15:01:25 +01:00
# include "mgag200_reg.h"
# define DRIVER_AUTHOR "Matthew Garrett"
# define DRIVER_NAME "mgag200"
# define DRIVER_DESC "MGA G200 SE"
# define DRIVER_DATE "20110418"
# define DRIVER_MAJOR 1
# define DRIVER_MINOR 0
# define DRIVER_PATCHLEVEL 0
# define RREG8(reg) ioread8(((void __iomem *)mdev->rmmio) + (reg))
# define WREG8(reg, v) iowrite8(v, ((void __iomem *)mdev->rmmio) + (reg))
# define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg))
# define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg))
2020-07-30 12:28:44 +02:00
# define MGA_BIOS_OFFSET 0x7ffc
2012-04-17 15:01:25 +01:00
# define ATTR_INDEX 0x1fc0
# define ATTR_DATA 0x1fc1
2021-07-14 16:22:28 +02:00
# define WREG_MISC(v) \
WREG8 ( MGA_MISC_OUT , v )
# define RREG_MISC(v) \
( ( v ) = RREG8 ( MGA_MISC_IN ) )
# define WREG_MISC_MASKED(v, mask) \
do { \
u8 misc_ ; \
u8 mask_ = ( mask ) ; \
RREG_MISC ( misc_ ) ; \
misc_ & = ~ mask_ ; \
misc_ | = ( ( v ) & mask_ ) ; \
WREG_MISC ( misc_ ) ; \
} while ( 0 )
2012-04-17 15:01:25 +01:00
# define WREG_ATTR(reg, v) \
do { \
RREG8 ( 0x1fda ) ; \
WREG8 ( ATTR_INDEX , reg ) ; \
WREG8 ( ATTR_DATA , v ) ; \
} while ( 0 ) \
2020-05-15 10:32:27 +02:00
# define RREG_SEQ(reg, v) \
do { \
WREG8 ( MGAREG_SEQ_INDEX , reg ) ; \
v = RREG8 ( MGAREG_SEQ_DATA ) ; \
} while ( 0 ) \
2012-04-17 15:01:25 +01:00
# define WREG_SEQ(reg, v) \
do { \
WREG8 ( MGAREG_SEQ_INDEX , reg ) ; \
WREG8 ( MGAREG_SEQ_DATA , v ) ; \
} while ( 0 ) \
2020-07-07 10:24:05 +02:00
# define RREG_CRT(reg, v) \
do { \
WREG8 ( MGAREG_CRTC_INDEX , reg ) ; \
v = RREG8 ( MGAREG_CRTC_DATA ) ; \
} while ( 0 ) \
2012-04-17 15:01:25 +01:00
# define WREG_CRT(reg, v) \
do { \
WREG8 ( MGAREG_CRTC_INDEX , reg ) ; \
WREG8 ( MGAREG_CRTC_DATA , v ) ; \
} while ( 0 ) \
2020-05-15 10:32:20 +02:00
# define RREG_ECRT(reg, v) \
do { \
WREG8 ( MGAREG_CRTCEXT_INDEX , reg ) ; \
v = RREG8 ( MGAREG_CRTCEXT_DATA ) ; \
} while ( 0 ) \
2012-04-17 15:01:25 +01:00
# define WREG_ECRT(reg, v) \
do { \
WREG8 ( MGAREG_CRTCEXT_INDEX , reg ) ; \
WREG8 ( MGAREG_CRTCEXT_DATA , v ) ; \
} while ( 0 ) \
# define GFX_INDEX 0x1fce
# define GFX_DATA 0x1fcf
# define WREG_GFX(reg, v) \
do { \
WREG8 ( GFX_INDEX , reg ) ; \
WREG8 ( GFX_DATA , v ) ; \
} while ( 0 ) \
# define DAC_INDEX 0x3c00
# define DAC_DATA 0x3c0a
# define WREG_DAC(reg, v) \
do { \
WREG8 ( DAC_INDEX , reg ) ; \
WREG8 ( DAC_DATA , v ) ; \
} while ( 0 ) \
# define MGA_MISC_OUT 0x1fc2
# define MGA_MISC_IN 0x1fcc
2022-07-28 14:40:51 +02:00
/*
* TODO : This is a pretty large set of default values for all kinds of
* settings . It should be split and set in the various DRM helpers ,
* such as the CRTC reset or atomic_enable helpers . The PLL values
* probably belong to each model ' s PLL code .
*/
# define MGAG200_DAC_DEFAULT(xvrefctrl, xpixclkctrl, xmiscctrl, xsyspllm, xsysplln, xsyspllp) \
/* 0x00: */ 0 , 0 , 0 , 0 , 0 , 0 , 0x00 , 0 , \
/* 0x08: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , \
/* 0x10: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , \
/* 0x18: */ ( xvrefctrl ) , \
/* 0x19: */ 0 , \
/* 0x1a: */ ( xpixclkctrl ) , \
/* 0x1b: */ 0xff , 0xbf , 0x20 , \
/* 0x1e: */ ( xmiscctrl ) , \
/* 0x1f: */ 0x20 , \
/* 0x20: */ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , \
/* 0x28: */ 0x00 , 0x00 , 0x00 , 0x00 , \
/* 0x2c: */ ( xsyspllm ) , \
/* 0x2d: */ ( xsysplln ) , \
/* 0x2e: */ ( xsyspllp ) , \
/* 0x2f: */ 0x40 , \
/* 0x30: */ 0x00 , 0xb0 , 0x00 , 0xc2 , 0x34 , 0x14 , 0x02 , 0x83 , \
/* 0x38: */ 0x00 , 0x93 , 0x00 , 0x77 , 0x00 , 0x00 , 0x00 , 0x3a , \
/* 0x40: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , \
/* 0x48: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 \
2022-07-28 14:41:01 +02:00
# define MGAG200_LUT_SIZE 256
2012-04-17 15:01:25 +01:00
# define MGAG200_MAX_FB_HEIGHT 4096
# define MGAG200_MAX_FB_WIDTH 4096
2021-07-14 16:22:37 +02:00
struct mga_device ;
2021-07-14 16:22:31 +02:00
/*
* Stores parameters for programming the PLLs
*
* Fref : reference frequency ( A : 25.175 Mhz , B : 28.361 , C : XX Mhz )
* Fo : output frequency
* Fvco = Fref * ( N / M )
* Fo = Fvco / P
*
* S = [ 0. .3 ]
*/
struct mgag200_pll_values {
unsigned int m ;
unsigned int n ;
unsigned int p ;
unsigned int s ;
} ;
2021-07-14 16:22:39 +02:00
struct mgag200_crtc_state {
struct drm_crtc_state base ;
2021-07-14 16:22:40 +02:00
2022-07-28 14:40:54 +02:00
/* Primary-plane format; required for modesetting and color mgmt. */
const struct drm_format_info * format ;
2021-07-14 16:22:40 +02:00
struct mgag200_pll_values pixpllc ;
2021-07-14 16:22:39 +02:00
} ;
static inline struct mgag200_crtc_state * to_mgag200_crtc_state ( struct drm_crtc_state * base )
{
return container_of ( base , struct mgag200_crtc_state , base ) ;
}
2012-04-17 15:01:25 +01:00
struct mga_i2c_chan {
struct i2c_adapter adapter ;
struct drm_device * dev ;
struct i2c_algo_bit_data bit ;
int data , clock ;
} ;
enum mga_type {
2020-07-30 12:28:44 +02:00
G200_PCI ,
G200_AGP ,
2012-04-17 15:01:25 +01:00
G200_SE_A ,
G200_SE_B ,
G200_WB ,
G200_EV ,
G200_EH ,
2016-10-21 12:47:07 -04:00
G200_EH3 ,
2012-04-17 15:01:25 +01:00
G200_ER ,
2015-08-21 09:24:05 -04:00
G200_EW3 ,
2012-04-17 15:01:25 +01:00
} ;
2022-06-01 13:25:18 +02:00
struct mgag200_device_info {
2022-06-01 13:25:20 +02:00
u16 max_hdisplay ;
u16 max_vdisplay ;
/*
* Maximum memory bandwidth ( MiB / sec ) . Setting this to zero disables
* the rsp test during mode validation .
*/
unsigned long max_mem_bandwidth ;
2022-06-01 13:25:21 +02:00
/* HW has external source (e.g., BMC) to synchronize with */
bool has_vidrst : 1 ;
2022-06-01 13:25:22 +02:00
struct {
unsigned data_bit : 3 ;
unsigned clock_bit : 3 ;
} i2c ;
2022-06-01 13:25:19 +02:00
/*
* HW does not handle ' startadd ' register correctly . Always set
* it ' s value to 0.
*/
bool bug_no_startadd : 1 ;
2022-06-01 13:25:18 +02:00
} ;
2022-06-01 13:25:20 +02:00
# define MGAG200_DEVICE_INFO_INIT(_max_hdisplay, _max_vdisplay, _max_mem_bandwidth, \
2022-06-01 13:25:22 +02:00
_has_vidrst , _i2c_data_bit , _i2c_clock_bit , \
_bug_no_startadd ) \
2022-06-01 13:25:18 +02:00
{ \
2022-06-01 13:25:20 +02:00
. max_hdisplay = ( _max_hdisplay ) , \
. max_vdisplay = ( _max_vdisplay ) , \
. max_mem_bandwidth = ( _max_mem_bandwidth ) , \
2022-06-01 13:25:21 +02:00
. has_vidrst = ( _has_vidrst ) , \
2022-06-01 13:25:22 +02:00
. i2c = { \
. data_bit = ( _i2c_data_bit ) , \
. clock_bit = ( _i2c_clock_bit ) , \
} , \
2022-06-01 13:25:19 +02:00
. bug_no_startadd = ( _bug_no_startadd ) , \
2022-06-01 13:25:18 +02:00
}
2022-07-28 14:40:58 +02:00
struct mgag200_device_funcs {
2022-07-28 14:40:59 +02:00
/*
* Disables an external reset source ( i . e . , BMC ) before programming
* a new display mode .
*/
void ( * disable_vidrst ) ( struct mga_device * mdev ) ;
/*
* Enables an external reset source ( i . e . , BMC ) after programming
* a new display mode .
*/
void ( * enable_vidrst ) ( struct mga_device * mdev ) ;
2022-07-28 14:41:00 +02:00
/*
* Validate that the given state can be programmed into PIXPLLC . On
* success , the calculated parameters should be stored in the CRTC ' s
* state in struct @ mgag200_crtc_state . pixpllc .
*/
int ( * pixpllc_atomic_check ) ( struct drm_crtc * crtc , struct drm_atomic_state * new_state ) ;
/*
* Program PIXPLLC from the CRTC state . The parameters should have been
* stored in struct @ mgag200_crtc_state . pixpllc by the corresponding
* implementation of @ pixpllc_atomic_check .
*/
void ( * pixpllc_atomic_update ) ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
2022-07-28 14:40:58 +02:00
} ;
2012-04-17 15:01:25 +01:00
struct mga_device {
2022-06-01 13:25:19 +02:00
struct drm_device base ;
2012-04-17 15:01:25 +01:00
2022-06-01 13:25:18 +02:00
const struct mgag200_device_info * info ;
2022-07-28 14:40:58 +02:00
const struct mgag200_device_funcs * funcs ;
2022-06-01 13:25:18 +02:00
2022-06-01 13:25:17 +02:00
struct resource * rmmio_res ;
2012-04-17 15:01:25 +01:00
void __iomem * rmmio ;
2022-06-01 13:25:17 +02:00
struct mutex rmmio_lock ; /* Protects access to rmmio */
2012-04-17 15:01:25 +01:00
2022-06-01 13:25:17 +02:00
struct resource * vram_res ;
2020-05-15 10:32:33 +02:00
void __iomem * vram ;
2022-06-01 13:25:16 +02:00
resource_size_t vram_available ;
2019-09-27 11:13:00 +02:00
2022-07-28 14:40:56 +02:00
struct drm_plane primary_plane ;
struct drm_crtc crtc ;
struct drm_encoder encoder ;
2022-05-16 15:43:40 +02:00
struct mga_i2c_chan i2c ;
2022-05-16 15:43:41 +02:00
struct drm_connector connector ;
2012-04-17 15:01:25 +01:00
} ;
2020-05-07 11:03:10 +02:00
static inline struct mga_device * to_mga_device ( struct drm_device * dev )
{
2020-06-05 15:58:02 +02:00
return container_of ( dev , struct mga_device , base ) ;
2020-05-07 11:03:10 +02:00
}
2022-06-01 13:25:14 +02:00
struct mgag200_g200_device {
struct mga_device base ;
/* PLL constants */
long ref_clk ;
long pclk_min ;
long pclk_max ;
} ;
static inline struct mgag200_g200_device * to_mgag200_g200_device ( struct drm_device * dev )
{
return container_of ( to_mga_device ( dev ) , struct mgag200_g200_device , base ) ;
}
struct mgag200_g200se_device {
struct mga_device base ;
/* SE model number stored in reg 0x1e24 */
u32 unique_rev_id ;
} ;
static inline struct mgag200_g200se_device * to_mgag200_g200se_device ( struct drm_device * dev )
{
return container_of ( to_mga_device ( dev ) , struct mgag200_g200se_device , base ) ;
}
/* mgag200_drv.c */
2022-06-01 13:25:15 +02:00
int mgag200_init_pci_options ( struct pci_dev * pdev , u32 option , u32 option2 ) ;
2022-06-01 13:25:16 +02:00
resource_size_t mgag200_probe_vram ( void __iomem * mem , resource_size_t size ) ;
2022-06-01 13:25:17 +02:00
resource_size_t mgag200_device_probe_vram ( struct mga_device * mdev ) ;
int mgag200_device_preinit ( struct mga_device * mdev ) ;
2022-07-28 14:41:03 +02:00
int mgag200_device_init ( struct mga_device * mdev ,
2022-07-28 14:40:58 +02:00
const struct mgag200_device_info * info ,
const struct mgag200_device_funcs * funcs ) ;
2022-06-01 13:25:14 +02:00
/* mgag200_<device type>.c */
2022-07-28 14:41:03 +02:00
struct mga_device * mgag200_g200_device_create ( struct pci_dev * pdev , const struct drm_driver * drv ) ;
2022-06-01 13:25:14 +02:00
struct mga_device * mgag200_g200se_device_create ( struct pci_dev * pdev , const struct drm_driver * drv ,
2022-06-01 13:25:19 +02:00
enum mga_type type ) ;
2022-07-28 14:40:51 +02:00
void mgag200_g200wb_init_registers ( struct mga_device * mdev ) ;
2022-07-28 14:41:00 +02:00
void mgag200_g200wb_pixpllc_atomic_update ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
2022-07-28 14:41:03 +02:00
struct mga_device * mgag200_g200wb_device_create ( struct pci_dev * pdev , const struct drm_driver * drv ) ;
struct mga_device * mgag200_g200ev_device_create ( struct pci_dev * pdev , const struct drm_driver * drv ) ;
2022-07-28 14:40:51 +02:00
void mgag200_g200eh_init_registers ( struct mga_device * mdev ) ;
2022-07-28 14:41:00 +02:00
void mgag200_g200eh_pixpllc_atomic_update ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
2022-07-28 14:41:03 +02:00
struct mga_device * mgag200_g200eh_device_create ( struct pci_dev * pdev ,
const struct drm_driver * drv ) ;
struct mga_device * mgag200_g200eh3_device_create ( struct pci_dev * pdev ,
const struct drm_driver * drv ) ;
struct mga_device * mgag200_g200er_device_create ( struct pci_dev * pdev ,
const struct drm_driver * drv ) ;
struct mga_device * mgag200_g200ew3_device_create ( struct pci_dev * pdev ,
const struct drm_driver * drv ) ;
2022-06-01 13:25:14 +02:00
2022-07-28 14:41:01 +02:00
/*
* mgag200_mode . c
*/
struct drm_crtc ;
struct drm_crtc_state ;
struct drm_display_mode ;
struct drm_plane ;
struct drm_atomic_state ;
extern const uint32_t mgag200_primary_plane_formats [ ] ;
extern const size_t mgag200_primary_plane_formats_size ;
extern const uint64_t mgag200_primary_plane_fmtmods [ ] ;
int mgag200_primary_plane_helper_atomic_check ( struct drm_plane * plane ,
struct drm_atomic_state * new_state ) ;
void mgag200_primary_plane_helper_atomic_update ( struct drm_plane * plane ,
struct drm_atomic_state * old_state ) ;
2023-02-09 16:41:05 +01:00
void mgag200_primary_plane_helper_atomic_enable ( struct drm_plane * plane ,
struct drm_atomic_state * state ) ;
2022-07-28 14:41:01 +02:00
void mgag200_primary_plane_helper_atomic_disable ( struct drm_plane * plane ,
struct drm_atomic_state * old_state ) ;
# define MGAG200_PRIMARY_PLANE_HELPER_FUNCS \
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS , \
. atomic_check = mgag200_primary_plane_helper_atomic_check , \
. atomic_update = mgag200_primary_plane_helper_atomic_update , \
2023-02-09 16:41:05 +01:00
. atomic_enable = mgag200_primary_plane_helper_atomic_enable , \
2022-07-28 14:41:01 +02:00
. atomic_disable = mgag200_primary_plane_helper_atomic_disable
# define MGAG200_PRIMARY_PLANE_FUNCS \
. update_plane = drm_atomic_helper_update_plane , \
. disable_plane = drm_atomic_helper_disable_plane , \
. destroy = drm_plane_cleanup , \
DRM_GEM_SHADOW_PLANE_FUNCS
enum drm_mode_status mgag200_crtc_helper_mode_valid ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode ) ;
int mgag200_crtc_helper_atomic_check ( struct drm_crtc * crtc , struct drm_atomic_state * new_state ) ;
void mgag200_crtc_helper_atomic_flush ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
void mgag200_crtc_helper_atomic_enable ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
void mgag200_crtc_helper_atomic_disable ( struct drm_crtc * crtc , struct drm_atomic_state * old_state ) ;
# define MGAG200_CRTC_HELPER_FUNCS \
. mode_valid = mgag200_crtc_helper_mode_valid , \
. atomic_check = mgag200_crtc_helper_atomic_check , \
. atomic_flush = mgag200_crtc_helper_atomic_flush , \
. atomic_enable = mgag200_crtc_helper_atomic_enable , \
. atomic_disable = mgag200_crtc_helper_atomic_disable
void mgag200_crtc_reset ( struct drm_crtc * crtc ) ;
struct drm_crtc_state * mgag200_crtc_atomic_duplicate_state ( struct drm_crtc * crtc ) ;
void mgag200_crtc_atomic_destroy_state ( struct drm_crtc * crtc , struct drm_crtc_state * crtc_state ) ;
# define MGAG200_CRTC_FUNCS \
. reset = mgag200_crtc_reset , \
. destroy = drm_crtc_cleanup , \
. set_config = drm_atomic_helper_set_config , \
. page_flip = drm_atomic_helper_page_flip , \
. atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state , \
. atomic_destroy_state = mgag200_crtc_atomic_destroy_state
# define MGAG200_DAC_ENCODER_FUNCS \
. destroy = drm_encoder_cleanup
int mgag200_vga_connector_helper_get_modes ( struct drm_connector * connector ) ;
# define MGAG200_VGA_CONNECTOR_HELPER_FUNCS \
. get_modes = mgag200_vga_connector_helper_get_modes
# define MGAG200_VGA_CONNECTOR_FUNCS \
. reset = drm_atomic_helper_connector_reset , \
. fill_modes = drm_helper_probe_single_connector_modes , \
. destroy = drm_connector_cleanup , \
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state , \
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state
2022-07-28 14:41:02 +02:00
void mgag200_set_mode_regs ( struct mga_device * mdev , const struct drm_display_mode * mode ) ;
void mgag200_set_format_regs ( struct mga_device * mdev , const struct drm_format_info * format ) ;
void mgag200_enable_display ( struct mga_device * mdev ) ;
2022-07-28 14:40:51 +02:00
void mgag200_init_registers ( struct mga_device * mdev ) ;
2022-07-28 14:41:01 +02:00
int mgag200_mode_config_init ( struct mga_device * mdev , resource_size_t vram_available ) ;
2012-04-17 15:01:25 +01:00
2022-07-28 14:40:59 +02:00
/* mgag200_bmc.c */
void mgag200_bmc_disable_vidrst ( struct mga_device * mdev ) ;
void mgag200_bmc_enable_vidrst ( struct mga_device * mdev ) ;
2013-04-05 15:28:32 +00:00
/* mgag200_i2c.c */
2022-05-16 15:43:40 +02:00
int mgag200_i2c_init ( struct mga_device * mdev , struct mga_i2c_chan * i2c ) ;
2012-04-17 15:01:25 +01:00
# endif /* __MGAG200_DRV_H__ */